rbbcc 0.4.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 +4 -4
- data/.semaphore/semaphore.yml +3 -1
- data/Gemfile +5 -0
- data/Gemfile.lock +10 -10
- data/docs/answers/14-strlen_count.rb +1 -1
- data/examples/collectsyscall.rb +155 -0
- data/examples/ruby_usdt.rb +105 -0
- data/examples/sbrk_trace.rb +204 -0
- data/examples/tools/bashreadline.rb +83 -0
- data/exe/rbbcc +4 -0
- data/lib/rbbcc/bcc.rb +45 -12
- data/lib/rbbcc/clib.rb +3 -2
- data/lib/rbbcc/debug.rb +17 -0
- data/lib/rbbcc/fiddle_ext.rb +34 -2
- data/lib/rbbcc/table.rb +26 -4
- data/lib/rbbcc/usdt.rb +21 -4
- data/lib/rbbcc/version.rb +1 -1
- data/rbbcc.gemspec +3 -7
- metadata +15 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb13ef05006088db3a3d16fdf3b5f444cd36a51c1d88278d5ddcb3ccb9e69663
|
4
|
+
data.tar.gz: 9cded3bc218135ef79af4376a8973dedad2e3614ab5c93f49850799842c0e5c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a05af6a130f05942ce7f9901afc8d65434b7b5851483522f875ef3a9d75d1bcb30cafb1b8ce972feea2b273329e736182740d1cc99e561139d82fd1cccd297c4
|
7
|
+
data.tar.gz: '0938ed389aa2b4159618c2c79ebd841e9c74160a8b40877b54075dff9590713f6ccc1d67c27593c13bd0e1bf9fe57d4296eb1a7d58e7f357526de7144e0b8ba4'
|
data/.semaphore/semaphore.yml
CHANGED
@@ -10,10 +10,12 @@ blocks:
|
|
10
10
|
jobs:
|
11
11
|
- name: ruby test
|
12
12
|
matrix:
|
13
|
+
- env_var: RUBY_VERSION
|
14
|
+
values: [ "2.6.5", "2.6.6", "2.7.1" ]
|
13
15
|
- env_var: LIBBCC_VERSION
|
14
16
|
values: [ "0.12.0", "0.11.0", "0.10.0" ]
|
15
17
|
commands:
|
16
18
|
- sem-version c 7
|
17
|
-
- sem-version ruby
|
19
|
+
- sem-version ruby $RUBY_VERSION
|
18
20
|
- checkout
|
19
21
|
- ./semaphore.sh
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rbbcc (0.
|
4
|
+
rbbcc (0.6.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
coderay (1.1.
|
10
|
-
method_source (0.
|
11
|
-
minitest (5.14.
|
12
|
-
pry (0.
|
13
|
-
coderay (~> 1.1
|
14
|
-
method_source (~>
|
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
|
@@ -19,10 +19,10 @@ PLATFORMS
|
|
19
19
|
|
20
20
|
DEPENDENCIES
|
21
21
|
bundler (~> 2.0)
|
22
|
-
minitest
|
23
|
-
pry
|
22
|
+
minitest (>= 5)
|
23
|
+
pry (~> 0.12)
|
24
24
|
rake (~> 13.0)
|
25
25
|
rbbcc!
|
26
26
|
|
27
27
|
BUNDLED WITH
|
28
|
-
2.1.
|
28
|
+
2.1.4
|
@@ -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
|
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,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# To run this example, please build the target ruby with an `--enable-dtrace` option in advance.
|
3
|
+
# To build via rbenv, sample command is:
|
4
|
+
# $ RUBY_CONFIGURE_OPTS='--enable-dtrace' rbenv install 2.7.0
|
5
|
+
#
|
6
|
+
# Example autput:
|
7
|
+
# # bundle exec ruby examples/ruby_usdt.rb $(pidof irb)
|
8
|
+
# TIME(s) COMM KLASS PATH
|
9
|
+
# 0.000000000 irb Struct::Key /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline.rb
|
10
|
+
# 0.000055206 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
11
|
+
# 0.000088588 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
12
|
+
# 0.000117740 irb Ripper::Lexer::Elem /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
13
|
+
# 0.000126697 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
14
|
+
# 0.000213388 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
15
|
+
# 0.000225678 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
16
|
+
# 0.000243638 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
17
|
+
# 0.000254680 irb Range /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb/ruby-lex.rb
|
18
|
+
# 0.000264707 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
19
|
+
# 0.000275579 irb Ripper::Lexer::Elem /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
20
|
+
# 0.000282438 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
21
|
+
# 0.000326136 irb String /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb.rb
|
22
|
+
# 0.001353621 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
23
|
+
# 0.001385320 irb IRB::Color::SymbolState /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb/color.rb
|
24
|
+
# 0.001397043 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb/color.rb
|
25
|
+
# 0.001416420 irb Ripper::Lexer::Elem /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
26
|
+
# 0.001423861 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
27
|
+
# 0.001462010 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
28
|
+
# 0.001478995 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
29
|
+
# 0.001487499 irb Range /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb/ruby-lex.rb
|
30
|
+
# 0.001496666 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
31
|
+
# 0.001508224 irb Ripper::Lexer::Elem /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
32
|
+
# 0.001515143 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
33
|
+
# 0.001556170 irb String /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb.rb
|
34
|
+
# 0.001726273 irb String /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
35
|
+
# 0.001946948 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
36
|
+
# 0.001956585 irb String /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline.rb
|
37
|
+
|
38
|
+
require 'rbbcc'
|
39
|
+
include RbBCC
|
40
|
+
|
41
|
+
pid = ARGV[0] || begin
|
42
|
+
puts("USAGE: #{$0} PID")
|
43
|
+
exit()
|
44
|
+
end
|
45
|
+
debug = !!ENV['DEBUG']
|
46
|
+
|
47
|
+
bpf_text = <<BPF
|
48
|
+
#include <uapi/linux/ptrace.h>
|
49
|
+
#include <linux/sched.h>
|
50
|
+
|
51
|
+
struct data_t {
|
52
|
+
u64 ts;
|
53
|
+
char comm[TASK_COMM_LEN];
|
54
|
+
char klass[64];
|
55
|
+
char path[256];
|
56
|
+
};
|
57
|
+
BPF_PERF_OUTPUT(events);
|
58
|
+
|
59
|
+
int do_trace_create_object(struct pt_regs *ctx) {
|
60
|
+
struct data_t data = {};
|
61
|
+
uint64_t addr, addr2;
|
62
|
+
|
63
|
+
data.ts = bpf_ktime_get_ns();
|
64
|
+
|
65
|
+
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
66
|
+
bpf_usdt_readarg_p(1, ctx, &data.klass, sizeof(data.klass));
|
67
|
+
bpf_usdt_readarg_p(2, ctx, &data.path, sizeof(data.path));
|
68
|
+
|
69
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
70
|
+
|
71
|
+
return 0;
|
72
|
+
};
|
73
|
+
BPF
|
74
|
+
|
75
|
+
u = USDT.new(pid: pid.to_i)
|
76
|
+
u.enable_probe(probe: "object__create", fn_name: "do_trace_create_object")
|
77
|
+
if debug
|
78
|
+
puts(u.get_text)
|
79
|
+
puts(bpf_text)
|
80
|
+
end
|
81
|
+
|
82
|
+
# initialize BPF
|
83
|
+
b = BCC.new(text: bpf_text, usdt_contexts: [u])
|
84
|
+
|
85
|
+
puts("%-18s %-6s %-24s %s" % ["TIME(s)", "COMM", "KLASS", "PATH"])
|
86
|
+
|
87
|
+
# process event
|
88
|
+
start = 0
|
89
|
+
b["events"].open_perf_buffer do |cpu, data, size|
|
90
|
+
event = b["events"].event(data)
|
91
|
+
if start == 0
|
92
|
+
start = event.ts
|
93
|
+
end
|
94
|
+
|
95
|
+
time_s = ((event.ts - start).to_f) / 1000000000
|
96
|
+
puts(
|
97
|
+
"%-18.9f %-6s %-24s %s" %
|
98
|
+
[time_s, event.comm, event.klass, event.path]
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
Signal.trap(:INT) { puts "\nDone."; exit }
|
103
|
+
loop do
|
104
|
+
b.perf_buffer_poll()
|
105
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Trace example for libc's USDT:
|
3
|
+
# - memory_sbrk_more
|
4
|
+
# - memory_sbrk_less
|
5
|
+
# - memory_mallopt_free_dyn_thresholds
|
6
|
+
# Description is here: https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Probes.html
|
7
|
+
#
|
8
|
+
# Example output:
|
9
|
+
# bundle exec ruby examples/sbrk_trace.rb -c ruby
|
10
|
+
# !! Trace start.
|
11
|
+
# [ 0.000000000] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x55f34b979000 size=135168
|
12
|
+
# [ 0.036549804] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9760000 size=135168
|
13
|
+
# [ 0.036804183] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9781000 size=143360
|
14
|
+
# [ 0.036855378] pid=32756 comm=ruby probe=memory_sbrk_less addr=0x557fd97a0000 size=16384
|
15
|
+
# [ 0.036931376] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd97a0000 size=147456
|
16
|
+
# [ 0.036940382] pid=32756 comm=ruby probe=memory_sbrk_less addr=0x557fd97c0000 size=16384
|
17
|
+
# [ 0.037022971] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd97c0000 size=151552
|
18
|
+
# [ 0.038602464] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd97e5000 size=204800
|
19
|
+
# [ 0.039398297] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9817000 size=135168
|
20
|
+
# [ 0.039909594] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9838000 size=135168
|
21
|
+
# [ 0.040536005] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9859000 size=163840
|
22
|
+
# ...
|
23
|
+
|
24
|
+
require 'rbbcc'
|
25
|
+
include RbBCC
|
26
|
+
|
27
|
+
def usage
|
28
|
+
puts("USAGE: #{$0} [-p PID|-c COMM]")
|
29
|
+
exit()
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_libc_location
|
33
|
+
if File.exist?('/lib/x86_64-linux-gnu/libc.so.6')
|
34
|
+
'/lib/x86_64-linux-gnu/libc.so.6'
|
35
|
+
else
|
36
|
+
`find /lib -name 'libc.so*' | grep -v musl | head -1`.chomp
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
usage if ARGV.size != 0 && ARGV.size != 2
|
41
|
+
|
42
|
+
pid = comm = nil
|
43
|
+
path = find_libc_location
|
44
|
+
case ARGV[0]
|
45
|
+
when '-p', '--pid'
|
46
|
+
pid = ARGV[1].to_i
|
47
|
+
when '-c', '--comm'
|
48
|
+
comm = ARGV[1]
|
49
|
+
when nil
|
50
|
+
# nop
|
51
|
+
else
|
52
|
+
usage
|
53
|
+
end
|
54
|
+
|
55
|
+
debug = !!ENV['DEBUG']
|
56
|
+
|
57
|
+
bpf_text = <<BPF
|
58
|
+
#include <uapi/linux/ptrace.h>
|
59
|
+
#include <linux/sched.h>
|
60
|
+
|
61
|
+
struct data_t {
|
62
|
+
u32 type;
|
63
|
+
u64 ts;
|
64
|
+
u32 pid;
|
65
|
+
char comm[TASK_COMM_LEN];
|
66
|
+
u64 addr;
|
67
|
+
u32 sbrk_size;
|
68
|
+
u32 adjusted_mmap;
|
69
|
+
u32 trim_thresholds;
|
70
|
+
};
|
71
|
+
BPF_PERF_OUTPUT(events);
|
72
|
+
|
73
|
+
static inline bool streq(uintptr_t str) {
|
74
|
+
char needle[] = "{{NEEDLE}}";
|
75
|
+
char haystack[sizeof(needle)];
|
76
|
+
bpf_probe_read(&haystack, sizeof(haystack), (void *)str);
|
77
|
+
for (int i = 0; i < sizeof(needle) - 1; ++i) {
|
78
|
+
if (needle[i] != haystack[i]) {
|
79
|
+
return false;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
return true;
|
83
|
+
}
|
84
|
+
|
85
|
+
#define PROBE_TYPE_more 1
|
86
|
+
#define PROBE_TYPE_less 2
|
87
|
+
#define PROBE_TYPE_free 3
|
88
|
+
|
89
|
+
{{FUNC_MORE}}
|
90
|
+
|
91
|
+
{{FUNC_LESS}}
|
92
|
+
|
93
|
+
int trace_memory_free(struct pt_regs *ctx) {
|
94
|
+
struct data_t data = {};
|
95
|
+
long buf;
|
96
|
+
|
97
|
+
data.type = PROBE_TYPE_free;
|
98
|
+
data.ts = bpf_ktime_get_ns();
|
99
|
+
data.pid = bpf_get_current_pid_tgid();
|
100
|
+
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
101
|
+
|
102
|
+
{{NEEDLE_START}}
|
103
|
+
bpf_usdt_readarg(1, ctx, &buf);
|
104
|
+
data.adjusted_mmap = buf;
|
105
|
+
|
106
|
+
bpf_usdt_readarg(2, ctx, &buf);
|
107
|
+
data.trim_thresholds = buf;
|
108
|
+
|
109
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
110
|
+
{{NEEDLE_END}}
|
111
|
+
|
112
|
+
return 0;
|
113
|
+
};
|
114
|
+
|
115
|
+
BPF
|
116
|
+
|
117
|
+
trace_fun_sbrk = <<FUNC
|
118
|
+
int trace_memory_sbrk_{{TYPE}}(struct pt_regs *ctx) {
|
119
|
+
struct data_t data = {};
|
120
|
+
long buf;
|
121
|
+
|
122
|
+
data.type = PROBE_TYPE_{{TYPE}};
|
123
|
+
data.ts = bpf_ktime_get_ns();
|
124
|
+
data.pid = bpf_get_current_pid_tgid();
|
125
|
+
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
126
|
+
|
127
|
+
{{NEEDLE_START}}
|
128
|
+
bpf_usdt_readarg(1, ctx, &buf);
|
129
|
+
data.addr = buf;
|
130
|
+
|
131
|
+
bpf_usdt_readarg(2, ctx, &buf);
|
132
|
+
data.sbrk_size = buf;
|
133
|
+
|
134
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
135
|
+
{{NEEDLE_END}}
|
136
|
+
|
137
|
+
return 0;
|
138
|
+
};
|
139
|
+
FUNC
|
140
|
+
|
141
|
+
PROBE_TYPE_more = 1
|
142
|
+
PROBE_TYPE_less = 2
|
143
|
+
PROBE_TYPE_free = 3
|
144
|
+
PROBE_MAP = {
|
145
|
+
PROBE_TYPE_more => 'memory_sbrk_more',
|
146
|
+
PROBE_TYPE_less => 'memory_sbrk_less',
|
147
|
+
PROBE_TYPE_free => 'memory_mallopt_free_dyn_thresholds'
|
148
|
+
}
|
149
|
+
|
150
|
+
bpf_text.sub!('{{FUNC_MORE}}', trace_fun_sbrk.gsub('{{TYPE}}', 'more'))
|
151
|
+
bpf_text.sub!('{{FUNC_LESS}}', trace_fun_sbrk.gsub('{{TYPE}}', 'less'))
|
152
|
+
|
153
|
+
if comm
|
154
|
+
bpf_text.sub!('{{NEEDLE}}', comm)
|
155
|
+
bpf_text.gsub!('{{NEEDLE_START}}', "if(streq((uintptr_t)data.comm)) {")
|
156
|
+
bpf_text.gsub!('{{NEEDLE_END}}', "}")
|
157
|
+
else
|
158
|
+
bpf_text.sub!('{{NEEDLE}}', "")
|
159
|
+
bpf_text.gsub!('{{NEEDLE_START}}', "")
|
160
|
+
bpf_text.gsub!('{{NEEDLE_END}}', "")
|
161
|
+
end
|
162
|
+
|
163
|
+
u = USDT.new(pid: pid, path: path)
|
164
|
+
u.enable_probe(probe: "memory_sbrk_more", fn_name: "trace_memory_sbrk_more")
|
165
|
+
u.enable_probe(probe: "memory_sbrk_less", fn_name: "trace_memory_sbrk_less")
|
166
|
+
if pid
|
167
|
+
# FIXME: Only available when PID is specified
|
168
|
+
# otherwise got an error:
|
169
|
+
# bpf: Failed to load program: Invalid argument
|
170
|
+
# last insn is not an exit or jmp
|
171
|
+
# It seems libbcc won't generate proper readarg helper
|
172
|
+
u.enable_probe(probe: "memory_mallopt_free_dyn_thresholds", fn_name: "trace_memory_free")
|
173
|
+
end
|
174
|
+
|
175
|
+
# initialize BPF
|
176
|
+
b = BCC.new(text: bpf_text, usdt_contexts: [u])
|
177
|
+
|
178
|
+
puts "!! Trace start."
|
179
|
+
# process event
|
180
|
+
start = 0
|
181
|
+
b["events"].open_perf_buffer do |cpu, data, size|
|
182
|
+
event = b["events"].event(data)
|
183
|
+
if start == 0
|
184
|
+
start = event.ts
|
185
|
+
end
|
186
|
+
|
187
|
+
time_s = ((event.ts - start).to_f) / 1000000000
|
188
|
+
if [PROBE_TYPE_more, PROBE_TYPE_less].include?(event.type)
|
189
|
+
puts(
|
190
|
+
"[%18.9f] pid=%d comm=%s probe=%s addr=%#x size=%d" %
|
191
|
+
[time_s, event.pid, event.comm, PROBE_MAP[event.type], event.addr, event.sbrk_size]
|
192
|
+
)
|
193
|
+
else
|
194
|
+
puts(
|
195
|
+
"[%18.9f] pid=%d comm=%s probe=%s adjusted_mmap=%d trim_thresholds=%d" %
|
196
|
+
[time_s, event.pid, event.comm, PROBE_MAP[event.type], event.adjusted_mmap, event.trim_thresholds]
|
197
|
+
)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
Signal.trap(:INT) { puts "\n!! Done."; exit }
|
202
|
+
loop do
|
203
|
+
b.perf_buffer_poll()
|
204
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# bashreadline Print entered bash commands from all running shells.
|
4
|
+
# For Linux, uses BCC, eBPF. Embedded C.
|
5
|
+
#
|
6
|
+
# USAGE: bashreadline [-s SHARED]
|
7
|
+
# This works by tracing the readline() function using a uretprobe (uprobes).
|
8
|
+
# When you failed to run the script directly with error:
|
9
|
+
# `Exception: could not determine address of symbol b'readline'`,
|
10
|
+
# you may need specify the location of libreadline.so library
|
11
|
+
# with `-s` option.
|
12
|
+
#
|
13
|
+
# Original bashreadline.py:
|
14
|
+
# Copyright 2016 Netflix, Inc.
|
15
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
16
|
+
# And Ruby version follows.
|
17
|
+
#
|
18
|
+
# 28-Jan-2016 Brendan Gregg Created bashreadline.py.
|
19
|
+
# 12-Feb-2016 Allan McAleavy migrated to BPF_PERF_OUTPUT
|
20
|
+
# 05-Jun-2020 Uchio Kondo Ported bashreadline.rb
|
21
|
+
|
22
|
+
require 'rbbcc'
|
23
|
+
require 'optparse'
|
24
|
+
include RbBCC
|
25
|
+
|
26
|
+
args = {}
|
27
|
+
opts = OptionParser.new
|
28
|
+
opts.on("-s", "--shared=LIBREADLINE_PATH"){|v| args[:shared] = v }
|
29
|
+
opts.parse!(ARGV)
|
30
|
+
|
31
|
+
name = args[:shared] || "/bin/bash"
|
32
|
+
|
33
|
+
# load BPF program
|
34
|
+
bpf_text = <<BPF
|
35
|
+
#include <uapi/linux/ptrace.h>
|
36
|
+
#include <linux/sched.h>
|
37
|
+
|
38
|
+
struct str_t {
|
39
|
+
u64 pid;
|
40
|
+
char str[80];
|
41
|
+
};
|
42
|
+
|
43
|
+
BPF_PERF_OUTPUT(events);
|
44
|
+
|
45
|
+
int printret(struct pt_regs *ctx) {
|
46
|
+
struct str_t data = {};
|
47
|
+
char comm[TASK_COMM_LEN] = {};
|
48
|
+
u32 pid;
|
49
|
+
if (!PT_REGS_RC(ctx))
|
50
|
+
return 0;
|
51
|
+
pid = bpf_get_current_pid_tgid();
|
52
|
+
data.pid = pid;
|
53
|
+
bpf_probe_read(&data.str, sizeof(data.str), (void *)PT_REGS_RC(ctx));
|
54
|
+
|
55
|
+
bpf_get_current_comm(&comm, sizeof(comm));
|
56
|
+
if (comm[0] == 'b' && comm[1] == 'a' && comm[2] == 's' && comm[3] == 'h' && comm[4] == 0 ) {
|
57
|
+
events.perf_submit(ctx,&data,sizeof(data));
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
return 0;
|
62
|
+
};
|
63
|
+
BPF
|
64
|
+
|
65
|
+
b = BCC.new(text: bpf_text)
|
66
|
+
b.attach_uretprobe(name: name, sym: "readline", fn_name: "printret")
|
67
|
+
|
68
|
+
# header
|
69
|
+
puts("%-9s %-6s %s" % ["TIME", "PID", "COMMAND"])
|
70
|
+
|
71
|
+
b["events"].open_perf_buffer do |cpu, data, size|
|
72
|
+
event = b["events"].event(data)
|
73
|
+
puts("%-9s %-6d %s" % [
|
74
|
+
Time.now.strftime("%H:%M:%S"),
|
75
|
+
event.pid,
|
76
|
+
event.str
|
77
|
+
])
|
78
|
+
end
|
79
|
+
|
80
|
+
trap(:INT) { puts; exit }
|
81
|
+
loop do
|
82
|
+
b.perf_buffer_poll
|
83
|
+
end
|
data/exe/rbbcc
ADDED
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 = [
|
@@ -120,7 +121,6 @@ module RbBCC
|
|
120
121
|
|
121
122
|
def decode_table_type(desc)
|
122
123
|
return desc if desc.is_a?(String)
|
123
|
-
|
124
124
|
anon = []
|
125
125
|
fields = []
|
126
126
|
# e.g. ["bpf_stacktrace", [["ip", "unsigned long long", [127]]], "struct_packed"]
|
@@ -152,11 +152,37 @@ module RbBCC
|
|
152
152
|
raise("Failed to decode type #{field.inspect}")
|
153
153
|
end
|
154
154
|
end
|
155
|
+
c = nil
|
155
156
|
if data_type == "union"
|
156
|
-
|
157
|
+
c = Fiddle::Importer.union(fields)
|
157
158
|
else
|
158
|
-
|
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
|
159
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
|
184
|
+
end
|
185
|
+
c
|
160
186
|
end
|
161
187
|
|
162
188
|
def sym(addr, pid, show_module: false, show_offset: false, demangle: true)
|
@@ -217,11 +243,18 @@ module RbBCC
|
|
217
243
|
text = code + text
|
218
244
|
end
|
219
245
|
|
246
|
+
|
247
|
+
cflags_safe = if cflags.empty? or !cflags[-1].nil?
|
248
|
+
cflags + [nil]
|
249
|
+
else
|
250
|
+
cflags
|
251
|
+
end
|
252
|
+
|
220
253
|
@module = Clib.bpf_module_create_c_from_string(
|
221
254
|
text,
|
222
255
|
debug,
|
223
|
-
|
224
|
-
|
256
|
+
cflags_safe.pack("p*"),
|
257
|
+
cflags_safe.size,
|
225
258
|
allow_rlimit
|
226
259
|
)
|
227
260
|
end
|
@@ -282,7 +315,7 @@ module RbBCC
|
|
282
315
|
if fd < 0
|
283
316
|
raise SystemCallError.new("Failed to attach BPF program #{fn_name} to tracepoint #{tp}", Fiddle.last_error)
|
284
317
|
end
|
285
|
-
|
318
|
+
Util.debug "Attach: #{tp}"
|
286
319
|
@tracepoint_fds[tp] = fd
|
287
320
|
self
|
288
321
|
end
|
@@ -297,7 +330,7 @@ module RbBCC
|
|
297
330
|
if fd < 0
|
298
331
|
raise SystemCallError.new("Failed to attach BPF program #{fn_name} to raw tracepoint #{tp}", Fiddle.last_error)
|
299
332
|
end
|
300
|
-
|
333
|
+
Util.debug "Attach: #{tp}"
|
301
334
|
@raw_tracepoint_fds[tp] = fd
|
302
335
|
self
|
303
336
|
end
|
@@ -309,7 +342,7 @@ module RbBCC
|
|
309
342
|
if fd < 0
|
310
343
|
raise SystemCallError.new("Failed to attach BPF program #{fn_name} to kprobe #{event}", Fiddle.last_error)
|
311
344
|
end
|
312
|
-
|
345
|
+
Util.debug "Attach: #{ev_name}"
|
313
346
|
@kprobe_fds[ev_name] = fd
|
314
347
|
[ev_name, fd]
|
315
348
|
end
|
@@ -322,7 +355,7 @@ module RbBCC
|
|
322
355
|
if fd < 0
|
323
356
|
raise SystemCallError.new("Failed to attach BPF program #{fn_name} to kretprobe #{event}", Fiddle.last_error)
|
324
357
|
end
|
325
|
-
|
358
|
+
Util.debug "Attach: #{ev_name}"
|
326
359
|
@kprobe_fds[ev_name] = fd
|
327
360
|
[ev_name, fd]
|
328
361
|
end
|
@@ -336,7 +369,7 @@ module RbBCC
|
|
336
369
|
if fd < 0
|
337
370
|
raise SystemCallError.new(Fiddle.last_error)
|
338
371
|
end
|
339
|
-
|
372
|
+
Util.debug "Attach: #{ev_name}"
|
340
373
|
|
341
374
|
@uprobe_fds[ev_name] = fd
|
342
375
|
[ev_name, fd]
|
@@ -351,7 +384,7 @@ module RbBCC
|
|
351
384
|
if fd < 0
|
352
385
|
raise SystemCallError.new(Fiddle.last_error)
|
353
386
|
end
|
354
|
-
|
387
|
+
Util.debug "Attach: #{ev_name}"
|
355
388
|
|
356
389
|
@uprobe_fds[ev_name] = fd
|
357
390
|
[ev_name, fd]
|
@@ -552,7 +585,7 @@ module RbBCC
|
|
552
585
|
else
|
553
586
|
next
|
554
587
|
end
|
555
|
-
|
588
|
+
Util.debug "Found fnc: #{func_name}"
|
556
589
|
if func_name.start_with?("kprobe__")
|
557
590
|
fn = load_func(func_name, BPF::KPROBE)
|
558
591
|
attach_kprobe(
|
data/lib/rbbcc/clib.rb
CHANGED
@@ -25,7 +25,7 @@ module RbBCC
|
|
25
25
|
end
|
26
26
|
|
27
27
|
extend Fiddle::Importer
|
28
|
-
targets = %w(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!
|
@@ -120,10 +120,11 @@ module RbBCC
|
|
120
120
|
extern 'char * bpf_perf_event_field(void *program, const char *event, size_t i)'
|
121
121
|
|
122
122
|
extern 'void * bcc_usdt_new_frompid(int, char *)'
|
123
|
+
extern 'void * bcc_usdt_new_frompath(char *path)'
|
123
124
|
extern 'int bcc_usdt_enable_probe(void *, char *, char *)'
|
124
125
|
extern 'char * bcc_usdt_genargs(void **, int)'
|
125
126
|
extern 'void bcc_usdt_foreach_uprobe(void *, void *)'
|
126
|
-
|
127
|
+
extern 'void bcc_usdt_close(void *usdt)'
|
127
128
|
BCCSymbol = struct([
|
128
129
|
"const char *name",
|
129
130
|
"const char *demangle_name",
|
data/lib/rbbcc/debug.rb
ADDED
data/lib/rbbcc/fiddle_ext.rb
CHANGED
@@ -2,8 +2,17 @@ require 'fiddle'
|
|
2
2
|
require 'fiddle/import'
|
3
3
|
|
4
4
|
class Fiddle::Pointer
|
5
|
-
def
|
6
|
-
|
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
|
data/lib/rbbcc/table.rb
CHANGED
@@ -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,
|
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
|
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
|
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}
|
@@ -17,12 +18,7 @@ Gem::Specification.new do |spec|
|
|
17
18
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
18
19
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
20
|
end
|
20
|
-
|
21
|
-
|
21
|
+
spec.bindir = "exe"
|
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", "~> 13.0"
|
26
|
-
spec.add_development_dependency "pry"
|
27
|
-
spec.add_development_dependency "minitest"
|
28
24
|
end
|
metadata
CHANGED
@@ -1,75 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbbcc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Uchio Kondo
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '2.0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '2.0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '13.0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '13.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: pry
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: minitest
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
11
|
+
date: 2020-11-19 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
69
13
|
description: BCC port for MRI. See https://github.com/iovisor/bcc
|
70
14
|
email:
|
71
15
|
- udzura@udzura.jp
|
72
|
-
executables:
|
16
|
+
executables:
|
17
|
+
- rbbcc
|
73
18
|
extensions: []
|
74
19
|
extra_rdoc_files: []
|
75
20
|
files:
|
@@ -112,6 +57,7 @@ files:
|
|
112
57
|
- examples/charty/Gemfile
|
113
58
|
- examples/charty/Gemfile.lock
|
114
59
|
- examples/charty/bitehist-unicode.rb
|
60
|
+
- examples/collectsyscall.rb
|
115
61
|
- examples/dddos.rb
|
116
62
|
- examples/disksnoop.rb
|
117
63
|
- examples/example.gif
|
@@ -123,17 +69,22 @@ files:
|
|
123
69
|
- examples/mallocstack.rb
|
124
70
|
- examples/networking/http_filter/http-parse-simple.c
|
125
71
|
- examples/networking/http_filter/http-parse-simple.rb
|
72
|
+
- examples/ruby_usdt.rb
|
73
|
+
- examples/sbrk_trace.rb
|
74
|
+
- examples/tools/bashreadline.rb
|
126
75
|
- examples/tools/execsnoop.rb
|
127
76
|
- examples/tools/runqlat.rb
|
128
77
|
- examples/urandomread-explicit.rb
|
129
78
|
- examples/urandomread.rb
|
130
79
|
- examples/usdt-test.rb
|
131
80
|
- examples/usdt.rb
|
81
|
+
- exe/rbbcc
|
132
82
|
- lib/rbbcc.rb
|
133
83
|
- lib/rbbcc/bcc.rb
|
134
84
|
- lib/rbbcc/clib.rb
|
135
85
|
- lib/rbbcc/consts.rb
|
136
86
|
- lib/rbbcc/cpu_helper.rb
|
87
|
+
- lib/rbbcc/debug.rb
|
137
88
|
- lib/rbbcc/disp_helper.rb
|
138
89
|
- lib/rbbcc/fiddle_ext.rb
|
139
90
|
- lib/rbbcc/symbol_cache.rb
|
@@ -144,7 +95,8 @@ files:
|
|
144
95
|
- rbbcc.gemspec
|
145
96
|
- semaphore.sh
|
146
97
|
homepage: https://github.com/udzura/rbbcc
|
147
|
-
licenses:
|
98
|
+
licenses:
|
99
|
+
- Apache-2.0
|
148
100
|
metadata: {}
|
149
101
|
post_install_message:
|
150
102
|
rdoc_options: []
|
@@ -161,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
113
|
- !ruby/object:Gem::Version
|
162
114
|
version: '0'
|
163
115
|
requirements: []
|
164
|
-
rubygems_version: 3.
|
116
|
+
rubygems_version: 3.1.2
|
165
117
|
signing_key:
|
166
118
|
specification_version: 4
|
167
119
|
summary: BCC port for MRI
|