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 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