rbbcc 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|