rbbcc 0.3.0 → 0.5.0
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 +4 -4
- data/.gitignore +5 -1
- data/.semaphore/semaphore.yml +19 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +6 -4
- data/README.md +5 -1
- data/Rakefile +8 -1
- data/docs/README.md +2 -0
- data/docs/answers/01-hello-world.rb +16 -0
- data/docs/answers/02-sys_sync.rb +18 -0
- data/docs/answers/03-hello_fields.rb +33 -0
- data/docs/answers/04-sync_timing.rb +46 -0
- data/docs/answers/05-sync_count.rb +54 -0
- data/docs/answers/06-disksnoop.rb +71 -0
- data/docs/answers/07-hello_perf_output.rb +59 -0
- data/docs/answers/08-sync_perf_output.rb +60 -0
- data/docs/answers/09-bitehist.rb +32 -0
- data/docs/answers/10-disklatency.rb +51 -0
- data/docs/answers/11-vfsreadlat.c +46 -0
- data/docs/answers/11-vfsreadlat.rb +66 -0
- data/docs/answers/12-urandomread.rb +38 -0
- data/docs/answers/13-disksnoop_fixed.rb +108 -0
- data/docs/answers/14-strlen_count.rb +46 -0
- data/docs/answers/15-nodejs_http_server.rb +44 -0
- data/docs/answers/16-task_switch.c +23 -0
- data/docs/answers/16-task_switch.rb +17 -0
- data/docs/answers/node-server.js +11 -0
- data/docs/projects_using_rbbcc.md +43 -0
- data/docs/tutorial_bcc_ruby_developer.md +774 -0
- data/docs/tutorial_bcc_ruby_developer_japanese.md +770 -0
- data/examples/networking/http_filter/http-parse-simple.c +114 -0
- data/examples/networking/http_filter/http-parse-simple.rb +85 -0
- data/examples/ruby_usdt.rb +105 -0
- data/examples/sbrk_trace.rb +204 -0
- data/lib/rbbcc/bcc.rb +67 -20
- data/lib/rbbcc/clib.rb +23 -10
- data/lib/rbbcc/debug.rb +17 -0
- data/lib/rbbcc/table.rb +36 -16
- data/lib/rbbcc/usdt.rb +21 -4
- data/lib/rbbcc/version.rb +1 -1
- data/rbbcc.gemspec +1 -4
- data/semaphore.sh +73 -0
- metadata +34 -46
data/lib/rbbcc/bcc.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rbbcc/consts'
|
2
2
|
require 'rbbcc/table'
|
3
3
|
require 'rbbcc/symbol_cache'
|
4
|
+
require 'rbbcc/debug'
|
4
5
|
|
5
6
|
module RbBCC
|
6
7
|
SYSCALL_PREFIXES = [
|
@@ -14,6 +15,20 @@ module RbBCC
|
|
14
15
|
|
15
16
|
class BCC
|
16
17
|
class << self
|
18
|
+
def _find_file(filename)
|
19
|
+
if filename
|
20
|
+
unless File.exist?(filename)
|
21
|
+
t = File.expand_path "../#{filename}", $0
|
22
|
+
if File.exist?(t)
|
23
|
+
filename = t
|
24
|
+
else
|
25
|
+
raise "Could not find file #{filename}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
return filename
|
30
|
+
end
|
31
|
+
|
17
32
|
def ksym(addr, show_module: false, show_offset: false)
|
18
33
|
self.sym(addr, -1, show_module: show_module, show_offset: show_offset, demangle: false)
|
19
34
|
end
|
@@ -161,25 +176,57 @@ module RbBCC
|
|
161
176
|
module_ = (show_module && module_) ? " [#{File.basename.basename(module_)}]" : ""
|
162
177
|
return name + module_
|
163
178
|
end
|
179
|
+
|
180
|
+
def attach_raw_socket(fn, dev)
|
181
|
+
unless fn.is_a?(Hash)
|
182
|
+
raise "arg 1 must be of BPF.Function Hash"
|
183
|
+
end
|
184
|
+
sock = Clib.bpf_open_raw_sock(dev)
|
185
|
+
if sock < 0
|
186
|
+
raise SystemCallError.new("Failed to open raw device %s" % dev, Fiddle.last_error)
|
187
|
+
end
|
188
|
+
|
189
|
+
res = Clib.bpf_attach_socket(sock, fn[:fd])
|
190
|
+
if res < 0
|
191
|
+
raise SystemCallError.new("Failed to attach BPF to device %s" % dev, Fiddle.last_error)
|
192
|
+
end
|
193
|
+
fn[:sock] = sock
|
194
|
+
fn
|
195
|
+
end
|
164
196
|
end
|
165
197
|
|
166
|
-
def initialize(text
|
198
|
+
def initialize(text: "", src_file: nil, hdr_file: nil, debug: 0, cflags: [], usdt_contexts: [], allow_rlimit: 0)
|
167
199
|
@kprobe_fds = {}
|
168
200
|
@uprobe_fds = {}
|
169
201
|
@tracepoint_fds = {}
|
170
202
|
@raw_tracepoint_fds = {}
|
171
|
-
|
172
|
-
if
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
debug,
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
203
|
+
|
204
|
+
if src_file
|
205
|
+
src_file = BCC._find_file(src_file)
|
206
|
+
hdr_file = BCC._find_file(hdr_file)
|
207
|
+
end
|
208
|
+
|
209
|
+
if src_file && src_file.end_with?(".b")
|
210
|
+
@module = Clib.bpf_module_create_b(src_file, hdr_file, debug, device)
|
211
|
+
else
|
212
|
+
if src_file
|
213
|
+
text = File.read(src_file)
|
214
|
+
end
|
215
|
+
|
216
|
+
@usdt_contexts = usdt_contexts
|
217
|
+
if code = gen_args_from_usdt
|
218
|
+
text = code + text
|
219
|
+
end
|
220
|
+
|
221
|
+
# Util.debug text
|
222
|
+
@module = Clib.bpf_module_create_c_from_string(
|
223
|
+
text,
|
224
|
+
debug,
|
225
|
+
cflags.pack('p*'),
|
226
|
+
cflags.size,
|
227
|
+
allow_rlimit
|
228
|
+
)
|
229
|
+
end
|
183
230
|
@funcs = {}
|
184
231
|
@tables = {}
|
185
232
|
@perf_buffers = {}
|
@@ -237,7 +284,7 @@ module RbBCC
|
|
237
284
|
if fd < 0
|
238
285
|
raise SystemCallError.new("Failed to attach BPF program #{fn_name} to tracepoint #{tp}", Fiddle.last_error)
|
239
286
|
end
|
240
|
-
|
287
|
+
Util.debug "Attach: #{tp}"
|
241
288
|
@tracepoint_fds[tp] = fd
|
242
289
|
self
|
243
290
|
end
|
@@ -252,7 +299,7 @@ module RbBCC
|
|
252
299
|
if fd < 0
|
253
300
|
raise SystemCallError.new("Failed to attach BPF program #{fn_name} to raw tracepoint #{tp}", Fiddle.last_error)
|
254
301
|
end
|
255
|
-
|
302
|
+
Util.debug "Attach: #{tp}"
|
256
303
|
@raw_tracepoint_fds[tp] = fd
|
257
304
|
self
|
258
305
|
end
|
@@ -264,7 +311,7 @@ module RbBCC
|
|
264
311
|
if fd < 0
|
265
312
|
raise SystemCallError.new("Failed to attach BPF program #{fn_name} to kprobe #{event}", Fiddle.last_error)
|
266
313
|
end
|
267
|
-
|
314
|
+
Util.debug "Attach: #{ev_name}"
|
268
315
|
@kprobe_fds[ev_name] = fd
|
269
316
|
[ev_name, fd]
|
270
317
|
end
|
@@ -277,7 +324,7 @@ module RbBCC
|
|
277
324
|
if fd < 0
|
278
325
|
raise SystemCallError.new("Failed to attach BPF program #{fn_name} to kretprobe #{event}", Fiddle.last_error)
|
279
326
|
end
|
280
|
-
|
327
|
+
Util.debug "Attach: #{ev_name}"
|
281
328
|
@kprobe_fds[ev_name] = fd
|
282
329
|
[ev_name, fd]
|
283
330
|
end
|
@@ -291,7 +338,7 @@ module RbBCC
|
|
291
338
|
if fd < 0
|
292
339
|
raise SystemCallError.new(Fiddle.last_error)
|
293
340
|
end
|
294
|
-
|
341
|
+
Util.debug "Attach: #{ev_name}"
|
295
342
|
|
296
343
|
@uprobe_fds[ev_name] = fd
|
297
344
|
[ev_name, fd]
|
@@ -306,7 +353,7 @@ module RbBCC
|
|
306
353
|
if fd < 0
|
307
354
|
raise SystemCallError.new(Fiddle.last_error)
|
308
355
|
end
|
309
|
-
|
356
|
+
Util.debug "Attach: #{ev_name}"
|
310
357
|
|
311
358
|
@uprobe_fds[ev_name] = fd
|
312
359
|
[ev_name, fd]
|
@@ -507,7 +554,7 @@ module RbBCC
|
|
507
554
|
else
|
508
555
|
next
|
509
556
|
end
|
510
|
-
|
557
|
+
Util.debug "Found fnc: #{func_name}"
|
511
558
|
if func_name.start_with?("kprobe__")
|
512
559
|
fn = load_func(func_name, BPF::KPROBE)
|
513
560
|
attach_kprobe(
|
data/lib/rbbcc/clib.rb
CHANGED
@@ -25,19 +25,27 @@ module RbBCC
|
|
25
25
|
end
|
26
26
|
|
27
27
|
extend Fiddle::Importer
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
targets = %w(0.14.0 0.13.0 0.12.0 0.11.0 0.10.0)
|
29
|
+
if default_load = ENV['LIBBCC_VERSION']
|
30
|
+
targets.unshift(default_load)
|
31
|
+
targets.uniq!
|
32
|
+
end
|
33
|
+
|
34
|
+
targets.each do |to_load|
|
35
|
+
begin
|
36
|
+
dlload "libbcc.so.#{to_load}"
|
37
|
+
self.libbcc_version = to_load
|
38
|
+
break
|
39
|
+
rescue Fiddle::DLError => e
|
40
|
+
if targets.last == to_load
|
41
|
+
raise LoadError, "no target libbcc to load"
|
42
|
+
end
|
43
|
+
end
|
37
44
|
end
|
38
45
|
typealias "size_t", "int"
|
39
46
|
|
40
47
|
extern 'void * bpf_module_create_c_from_string(char *, unsigned int, char **, int, long)'
|
48
|
+
extern 'void * bpf_module_create_b(char *filename, char *proto_filename, unsigned int flags, char *dev_name)'
|
41
49
|
extern 'int bpf_num_functions(void *)'
|
42
50
|
extern 'char * bpf_function_name(void *, int)'
|
43
51
|
extern 'void bpf_module_destroy(void *)'
|
@@ -70,6 +78,7 @@ module RbBCC
|
|
70
78
|
extern 'char * bpf_table_key_desc(void *, char *)'
|
71
79
|
extern 'char * bpf_table_leaf_desc(void *, char *)'
|
72
80
|
extern 'int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags)'
|
81
|
+
extern 'int bpf_delete_elem(int fd, void *key)'
|
73
82
|
|
74
83
|
extern 'int bpf_attach_kprobe(int, int, char *, char *, unsigned long, int)'
|
75
84
|
extern 'int bpf_detach_kprobe(char *)'
|
@@ -111,10 +120,11 @@ module RbBCC
|
|
111
120
|
extern 'char * bpf_perf_event_field(void *program, const char *event, size_t i)'
|
112
121
|
|
113
122
|
extern 'void * bcc_usdt_new_frompid(int, char *)'
|
123
|
+
extern 'void * bcc_usdt_new_frompath(char *path)'
|
114
124
|
extern 'int bcc_usdt_enable_probe(void *, char *, char *)'
|
115
125
|
extern 'char * bcc_usdt_genargs(void **, int)'
|
116
126
|
extern 'void bcc_usdt_foreach_uprobe(void *, void *)'
|
117
|
-
|
127
|
+
extern 'void bcc_usdt_close(void *usdt)'
|
118
128
|
BCCSymbol = struct([
|
119
129
|
"const char *name",
|
120
130
|
"const char *demangle_name",
|
@@ -147,6 +157,9 @@ module RbBCC
|
|
147
157
|
extern 'int perf_reader_poll(int num_readers, struct perf_reader **readers, int timeout)'
|
148
158
|
|
149
159
|
extern 'void bcc_procutils_free(const char *ptr)'
|
160
|
+
|
161
|
+
extern 'int bpf_open_raw_sock(const char *name)'
|
162
|
+
extern 'int bpf_attach_socket(int sockfd, int progfd)'
|
150
163
|
end
|
151
164
|
end
|
152
165
|
|
data/lib/rbbcc/debug.rb
ADDED
data/lib/rbbcc/table.rb
CHANGED
@@ -78,7 +78,9 @@ module RbBCC
|
|
78
78
|
return next_key
|
79
79
|
end
|
80
80
|
|
81
|
-
def [](
|
81
|
+
def [](_key)
|
82
|
+
key = normalize_key(_key)
|
83
|
+
|
82
84
|
leaf = Fiddle::Pointer.malloc(self.leafsize)
|
83
85
|
res = Clib.bpf_lookup_elem(self.map_fd, key, leaf)
|
84
86
|
if res < 0
|
@@ -91,11 +93,20 @@ module RbBCC
|
|
91
93
|
self[key] || raise(KeyError, "key not found")
|
92
94
|
end
|
93
95
|
|
94
|
-
def []=(
|
96
|
+
def []=(_key, leaf)
|
97
|
+
key = normalize_key(_key)
|
95
98
|
res = Clib.bpf_update_elem(self.map_fd, key, leaf, 0)
|
96
99
|
if res < 0
|
97
100
|
raise SystemCallError.new("Could not update table", Fiddle.last_error)
|
98
101
|
end
|
102
|
+
leaf
|
103
|
+
end
|
104
|
+
|
105
|
+
def delete(key)
|
106
|
+
res = Clib.bpf_delete_elem(self.map_fd, key)
|
107
|
+
if res < 0
|
108
|
+
raise KeyError, "key not found"
|
109
|
+
end
|
99
110
|
res
|
100
111
|
end
|
101
112
|
|
@@ -127,6 +138,11 @@ module RbBCC
|
|
127
138
|
enum_for(:each_pair).to_a
|
128
139
|
end
|
129
140
|
|
141
|
+
def clear
|
142
|
+
each_key {|key| self.delete(key) }
|
143
|
+
return items # reload contents
|
144
|
+
end
|
145
|
+
|
130
146
|
def print_log2_hist(val_type="value",
|
131
147
|
section_header: "Bucket ptr",
|
132
148
|
section_print_fn: nil,
|
@@ -167,6 +183,17 @@ module RbBCC
|
|
167
183
|
end
|
168
184
|
|
169
185
|
private
|
186
|
+
def normalize_key(key)
|
187
|
+
case key
|
188
|
+
when Fiddle::Pointer
|
189
|
+
key
|
190
|
+
when Integer
|
191
|
+
byref(key, keysize)
|
192
|
+
else
|
193
|
+
raise KeyError, "#{key.inspect} must be integer or pointor"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
170
197
|
def byref(value, size=sizeof("int"))
|
171
198
|
pack_fmt = case size
|
172
199
|
when sizeof("int") ; "i!"
|
@@ -194,8 +221,13 @@ module RbBCC
|
|
194
221
|
end
|
195
222
|
alias length size
|
196
223
|
|
197
|
-
def
|
198
|
-
|
224
|
+
def clearitem(key)
|
225
|
+
self[key] = byref(0, @leafsize)
|
226
|
+
end
|
227
|
+
|
228
|
+
def delete(key)
|
229
|
+
# Delete in Array type does not have an effect, so zero out instead
|
230
|
+
clearitem(key)
|
199
231
|
end
|
200
232
|
|
201
233
|
def each(&b)
|
@@ -203,18 +235,6 @@ module RbBCC
|
|
203
235
|
b.call(v.to_bcc_value)
|
204
236
|
end
|
205
237
|
end
|
206
|
-
|
207
|
-
private
|
208
|
-
def normalize_key(key)
|
209
|
-
case key
|
210
|
-
when Fiddle::Pointer
|
211
|
-
key
|
212
|
-
when Integer
|
213
|
-
byref(key, keysize)
|
214
|
-
else
|
215
|
-
raise KeyError, "#{key.inspect} must be integer or pointor"
|
216
|
-
end
|
217
|
-
end
|
218
238
|
end
|
219
239
|
|
220
240
|
class PerfEventArray < TableBase
|
data/lib/rbbcc/usdt.rb
CHANGED
@@ -4,15 +4,21 @@ module RbBCC
|
|
4
4
|
USDTProbe = Struct.new(:binpath, :fn_name, :addr, :pid)
|
5
5
|
|
6
6
|
class USDT
|
7
|
-
|
8
|
-
def initialize(pid:)
|
7
|
+
def initialize(pid: nil, path: nil)
|
9
8
|
@pid = pid
|
10
|
-
@
|
9
|
+
@path = path
|
10
|
+
if pid
|
11
|
+
@context = Clib.bcc_usdt_new_frompid(pid, path)
|
12
|
+
elsif path
|
13
|
+
@context = Clib.bcc_usdt_new_frompath(path)
|
14
|
+
else
|
15
|
+
raise "Either a pid or a binary path must be specified"
|
16
|
+
end
|
11
17
|
if !@context || @context.null?
|
12
18
|
raise SystemCallError.new(Fiddle.last_error)
|
13
19
|
end
|
14
20
|
end
|
15
|
-
attr_reader :pid, :context
|
21
|
+
attr_reader :pid, :path, :context
|
16
22
|
|
17
23
|
def enable_probe(probe:, fn_name:)
|
18
24
|
ret = Clib.bcc_usdt_enable_probe(@context, probe, fn_name)
|
@@ -33,5 +39,16 @@ module RbBCC
|
|
33
39
|
|
34
40
|
return probes
|
35
41
|
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def __del__
|
45
|
+
lambda { Clib.bcc_usdt_close(@context); Util.debug("USDT GC'ed.") }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
at_exit do
|
51
|
+
ObjectSpace.each_object(RbBCC::USDT) do |o|
|
52
|
+
o.send(:__del__).call
|
36
53
|
end
|
37
54
|
end
|
data/lib/rbbcc/version.rb
CHANGED
data/rbbcc.gemspec
CHANGED
@@ -7,6 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.version = RbBCC::VERSION
|
8
8
|
spec.authors = ["Uchio Kondo"]
|
9
9
|
spec.email = ["udzura@udzura.jp"]
|
10
|
+
spec.license = "Apache-2.0"
|
10
11
|
|
11
12
|
spec.summary = %q{BCC port for MRI}
|
12
13
|
spec.description = %q{BCC port for MRI. See https://github.com/iovisor/bcc}
|
@@ -20,8 +21,4 @@ Gem::Specification.new do |spec|
|
|
20
21
|
#spec.bindir = "exe"
|
21
22
|
#spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
23
|
spec.require_paths = ["lib"]
|
23
|
-
|
24
|
-
spec.add_development_dependency "bundler", "~> 2.0"
|
25
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
-
spec.add_development_dependency "pry"
|
27
24
|
end
|
data/semaphore.sh
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# packages
|
4
|
+
|
5
|
+
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
|
6
|
+
echo "deb https://repo.iovisor.org/apt/$(lsb_release -cs) $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/iovisor.list
|
7
|
+
sudo apt -y update
|
8
|
+
sudo apt -y install libbcc
|
9
|
+
|
10
|
+
# build libbcc 0.11/0.12
|
11
|
+
ORIG_DIR=$(pwd)
|
12
|
+
sudo mkdir -p /opt/bcc
|
13
|
+
|
14
|
+
cd /
|
15
|
+
sudo chown $(whoami) /opt/bcc
|
16
|
+
cache has_key libbcc-so && cache restore libbcc-so
|
17
|
+
sudo chown -R root /opt/bcc
|
18
|
+
cd -
|
19
|
+
|
20
|
+
if test "$(ls /opt/bcc | wc -l)" -le "0"; then
|
21
|
+
sudo apt -y install bison build-essential cmake flex git libedit-dev \
|
22
|
+
libllvm6.0 llvm-6.0-dev libclang-6.0-dev python zlib1g-dev libelf-dev
|
23
|
+
|
24
|
+
sudo mkdir -p /opt/bcc-work
|
25
|
+
sudo chown $(whoami) /opt/bcc-work
|
26
|
+
cd /opt/bcc-work
|
27
|
+
git clone https://github.com/iovisor/bcc.git
|
28
|
+
mkdir bcc/build
|
29
|
+
cd bcc
|
30
|
+
|
31
|
+
git checkout v0.11.0
|
32
|
+
git submodule init
|
33
|
+
git submodule sync
|
34
|
+
git submodule update
|
35
|
+
cd build
|
36
|
+
cmake .. -DCMAKE_INSTALL_PREFIX=/opt/bcc
|
37
|
+
make -j$(nproc)
|
38
|
+
sudo make install
|
39
|
+
make clean
|
40
|
+
cd ..
|
41
|
+
|
42
|
+
V0_12_HASH=2d099cd8c5cb1598d6e911c0b389132ebc7c101b
|
43
|
+
git checkout $V0_12_HASH
|
44
|
+
git submodule init
|
45
|
+
git submodule sync
|
46
|
+
git submodule update
|
47
|
+
cd build
|
48
|
+
cmake .. -DCMAKE_INSTALL_PREFIX=/opt/bcc
|
49
|
+
make -j$(nproc)
|
50
|
+
sudo make install
|
51
|
+
|
52
|
+
cd /
|
53
|
+
cache has_key libbcc-so && cache clear libbcc-so
|
54
|
+
cache store libbcc-so opt/bcc
|
55
|
+
cd -
|
56
|
+
fi
|
57
|
+
cd $ORIG_DIR
|
58
|
+
|
59
|
+
# link all tha objects under /lib from /opt/bcc
|
60
|
+
sudo ln -sf /opt/bcc/lib/libbcc.so.0.11.0 /opt/bcc/lib/libbcc.so.0.12.0 /usr/lib/x86_64-linux-gnu/
|
61
|
+
|
62
|
+
# Doing tests
|
63
|
+
set -e
|
64
|
+
|
65
|
+
bundle install --path vendor/bundle
|
66
|
+
|
67
|
+
bundle exec ruby -e "require 'rbbcc'; puts 'Using rbbcc: %s && libbcc: %s' % [RbBCC::VERSION, RbBCC::Clib.libbcc_version.to_s]"
|
68
|
+
if test "$(bundle exec ruby -e 'require %q(rbbcc); print RbBCC::Clib.libbcc_version.to_s')" != "${LIBBCC_VERSION}"; then
|
69
|
+
echo "Test target mismatch"
|
70
|
+
exit 127
|
71
|
+
fi
|
72
|
+
|
73
|
+
sudo -E env PATH=$PATH bundle exec rake test
|