rbbcc 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/examples/hello_ring_buffer.rb +64 -0
- data/examples/syscalluname.rb +39 -0
- data/examples/table.rb +15 -0
- data/examples/urandomread-explicit.rb +2 -0
- data/examples/urandomread.rb +2 -0
- data/lib/rbbcc/bcc.rb +16 -0
- data/lib/rbbcc/clib.rb +5 -0
- data/lib/rbbcc/table.rb +115 -54
- data/lib/rbbcc/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b46fa6dd0b99e4a178bc00bad497beab5d72426517f3d7b328c29d492e9e8a1
|
4
|
+
data.tar.gz: a5f84fdc89d50621b3dd06eca22aea243efc1991ec053acece136016ccbdfb64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 532f1d544b56d82e68d5931aac278bf36a850943c3e78e8851c59e56852ebe4f6a3d974fa6c129544f0c7f895696bd9b894f3d033490faff8c408bbd7deed424
|
7
|
+
data.tar.gz: 03de507c9094d850d77253610d2ffe08e2ee4ad97048e742f4c283ce6d8748de68f019a0e247ac826b5cbcbd48664a359ec57c92113f5f4015bc0c0f1984b482
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This is a Hello World example that uses BPF_PERF_OUTPUT.
|
4
|
+
# Ported from hello_perf_output.py
|
5
|
+
|
6
|
+
require 'rbbcc'
|
7
|
+
include RbBCC
|
8
|
+
|
9
|
+
# define BPF program
|
10
|
+
prog = """
|
11
|
+
#include <linux/sched.h>
|
12
|
+
|
13
|
+
struct data_t {
|
14
|
+
u32 pid;
|
15
|
+
u64 ts;
|
16
|
+
char comm[TASK_COMM_LEN];
|
17
|
+
};
|
18
|
+
BPF_RINGBUF_OUTPUT(buffer, 1 << 4);
|
19
|
+
|
20
|
+
int hello(struct pt_regs *ctx) {
|
21
|
+
struct data_t data = {};
|
22
|
+
|
23
|
+
data.pid = bpf_get_current_pid_tgid();
|
24
|
+
data.ts = bpf_ktime_get_ns();
|
25
|
+
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
26
|
+
|
27
|
+
buffer.ringbuf_output(&data, sizeof(data), 0);
|
28
|
+
|
29
|
+
return 0;
|
30
|
+
}
|
31
|
+
"""
|
32
|
+
|
33
|
+
# load BPF program
|
34
|
+
b = BCC.new(text: prog)
|
35
|
+
b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
|
36
|
+
|
37
|
+
# header
|
38
|
+
puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
|
39
|
+
|
40
|
+
# process event
|
41
|
+
start = 0
|
42
|
+
print_event = lambda { |ctx, data, size|
|
43
|
+
event = b["buffer"].event(data)
|
44
|
+
if start == 0
|
45
|
+
start = event.ts
|
46
|
+
end
|
47
|
+
|
48
|
+
time_s = ((event.ts - start).to_f) / 1000000000
|
49
|
+
# event.comm.pack("c*").sprit
|
50
|
+
puts("%-18.9f %-16s %-6d %s" % [time_s, event.comm, event.pid,
|
51
|
+
"Hello, ringbuf!"])
|
52
|
+
}
|
53
|
+
|
54
|
+
# loop with callback to print_event
|
55
|
+
b["buffer"].open_ring_buffer(&print_event)
|
56
|
+
|
57
|
+
loop do
|
58
|
+
begin
|
59
|
+
b.ring_buffer_poll()
|
60
|
+
sleep(0.5)
|
61
|
+
rescue Interrupt
|
62
|
+
exit()
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# syscalluname.rb Example of instrumenting a kernel tracepoint.
|
4
|
+
#
|
5
|
+
# Copyright 2024 Uchio Kondo
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
7
|
+
|
8
|
+
require 'rbbcc'
|
9
|
+
include RbBCC
|
10
|
+
|
11
|
+
b = BCC.new(text: %[
|
12
|
+
#include <linux/utsname.h>
|
13
|
+
|
14
|
+
TRACEPOINT_PROBE(syscalls, sys_enter_newuname) {
|
15
|
+
// args is from
|
16
|
+
// /sys/kernel/debug/tracing/events/syscalls/sys_enter_newuname/format
|
17
|
+
char release[16];
|
18
|
+
bpf_probe_read_user_str(release, 16, args->name->release);
|
19
|
+
// avoid broken data
|
20
|
+
if (release[0] == '5' || release[0] == '6') {
|
21
|
+
bpf_trace_printk("%s\\n", release);
|
22
|
+
}
|
23
|
+
return 0;
|
24
|
+
}
|
25
|
+
])
|
26
|
+
|
27
|
+
# header
|
28
|
+
printf("%-18s %-16s %-6s %s\n", "TIME(s)", "COMM", "PID", "RELEASE")
|
29
|
+
|
30
|
+
# format output
|
31
|
+
loop do
|
32
|
+
begin
|
33
|
+
b.trace_fields do |task, pid, cpu, flags, ts, msg|
|
34
|
+
puts("%-18.9f %-16s %-6d %s" % [ts, task, pid, msg])
|
35
|
+
end
|
36
|
+
rescue Interrupt
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
end
|
data/examples/table.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rbbcc'
|
4
|
+
include RbBCC
|
5
|
+
|
6
|
+
b = BCC.new(text: <<CLANG)
|
7
|
+
BPF_HASH(the_table_name, int);
|
8
|
+
CLANG
|
9
|
+
|
10
|
+
table = b.get_table('the_table_name', leaftype: 'int')
|
11
|
+
|
12
|
+
table[10] = 1
|
13
|
+
table[20] = 2
|
14
|
+
puts table[10].to_bcc_value == 1
|
15
|
+
puts table[20].to_bcc_value == 2
|
data/examples/urandomread.rb
CHANGED
data/lib/rbbcc/bcc.rb
CHANGED
@@ -262,6 +262,7 @@ module RbBCC
|
|
262
262
|
@funcs = {}
|
263
263
|
@tables = {}
|
264
264
|
@perf_buffers = {}
|
265
|
+
@_ringbuf_manager = nil
|
265
266
|
|
266
267
|
unless @module
|
267
268
|
raise "BPF module not created"
|
@@ -555,6 +556,21 @@ module RbBCC
|
|
555
556
|
Clib.perf_reader_poll(readers.size, pack, timeout)
|
556
557
|
end
|
557
558
|
|
559
|
+
def _open_ring_buffer(map_fd, fn, ctx)
|
560
|
+
buf = Clib.bpf_new_ringbuf(map_fd, fn, ctx)
|
561
|
+
if !buf
|
562
|
+
raise "Could not open ring buffer"
|
563
|
+
end
|
564
|
+
@_ringbuf_manager ||= buf
|
565
|
+
end
|
566
|
+
|
567
|
+
def ring_buffer_poll(timeout=-1)
|
568
|
+
unless @_ringbuf_manager
|
569
|
+
raise "No ring buffers to poll"
|
570
|
+
end
|
571
|
+
Clib.bpf_poll_ringbuf(@_ringbuf_manager, timeout)
|
572
|
+
end
|
573
|
+
|
558
574
|
def ksymname(name)
|
559
575
|
SymbolCache.resolve_global(name)
|
560
576
|
end
|
data/lib/rbbcc/clib.rb
CHANGED
@@ -133,6 +133,11 @@ module RbBCC
|
|
133
133
|
extern 'size_t bpf_perf_event_fields(void *program, const char *event)'
|
134
134
|
extern 'char * bpf_perf_event_field(void *program, const char *event, size_t i)'
|
135
135
|
|
136
|
+
# typedef int (*ring_buffer_sample_fn)(void *ctx, void *data, size_t size);
|
137
|
+
extern 'void * bpf_new_ringbuf(int map_fd, void *sample_cb, void *ctx)'
|
138
|
+
extern 'int bpf_poll_ringbuf(void *rb, int timeout_ms)'
|
139
|
+
extern 'void bpf_free_ringbuf(void *rb)'
|
140
|
+
|
136
141
|
extern 'void * bcc_usdt_new_frompid(int, char *)'
|
137
142
|
extern 'void * bcc_usdt_new_frompath(char *path)'
|
138
143
|
extern 'int bcc_usdt_enable_probe(void *, char *, char *)'
|
data/lib/rbbcc/table.rb
CHANGED
@@ -5,6 +5,61 @@ require 'rbbcc/disp_helper'
|
|
5
5
|
require 'rbbcc/cpu_helper'
|
6
6
|
|
7
7
|
module RbBCC
|
8
|
+
module EventTypeSupported
|
9
|
+
def get_event_class
|
10
|
+
ct_mapping = {
|
11
|
+
's8': 'char',
|
12
|
+
'u8': 'unsined char',
|
13
|
+
's8 *': 'char *',
|
14
|
+
's16': 'short',
|
15
|
+
'u16': 'unsigned short',
|
16
|
+
's32': 'int',
|
17
|
+
'u32': 'unsigned int',
|
18
|
+
's64': 'long long',
|
19
|
+
'u64': 'unsigned long long'
|
20
|
+
}
|
21
|
+
|
22
|
+
array_type = /(.+) \[([0-9]+)\]$/
|
23
|
+
fields = []
|
24
|
+
num_fields = Clib.bpf_perf_event_fields(self.bpf.module, @name)
|
25
|
+
num_fields.times do |i|
|
26
|
+
field = Clib.__extract_char(Clib.bpf_perf_event_field(self.bpf.module, @name, i))
|
27
|
+
field_name, field_type = *field.split('#')
|
28
|
+
if field_type =~ /enum .*/
|
29
|
+
field_type = "int" #it is indeed enum...
|
30
|
+
end
|
31
|
+
if _field_type = ct_mapping[field_type.to_sym]
|
32
|
+
field_type = _field_type
|
33
|
+
end
|
34
|
+
|
35
|
+
m = array_type.match(field_type)
|
36
|
+
if m
|
37
|
+
field_type = "#{m[1]}[#{m[2]}]"
|
38
|
+
fields << [field_type, field_name].join(" ")
|
39
|
+
else
|
40
|
+
fields << [field_type, field_name].join(" ")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
klass = Fiddle::Importer.struct(fields)
|
44
|
+
char_ps = fields.select {|f| f =~ /^char\[(\d+)\] ([_a-zA-Z0-9]+)/ }
|
45
|
+
unless char_ps.empty?
|
46
|
+
m = Module.new do
|
47
|
+
char_ps.each do |char_p|
|
48
|
+
md = /^char\[(\d+)\] ([_a-zA-Z0-9]+)/.match(char_p)
|
49
|
+
define_method md[2] do
|
50
|
+
# Split the char[] in the place where the first \0 appears
|
51
|
+
raw = super()
|
52
|
+
raw = raw[0...raw.index(0)] if raw.index(0)
|
53
|
+
raw.pack("c*")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
klass.prepend m
|
58
|
+
end
|
59
|
+
klass
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
8
63
|
module Table
|
9
64
|
BPF_MAP_TYPE_HASH = 1
|
10
65
|
BPF_MAP_TYPE_ARRAY = 2
|
@@ -24,6 +79,17 @@ module RbBCC
|
|
24
79
|
BPF_MAP_TYPE_CPUMAP = 16
|
25
80
|
BPF_MAP_TYPE_XSKMAP = 17
|
26
81
|
BPF_MAP_TYPE_SOCKHASH = 18
|
82
|
+
BPF_MAP_TYPE_CGROUP_STORAGE = 19
|
83
|
+
BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20
|
84
|
+
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 21
|
85
|
+
BPF_MAP_TYPE_QUEUE = 22
|
86
|
+
BPF_MAP_TYPE_STACK = 23
|
87
|
+
BPF_MAP_TYPE_SK_STORAGE = 24
|
88
|
+
BPF_MAP_TYPE_DEVMAP_HASH = 25
|
89
|
+
BPF_MAP_TYPE_STRUCT_OPS = 26
|
90
|
+
BPF_MAP_TYPE_RINGBUF = 27
|
91
|
+
BPF_MAP_TYPE_INODE_STORAGE = 28
|
92
|
+
BPF_MAP_TYPE_TASK_STORAGE = 29
|
27
93
|
|
28
94
|
def self.new(bpf, map_id, map_fd, keytype, leaftype, name, **kwargs)
|
29
95
|
ttype = Clib.bpf_table_type_id(bpf.module, map_id)
|
@@ -34,6 +100,8 @@ module RbBCC
|
|
34
100
|
ArrayTable.new(bpf, map_id, map_fd, keytype, leaftype)
|
35
101
|
when BPF_MAP_TYPE_PERF_EVENT_ARRAY
|
36
102
|
PerfEventArray.new(bpf, map_id, map_fd, keytype, leaftype, name: name)
|
103
|
+
when BPF_MAP_TYPE_RINGBUF
|
104
|
+
RingBuf.new(bpf, map_id, map_fd, keytype, leaftype, name: name)
|
37
105
|
when BPF_MAP_TYPE_STACK_TRACE
|
38
106
|
StackTrace.new(bpf, map_id, map_fd, keytype, leaftype)
|
39
107
|
else
|
@@ -260,6 +328,8 @@ module RbBCC
|
|
260
328
|
end
|
261
329
|
|
262
330
|
class PerfEventArray < TableBase
|
331
|
+
include EventTypeSupported
|
332
|
+
|
263
333
|
def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
|
264
334
|
super
|
265
335
|
@open_key_fds = {}
|
@@ -285,60 +355,6 @@ module RbBCC
|
|
285
355
|
end
|
286
356
|
end
|
287
357
|
|
288
|
-
private
|
289
|
-
def get_event_class
|
290
|
-
ct_mapping = {
|
291
|
-
's8': 'char',
|
292
|
-
'u8': 'unsined char',
|
293
|
-
's8 *': 'char *',
|
294
|
-
's16': 'short',
|
295
|
-
'u16': 'unsigned short',
|
296
|
-
's32': 'int',
|
297
|
-
'u32': 'unsigned int',
|
298
|
-
's64': 'long long',
|
299
|
-
'u64': 'unsigned long long'
|
300
|
-
}
|
301
|
-
|
302
|
-
array_type = /(.+) \[([0-9]+)\]$/
|
303
|
-
fields = []
|
304
|
-
num_fields = Clib.bpf_perf_event_fields(self.bpf.module, @name)
|
305
|
-
num_fields.times do |i|
|
306
|
-
field = Clib.__extract_char(Clib.bpf_perf_event_field(self.bpf.module, @name, i))
|
307
|
-
field_name, field_type = *field.split('#')
|
308
|
-
if field_type =~ /enum .*/
|
309
|
-
field_type = "int" #it is indeed enum...
|
310
|
-
end
|
311
|
-
if _field_type = ct_mapping[field_type.to_sym]
|
312
|
-
field_type = _field_type
|
313
|
-
end
|
314
|
-
|
315
|
-
m = array_type.match(field_type)
|
316
|
-
if m
|
317
|
-
field_type = "#{m[1]}[#{m[2]}]"
|
318
|
-
fields << [field_type, field_name].join(" ")
|
319
|
-
else
|
320
|
-
fields << [field_type, field_name].join(" ")
|
321
|
-
end
|
322
|
-
end
|
323
|
-
klass = Fiddle::Importer.struct(fields)
|
324
|
-
char_ps = fields.select {|f| f =~ /^char\[(\d+)\] ([_a-zA-Z0-9]+)/ }
|
325
|
-
unless char_ps.empty?
|
326
|
-
m = Module.new do
|
327
|
-
char_ps.each do |char_p|
|
328
|
-
md = /^char\[(\d+)\] ([_a-zA-Z0-9]+)/.match(char_p)
|
329
|
-
define_method md[2] do
|
330
|
-
# Split the char[] in the place where the first \0 appears
|
331
|
-
raw = super()
|
332
|
-
raw = raw[0...raw.index(0)] if raw.index(0)
|
333
|
-
raw.pack("c*")
|
334
|
-
end
|
335
|
-
end
|
336
|
-
end
|
337
|
-
klass.prepend m
|
338
|
-
end
|
339
|
-
klass
|
340
|
-
end
|
341
|
-
|
342
358
|
def _open_perf_buffer(cpu, callback, page_cnt, lost_cb)
|
343
359
|
# bind("void raw_cb_callback(void *, void *, int)")
|
344
360
|
fn = Fiddle::Closure::BlockCaller.new(
|
@@ -382,6 +398,51 @@ module RbBCC
|
|
382
398
|
end
|
383
399
|
end
|
384
400
|
|
401
|
+
class RingBuf < TableBase
|
402
|
+
include EventTypeSupported
|
403
|
+
|
404
|
+
def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
|
405
|
+
super
|
406
|
+
@_ringbuf = nil
|
407
|
+
@_ringbuf_manager = nil
|
408
|
+
@event_class = nil
|
409
|
+
end
|
410
|
+
|
411
|
+
def event(data)
|
412
|
+
@event_class ||= get_event_class
|
413
|
+
ev = @event_class.malloc
|
414
|
+
Fiddle::Pointer.new(ev.to_ptr)[0, @event_class.size] = data[0, @event_class.size]
|
415
|
+
return ev
|
416
|
+
end
|
417
|
+
|
418
|
+
def open_ring_buffer(ctx=nil, &callback)
|
419
|
+
# bind("int ring_buffer_sample_fn(void *, void *, int)")
|
420
|
+
fn = Fiddle::Closure::BlockCaller.new(
|
421
|
+
Fiddle::TYPE_INT,
|
422
|
+
[Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT]
|
423
|
+
) do |_dummy, data, size|
|
424
|
+
begin
|
425
|
+
_ret = callback.call(ctx, data, size)
|
426
|
+
ret = _ret.to_i
|
427
|
+
ret
|
428
|
+
rescue NoMethodError
|
429
|
+
# Callback for ringbufs should _always_ return an integer.
|
430
|
+
# simply fall back to returning 0 when failed
|
431
|
+
0
|
432
|
+
rescue => e
|
433
|
+
if Fiddle.last_error == 32 # EPIPE
|
434
|
+
exit
|
435
|
+
else
|
436
|
+
raise e
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
@bpf._open_ring_buffer(@map_fd, fn, ctx)
|
442
|
+
nil
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
385
446
|
class StackTrace < TableBase
|
386
447
|
MAX_DEPTH = 127
|
387
448
|
BPF_F_STACK_BUILD_ID = (1<<5)
|
data/lib/rbbcc/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbbcc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Uchio Kondo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: BCC port for MRI. See https://github.com/iovisor/bcc
|
14
14
|
email:
|
@@ -72,6 +72,7 @@ files:
|
|
72
72
|
- examples/extract_arg.rb
|
73
73
|
- examples/hello_fields.rb
|
74
74
|
- examples/hello_perf_output.rb
|
75
|
+
- examples/hello_ring_buffer.rb
|
75
76
|
- examples/hello_world.rb
|
76
77
|
- examples/kvm_hypercall.rb
|
77
78
|
- examples/mallocstack.rb
|
@@ -79,6 +80,8 @@ files:
|
|
79
80
|
- examples/networking/http_filter/http-parse-simple.rb
|
80
81
|
- examples/ruby_usdt.rb
|
81
82
|
- examples/sbrk_trace.rb
|
83
|
+
- examples/syscalluname.rb
|
84
|
+
- examples/table.rb
|
82
85
|
- examples/tools/bashreadline.rb
|
83
86
|
- examples/tools/execsnoop.rb
|
84
87
|
- examples/tools/runqlat.rb
|