rbbcc 0.6.4 → 0.8.0
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/.dockerignore +4 -0
- data/.github/workflows/ci.yml +38 -0
- data/Dockerfile.ci +98 -0
- data/Gemfile.lock +13 -10
- data/README.md +1 -1
- data/ci/Dockerfile.0.12.0-2.7.2 +1 -0
- data/ci/Dockerfile.0.12.0-3.0.0 +1 -0
- data/ci/Dockerfile.0.16.0-2.7.2 +1 -0
- data/ci/Dockerfile.0.16.0-3.0.0 +1 -0
- data/ci/Dockerfile.0.17.0-2.7.2 +1 -0
- data/ci/Dockerfile.0.17.0-3.0.0 +1 -0
- data/examples/bitehist.rb +1 -1
- data/examples/collectsyscall.rb +37 -10
- data/examples/hello_ring_buffer.rb +64 -0
- data/examples/sbrk_trace.rb +1 -1
- 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 +17 -0
- data/lib/rbbcc/clib.rb +6 -1
- data/lib/rbbcc/pointer.rb +15 -0
- data/lib/rbbcc/table.rb +115 -54
- data/lib/rbbcc/version.rb +1 -1
- metadata +19 -7
- data/.semaphore/semaphore.yml +0 -21
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/.dockerignore
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
name: Tests
|
2
|
+
on:
|
3
|
+
push:
|
4
|
+
branches: [ default ]
|
5
|
+
pull_request:
|
6
|
+
branches: [ default ]
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
test:
|
10
|
+
strategy:
|
11
|
+
matrix:
|
12
|
+
libbcc_version: [0.17.0, 0.16.0, 0.12.0]
|
13
|
+
ruby_version: [2.7.2, 3.0.0]
|
14
|
+
|
15
|
+
runs-on: ubuntu-18.04
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v2
|
18
|
+
- name: Login to ghcr.io
|
19
|
+
run: |
|
20
|
+
echo ${{ secrets.CR_PAT }} | docker login ghcr.io -u udzura --password-stdin
|
21
|
+
- name: Build docker container with all deps
|
22
|
+
run: |
|
23
|
+
docker build -t rbbcc-ci-${{ matrix.libbcc_version }}-${{ matrix.ruby_version }} \
|
24
|
+
-f ci/Dockerfile.${{ matrix.libbcc_version }}-${{ matrix.ruby_version }} ci/
|
25
|
+
- name: Run test
|
26
|
+
run: |
|
27
|
+
/bin/bash -c \
|
28
|
+
"docker run --privileged \
|
29
|
+
--pid=host \
|
30
|
+
-v $(pwd):/rbbcc \
|
31
|
+
-v /sys/kernel/debug:/sys/kernel/debug:rw \
|
32
|
+
-v /lib/modules:/lib/modules:ro \
|
33
|
+
-v /usr/src:/usr/src:ro \
|
34
|
+
-v /usr/include/linux:/usr/include/linux:ro \
|
35
|
+
rbbcc-ci-${{ matrix.libbcc_version }}-${{ matrix.ruby_version }} \
|
36
|
+
/bin/bash -c \
|
37
|
+
'cd /rbbcc && bundle install && bundle exec rake test'"
|
38
|
+
|
data/Dockerfile.ci
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# ref: https://github.com/iovisor/bcc/blob/master/Dockerfile.tests
|
2
|
+
FROM ubuntu:18.04
|
3
|
+
|
4
|
+
ENV LLVM_VERSION="9"
|
5
|
+
|
6
|
+
ARG BCC_VERSION="0.16.0"
|
7
|
+
ENV BCC_VERSION=$BCC_VERSION
|
8
|
+
|
9
|
+
ARG RUBY_VERSION="2.7.2"
|
10
|
+
ENV RUBY_VERSION=$RUBY_VERSION
|
11
|
+
|
12
|
+
ARG RUBY_VERSION_ARCHIVE="ruby-${RUBY_VERSION}.tar.bz2"
|
13
|
+
ENV RUBY_VERSION_ARCHIVE=$RUBY_VERSION_ARCHIVE
|
14
|
+
|
15
|
+
ARG RUBY_EXTRA_OPTS=""
|
16
|
+
ENV RUBY_EXTRA_OPTS=$RUBY_EXTRA_OPTS
|
17
|
+
|
18
|
+
ARG BCC_EXTRA_OPTS=""
|
19
|
+
ENV BCC_EXTRA_OPTS=$BCC_EXTRA_OPTS
|
20
|
+
|
21
|
+
RUN apt-get update && apt-get install -y curl gnupg && \
|
22
|
+
llvmRepository="\n\
|
23
|
+
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main\n\
|
24
|
+
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic main\n\
|
25
|
+
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-${LLVM_VERSION} main\n\
|
26
|
+
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-${LLVM_VERSION} main\n" && \
|
27
|
+
echo $llvmRepository >> /etc/apt/sources.list && \
|
28
|
+
curl -L https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \
|
29
|
+
apt-get update && apt-get install -y \
|
30
|
+
util-linux \
|
31
|
+
bison \
|
32
|
+
binutils-dev \
|
33
|
+
cmake \
|
34
|
+
flex \
|
35
|
+
g++ \
|
36
|
+
git \
|
37
|
+
kmod \
|
38
|
+
wget \
|
39
|
+
libelf-dev \
|
40
|
+
zlib1g-dev \
|
41
|
+
libiberty-dev \
|
42
|
+
libbfd-dev \
|
43
|
+
libedit-dev \
|
44
|
+
clang-${LLVM_VERSION} \
|
45
|
+
libclang-${LLVM_VERSION}-dev \
|
46
|
+
libclang-common-${LLVM_VERSION}-dev \
|
47
|
+
libclang1-${LLVM_VERSION} \
|
48
|
+
llvm-${LLVM_VERSION} \
|
49
|
+
llvm-${LLVM_VERSION}-dev \
|
50
|
+
llvm-${LLVM_VERSION}-runtime \
|
51
|
+
libllvm${LLVM_VERSION} \
|
52
|
+
systemtap-sdt-dev \
|
53
|
+
sudo \
|
54
|
+
iproute2 \
|
55
|
+
iputils-ping \
|
56
|
+
bridge-utils \
|
57
|
+
libtinfo5 \
|
58
|
+
libtinfo-dev && \
|
59
|
+
wget -O ruby-install-0.7.1.tar.gz \
|
60
|
+
https://github.com/postmodern/ruby-install/archive/v0.7.1.tar.gz && \
|
61
|
+
tar -xzvf ruby-install-0.7.1.tar.gz && \
|
62
|
+
cd ruby-install-0.7.1/ && \
|
63
|
+
make install && \
|
64
|
+
sed -i 's/^ruby_archive=.*/ruby_archive="${ruby_archive:-ruby-$ruby_version.tar.bz2}"/' /usr/local/share/ruby-install/ruby/functions.sh && \
|
65
|
+
env ruby_archive=$RUBY_VERSION_ARCHIVE ruby-install --system $RUBY_EXTRA_OPTS ruby $RUBY_VERSION && \
|
66
|
+
git config --global user.name 'udzura' && \
|
67
|
+
git config --global user.email 'udzura@udzura.jp' && \
|
68
|
+
wget -O bcc-$BCC_VERSION.tar.gz \
|
69
|
+
https://github.com/iovisor/bcc/releases/download/v$BCC_VERSION/bcc-src-with-submodule.tar.gz && \
|
70
|
+
tar -xzvf bcc-$BCC_VERSION.tar.gz && \
|
71
|
+
cd bcc/ && \
|
72
|
+
( test "$BCC_VERSION" = "0.12.0" && curl https://github.com/iovisor/bcc/commit/977a7e3a568c4c929fabeb4a025528d9b6f1e84c.patch | patch -p1 || true ) && \
|
73
|
+
git init . && git add . && git commit -m 'Dummy' && git tag v$BCC_VERSION && \
|
74
|
+
mkdir build && cd build/ && \
|
75
|
+
cmake $BCC_EXTRA_OPTS -DCMAKE_BUILD_TYPE=Release .. && \
|
76
|
+
cd src/cc && \
|
77
|
+
make -j8 && make install && \
|
78
|
+
cd ../.. && \
|
79
|
+
apt-get remove --purge -y \
|
80
|
+
binutils-dev \
|
81
|
+
libelf-dev \
|
82
|
+
zlib1g-dev \
|
83
|
+
libiberty-dev \
|
84
|
+
libbfd-dev \
|
85
|
+
libedit-dev \
|
86
|
+
clang-${LLVM_VERSION} \
|
87
|
+
libclang-${LLVM_VERSION}-dev \
|
88
|
+
libclang-common-${LLVM_VERSION}-dev \
|
89
|
+
libclang1-${LLVM_VERSION} \
|
90
|
+
llvm-${LLVM_VERSION} \
|
91
|
+
llvm-${LLVM_VERSION}-dev \
|
92
|
+
llvm-${LLVM_VERSION}-runtime \
|
93
|
+
libllvm${LLVM_VERSION} \
|
94
|
+
systemtap-sdt-dev \
|
95
|
+
libtinfo-dev && \
|
96
|
+
apt autoremove -y && \
|
97
|
+
apt-get clean -y && \
|
98
|
+
rm -rf *.tar.gz bcc/
|
data/Gemfile.lock
CHANGED
@@ -8,29 +8,32 @@ GIT
|
|
8
8
|
PATH
|
9
9
|
remote: .
|
10
10
|
specs:
|
11
|
-
rbbcc (0.
|
11
|
+
rbbcc (0.8.0)
|
12
12
|
|
13
13
|
GEM
|
14
14
|
remote: https://rubygems.org/
|
15
15
|
specs:
|
16
|
-
appbundler (0.13.
|
16
|
+
appbundler (0.13.4)
|
17
17
|
mixlib-cli (>= 1.4, < 3.0)
|
18
18
|
mixlib-shellout (>= 2.0, < 4.0)
|
19
|
-
chef-utils (
|
19
|
+
chef-utils (17.10.0)
|
20
|
+
concurrent-ruby
|
20
21
|
coderay (1.1.3)
|
22
|
+
concurrent-ruby (1.1.10)
|
21
23
|
method_source (1.0.0)
|
22
|
-
minitest (5.
|
24
|
+
minitest (5.16.1)
|
23
25
|
mixlib-cli (2.1.8)
|
24
|
-
mixlib-shellout (3.2.
|
26
|
+
mixlib-shellout (3.2.7)
|
25
27
|
chef-utils
|
26
|
-
pry (0.
|
28
|
+
pry (0.14.1)
|
27
29
|
coderay (~> 1.1)
|
28
30
|
method_source (~> 1.0)
|
29
|
-
rake (13.0.
|
30
|
-
specific_install (0.3.
|
31
|
+
rake (13.0.6)
|
32
|
+
specific_install (0.3.7)
|
31
33
|
|
32
34
|
PLATFORMS
|
33
|
-
|
35
|
+
aarch64-linux
|
36
|
+
arm64-darwin-21
|
34
37
|
|
35
38
|
DEPENDENCIES
|
36
39
|
appbundler
|
@@ -43,4 +46,4 @@ DEPENDENCIES
|
|
43
46
|
specific_install
|
44
47
|
|
45
48
|
BUNDLED WITH
|
46
|
-
2.
|
49
|
+
2.3.16
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# RbBCC
|
2
2
|
|
3
|
-
[](https://badge.fury.io/rb/rbbcc) [](https://badge.fury.io/rb/rbbcc) [](https://github.com/udzura/rbbcc/actions?query=workflow%3ATests)
|
4
4
|
|
5
5
|
RbBCC is a port of [BCC](https://github.com/iovisor/bcc) in MRI. See iovisor project page.
|
6
6
|
|
@@ -0,0 +1 @@
|
|
1
|
+
FROM ghcr.io/udzura/rbbcc-ci-images:libbcc-0.12.0
|
@@ -0,0 +1 @@
|
|
1
|
+
FROM ghcr.io/udzura/rbbcc-ci-images:libbcc-0.12.0-ruby-3.0.0
|
@@ -0,0 +1 @@
|
|
1
|
+
FROM ghcr.io/udzura/rbbcc-ci-images:libbcc-0.16.0
|
@@ -0,0 +1 @@
|
|
1
|
+
FROM ghcr.io/udzura/rbbcc-ci-images:libbcc-0.16.0-ruby-3.0.0
|
@@ -0,0 +1 @@
|
|
1
|
+
FROM ghcr.io/udzura/rbbcc-ci-images:libbcc-0.17.0
|
@@ -0,0 +1 @@
|
|
1
|
+
FROM ghcr.io/udzura/rbbcc-ci-images:libbcc-0.17.0-ruby-3.0.0
|
data/examples/bitehist.rb
CHANGED
@@ -17,7 +17,7 @@ b = BCC.new(text: <<CLANG)
|
|
17
17
|
BPF_HISTOGRAM(dist);
|
18
18
|
BPF_HISTOGRAM(dist_linear);
|
19
19
|
|
20
|
-
int
|
20
|
+
int kprobe__blk_account_io_done(struct pt_regs *ctx, struct request *req)
|
21
21
|
{
|
22
22
|
dist.increment(bpf_log2l(req->__data_len / 1024));
|
23
23
|
dist_linear.increment(req->__data_len / 1024);
|
data/examples/collectsyscall.rb
CHANGED
@@ -38,10 +38,14 @@ require 'rbbcc'
|
|
38
38
|
include RbBCC
|
39
39
|
|
40
40
|
$pid = nil
|
41
|
+
$comm = nil
|
41
42
|
|
42
43
|
if ARGV.size == 2 &&
|
43
44
|
ARGV[0] == '-p'
|
44
45
|
$pid = ARGV[1].to_i
|
46
|
+
elsif ARGV.size == 2 &&
|
47
|
+
ARGV[0] == '-c'
|
48
|
+
$comm = ARGV[1]
|
45
49
|
elsif ARGV[0] == '-h' ||
|
46
50
|
ARGV[0] == '--help'
|
47
51
|
$stderr.puts "Usage: #{$0} [-p PID]"
|
@@ -77,11 +81,15 @@ BPF_HASH(store, struct key_t, struct leaf_t);
|
|
77
81
|
TRACEPOINT_PROBE(raw_syscalls, sys_enter) {
|
78
82
|
struct key_t key = {0};
|
79
83
|
struct leaf_t initial = {0}, *val_;
|
84
|
+
char comm[16];
|
80
85
|
|
81
|
-
key.pid = bpf_get_current_pid_tgid();
|
86
|
+
// key.pid = bpf_get_current_pid_tgid();
|
87
|
+
key.pid = (bpf_get_current_pid_tgid() >> 32);
|
82
88
|
key.syscall_nr = args->id;
|
83
89
|
|
84
90
|
DO_FILTER_BY_PID
|
91
|
+
bpf_get_current_comm(&comm, sizeof(comm));
|
92
|
+
DO_FILTER_BY_COMM
|
85
93
|
|
86
94
|
val_ = store.lookup_or_try_init(&key, &initial);
|
87
95
|
if (val_) {
|
@@ -98,15 +106,17 @@ TRACEPOINT_PROBE(raw_syscalls, sys_exit) {
|
|
98
106
|
struct key_t key = {0};
|
99
107
|
struct leaf_t *val_;
|
100
108
|
|
101
|
-
key.pid = bpf_get_current_pid_tgid();
|
109
|
+
key.pid = (bpf_get_current_pid_tgid() >> 32);
|
102
110
|
key.syscall_nr = args->id;
|
103
111
|
|
104
112
|
val_ = store.lookup(&key);
|
105
113
|
if (val_) {
|
106
114
|
struct leaf_t val = *val_;
|
107
|
-
|
108
|
-
|
109
|
-
|
115
|
+
if(val.enter_ns) {
|
116
|
+
u64 delta = bpf_ktime_get_ns() - val.enter_ns;
|
117
|
+
val.enter_ns = 0;
|
118
|
+
val.elapsed_ns += delta;
|
119
|
+
}
|
110
120
|
store.update(&key, &val);
|
111
121
|
}
|
112
122
|
return 0;
|
@@ -121,6 +131,22 @@ else
|
|
121
131
|
prog.sub!('DO_FILTER_BY_PID', '')
|
122
132
|
end
|
123
133
|
|
134
|
+
if $comm
|
135
|
+
prog.sub!('DO_FILTER_BY_COMM', <<~FILTER)
|
136
|
+
int idx;
|
137
|
+
int matched = 1;
|
138
|
+
char *needle = "#{$comm}";
|
139
|
+
for(idx=0;idx<sizeof(comm);++idx) {
|
140
|
+
if (comm[idx] != needle[idx]) matched = 0;
|
141
|
+
if (!needle[idx]) break;
|
142
|
+
if (!comm[idx]) break;
|
143
|
+
}
|
144
|
+
if(!matched) return 0;
|
145
|
+
FILTER
|
146
|
+
else
|
147
|
+
prog.sub!('DO_FILTER_BY_COMM', '')
|
148
|
+
end
|
149
|
+
|
124
150
|
b = BCC.new(text: prog)
|
125
151
|
|
126
152
|
puts "Collecting syscalls..."
|
@@ -134,14 +160,15 @@ info_by_pids = {}
|
|
134
160
|
comms = {}
|
135
161
|
store = b.get_table("store")
|
136
162
|
store.items.each do |k, v|
|
137
|
-
#
|
163
|
+
#require 'pry'; binding.pry
|
164
|
+
count, elapsed_ns, _dummy, comm = v[0, 40].unpack("Q Q Q Z16")
|
138
165
|
info_by_pids[k.pid] ||= {}
|
139
166
|
info_by_pids[k.pid][k.syscall_nr] = {
|
140
167
|
name: to_name(k.syscall_nr),
|
141
|
-
count:
|
142
|
-
elapsed_ms:
|
168
|
+
count: count,
|
169
|
+
elapsed_ms: elapsed_ns / 1000000.0
|
143
170
|
}
|
144
|
-
comms[k.pid] ||=
|
171
|
+
comms[k.pid] ||= comm
|
145
172
|
end
|
146
173
|
|
147
174
|
pids = info_by_pids.keys.sort
|
@@ -149,7 +176,7 @@ pids.each do |pid|
|
|
149
176
|
puts "PID=#{pid}(maybe: #{comms[pid]}) --->"
|
150
177
|
i = info_by_pids[pid]
|
151
178
|
i.to_a.sort_by {|k, v| [-v[:count], -v[:elapsed_ms]] }.each do |nr, record|
|
152
|
-
puts "\t%<name>-
|
179
|
+
puts "\t%<name>-22s %<count>7d %<elapsed_ms>10.3f ms" % record
|
153
180
|
end
|
154
181
|
puts
|
155
182
|
end
|
@@ -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
|
data/examples/sbrk_trace.rb
CHANGED
@@ -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"
|
@@ -480,6 +481,7 @@ module RbBCC
|
|
480
481
|
def trace_fields(&do_each_line)
|
481
482
|
ret = []
|
482
483
|
while buf = trace_readline
|
484
|
+
next if buf.chomp.empty?
|
483
485
|
next if buf.start_with? "CPU:"
|
484
486
|
task = buf[0..15].lstrip()
|
485
487
|
meta, _addr, msg = buf[17..-1].split(": ", 3)
|
@@ -554,6 +556,21 @@ module RbBCC
|
|
554
556
|
Clib.perf_reader_poll(readers.size, pack, timeout)
|
555
557
|
end
|
556
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
|
+
|
557
574
|
def ksymname(name)
|
558
575
|
SymbolCache.resolve_global(name)
|
559
576
|
end
|
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.17.0 0.16.0 0.15.0 0.14.0 0.13.0 0.12.0 0.11.0 0.10.0)
|
28
|
+
targets = %w(0.18.0 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!
|
@@ -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
|
-
autorequire:
|
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:
|
@@ -18,9 +18,11 @@ executables:
|
|
18
18
|
extensions: []
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
|
+
- ".dockerignore"
|
22
|
+
- ".github/workflows/ci.yml"
|
21
23
|
- ".gitignore"
|
22
|
-
- ".semaphore/semaphore.yml"
|
23
24
|
- Dockerfile
|
25
|
+
- Dockerfile.ci
|
24
26
|
- Dockerfile.dfm-example
|
25
27
|
- Gemfile
|
26
28
|
- Gemfile.lock
|
@@ -29,6 +31,12 @@ files:
|
|
29
31
|
- Rakefile
|
30
32
|
- bin/console
|
31
33
|
- bin/setup
|
34
|
+
- ci/Dockerfile.0.12.0-2.7.2
|
35
|
+
- ci/Dockerfile.0.12.0-3.0.0
|
36
|
+
- ci/Dockerfile.0.16.0-2.7.2
|
37
|
+
- ci/Dockerfile.0.16.0-3.0.0
|
38
|
+
- ci/Dockerfile.0.17.0-2.7.2
|
39
|
+
- ci/Dockerfile.0.17.0-3.0.0
|
32
40
|
- docs/README.md
|
33
41
|
- docs/answers/01-hello-world.rb
|
34
42
|
- docs/answers/02-sys_sync.rb
|
@@ -64,6 +72,7 @@ files:
|
|
64
72
|
- examples/extract_arg.rb
|
65
73
|
- examples/hello_fields.rb
|
66
74
|
- examples/hello_perf_output.rb
|
75
|
+
- examples/hello_ring_buffer.rb
|
67
76
|
- examples/hello_world.rb
|
68
77
|
- examples/kvm_hypercall.rb
|
69
78
|
- examples/mallocstack.rb
|
@@ -71,6 +80,8 @@ files:
|
|
71
80
|
- examples/networking/http_filter/http-parse-simple.rb
|
72
81
|
- examples/ruby_usdt.rb
|
73
82
|
- examples/sbrk_trace.rb
|
83
|
+
- examples/syscalluname.rb
|
84
|
+
- examples/table.rb
|
74
85
|
- examples/tools/bashreadline.rb
|
75
86
|
- examples/tools/execsnoop.rb
|
76
87
|
- examples/tools/runqlat.rb
|
@@ -89,6 +100,7 @@ files:
|
|
89
100
|
- lib/rbbcc/fiddle_ext.rb
|
90
101
|
- lib/rbbcc/invoker.rb
|
91
102
|
- lib/rbbcc/plugin.rb
|
103
|
+
- lib/rbbcc/pointer.rb
|
92
104
|
- lib/rbbcc/symbol_cache.rb
|
93
105
|
- lib/rbbcc/table.rb
|
94
106
|
- lib/rbbcc/usdt.rb
|
@@ -100,7 +112,7 @@ homepage: https://github.com/udzura/rbbcc
|
|
100
112
|
licenses:
|
101
113
|
- Apache-2.0
|
102
114
|
metadata: {}
|
103
|
-
post_install_message:
|
115
|
+
post_install_message:
|
104
116
|
rdoc_options: []
|
105
117
|
require_paths:
|
106
118
|
- lib
|
@@ -115,8 +127,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
127
|
- !ruby/object:Gem::Version
|
116
128
|
version: '0'
|
117
129
|
requirements: []
|
118
|
-
rubygems_version: 3.
|
119
|
-
signing_key:
|
130
|
+
rubygems_version: 3.4.0.dev
|
131
|
+
signing_key:
|
120
132
|
specification_version: 4
|
121
133
|
summary: BCC port for MRI
|
122
134
|
test_files: []
|
data/.semaphore/semaphore.yml
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
version: v1.0
|
2
|
-
name: Ruby Test
|
3
|
-
agent:
|
4
|
-
machine:
|
5
|
-
type: e1-standard-2
|
6
|
-
os_image: ubuntu1804
|
7
|
-
blocks:
|
8
|
-
- name: Basic Test
|
9
|
-
task:
|
10
|
-
jobs:
|
11
|
-
- name: ruby test
|
12
|
-
matrix:
|
13
|
-
- env_var: RUBY_VERSION
|
14
|
-
values: [ "2.6.5", "2.6.6", "2.7.1" ]
|
15
|
-
- env_var: LIBBCC_VERSION
|
16
|
-
values: [ "0.12.0", "0.11.0", "0.10.0" ]
|
17
|
-
commands:
|
18
|
-
- sem-version c 7
|
19
|
-
- sem-version ruby $RUBY_VERSION
|
20
|
-
- checkout
|
21
|
-
- ./semaphore.sh
|