rbbcc 0.5.0 → 0.6.4
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 +9 -0
- data/Gemfile.lock +26 -8
- data/docs/answers/14-strlen_count.rb +1 -1
- data/examples/collectsyscall.rb +155 -0
- data/examples/tools/bashreadline.rb +83 -0
- data/exe/rbbcc +16 -0
- data/lib/rbbcc.rb +4 -3
- data/lib/rbbcc/bcc.rb +42 -10
- data/lib/rbbcc/clib.rb +16 -2
- data/lib/rbbcc/fiddle_ext.rb +34 -2
- data/lib/rbbcc/invoker.rb +28 -0
- data/lib/rbbcc/plugin.rb +28 -0
- data/lib/rbbcc/table.rb +26 -4
- data/lib/rbbcc/version.rb +1 -1
- data/rbbcc.gemspec +2 -2
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92b4487b6e8f5b72aad25113da967b51b2feb064361676b093441b6fd0bab672
|
4
|
+
data.tar.gz: 03d71e58ddebacdbf41f0c1ad4422bcfa1b9acdda3ac568068a2a8751b594a97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb9234154fe245bf001676f1a6e7b1e5bcce31e4962bd0d646746d1f3c286722def93899877c9a200a516fd33366ef7c73fcf2a7a22731fb76225edb5477f449
|
7
|
+
data.tar.gz: 89415cbd8cadade4b49b53b5fd1c024198bfbd3424e0d95ecaf8e00381495570e171bcf54f4c395ddf40d762821da1425945761d80166aef724e038f43ae0f3c
|
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
@@ -7,3 +7,12 @@ gem "bundler", "~> 2.0"
|
|
7
7
|
gem "rake", "~> 13.0"
|
8
8
|
gem "pry", "~> 0.12"
|
9
9
|
gem "minitest", ">= 5"
|
10
|
+
|
11
|
+
group :omnibus_package do
|
12
|
+
gem "appbundler"
|
13
|
+
gem "specific_install"
|
14
|
+
end
|
15
|
+
|
16
|
+
group :plugin_dev do
|
17
|
+
gem "rbbcc-hello", git: "https://github.com/udzura/rbbcc-hello.git"
|
18
|
+
end
|
data/Gemfile.lock
CHANGED
@@ -1,28 +1,46 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/udzura/rbbcc-hello.git
|
3
|
+
revision: 2e1af47d22e7cc92e970dc6c058e113cf00821db
|
4
|
+
specs:
|
5
|
+
rbbcc-hello (0.1.0)
|
6
|
+
rbbcc
|
7
|
+
|
1
8
|
PATH
|
2
9
|
remote: .
|
3
10
|
specs:
|
4
|
-
rbbcc (0.
|
11
|
+
rbbcc (0.6.4)
|
5
12
|
|
6
13
|
GEM
|
7
14
|
remote: https://rubygems.org/
|
8
15
|
specs:
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
appbundler (0.13.2)
|
17
|
+
mixlib-cli (>= 1.4, < 3.0)
|
18
|
+
mixlib-shellout (>= 2.0, < 4.0)
|
19
|
+
chef-utils (16.6.14)
|
20
|
+
coderay (1.1.3)
|
21
|
+
method_source (1.0.0)
|
22
|
+
minitest (5.14.2)
|
23
|
+
mixlib-cli (2.1.8)
|
24
|
+
mixlib-shellout (3.2.2)
|
25
|
+
chef-utils
|
26
|
+
pry (0.13.1)
|
27
|
+
coderay (~> 1.1)
|
28
|
+
method_source (~> 1.0)
|
15
29
|
rake (13.0.1)
|
30
|
+
specific_install (0.3.5)
|
16
31
|
|
17
32
|
PLATFORMS
|
18
33
|
ruby
|
19
34
|
|
20
35
|
DEPENDENCIES
|
36
|
+
appbundler
|
21
37
|
bundler (~> 2.0)
|
22
38
|
minitest (>= 5)
|
23
39
|
pry (~> 0.12)
|
24
40
|
rake (~> 13.0)
|
25
41
|
rbbcc!
|
42
|
+
rbbcc-hello!
|
43
|
+
specific_install
|
26
44
|
|
27
45
|
BUNDLED WITH
|
28
|
-
2.1.
|
46
|
+
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,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
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if ARGV[0] == '-v' || ARGV[0] == '--version'
|
4
|
+
require 'rbbcc/version'
|
5
|
+
print "RbBCC: version "
|
6
|
+
puts RbBCC::VERSION
|
7
|
+
print "Using "
|
8
|
+
puts RUBY_DESCRIPTION
|
9
|
+
elsif ARGV[0] == '--invoke'
|
10
|
+
require 'rbbcc/invoker'
|
11
|
+
ARGV.shift
|
12
|
+
RbBCC::Invoker.new(ARGV).run
|
13
|
+
else
|
14
|
+
binpath = File.readlink "/proc/self/exe"
|
15
|
+
exec binpath, *ARGV
|
16
|
+
end
|
data/lib/rbbcc.rb
CHANGED
data/lib/rbbcc/bcc.rb
CHANGED
@@ -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
|
-
|
157
|
+
c = Fiddle::Importer.union(fields)
|
158
158
|
else
|
159
|
-
|
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
|
160
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
|
161
186
|
end
|
162
187
|
|
163
188
|
def sym(addr, pid, show_module: false, show_offset: false, demangle: true)
|
@@ -195,7 +220,7 @@ module RbBCC
|
|
195
220
|
end
|
196
221
|
end
|
197
222
|
|
198
|
-
def initialize(text: "", src_file: nil, hdr_file: nil, debug: 0, cflags: [], usdt_contexts: [], allow_rlimit: 0)
|
223
|
+
def initialize(text: "", src_file: nil, hdr_file: nil, debug: 0, cflags: [], usdt_contexts: [], allow_rlimit: 0, dev_name: nil)
|
199
224
|
@kprobe_fds = {}
|
200
225
|
@uprobe_fds = {}
|
201
226
|
@tracepoint_fds = {}
|
@@ -207,7 +232,7 @@ module RbBCC
|
|
207
232
|
end
|
208
233
|
|
209
234
|
if src_file && src_file.end_with?(".b")
|
210
|
-
@module = Clib.bpf_module_create_b(src_file, hdr_file, debug,
|
235
|
+
@module = Clib.bpf_module_create_b(src_file, hdr_file, debug, dev_name)
|
211
236
|
else
|
212
237
|
if src_file
|
213
238
|
text = File.read(src_file)
|
@@ -218,13 +243,20 @@ module RbBCC
|
|
218
243
|
text = code + text
|
219
244
|
end
|
220
245
|
|
221
|
-
|
222
|
-
|
246
|
+
|
247
|
+
cflags_safe = if cflags.empty? or !cflags[-1].nil?
|
248
|
+
cflags + [nil]
|
249
|
+
else
|
250
|
+
cflags
|
251
|
+
end
|
252
|
+
|
253
|
+
@module = Clib.do_bpf_module_create_c_from_string(
|
223
254
|
text,
|
224
255
|
debug,
|
225
|
-
|
226
|
-
|
227
|
-
allow_rlimit
|
256
|
+
cflags_safe.pack("p*"),
|
257
|
+
cflags_safe.size,
|
258
|
+
allow_rlimit,
|
259
|
+
dev_name
|
228
260
|
)
|
229
261
|
end
|
230
262
|
@funcs = {}
|
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.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!
|
@@ -44,24 +44,38 @@ module RbBCC
|
|
44
44
|
end
|
45
45
|
typealias "size_t", "int"
|
46
46
|
|
47
|
-
extern 'void * bpf_module_create_c_from_string(char *, unsigned int, char **, int, long)'
|
48
47
|
extern 'void * bpf_module_create_b(char *filename, char *proto_filename, unsigned int flags, char *dev_name)'
|
49
48
|
extern 'int bpf_num_functions(void *)'
|
50
49
|
extern 'char * bpf_function_name(void *, int)'
|
51
50
|
extern 'void bpf_module_destroy(void *)'
|
52
51
|
|
53
52
|
if libbcc_version_gteq?("0.11.0")
|
53
|
+
extern 'void * bpf_module_create_c_from_string(
|
54
|
+
const char *text, unsigned int flags, const char *cflags[],
|
55
|
+
int ncflags, int allow_rlimit,
|
56
|
+
const char *dev_name)'
|
54
57
|
extern 'int bcc_func_load(
|
55
58
|
void *program, int prog_type, const char *name,
|
56
59
|
const struct bpf_insn *insns, int prog_len,
|
57
60
|
const char *license, unsigned int kern_version,
|
58
61
|
int log_level, char *log_buf, unsigned int log_buf_size,
|
59
62
|
const char *dev_name)'
|
63
|
+
def self.do_bpf_module_create_c_from_string(text, flags, cflags, ncflags, allow_limit, dev_name)
|
64
|
+
bpf_module_create_c_from_string(text, flags, cflags, ncflags, allow_limit, dev_name)
|
65
|
+
end
|
66
|
+
|
60
67
|
def self.do_bcc_func_load(mod, prog_type, name, insns, len, license, kver, loglv, buf, buf_size, device)
|
61
68
|
bcc_func_load(mod, prog_type, name, insns, len, license, kver, loglv, buf, buf_size, device)
|
62
69
|
end
|
63
70
|
else
|
71
|
+
extern 'void * bpf_module_create_c_from_string(
|
72
|
+
const char *text, unsigned int flags, const char *cflags[],
|
73
|
+
int ncflags, int allow_rlimit)'
|
64
74
|
extern 'int bcc_func_load(void *, int, char *, void *, int, char *, unsigned int, int, char *, unsigned int)'
|
75
|
+
def self.do_bpf_module_create_c_from_string(text, flags, cflags, ncflags, allow_limit, dev_name=nil)
|
76
|
+
bpf_module_create_c_from_string(text, flags, cflags, ncflags, allow_limit)
|
77
|
+
end
|
78
|
+
|
65
79
|
def self.do_bcc_func_load(mod, prog_type, name, insns, len, license, kver, loglv, buf, buf_size, device)
|
66
80
|
bcc_func_load(mod, prog_type, name, insns, len, license, kver, loglv, buf, buf_size)
|
67
81
|
end
|
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
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rbbcc/plugin'
|
3
|
+
|
4
|
+
module RbBCC
|
5
|
+
class Invoker
|
6
|
+
def initialize(args)
|
7
|
+
@command = args.shift
|
8
|
+
raise "Invalid option. Please specify script name" unless @command
|
9
|
+
|
10
|
+
args.shift if args[0] == '--'
|
11
|
+
@args = args
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
plugins = Gem::Specification
|
16
|
+
.find_all
|
17
|
+
.select{|s| s.name =~ /^rbbcc-/ }
|
18
|
+
.map(&:name)
|
19
|
+
plugins.each {|n| require n }
|
20
|
+
|
21
|
+
script = RbBCC::Plugin.find_script_name(@command)
|
22
|
+
raise Errno::ENOENT, "Script not found: #{@command}" unless script
|
23
|
+
|
24
|
+
binpath = File.readlink "/proc/self/exe"
|
25
|
+
Process.exec binpath, script, *@args
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/rbbcc/plugin.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module RbBCC
|
2
|
+
module Plugin
|
3
|
+
ScriptLocation = Struct.new(:name, :location)
|
4
|
+
|
5
|
+
def self.scripts
|
6
|
+
@scripts ||= []
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.find_script_name(name)
|
10
|
+
scripts.find{|s|
|
11
|
+
s.name == name || "#{s.name}.rb" == name
|
12
|
+
}&.location
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.register!
|
16
|
+
caller_loc = caller[0].split(':')[0]
|
17
|
+
plugin_loc = File.expand_path("../../script", caller_loc)
|
18
|
+
unless File.directory?(plugin_loc)
|
19
|
+
raise "Cannot find a script directory #{plugin_loc}. Maybe an invalid project"
|
20
|
+
end
|
21
|
+
|
22
|
+
found = Dir.glob("#{plugin_loc}/*.rb")
|
23
|
+
.map{|path| ScriptLocation.new File.basename(path, '.rb'), path }
|
24
|
+
self.scripts.concat found
|
25
|
+
self.scripts
|
26
|
+
end
|
27
|
+
end
|
28
|
+
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/version.rb
CHANGED
data/rbbcc.gemspec
CHANGED
@@ -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
|
-
|
22
|
-
|
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.
|
4
|
+
version: 0.6.4
|
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-
|
11
|
+
date: 2020-11-26 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
|
@@ -69,12 +71,14 @@ files:
|
|
69
71
|
- examples/networking/http_filter/http-parse-simple.rb
|
70
72
|
- examples/ruby_usdt.rb
|
71
73
|
- examples/sbrk_trace.rb
|
74
|
+
- examples/tools/bashreadline.rb
|
72
75
|
- examples/tools/execsnoop.rb
|
73
76
|
- examples/tools/runqlat.rb
|
74
77
|
- examples/urandomread-explicit.rb
|
75
78
|
- examples/urandomread.rb
|
76
79
|
- examples/usdt-test.rb
|
77
80
|
- examples/usdt.rb
|
81
|
+
- exe/rbbcc
|
78
82
|
- lib/rbbcc.rb
|
79
83
|
- lib/rbbcc/bcc.rb
|
80
84
|
- lib/rbbcc/clib.rb
|
@@ -83,6 +87,8 @@ files:
|
|
83
87
|
- lib/rbbcc/debug.rb
|
84
88
|
- lib/rbbcc/disp_helper.rb
|
85
89
|
- lib/rbbcc/fiddle_ext.rb
|
90
|
+
- lib/rbbcc/invoker.rb
|
91
|
+
- lib/rbbcc/plugin.rb
|
86
92
|
- lib/rbbcc/symbol_cache.rb
|
87
93
|
- lib/rbbcc/table.rb
|
88
94
|
- lib/rbbcc/usdt.rb
|
@@ -109,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
115
|
- !ruby/object:Gem::Version
|
110
116
|
version: '0'
|
111
117
|
requirements: []
|
112
|
-
rubygems_version: 3.
|
118
|
+
rubygems_version: 3.1.2
|
113
119
|
signing_key:
|
114
120
|
specification_version: 4
|
115
121
|
summary: BCC port for MRI
|