rbbcc 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0cafb82823139848b9c16a2182ef4ba3c86c391126700ee6cbb31ab0a427da85
4
- data.tar.gz: 711be4b7c0bf09879445d02b7bf0379b9c51dc186f56129227c416a0515e00ff
3
+ metadata.gz: 30e4967edcbc916ed8e11549202d7c6dd8283554e9d75a3e3f88ac1a58466110
4
+ data.tar.gz: 6668b27c98059c41509b33b9fe8d8effff4001a709df2b6ec944687f020591da
5
5
  SHA512:
6
- metadata.gz: 007c4273121411d6548b071fe48fda59c36af94a36c7de183a8fbacceba722c837115af8a2892ec79277957217b5152b58ec12ce4dd56c153293a2ac6fae9894
7
- data.tar.gz: 94da55a1738a534d0bffc95ac2ebabcb431e5ea98785506a0006e1d249b83d602f8bbcaec47890124afbf42a9a11f394f986b9795b194db0acb101a8d536ca26
6
+ metadata.gz: 8a08a60ce0dcd05c27be3388eb9e8fbe9c6cba7b877d0e55b0df348d6023586a90d4d4d7b52ec5312c2b8241fd1dbc09cd350153ecc6f9fc0fb852c1c89655a9
7
+ data.tar.gz: 689770db707201cc089c43fb4997a685c05af2b4d717c25c8891d4e5351909c9eb4c5ca0e8d19e86fe2a88e60e30dde1bd5a4eec359dc0e775ed39f32054e485
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbbcc (0.11.0)
4
+ rbbcc (0.11.2)
5
5
  fiddle
6
6
 
7
7
  GEM
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # pin_maps_a.rb
4
+ # Program A: create HashMap/ArrayMap, hook execve, count up, and pin maps.
5
+ #
6
+ # Usage (root):
7
+ # sudo ruby examples/pin_maps_a.rb --pin-dir /sys/fs/bpf/rbbcc_pin_demo
8
+
9
+ require 'rbbcc'
10
+ require 'optparse'
11
+ require 'fileutils'
12
+
13
+ include RbBCC
14
+
15
+ BPF_TEXT = <<~CLANG
16
+ BPF_HASH(pin_hash_map, u32, u64, 1024);
17
+ BPF_ARRAY(pin_array_map, u64, 1);
18
+
19
+ int trace_execve(void *ctx) {
20
+ u64 zero = 0;
21
+ u32 pid = bpf_get_current_pid_tgid();
22
+ u32 idx = 0;
23
+ u64 *hval;
24
+ u64 *aval;
25
+
26
+ hval = pin_hash_map.lookup_or_try_init(&pid, &zero);
27
+ if (hval) {
28
+ __sync_fetch_and_add(hval, 1);
29
+ }
30
+
31
+ aval = pin_array_map.lookup(&idx);
32
+ if (aval) {
33
+ __sync_fetch_and_add(aval, 1);
34
+ }
35
+
36
+ return 0;
37
+ }
38
+ CLANG
39
+
40
+ options = {
41
+ pin_dir: '/sys/fs/bpf/rbbcc_pin_demo'
42
+ }
43
+
44
+ OptionParser.new do |opts|
45
+ opts.banner = 'Usage: pin_maps_a.rb [options]'
46
+
47
+ opts.on('--pin-dir DIR', 'Pin directory under bpffs') do |v|
48
+ options[:pin_dir] = v
49
+ end
50
+ end.parse!
51
+
52
+ b = BCC.new(text: BPF_TEXT)
53
+ b.attach_kprobe(
54
+ event: b.get_syscall_fnname('execve'),
55
+ fn_name: 'trace_execve'
56
+ )
57
+
58
+ hash_map = b['pin_hash_map']
59
+ array_map = b['pin_array_map']
60
+
61
+ # Initialize global counter slot.
62
+ array_map[0] = 0
63
+
64
+ FileUtils.mkdir_p(options[:pin_dir])
65
+ hash_path = File.join(options[:pin_dir], 'pin_hash_map')
66
+ array_path = File.join(options[:pin_dir], 'pin_array_map')
67
+
68
+ File.unlink(hash_path) if File.exist?(hash_path)
69
+ File.unlink(array_path) if File.exist?(array_path)
70
+
71
+ BCC.pin!(hash_map.map_fd, hash_path)
72
+ BCC.pin!(array_map.map_fd, array_path)
73
+
74
+ puts 'Pinned maps created.'
75
+ puts " hash map: #{hash_path}"
76
+ puts " array map: #{array_path}"
77
+ puts 'kprobe attached to execve. Run some commands in another terminal.'
78
+ puts 'Press Ctrl-C to stop Program A.'
79
+
80
+ begin
81
+ loop do
82
+ sleep 1
83
+ total = array_map[0]&.to_bcc_value || 0
84
+ puts "execve total count: #{total}"
85
+ end
86
+ rescue Interrupt
87
+ puts '\nStopping Program A...'
88
+ end
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # pin_maps_b.rb
4
+ # Program B: open pinned HashMap/ArrayMap with from_pin and read/update values.
5
+ #
6
+ # Usage (root):
7
+ # sudo ruby examples/pin_maps_b.rb --pin-dir /sys/fs/bpf/rbbcc_pin_demo
8
+
9
+ require 'rbbcc'
10
+ require 'optparse'
11
+
12
+ include RbBCC
13
+
14
+ options = {
15
+ pin_dir: '/sys/fs/bpf/rbbcc_pin_demo'
16
+ }
17
+
18
+ OptionParser.new do |opts|
19
+ opts.banner = 'Usage: pin_maps_b.rb [options]'
20
+
21
+ opts.on('--pin-dir DIR', 'Pin directory under bpffs') do |v|
22
+ options[:pin_dir] = v
23
+ end
24
+ end.parse!
25
+
26
+ hash_path = File.join(options[:pin_dir], 'pin_hash_map')
27
+ array_path = File.join(options[:pin_dir], 'pin_array_map')
28
+
29
+ unless File.exist?(hash_path) && File.exist?(array_path)
30
+ abort("Pinned map files are missing. Run pin_maps_a.rb first: #{options[:pin_dir]}")
31
+ end
32
+
33
+ # Explicitly pass key/leaf type and size; no type detection is performed.
34
+ hash_map = HashTable.from_pin(
35
+ hash_path,
36
+ 'unsigned int',
37
+ 'unsigned long long',
38
+ keysize: 4,
39
+ leafsize: 8
40
+ )
41
+ array_map = ArrayTable.from_pin(
42
+ array_path,
43
+ 'unsigned int',
44
+ 'unsigned long long',
45
+ keysize: 4,
46
+ leafsize: 8
47
+ )
48
+
49
+ puts 'Loaded pinned maps.'
50
+ puts " hash map fd: #{hash_map.map_fd}"
51
+ puts " array map fd: #{array_map.map_fd}"
52
+ puts " hash ttype: #{hash_map.ttype}"
53
+ puts " array ttype: #{array_map.ttype}"
54
+
55
+ puts 'Read existing values:'
56
+ puts " hash[1] = #{hash_map[1]&.to_bcc_value.inspect}"
57
+ puts " hash[2] = #{hash_map[2]&.to_bcc_value.inspect}"
58
+ puts " array[0] = #{array_map[0]&.to_bcc_value.inspect}"
59
+ puts " array[1] = #{array_map[1]&.to_bcc_value.inspect}"
60
+
61
+ hash_map[3] = 1
62
+ array_map[0] = (array_map[0]&.to_bcc_value || 0) + 1
63
+
64
+ puts 'Updated values:'
65
+ puts " hash[3] = #{hash_map[3]&.to_bcc_value.inspect}"
66
+ puts " array[0] = #{array_map[0]&.to_bcc_value.inspect}"
67
+
68
+ puts 'Iterate hash entries:'
69
+ hash_map.each_pair do |k, v|
70
+ puts " #{k.to_bcc_value} => #{v.to_bcc_value}"
71
+ end
data/lib/rbbcc/bcc.rb CHANGED
@@ -242,6 +242,7 @@ module RbBCC
242
242
  @uprobe_fds = {}
243
243
  @tracepoint_fds = {}
244
244
  @raw_tracepoint_fds = {}
245
+ @lsm_fds = {}
245
246
 
246
247
  if src_file
247
248
  src_file = BCC._find_file(src_file)
@@ -433,6 +434,34 @@ module RbBCC
433
434
  @tracepoint_fds.delete(tp)
434
435
  end
435
436
 
437
+ def attach_lsm(fn_name: "")
438
+ if @lsm_fds.keys.include?(fn_name)
439
+ raise "LSM #{fn_name} has been attached"
440
+ end
441
+
442
+ fn = load_func(fn_name, BPF::LSM)
443
+ fd = Clib.bpf_attach_lsm(fn[:fd])
444
+ if fd < 0
445
+ raise SystemCallError.new("Failed to attach LSM #{fn_name}", Fiddle.last_error)
446
+ end
447
+ Util.debug "Attach: #{fn_name}"
448
+ @lsm_fds[fn_name] = fd
449
+ self
450
+ end
451
+
452
+ def detach_lsm(fn_name)
453
+ unless @lsm_fds.keys.include?(fn_name)
454
+ raise "LSM #{fn_name} is not attached"
455
+ end
456
+
457
+ begin
458
+ File.for_fd(@lsm_fds[fn_name]).close
459
+ rescue => e
460
+ warn "Closing fd failed: #{e.inspect}. Ignore and skip"
461
+ end
462
+ @lsm_fds.delete(fn_name)
463
+ end
464
+
436
465
  def detach_kprobe_event(ev_name)
437
466
  unless @kprobe_fds.keys.include?(ev_name)
438
467
  raise "Event #{ev_name} not registered"
@@ -471,6 +500,10 @@ module RbBCC
471
500
  @tracepoint_fds.size
472
501
  end
473
502
 
503
+ def num_open_lsms
504
+ @lsm_fds.size
505
+ end
506
+
474
507
  def tracefile
475
508
  @tracefile ||= File.open("#{TRACEFS}/trace_pipe", "rb")
476
509
  end
@@ -528,6 +561,10 @@ module RbBCC
528
561
  detach_raw_tracepoint(k)
529
562
  end
530
563
 
564
+ @lsm_fds.each do |k, v|
565
+ detach_lsm(k)
566
+ end
567
+
531
568
  if @module
532
569
  Clib.bpf_module_destroy(@module)
533
570
  end
@@ -644,8 +681,7 @@ module RbBCC
644
681
  fn_name: fn[:name]
645
682
  )
646
683
  elsif func_name.start_with?("lsm__")
647
- # LSM_PROBE programs are attached by libbcc while loading.
648
- load_func(func_name, BPF::LSM)
684
+ attach_lsm(fn_name: func_name)
649
685
  end
650
686
  end
651
687
  end
data/lib/rbbcc/clib.rb CHANGED
@@ -114,6 +114,7 @@ module RbBCC
114
114
  extern 'int bpf_attach_tracepoint(int progfd, char *tp_category, char *tp_name)'
115
115
  extern 'int bpf_detach_tracepoint(char *tp_category, char *tp_name)'
116
116
  extern 'int bpf_attach_raw_tracepoint(int progfd, char *tp_name)'
117
+ extern 'int bpf_attach_lsm(int progfd)'
117
118
  extern 'int bpf_open_perf_event(unsigned int, unsigned long, int, int)'
118
119
  extern 'int bpf_close_perf_event_fd(int)'
119
120
  extern 'int bpf_get_first_key(int, void *, int)'
@@ -193,6 +194,7 @@ module RbBCC
193
194
  extern 'int bpf_open_raw_sock(const char *name)'
194
195
  extern 'int bpf_attach_socket(int sockfd, int progfd)'
195
196
  extern 'int bpf_obj_pin(int fd, const char *pathname)'
197
+ extern 'int bpf_obj_get(const char *pathname)'
196
198
  end
197
199
  end
198
200
 
data/lib/rbbcc/table.rb CHANGED
@@ -115,13 +115,36 @@ module RbBCC
115
115
  include CPUHelper
116
116
  include Enumerable
117
117
 
118
- def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
118
+ class << self
119
+ def from_pin(path, keytype, leaftype, keysize: nil, leafsize: nil, **kwargs)
120
+ map_fd = Clib.bpf_obj_get(path)
121
+ if map_fd < 0
122
+ raise SystemCallError.new("Could not open pinned map", Fiddle.last_error)
123
+ end
124
+
125
+ new(nil, nil, map_fd, keytype, leaftype,
126
+ keysize: keysize, leafsize: leafsize, **kwargs)
127
+ end
128
+ end
129
+
130
+ def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil, keysize: nil, leafsize: nil)
119
131
  @bpf, @map_id, @map_fd, @keysize, @leafsize = \
120
- bpf, map_id, map_fd, sizeof(keytype), sizeof(leaftype)
132
+ bpf, map_id, map_fd,
133
+ keysize || sizeof(keytype),
134
+ leafsize || sizeof(leaftype)
121
135
  @keytype = keytype
122
136
  @leaftype = leaftype
123
- @ttype = Clib.bpf_table_type_id(self.bpf.module, self.map_id)
124
- @flags = Clib.bpf_table_flags_id(self.bpf.module, self.map_id)
137
+ if @bpf
138
+ @ttype = Clib.bpf_table_type_id(self.bpf.module, self.map_id)
139
+ @flags = Clib.bpf_table_flags_id(self.bpf.module, self.map_id)
140
+ else
141
+ @ttype = case self
142
+ when HashTable
143
+ Table::BPF_MAP_TYPE_HASH
144
+ when ArrayTable
145
+ Table::BPF_MAP_TYPE_ARRAY
146
+ end
147
+ end
125
148
  @name = name
126
149
  end
127
150
  attr_reader :bpf, :map_id, :map_fd, :keysize, :keytype, :leafsize, :leaftype, :ttype, :flags, :name
@@ -275,7 +298,7 @@ module RbBCC
275
298
  leaf.bcc_value_type = leaftype
276
299
  leaf
277
300
  when Integer
278
- ret = byref(leaf, keysize)
301
+ ret = byref(leaf, leafsize)
279
302
  ret.bcc_value_type = leaftype
280
303
  ret
281
304
  else
@@ -300,9 +323,9 @@ module RbBCC
300
323
  end
301
324
 
302
325
  class ArrayTable < TableBase
303
- def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
326
+ def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil, keysize: nil, leafsize: nil)
304
327
  super
305
- @max_entries = Clib.bpf_table_max_entries_id(bpf.module, map_id)
328
+ @max_entries = Clib.bpf_table_max_entries_id(bpf.module, map_id) if bpf
306
329
  end
307
330
 
308
331
  # We now emulate the Array class of Ruby
data/lib/rbbcc/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RbBCC
2
- VERSION = "0.11.0"
2
+ VERSION = "0.11.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbbcc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uchio Kondo
@@ -96,6 +96,8 @@ files:
96
96
  - examples/mallocstack.rb
97
97
  - examples/networking/http_filter/http-parse-simple.c
98
98
  - examples/networking/http_filter/http-parse-simple.rb
99
+ - examples/pin_maps_a.rb
100
+ - examples/pin_maps_b.rb
99
101
  - examples/py-orig/sockblock.py
100
102
  - examples/ruby_usdt.rb
101
103
  - examples/sbrk_trace.rb