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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92b4487b6e8f5b72aad25113da967b51b2feb064361676b093441b6fd0bab672
4
- data.tar.gz: 03d71e58ddebacdbf41f0c1ad4422bcfa1b9acdda3ac568068a2a8751b594a97
3
+ metadata.gz: 5b46fa6dd0b99e4a178bc00bad497beab5d72426517f3d7b328c29d492e9e8a1
4
+ data.tar.gz: a5f84fdc89d50621b3dd06eca22aea243efc1991ec053acece136016ccbdfb64
5
5
  SHA512:
6
- metadata.gz: bb9234154fe245bf001676f1a6e7b1e5bcce31e4962bd0d646746d1f3c286722def93899877c9a200a516fd33366ef7c73fcf2a7a22731fb76225edb5477f449
7
- data.tar.gz: 89415cbd8cadade4b49b53b5fd1c024198bfbd3424e0d95ecaf8e00381495570e171bcf54f4c395ddf40d762821da1425945761d80166aef724e038f43ae0f3c
6
+ metadata.gz: 532f1d544b56d82e68d5931aac278bf36a850943c3e78e8851c59e56852ebe4f6a3d974fa6c129544f0c7f895696bd9b894f3d033490faff8c408bbd7deed424
7
+ data.tar.gz: 03de507c9094d850d77253610d2ffe08e2ee4ad97048e742f4c283ce6d8748de68f019a0e247ac826b5cbcbd48664a359ec57c92113f5f4015bc0c0f1984b482
data/.dockerignore ADDED
@@ -0,0 +1,4 @@
1
+ vendor/*
2
+ pkg/*
3
+ examples/*.gif
4
+ .git/*
@@ -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.6.4)
11
+ rbbcc (0.8.0)
12
12
 
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
- appbundler (0.13.2)
16
+ appbundler (0.13.4)
17
17
  mixlib-cli (>= 1.4, < 3.0)
18
18
  mixlib-shellout (>= 2.0, < 4.0)
19
- chef-utils (16.6.14)
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.14.2)
24
+ minitest (5.16.1)
23
25
  mixlib-cli (2.1.8)
24
- mixlib-shellout (3.2.2)
26
+ mixlib-shellout (3.2.7)
25
27
  chef-utils
26
- pry (0.13.1)
28
+ pry (0.14.1)
27
29
  coderay (~> 1.1)
28
30
  method_source (~> 1.0)
29
- rake (13.0.1)
30
- specific_install (0.3.5)
31
+ rake (13.0.6)
32
+ specific_install (0.3.7)
31
33
 
32
34
  PLATFORMS
33
- ruby
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.1.4
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 status](https://udzura.semaphoreci.com/badges/rbbcc.svg)](https://udzura.semaphoreci.com/projects/rbbcc)
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 kprobe__blk_account_io_completion(struct pt_regs *ctx, struct request *req)
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);
@@ -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
- u64 delta = bpf_ktime_get_ns() - val.enter_ns;
108
- val.enter_ns = 0;
109
- val.elapsed_ns += delta;
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
- # require 'pry'; binding.pry
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: v.count,
142
- elapsed_ms: v.elapsed_ns / 1000000.0
168
+ count: count,
169
+ elapsed_ms: elapsed_ns / 1000000.0
143
170
  }
144
- comms[k.pid] ||= v.comm
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>-20s %<count>3d %<elapsed_ms>8.3f ms" % record
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
@@ -33,7 +33,7 @@ def find_libc_location
33
33
  if File.exist?('/lib/x86_64-linux-gnu/libc.so.6')
34
34
  '/lib/x86_64-linux-gnu/libc.so.6'
35
35
  else
36
- `find /lib -name 'libc.so*' | grep -v musl | head -1`.chomp
36
+ `find /lib/ -name 'libc.so*' | tail -1`.chomp
37
37
  end
38
38
  end
39
39
 
@@ -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
@@ -16,6 +16,8 @@
16
16
  # Copyright 2016 Netflix, Inc.
17
17
  # Licensed under the Apache License, Version 2.0 (the "License")
18
18
 
19
+ # FIXME: random/urandom_read is removed from newer kernel!!
20
+
19
21
  require 'rbbcc'
20
22
  include RbBCC
21
23
 
@@ -11,6 +11,8 @@
11
11
  # Copyright 2016 Netflix, Inc.
12
12
  # Licensed under the Apache License, Version 2.0 (the "License")
13
13
 
14
+ # FIXME: random/urandom_read is removed from newer kernel!!
15
+
14
16
  require 'rbbcc'
15
17
  include RbBCC
16
18
 
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 *)'
@@ -0,0 +1,15 @@
1
+ module RbBCC
2
+ class Pointer
3
+ def initialize(p, value_type: nil, size: nil)
4
+ @raw_pointer = p
5
+ @size = size || p.size
6
+ @value_type = value_type
7
+ end
8
+
9
+ attr_reader :raw_pointer
10
+
11
+ def value
12
+
13
+ end
14
+ end
15
+ end
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
@@ -1,3 +1,3 @@
1
1
  module RbBCC
2
- VERSION = "0.6.4"
2
+ VERSION = "0.8.0"
3
3
  end
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.6.4
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: 2020-11-26 00:00:00.000000000 Z
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.1.2
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: []
@@ -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