rbbcc 0.11.4 → 0.11.6
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/.gitignore +2 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +3 -1
- data/examples/ringbuf_pin_a.rb +51 -0
- data/examples/ringbuf_pin_b.rb +29 -0
- data/examples/ssl_http_trace.rb +274 -0
- data/lib/rbbcc/bcc.rb +4 -1
- data/lib/rbbcc/consts.rb +5 -1
- data/lib/rbbcc/table.rb +35 -3
- data/lib/rbbcc/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4bd5c0ae3d72c8e4e931d4ecb48872212c1389dd56897a5c16ca3626a1a7a725
|
|
4
|
+
data.tar.gz: c117a487cbc4c1b5fed3df4eea8813d4b6c16ea3c6dcd306e41b504fb2776bc3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c11515d0a7b919ffaa6c0001cc74b96f0bbc217e07fa46c2fe6b37398499a6cb81fac23425e45f32b8802b6b90a6c107f845ef3b610ea7838d8b29178129adc
|
|
7
|
+
data.tar.gz: 253c500eebc928aa13327496b4cdb96f844a91df06aa5c4bf85561a1958f2c181f792e24262b1ae9d5ac0562796ffb475ae178b2a88a8451f17e50f6c1f7f727
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
rbbcc (0.11.
|
|
4
|
+
rbbcc (0.11.6)
|
|
5
5
|
fiddle
|
|
6
6
|
|
|
7
7
|
GEM
|
|
@@ -9,6 +9,7 @@ GEM
|
|
|
9
9
|
specs:
|
|
10
10
|
coderay (1.1.3)
|
|
11
11
|
fiddle (1.1.8)
|
|
12
|
+
http-2 (1.1.3)
|
|
12
13
|
io-console (0.8.2)
|
|
13
14
|
method_source (1.1.0)
|
|
14
15
|
minitest (5.27.0)
|
|
@@ -28,6 +29,7 @@ PLATFORMS
|
|
|
28
29
|
|
|
29
30
|
DEPENDENCIES
|
|
30
31
|
bundler (~> 2.0)
|
|
32
|
+
http-2 (~> 1.1)
|
|
31
33
|
minitest (~> 5)
|
|
32
34
|
pry (~> 0.12)
|
|
33
35
|
rake (~> 13.0)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'rbbcc'
|
|
3
|
+
include RbBCC
|
|
4
|
+
|
|
5
|
+
PIN_PATH = "/sys/fs/bpf/pinned_ringbuf"
|
|
6
|
+
|
|
7
|
+
if File.exist?(PIN_PATH)
|
|
8
|
+
puts "Removing old pinned map at #{PIN_PATH}..."
|
|
9
|
+
File.unlink(PIN_PATH)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
bpf_text = <<~CLANG
|
|
13
|
+
#include <uapi/linux/ptrace.h>
|
|
14
|
+
|
|
15
|
+
struct data_t {
|
|
16
|
+
u32 pid;
|
|
17
|
+
char comm[16];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
BPF_RINGBUF_OUTPUT(events, 4);
|
|
21
|
+
|
|
22
|
+
int trace_uname(struct pt_regs *ctx) {
|
|
23
|
+
struct data_t *data = events.ringbuf_reserve(sizeof(struct data_t));
|
|
24
|
+
if (!data) return 0;
|
|
25
|
+
|
|
26
|
+
data->pid = bpf_get_current_pid_tgid() >> 32;
|
|
27
|
+
bpf_get_current_comm(&data->comm, sizeof(data->comm));
|
|
28
|
+
|
|
29
|
+
events.ringbuf_submit(data, 0);
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
CLANG
|
|
33
|
+
|
|
34
|
+
puts "Process A (Ruby): Loading BPF and attaching tracepoint..."
|
|
35
|
+
b = BCC.new(text: bpf_text)
|
|
36
|
+
b.attach_tracepoint(tp: "syscalls:sys_enter_newuname", fn_name: "trace_uname")
|
|
37
|
+
|
|
38
|
+
puts "Process A (Ruby): Pinning ringbuf map to #{PIN_PATH}..."
|
|
39
|
+
b["events"].pin!(PIN_PATH)
|
|
40
|
+
|
|
41
|
+
puts "\n[Process A Active] Kept alive to feed events. Press Ctrl+C to stop."
|
|
42
|
+
begin
|
|
43
|
+
loop do
|
|
44
|
+
sleep 1
|
|
45
|
+
end
|
|
46
|
+
ensure
|
|
47
|
+
if File.exist?(PIN_PATH)
|
|
48
|
+
puts "\nUnpinning map..."
|
|
49
|
+
File.unlink(PIN_PATH)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'rbbcc'
|
|
3
|
+
include RbBCC
|
|
4
|
+
|
|
5
|
+
PIN_PATH = "/sys/fs/bpf/pinned_ringbuf"
|
|
6
|
+
|
|
7
|
+
type = "struct data_t {
|
|
8
|
+
u32 pid;
|
|
9
|
+
char comm[16];
|
|
10
|
+
};"
|
|
11
|
+
|
|
12
|
+
puts "Process B (Ruby): Initializing consumer client..."
|
|
13
|
+
buf = RingBuf.from_pin(PIN_PATH, type, 4)
|
|
14
|
+
|
|
15
|
+
# ring_buffer listner
|
|
16
|
+
buf.open_ring_buffer do |cpu, data, size|
|
|
17
|
+
event = buf.event(data)
|
|
18
|
+
puts "[Process B Captured] PID: #{event.pid.to_s.ljust(6)} | COMMAND: #{event.comm}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
puts "\n[Process B Active] Successfully hooked to pinned map (FD: #{buf.map_fd}). Listening for events...\n\n"
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
loop do
|
|
25
|
+
buf.ring_buffer_poll()
|
|
26
|
+
end
|
|
27
|
+
rescue Interrupt
|
|
28
|
+
puts "\nExiting Process B."
|
|
29
|
+
end
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "rbbcc"
|
|
5
|
+
include RbBCC
|
|
6
|
+
|
|
7
|
+
begin
|
|
8
|
+
require "http/2"
|
|
9
|
+
rescue LoadError
|
|
10
|
+
# Fallback for local vendor source
|
|
11
|
+
local_http2_lib = File.expand_path("../.agent/sources/http-2/lib", __dir__)
|
|
12
|
+
$LOAD_PATH.unshift(local_http2_lib) unless $LOAD_PATH.include?(local_http2_lib)
|
|
13
|
+
require "http/2"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
FRAME_TYPE_NAMES = {
|
|
17
|
+
0x0 => "DATA",
|
|
18
|
+
0x1 => "HEADERS",
|
|
19
|
+
0x2 => "PRIORITY",
|
|
20
|
+
0x3 => "RST_STREAM",
|
|
21
|
+
0x4 => "SETTINGS",
|
|
22
|
+
0x5 => "PUSH_PROMISE",
|
|
23
|
+
0x6 => "PING",
|
|
24
|
+
0x7 => "GOAWAY",
|
|
25
|
+
0x8 => "WINDOW_UPDATE",
|
|
26
|
+
0x9 => "CONTINUATION"
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
HTTP2_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".b
|
|
30
|
+
HTTP1_METHODS = %w[GET POST PUT PATCH DELETE HEAD OPTIONS TRACE CONNECT].freeze
|
|
31
|
+
|
|
32
|
+
BPF_TEXT = <<~BPF
|
|
33
|
+
#include <uapi/linux/ptrace.h>
|
|
34
|
+
|
|
35
|
+
#define MAX_PAYLOAD_SIZE 1024
|
|
36
|
+
|
|
37
|
+
struct event_t {
|
|
38
|
+
u32 pid;
|
|
39
|
+
char event_name[8];
|
|
40
|
+
unsigned char payload[MAX_PAYLOAD_SIZE];
|
|
41
|
+
u32 data_len;
|
|
42
|
+
s32 read_ret;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
BPF_RINGBUF_OUTPUT(events, 256);
|
|
46
|
+
|
|
47
|
+
int trace_ssl_write(struct pt_regs *ctx) {
|
|
48
|
+
u32 tgid = bpf_get_current_pid_tgid() >> 32;
|
|
49
|
+
|
|
50
|
+
const char *user_buf = (const char *)PT_REGS_PARM2(ctx);
|
|
51
|
+
u64 num = (u64)PT_REGS_PARM3(ctx);
|
|
52
|
+
if (!user_buf || num <= 0) return 0;
|
|
53
|
+
|
|
54
|
+
struct event_t *event = events.ringbuf_reserve(sizeof(struct event_t));
|
|
55
|
+
if (!event) return 0;
|
|
56
|
+
|
|
57
|
+
event->pid = tgid;
|
|
58
|
+
__builtin_memcpy(event->event_name, "ssl_w", 6);
|
|
59
|
+
|
|
60
|
+
u32 len = num > MAX_PAYLOAD_SIZE ? MAX_PAYLOAD_SIZE : (u32)num;
|
|
61
|
+
event->data_len = len;
|
|
62
|
+
|
|
63
|
+
event->read_ret = bpf_probe_read_user(event->payload, len, user_buf);
|
|
64
|
+
if (event->read_ret < 0) {
|
|
65
|
+
event->data_len = 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
events.ringbuf_submit(event, 0);
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
BPF
|
|
72
|
+
|
|
73
|
+
def hex_ascii_dump(payload, width: 16)
|
|
74
|
+
lines = []
|
|
75
|
+
payload.bytes.each_slice(width).with_index do |slice, idx|
|
|
76
|
+
offset = idx * width
|
|
77
|
+
hex = slice.map { |b| "%02x" % b }.join(" ")
|
|
78
|
+
ascii = slice.map { |b| b >= 32 && b <= 126 ? b.chr : "." }.join
|
|
79
|
+
lines << format("%04x %-#{width * 3 - 1}s %s", offset, hex, ascii)
|
|
80
|
+
end
|
|
81
|
+
lines.join("\n")
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def payload_from_event(event)
|
|
85
|
+
raw = event.payload
|
|
86
|
+
bytes = case raw
|
|
87
|
+
when String
|
|
88
|
+
raw.b
|
|
89
|
+
when Array
|
|
90
|
+
raw.map { |v| v & 0xff }.pack("C*")
|
|
91
|
+
else
|
|
92
|
+
if raw.respond_to?(:to_a)
|
|
93
|
+
raw.to_a.map { |v| v & 0xff }.pack("C*")
|
|
94
|
+
else
|
|
95
|
+
raw.to_s.b
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
len = [event.data_len.to_i, bytes.bytesize].min
|
|
100
|
+
bytes.byteslice(0, len) || "".b
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def parse_http2_frames(payload)
|
|
104
|
+
frames = []
|
|
105
|
+
i = 0
|
|
106
|
+
total = payload.bytesize
|
|
107
|
+
|
|
108
|
+
while i + 9 <= total
|
|
109
|
+
length_bytes = payload.byteslice(i, 3).bytes
|
|
110
|
+
length = (length_bytes[0] << 16) | (length_bytes[1] << 8) | length_bytes[2]
|
|
111
|
+
frame_type = payload.getbyte(i + 3)
|
|
112
|
+
flags = payload.getbyte(i + 4)
|
|
113
|
+
stream_id = payload.byteslice(i + 5, 4).unpack1("N") & 0x7fff_ffff
|
|
114
|
+
i += 9
|
|
115
|
+
break if i + length > total
|
|
116
|
+
|
|
117
|
+
frame_payload = payload.byteslice(i, length)
|
|
118
|
+
i += length
|
|
119
|
+
frames << [frame_type, flags, stream_id, frame_payload]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
frames
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def extract_headers_fragment(frame_type, flags, frame_payload)
|
|
126
|
+
return frame_payload if frame_type == 0x9 # CONTINUATION
|
|
127
|
+
return nil unless frame_type == 0x1 # HEADERS only
|
|
128
|
+
|
|
129
|
+
start_idx = 0
|
|
130
|
+
end_idx = frame_payload.bytesize
|
|
131
|
+
|
|
132
|
+
if (flags & 0x08) != 0 # PADDED
|
|
133
|
+
return nil if end_idx.zero?
|
|
134
|
+
|
|
135
|
+
pad_len = frame_payload.getbyte(0)
|
|
136
|
+
start_idx += 1
|
|
137
|
+
end_idx = [start_idx, end_idx - pad_len].max
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if (flags & 0x20) != 0 # PRIORITY
|
|
141
|
+
return nil if start_idx + 5 > end_idx
|
|
142
|
+
|
|
143
|
+
start_idx += 5
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
frame_payload.byteslice(start_idx, end_idx - start_idx) || "".b
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def decode_pseudo_headers_with_hpack(header_block, decompressor)
|
|
150
|
+
pairs = decompressor.decode(header_block.b)
|
|
151
|
+
pseudo = {}
|
|
152
|
+
pairs.each do |k, v|
|
|
153
|
+
pseudo[k] = v
|
|
154
|
+
end
|
|
155
|
+
pseudo
|
|
156
|
+
rescue StandardError => e
|
|
157
|
+
{ ":error" => e.message }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def maybe_http1_summary(payload)
|
|
161
|
+
text = payload.force_encoding(Encoding::UTF_8)
|
|
162
|
+
first_line = text.split("\r\n", 2).first
|
|
163
|
+
return nil if first_line.nil? || first_line.empty?
|
|
164
|
+
|
|
165
|
+
if HTTP1_METHODS.any? { |m| first_line.start_with?("#{m} ") }
|
|
166
|
+
return ["request", first_line]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
if first_line.start_with?("HTTP/1.1 ") || first_line.start_with?("HTTP/1.0 ")
|
|
170
|
+
return ["response", first_line]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
nil
|
|
174
|
+
rescue ArgumentError, Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError
|
|
175
|
+
nil
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def main
|
|
179
|
+
puts "SSL HTTP tracer (Ruby + ring buffer) を初期化中..."
|
|
180
|
+
|
|
181
|
+
b = BCC.new(text: BPF_TEXT)
|
|
182
|
+
|
|
183
|
+
libssl_path = ENV.fetch("LIBSSL_PATH", "/usr/lib/aarch64-linux-gnu/libssl.so.3")
|
|
184
|
+
b.attach_uprobe(name: libssl_path, sym: "SSL_write", fn_name: "trace_ssl_write")
|
|
185
|
+
puts "Attached uprobe: SSL_write (#{libssl_path})"
|
|
186
|
+
|
|
187
|
+
decompressor = HTTP2::Header::Decompressor.new
|
|
188
|
+
continuation_state = {}
|
|
189
|
+
|
|
190
|
+
b["events"].open_ring_buffer do |_ctx, data, _size|
|
|
191
|
+
event = b["events"].event(data)
|
|
192
|
+
event_name = event.event_name.to_s
|
|
193
|
+
next unless event_name == "ssl_w"
|
|
194
|
+
|
|
195
|
+
payload = payload_from_event(event)
|
|
196
|
+
puts "[PID: #{event.pid}] len=#{event.data_len} read_ret=#{event.read_ret}"
|
|
197
|
+
next if event.data_len.to_i <= 0
|
|
198
|
+
|
|
199
|
+
summary = maybe_http1_summary(payload)
|
|
200
|
+
if summary
|
|
201
|
+
kind, line = summary
|
|
202
|
+
puts "[HTTP/1.x #{kind}] #{line}"
|
|
203
|
+
puts hex_ascii_dump(payload)
|
|
204
|
+
next
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
rest = payload
|
|
208
|
+
if rest.start_with?(HTTP2_PREFACE)
|
|
209
|
+
puts "[H2] client preface detected"
|
|
210
|
+
rest = rest.byteslice(HTTP2_PREFACE.bytesize..) || "".b
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
frames = parse_http2_frames(rest)
|
|
214
|
+
if frames.empty?
|
|
215
|
+
puts hex_ascii_dump(payload)
|
|
216
|
+
next
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
frames.each do |frame_type, flags, stream_id, frame_payload|
|
|
220
|
+
frame_name = FRAME_TYPE_NAMES.fetch(frame_type, "UNKNOWN(#{frame_type})")
|
|
221
|
+
puts "[H2] type=#{frame_name} flags=0x#{format('%02x', flags)} stream=#{stream_id} len=#{frame_payload.bytesize}"
|
|
222
|
+
|
|
223
|
+
case frame_type
|
|
224
|
+
when 0x1 # HEADERS
|
|
225
|
+
fragment = extract_headers_fragment(frame_type, flags, frame_payload)
|
|
226
|
+
if fragment.nil?
|
|
227
|
+
puts "[HPACK] parse_error=invalid HEADERS payload"
|
|
228
|
+
next
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
key = [event.pid.to_i, stream_id]
|
|
232
|
+
if (flags & 0x04) != 0 # END_HEADERS
|
|
233
|
+
pseudo = decode_pseudo_headers_with_hpack(fragment, decompressor)
|
|
234
|
+
if pseudo.key?(":error")
|
|
235
|
+
puts "[HPACK] decode_error=#{pseudo[":error"]}"
|
|
236
|
+
else
|
|
237
|
+
puts "[HPACK] :method=#{pseudo.fetch(":method", "?")} :path=#{pseudo.fetch(":path", "?")}"
|
|
238
|
+
end
|
|
239
|
+
else
|
|
240
|
+
continuation_state[key] = fragment.dup
|
|
241
|
+
puts "[HPACK] collecting CONTINUATION fragments"
|
|
242
|
+
end
|
|
243
|
+
when 0x9 # CONTINUATION
|
|
244
|
+
key = [event.pid.to_i, stream_id]
|
|
245
|
+
fragment = extract_headers_fragment(frame_type, flags, frame_payload)
|
|
246
|
+
unless continuation_state.key?(key)
|
|
247
|
+
puts "[HPACK] note=orphan CONTINUATION frame"
|
|
248
|
+
next
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
continuation_state[key] << fragment
|
|
252
|
+
next if (flags & 0x04).zero?
|
|
253
|
+
|
|
254
|
+
header_block = continuation_state.delete(key)
|
|
255
|
+
pseudo = decode_pseudo_headers_with_hpack(header_block, decompressor)
|
|
256
|
+
if pseudo.key?(":error")
|
|
257
|
+
puts "[HPACK] decode_error=#{pseudo[":error"]}"
|
|
258
|
+
else
|
|
259
|
+
puts "[HPACK] :method=#{pseudo.fetch(":method", "?")} :path=#{pseudo.fetch(":path", "?")}"
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
puts "監視開始。Ctrl+C で終了"
|
|
266
|
+
loop do
|
|
267
|
+
b.ring_buffer_poll(100)
|
|
268
|
+
rescue Interrupt
|
|
269
|
+
puts "\n終了します。"
|
|
270
|
+
exit(0)
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
main if $PROGRAM_NAME == __FILE__
|
data/lib/rbbcc/bcc.rb
CHANGED
|
@@ -607,7 +607,10 @@ module RbBCC
|
|
|
607
607
|
end
|
|
608
608
|
|
|
609
609
|
def _open_ring_buffer(map_fd, fn, ctx)
|
|
610
|
-
|
|
610
|
+
# Avoid GC'ing function pointer
|
|
611
|
+
@_ring_buffer_fns ||= []
|
|
612
|
+
@_ring_buffer_fns << fn
|
|
613
|
+
buf = Clib.bpf_new_ringbuf(map_fd, @_ring_buffer_fns[-1], ctx)
|
|
611
614
|
if !buf
|
|
612
615
|
raise "Could not open ring buffer"
|
|
613
616
|
end
|
data/lib/rbbcc/consts.rb
CHANGED
data/lib/rbbcc/table.rb
CHANGED
|
@@ -40,6 +40,8 @@ module RbBCC
|
|
|
40
40
|
fields << [field_type, field_name].join(" ")
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
|
+
return nil if fields.empty?
|
|
44
|
+
|
|
43
45
|
klass = Fiddle::Importer.struct(fields)
|
|
44
46
|
char_ps = fields.select {|f| f =~ /^char\[(\d+)\] ([_a-zA-Z0-9]+)/ }
|
|
45
47
|
unless char_ps.empty?
|
|
@@ -280,6 +282,11 @@ module RbBCC
|
|
|
280
282
|
false # TODO: implement me in the future
|
|
281
283
|
end
|
|
282
284
|
|
|
285
|
+
# Just a wrapper to BCC class method
|
|
286
|
+
def pin!(path)
|
|
287
|
+
BCC.pin!(self.map_fd, path)
|
|
288
|
+
end
|
|
289
|
+
|
|
283
290
|
private
|
|
284
291
|
def normalize_key(key)
|
|
285
292
|
case key
|
|
@@ -368,7 +375,7 @@ module RbBCC
|
|
|
368
375
|
end
|
|
369
376
|
|
|
370
377
|
def event(data)
|
|
371
|
-
@event_class ||= get_event_class
|
|
378
|
+
@event_class ||= (get_event_class || self.leaftype)
|
|
372
379
|
ev = @event_class.malloc
|
|
373
380
|
Fiddle::Pointer.new(ev.to_ptr)[0, @event_class.size] = data[0, @event_class.size]
|
|
374
381
|
return ev
|
|
@@ -429,7 +436,28 @@ module RbBCC
|
|
|
429
436
|
|
|
430
437
|
class RingBuf < TableBase
|
|
431
438
|
include EventTypeSupported
|
|
432
|
-
|
|
439
|
+
|
|
440
|
+
# Make a dynamic BCC program to load the pinned ringbuf map
|
|
441
|
+
def self.from_pin(path, leaftype, size, name: "events")
|
|
442
|
+
map_fd = Clib.bpf_obj_get(path)
|
|
443
|
+
if map_fd < 0
|
|
444
|
+
raise SystemCallError.new("Could not open pinned map", Fiddle.last_error)
|
|
445
|
+
end
|
|
446
|
+
leaftype_typename = case leaftype
|
|
447
|
+
when /\Astruct\s+(\w+)\s+{/m
|
|
448
|
+
"struct #{Regexp.last_match(1)}"
|
|
449
|
+
else
|
|
450
|
+
leaftype
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
prog = <<~CLANG
|
|
454
|
+
#{leaftype}
|
|
455
|
+
BPF_TABLE_PINNED("ringbuf", u32, #{leaftype_typename}, #{name}, #{size}, "#{path}");
|
|
456
|
+
CLANG
|
|
457
|
+
b = BCC.new(text: prog)
|
|
458
|
+
b[name.to_s]
|
|
459
|
+
end
|
|
460
|
+
|
|
433
461
|
def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
|
|
434
462
|
super
|
|
435
463
|
@_ringbuf = nil
|
|
@@ -438,7 +466,7 @@ module RbBCC
|
|
|
438
466
|
end
|
|
439
467
|
|
|
440
468
|
def event(data)
|
|
441
|
-
@event_class ||= get_event_class
|
|
469
|
+
@event_class ||= (get_event_class || self.leaftype)
|
|
442
470
|
ev = @event_class.malloc
|
|
443
471
|
Fiddle::Pointer.new(ev.to_ptr)[0, @event_class.size] = data[0, @event_class.size]
|
|
444
472
|
return ev
|
|
@@ -470,6 +498,10 @@ module RbBCC
|
|
|
470
498
|
@bpf._open_ring_buffer(@map_fd, fn, ctx)
|
|
471
499
|
nil
|
|
472
500
|
end
|
|
501
|
+
|
|
502
|
+
def ring_buffer_poll(timeout=-1)
|
|
503
|
+
@bpf.ring_buffer_poll(timeout)
|
|
504
|
+
end
|
|
473
505
|
end
|
|
474
506
|
|
|
475
507
|
class StackTrace < TableBase
|
data/lib/rbbcc/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rbbcc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.11.
|
|
4
|
+
version: 0.11.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Uchio Kondo
|
|
@@ -99,8 +99,11 @@ files:
|
|
|
99
99
|
- examples/pin_maps_a.rb
|
|
100
100
|
- examples/pin_maps_b.rb
|
|
101
101
|
- examples/py-orig/sockblock.py
|
|
102
|
+
- examples/ringbuf_pin_a.rb
|
|
103
|
+
- examples/ringbuf_pin_b.rb
|
|
102
104
|
- examples/ruby_usdt.rb
|
|
103
105
|
- examples/sbrk_trace.rb
|
|
106
|
+
- examples/ssl_http_trace.rb
|
|
104
107
|
- examples/syscalluname.rb
|
|
105
108
|
- examples/table.rb
|
|
106
109
|
- examples/tools/bashreadline.rb
|