rbbcc 0.6.1 → 0.6.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: ebc0f160a61c94cd58882b81c3c58ecc99dfb6317e407cec2dc762c4babc3889
4
- data.tar.gz: 36aead215ae4146d841f787939432a7cdb12cb4ad7487c92dd2044b9c5123b47
3
+ metadata.gz: fb13ef05006088db3a3d16fdf3b5f444cd36a51c1d88278d5ddcb3ccb9e69663
4
+ data.tar.gz: 9cded3bc218135ef79af4376a8973dedad2e3614ab5c93f49850799842c0e5c2
5
5
  SHA512:
6
- metadata.gz: 84fe74378f90debecf862251d74b356dc8dde3f1a16da540bdca0255af8b2c7037053a78e0e1abc886014ee481a0320af05eda715976a774bd79dcd7d6d15b47
7
- data.tar.gz: 91f4de3770052fc2cd23406f41aaef3796facd018d4d746828532b17ccb00acb75f3b38a08920a2ec446381e16cf7642f6331410db8a05f0098fed6834e971ab
6
+ metadata.gz: a05af6a130f05942ce7f9901afc8d65434b7b5851483522f875ef3a9d75d1bcb30cafb1b8ce972feea2b273329e736182740d1cc99e561139d82fd1cccd297c4
7
+ data.tar.gz: '0938ed389aa2b4159618c2c79ebd841e9c74160a8b40877b54075dff9590713f6ccc1d67c27593c13bd0e1bf9fe57d4296eb1a7d58e7f357526de7144e0b8ba4'
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbbcc (0.6.1)
4
+ rbbcc (0.6.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- coderay (1.1.2)
10
- method_source (0.9.2)
11
- minitest (5.14.0)
12
- pry (0.12.2)
13
- coderay (~> 1.1.0)
14
- method_source (~> 0.9.0)
9
+ coderay (1.1.3)
10
+ method_source (1.0.0)
11
+ minitest (5.14.2)
12
+ pry (0.13.1)
13
+ coderay (~> 1.1)
14
+ method_source (~> 1.0)
15
15
  rake (13.0.1)
16
16
 
17
17
  PLATFORMS
@@ -42,5 +42,5 @@ end
42
42
  puts("%10s %s" % ["COUNT", "STRING"])
43
43
  counts = b.get_table("counts")
44
44
  counts.items.sort_by{|k, v| v.to_bcc_value }.each do |k, v|
45
- puts("%10d %s" % [v.to_bcc_value, k[0, k.size].unpack("Z*")[0]])
45
+ puts("%10d %s" % [v.to_bcc_value, k.to_bcc_value.c])
46
46
  end
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Example to use complecated structure in BPF Map key:
4
+ # This program collects and shows raw syscall usage summary.
5
+ #
6
+ # Usage:
7
+ # bundle exec ruby examples/collectsyscall.rb
8
+ #
9
+ # Output example:
10
+ # Collecting syscalls...
11
+ # ^C
12
+ # PID=1098(maybe: gmain) --->
13
+ # inotify_add_watch 4 0.019 ms
14
+ # poll 1 0.000 ms
15
+ #
16
+ # PID=1114(maybe: dbus-daemon) --->
17
+ # stat 12 0.021 ms
18
+ # openat 3 0.015 ms
19
+ # getdents 2 0.013 ms
20
+ # recvmsg 2 0.006 ms
21
+ # sendmsg 1 0.008 ms
22
+ # close 1 0.002 ms
23
+ # fstat 1 0.002 ms
24
+ # epoll_wait 1 0.000 ms
25
+ #
26
+ # PID=1175(maybe: memcached) --->
27
+ # epoll_wait 3 2012.455 ms
28
+ #
29
+ # PID=1213(maybe: redis-server) --->
30
+ # read 64 0.736 ms
31
+ # epoll_wait 32 3782.098 ms
32
+ # openat 32 1.149 ms
33
+ # getpid 32 0.074 ms
34
+ # close 32 0.045 ms
35
+ # ....
36
+
37
+ require 'rbbcc'
38
+ include RbBCC
39
+
40
+ $pid = nil
41
+
42
+ if ARGV.size == 2 &&
43
+ ARGV[0] == '-p'
44
+ $pid = ARGV[1].to_i
45
+ elsif ARGV[0] == '-h' ||
46
+ ARGV[0] == '--help'
47
+ $stderr.puts "Usage: #{$0} [-p PID]"
48
+ exit 1
49
+ end
50
+
51
+ SYSCALL_MAP = `ausyscall --dump`
52
+ .lines
53
+ .map{|l| l.chomp.split }
54
+ .each_with_object(Hash.new) {|(k, v), ha| ha[k.to_i] = v }
55
+
56
+ # if no ausyscall(8) then shows number itself
57
+ # it is included in auditd package (e.g. Ubuntu)
58
+ def to_name(nr)
59
+ SYSCALL_MAP[nr] || nr.to_s
60
+ end
61
+
62
+ prog = <<BPF
63
+ #include <uapi/linux/ptrace.h>
64
+
65
+ struct key_t {
66
+ u32 pid;
67
+ u64 syscall_nr;
68
+ };
69
+ struct leaf_t{
70
+ u64 count;
71
+ u64 elapsed_ns;
72
+ u64 enter_ns;
73
+ char comm[16];
74
+ };
75
+ BPF_HASH(store, struct key_t, struct leaf_t);
76
+
77
+ TRACEPOINT_PROBE(raw_syscalls, sys_enter) {
78
+ struct key_t key = {0};
79
+ struct leaf_t initial = {0}, *val_;
80
+
81
+ key.pid = bpf_get_current_pid_tgid();
82
+ key.syscall_nr = args->id;
83
+
84
+ DO_FILTER_BY_PID
85
+
86
+ val_ = store.lookup_or_try_init(&key, &initial);
87
+ if (val_) {
88
+ struct leaf_t val = *val_;
89
+ val.count++;
90
+ val.enter_ns = bpf_ktime_get_ns();
91
+ bpf_get_current_comm(&val.comm, sizeof(val.comm));
92
+ store.update(&key, &val);
93
+ }
94
+ return 0;
95
+ }
96
+
97
+ TRACEPOINT_PROBE(raw_syscalls, sys_exit) {
98
+ struct key_t key = {0};
99
+ struct leaf_t *val_;
100
+
101
+ key.pid = bpf_get_current_pid_tgid();
102
+ key.syscall_nr = args->id;
103
+
104
+ val_ = store.lookup(&key);
105
+ if (val_) {
106
+ struct leaf_t val = *val_;
107
+ u64 delta = bpf_ktime_get_ns() - val.enter_ns;
108
+ val.enter_ns = 0;
109
+ val.elapsed_ns += delta;
110
+ store.update(&key, &val);
111
+ }
112
+ return 0;
113
+ }
114
+ BPF
115
+
116
+ if $pid
117
+ prog.sub!('DO_FILTER_BY_PID', <<~FILTER)
118
+ if (key.pid != #{$pid}) return 0;
119
+ FILTER
120
+ else
121
+ prog.sub!('DO_FILTER_BY_PID', '')
122
+ end
123
+
124
+ b = BCC.new(text: prog)
125
+
126
+ puts "Collecting syscalls..."
127
+ begin
128
+ sleep(99999999)
129
+ rescue Interrupt
130
+ puts
131
+ end
132
+
133
+ info_by_pids = {}
134
+ comms = {}
135
+ store = b.get_table("store")
136
+ store.items.each do |k, v|
137
+ # require 'pry'; binding.pry
138
+ info_by_pids[k.pid] ||= {}
139
+ info_by_pids[k.pid][k.syscall_nr] = {
140
+ name: to_name(k.syscall_nr),
141
+ count: v.count,
142
+ elapsed_ms: v.elapsed_ns / 1000000.0
143
+ }
144
+ comms[k.pid] ||= v.comm
145
+ end
146
+
147
+ pids = info_by_pids.keys.sort
148
+ pids.each do |pid|
149
+ puts "PID=#{pid}(maybe: #{comms[pid]}) --->"
150
+ i = info_by_pids[pid]
151
+ i.to_a.sort_by {|k, v| [-v[:count], -v[:elapsed_ms]] }.each do |nr, record|
152
+ puts "\t%<name>-20s %<count>3d %<elapsed_ms>8.3f ms" % record
153
+ end
154
+ puts
155
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ binpath = File.readlink "/proc/self/exe"
4
+ exec binpath, *ARGV
@@ -121,7 +121,6 @@ module RbBCC
121
121
 
122
122
  def decode_table_type(desc)
123
123
  return desc if desc.is_a?(String)
124
-
125
124
  anon = []
126
125
  fields = []
127
126
  # e.g. ["bpf_stacktrace", [["ip", "unsigned long long", [127]]], "struct_packed"]
@@ -153,11 +152,37 @@ module RbBCC
153
152
  raise("Failed to decode type #{field.inspect}")
154
153
  end
155
154
  end
155
+ c = nil
156
156
  if data_type == "union"
157
- return Fiddle::Importer.union(fields)
157
+ c = Fiddle::Importer.union(fields)
158
158
  else
159
- return Fiddle::Importer.struct(fields)
159
+ c = Fiddle::Importer.struct(fields)
160
+ end
161
+
162
+ fields.each do |field|
163
+ md = /^char\[(\d+)\] ([_a-zA-Z0-9]+)/.match(field)
164
+ if md
165
+ c.alias_method "__super_#{md[2]}", md[2]
166
+ c.define_method md[2] do
167
+ # Split the char[] in the place where the first \0 appears
168
+ raw = __send__("__super_#{md[2]}")
169
+ raw = raw[0...raw.index(0)] if raw.index(0)
170
+ raw.pack("c*")
171
+ end
172
+ end
173
+ end
174
+
175
+ c.define_singleton_method :original_desc do
176
+ desc
177
+ end
178
+ c.define_singleton_method :fields do
179
+ fields
180
+ end
181
+ orig_name = c.inspect
182
+ c.define_singleton_method :inspect do
183
+ orig_name.sub /(?=>$)/, " original_desc=#{desc.inspect}" rescue super
160
184
  end
185
+ c
161
186
  end
162
187
 
163
188
  def sym(addr, pid, show_module: false, show_offset: false, demangle: true)
@@ -25,7 +25,7 @@ module RbBCC
25
25
  end
26
26
 
27
27
  extend Fiddle::Importer
28
- targets = %w(0.14.0 0.13.0 0.12.0 0.11.0 0.10.0)
28
+ targets = %w(0.17.0 0.16.0 0.15.0 0.14.0 0.13.0 0.12.0 0.11.0 0.10.0)
29
29
  if default_load = ENV['LIBBCC_VERSION']
30
30
  targets.unshift(default_load)
31
31
  targets.uniq!
@@ -2,8 +2,17 @@ require 'fiddle'
2
2
  require 'fiddle/import'
3
3
 
4
4
  class Fiddle::Pointer
5
- def to_bcc_value
6
- case self.size
5
+ def bcc_value
6
+ @bcc_value ||= _bcc_value
7
+ end
8
+ alias to_bcc_value bcc_value
9
+
10
+ def _bcc_value
11
+ if self.bcc_value_type.is_a?(Class)
12
+ return self.bcc_value_type.new(self)
13
+ end
14
+
15
+ case self.bcc_size
7
16
  when Fiddle::Importer.sizeof("int")
8
17
  self[0, self.size].unpack("i!").first
9
18
  when Fiddle::Importer.sizeof("long")
@@ -12,4 +21,27 @@ class Fiddle::Pointer
12
21
  self[0, self.size].unpack("Z*").first
13
22
  end
14
23
  end
24
+
25
+ def method_missing(name, *a)
26
+ fields = \
27
+ if self.respond_to?(:bcc_value_type) && \
28
+ self.bcc_value_type.respond_to?(:fields)
29
+ self.bcc_value_type.fields.map{|v| v.split.last.to_sym }
30
+ else
31
+ nil
32
+ end
33
+ return super unless fields
34
+
35
+ if fields.include?(name) && bcc_value.respond_to?(name)
36
+ bcc_value.send(name)
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ attr_accessor :bcc_value_type
43
+ attr_writer :bcc_size
44
+ def bcc_size
45
+ @bcc_size || self.size
46
+ end
15
47
  end
@@ -50,12 +50,13 @@ module RbBCC
50
50
  def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
51
51
  @bpf, @map_id, @map_fd, @keysize, @leafsize = \
52
52
  bpf, map_id, map_fd, sizeof(keytype), sizeof(leaftype)
53
+ @keytype = keytype
53
54
  @leaftype = leaftype
54
55
  @ttype = Clib.bpf_table_type_id(self.bpf.module, self.map_id)
55
56
  @flags = Clib.bpf_table_flags_id(self.bpf.module, self.map_id)
56
57
  @name = name
57
58
  end
58
- attr_reader :bpf, :map_id, :map_fd, :keysize, :leafsize, :leaftype, :ttype, :flags, :name
59
+ attr_reader :bpf, :map_id, :map_fd, :keysize, :keytype, :leafsize, :leaftype, :ttype, :flags, :name
59
60
 
60
61
  def next(key)
61
62
  next_key = Fiddle::Pointer.malloc(self.keysize)
@@ -86,6 +87,7 @@ module RbBCC
86
87
  if res < 0
87
88
  nil
88
89
  end
90
+ leaf.bcc_value_type = leaftype
89
91
  return leaf
90
92
  end
91
93
 
@@ -93,8 +95,9 @@ module RbBCC
93
95
  self[key] || raise(KeyError, "key not found")
94
96
  end
95
97
 
96
- def []=(_key, leaf)
98
+ def []=(_key, _leaf)
97
99
  key = normalize_key(_key)
100
+ leaf = normalize_leaf(_leaf)
98
101
  res = Clib.bpf_update_elem(self.map_fd, key, leaf, 0)
99
102
  if res < 0
100
103
  raise SystemCallError.new("Could not update table", Fiddle.last_error)
@@ -186,11 +189,29 @@ module RbBCC
186
189
  def normalize_key(key)
187
190
  case key
188
191
  when Fiddle::Pointer
192
+ key.bcc_value_type = keytype
193
+ key.bcc_size = keysize
189
194
  key
190
195
  when Integer
191
- byref(key, keysize)
196
+ ret = byref(key, keysize)
197
+ ret.bcc_value_type = keytype
198
+ ret
192
199
  else
193
- raise KeyError, "#{key.inspect} must be integer or pointor"
200
+ raise ArgumentError, "#{key.inspect} must be integer or pointor"
201
+ end
202
+ end
203
+
204
+ def normalize_leaf(leaf)
205
+ case leaf
206
+ when Fiddle::Pointer
207
+ leaf.bcc_value_type = leaftype
208
+ leaf
209
+ when Integer
210
+ ret = byref(leaf, keysize)
211
+ ret.bcc_value_type = leaftype
212
+ ret
213
+ else
214
+ raise KeyError, "#{leaf.inspect} must be integer or pointor"
194
215
  end
195
216
  end
196
217
 
@@ -202,6 +223,7 @@ module RbBCC
202
223
  end
203
224
  ptr = Fiddle::Pointer.malloc(size)
204
225
  ptr[0, size] = [value].pack(pack_fmt)
226
+ ptr.bcc_size = size
205
227
  ptr
206
228
  end
207
229
  end
@@ -1,3 +1,3 @@
1
1
  module RbBCC
2
- VERSION = "0.6.1"
2
+ VERSION = "0.6.2"
3
3
  end
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
19
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
20
  end
21
- #spec.bindir = "exe"
22
- #spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
  end
metadata CHANGED
@@ -1,19 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbbcc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uchio Kondo
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-14 00:00:00.000000000 Z
11
+ date: 2020-11-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: BCC port for MRI. See https://github.com/iovisor/bcc
14
14
  email:
15
15
  - udzura@udzura.jp
16
- executables: []
16
+ executables:
17
+ - rbbcc
17
18
  extensions: []
18
19
  extra_rdoc_files: []
19
20
  files:
@@ -56,6 +57,7 @@ files:
56
57
  - examples/charty/Gemfile
57
58
  - examples/charty/Gemfile.lock
58
59
  - examples/charty/bitehist-unicode.rb
60
+ - examples/collectsyscall.rb
59
61
  - examples/dddos.rb
60
62
  - examples/disksnoop.rb
61
63
  - examples/example.gif
@@ -76,6 +78,7 @@ files:
76
78
  - examples/urandomread.rb
77
79
  - examples/usdt-test.rb
78
80
  - examples/usdt.rb
81
+ - exe/rbbcc
79
82
  - lib/rbbcc.rb
80
83
  - lib/rbbcc/bcc.rb
81
84
  - lib/rbbcc/clib.rb