rbbcc 0.4.2 → 0.6.3
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 +13 -0
- data/Gemfile.lock +26 -10
- 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 +37 -6
- data/lib/rbbcc/clib.rb +1 -1
- 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 +3 -7
- metadata +14 -63
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ca8253cb2fb2d8bd3824d294d54f13d5e34a9326d25244ce7ea4d4fddc202978
|
|
4
|
+
data.tar.gz: 71796d5a508760ed617347d2275f30e90fb9a8b9d68354aba884b33d4625cd3e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b36369cea2736423e7722b8cf087460b3966d0f73b6b9579b98aba643e0c4f6eef3bcd0f0089d0f25da61df3b2b612165ad8d1d25911511138b4b228eb94a6e5
|
|
7
|
+
data.tar.gz: 6e8047c3928dd676218a88c618c8546ae20de8a499acd6d700df0d0a1f4363fbee26cb168fd1190de879f939a57fc4a43cfaa453cecf50c52c0ab105f080b04f
|
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
|
@@ -2,3 +2,16 @@ source "https://rubygems.org"
|
|
|
2
2
|
|
|
3
3
|
# Specify your gem's dependencies in rbbcc.gemspec
|
|
4
4
|
gemspec
|
|
5
|
+
|
|
6
|
+
gem "bundler", "~> 2.0"
|
|
7
|
+
gem "rake", "~> 13.0"
|
|
8
|
+
gem "pry", "~> 0.12"
|
|
9
|
+
gem "minitest", ">= 5"
|
|
10
|
+
|
|
11
|
+
group :omnibus_package do
|
|
12
|
+
gem "appbundler"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
group :plugin_dev do
|
|
16
|
+
gem "rbbcc-hello", git: "https://github.com/udzura/rbbcc-hello.git"
|
|
17
|
+
end
|
data/Gemfile.lock
CHANGED
|
@@ -1,28 +1,44 @@
|
|
|
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.3)
|
|
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)
|
|
16
30
|
|
|
17
31
|
PLATFORMS
|
|
18
32
|
ruby
|
|
19
33
|
|
|
20
34
|
DEPENDENCIES
|
|
35
|
+
appbundler
|
|
21
36
|
bundler (~> 2.0)
|
|
22
|
-
minitest
|
|
23
|
-
pry
|
|
37
|
+
minitest (>= 5)
|
|
38
|
+
pry (~> 0.12)
|
|
24
39
|
rake (~> 13.0)
|
|
25
40
|
rbbcc!
|
|
41
|
+
rbbcc-hello!
|
|
26
42
|
|
|
27
43
|
BUNDLED WITH
|
|
28
|
-
2.1.
|
|
44
|
+
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)
|
|
@@ -218,12 +243,18 @@ module RbBCC
|
|
|
218
243
|
text = code + text
|
|
219
244
|
end
|
|
220
245
|
|
|
221
|
-
|
|
246
|
+
|
|
247
|
+
cflags_safe = if cflags.empty? or !cflags[-1].nil?
|
|
248
|
+
cflags + [nil]
|
|
249
|
+
else
|
|
250
|
+
cflags
|
|
251
|
+
end
|
|
252
|
+
|
|
222
253
|
@module = Clib.bpf_module_create_c_from_string(
|
|
223
254
|
text,
|
|
224
255
|
debug,
|
|
225
|
-
|
|
226
|
-
|
|
256
|
+
cflags_safe.pack("p*"),
|
|
257
|
+
cflags_safe.size,
|
|
227
258
|
allow_rlimit
|
|
228
259
|
)
|
|
229
260
|
end
|
data/lib/rbbcc/clib.rb
CHANGED
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
|
@@ -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.3
|
|
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-20 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
|
|
@@ -125,12 +71,14 @@ files:
|
|
|
125
71
|
- examples/networking/http_filter/http-parse-simple.rb
|
|
126
72
|
- examples/ruby_usdt.rb
|
|
127
73
|
- examples/sbrk_trace.rb
|
|
74
|
+
- examples/tools/bashreadline.rb
|
|
128
75
|
- examples/tools/execsnoop.rb
|
|
129
76
|
- examples/tools/runqlat.rb
|
|
130
77
|
- examples/urandomread-explicit.rb
|
|
131
78
|
- examples/urandomread.rb
|
|
132
79
|
- examples/usdt-test.rb
|
|
133
80
|
- examples/usdt.rb
|
|
81
|
+
- exe/rbbcc
|
|
134
82
|
- lib/rbbcc.rb
|
|
135
83
|
- lib/rbbcc/bcc.rb
|
|
136
84
|
- lib/rbbcc/clib.rb
|
|
@@ -139,6 +87,8 @@ files:
|
|
|
139
87
|
- lib/rbbcc/debug.rb
|
|
140
88
|
- lib/rbbcc/disp_helper.rb
|
|
141
89
|
- lib/rbbcc/fiddle_ext.rb
|
|
90
|
+
- lib/rbbcc/invoker.rb
|
|
91
|
+
- lib/rbbcc/plugin.rb
|
|
142
92
|
- lib/rbbcc/symbol_cache.rb
|
|
143
93
|
- lib/rbbcc/table.rb
|
|
144
94
|
- lib/rbbcc/usdt.rb
|
|
@@ -147,7 +97,8 @@ files:
|
|
|
147
97
|
- rbbcc.gemspec
|
|
148
98
|
- semaphore.sh
|
|
149
99
|
homepage: https://github.com/udzura/rbbcc
|
|
150
|
-
licenses:
|
|
100
|
+
licenses:
|
|
101
|
+
- Apache-2.0
|
|
151
102
|
metadata: {}
|
|
152
103
|
post_install_message:
|
|
153
104
|
rdoc_options: []
|
|
@@ -164,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
164
115
|
- !ruby/object:Gem::Version
|
|
165
116
|
version: '0'
|
|
166
117
|
requirements: []
|
|
167
|
-
rubygems_version: 3.
|
|
118
|
+
rubygems_version: 3.1.2
|
|
168
119
|
signing_key:
|
|
169
120
|
specification_version: 4
|
|
170
121
|
summary: BCC port for MRI
|