rbbcc 0.6.4 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.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
|
-
[![Gem Version](https://badge.fury.io/rb/rbbcc.svg)](https://badge.fury.io/rb/rbbcc) [![CI
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/rbbcc.svg)](https://badge.fury.io/rb/rbbcc) [![CI Status](https://github.com/udzura/rbbcc/workflows/Tests/badge.svg)](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
|