rbbcc 0.11.6 → 0.11.8
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/Gemfile.lock +1 -1
- data/lib/rbbcc/table.rb +8 -7
- data/lib/rbbcc/version.rb +1 -1
- data/rbbcc.gemspec +5 -2
- metadata +2 -62
- data/docs/README.md +0 -7
- data/docs/answers/01-hello-world.rb +0 -16
- data/docs/answers/02-sys_sync.rb +0 -18
- data/docs/answers/03-hello_fields.rb +0 -33
- data/docs/answers/04-sync_timing.rb +0 -46
- data/docs/answers/05-sync_count.rb +0 -54
- data/docs/answers/06-disksnoop.rb +0 -71
- data/docs/answers/07-hello_perf_output.rb +0 -59
- data/docs/answers/08-sync_perf_output.rb +0 -60
- data/docs/answers/09-bitehist.rb +0 -32
- data/docs/answers/10-disklatency.rb +0 -51
- data/docs/answers/11-vfsreadlat.c +0 -46
- data/docs/answers/11-vfsreadlat.rb +0 -66
- data/docs/answers/12-urandomread.rb +0 -38
- data/docs/answers/13-disksnoop_fixed.rb +0 -108
- data/docs/answers/14-strlen_count.rb +0 -46
- data/docs/answers/15-nodejs_http_server.rb +0 -44
- data/docs/answers/16-task_switch.c +0 -23
- data/docs/answers/16-task_switch.rb +0 -17
- data/docs/answers/node-server.js +0 -11
- data/docs/getting_started.md +0 -154
- data/docs/projects_using_rbbcc.md +0 -43
- data/docs/tutorial_bcc_ruby_developer.md +0 -774
- data/docs/tutorial_bcc_ruby_developer_japanese.md +0 -770
- data/examples/bitehist.rb +0 -46
- data/examples/charty/Gemfile +0 -11
- data/examples/charty/Gemfile.lock +0 -48
- data/examples/charty/bitehist-unicode.rb +0 -87
- data/examples/collectsyscall.rb +0 -182
- data/examples/dddos.rb +0 -112
- data/examples/disksnoop.rb +0 -73
- data/examples/dns_blocker.rb +0 -134
- data/examples/example.gif +0 -0
- data/examples/extract_arg.rb +0 -26
- data/examples/hello_fields.rb +0 -32
- data/examples/hello_perf_output.rb +0 -64
- data/examples/hello_ring_buffer.rb +0 -64
- data/examples/hello_world.rb +0 -6
- data/examples/kvm_hypercall.rb +0 -69
- data/examples/lsm_sockblock.rb +0 -141
- data/examples/mallocstack.rb +0 -63
- data/examples/networking/http_filter/http-parse-simple.c +0 -114
- data/examples/networking/http_filter/http-parse-simple.rb +0 -85
- data/examples/pin_maps_a.rb +0 -88
- data/examples/pin_maps_b.rb +0 -71
- data/examples/py-orig/sockblock.py +0 -119
- data/examples/ringbuf_pin_a.rb +0 -51
- data/examples/ringbuf_pin_b.rb +0 -29
- data/examples/ruby_usdt.rb +0 -105
- data/examples/sbrk_trace.rb +0 -204
- data/examples/ssl_http_trace.rb +0 -274
- data/examples/syscalluname.rb +0 -39
- data/examples/table.rb +0 -15
- data/examples/tools/bashreadline.rb +0 -83
- data/examples/tools/execsnoop.rb +0 -229
- data/examples/tools/runqlat.rb +0 -148
- data/examples/urandomread-explicit.rb +0 -58
- data/examples/urandomread.rb +0 -39
- data/examples/usdt-test.rb +0 -6
- data/examples/usdt.rb +0 -26
data/examples/pin_maps_a.rb
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# pin_maps_a.rb
|
|
4
|
-
# Program A: create HashMap/ArrayMap, hook execve, count up, and pin maps.
|
|
5
|
-
#
|
|
6
|
-
# Usage (root):
|
|
7
|
-
# sudo ruby examples/pin_maps_a.rb --pin-dir /sys/fs/bpf/rbbcc_pin_demo
|
|
8
|
-
|
|
9
|
-
require 'rbbcc'
|
|
10
|
-
require 'optparse'
|
|
11
|
-
require 'fileutils'
|
|
12
|
-
|
|
13
|
-
include RbBCC
|
|
14
|
-
|
|
15
|
-
BPF_TEXT = <<~CLANG
|
|
16
|
-
BPF_HASH(pin_hash_map, u32, u64, 1024);
|
|
17
|
-
BPF_ARRAY(pin_array_map, u64, 1);
|
|
18
|
-
|
|
19
|
-
int trace_execve(void *ctx) {
|
|
20
|
-
u64 zero = 0;
|
|
21
|
-
u32 pid = bpf_get_current_pid_tgid();
|
|
22
|
-
u32 idx = 0;
|
|
23
|
-
u64 *hval;
|
|
24
|
-
u64 *aval;
|
|
25
|
-
|
|
26
|
-
hval = pin_hash_map.lookup_or_try_init(&pid, &zero);
|
|
27
|
-
if (hval) {
|
|
28
|
-
__sync_fetch_and_add(hval, 1);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
aval = pin_array_map.lookup(&idx);
|
|
32
|
-
if (aval) {
|
|
33
|
-
__sync_fetch_and_add(aval, 1);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return 0;
|
|
37
|
-
}
|
|
38
|
-
CLANG
|
|
39
|
-
|
|
40
|
-
options = {
|
|
41
|
-
pin_dir: '/sys/fs/bpf/rbbcc_pin_demo'
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
OptionParser.new do |opts|
|
|
45
|
-
opts.banner = 'Usage: pin_maps_a.rb [options]'
|
|
46
|
-
|
|
47
|
-
opts.on('--pin-dir DIR', 'Pin directory under bpffs') do |v|
|
|
48
|
-
options[:pin_dir] = v
|
|
49
|
-
end
|
|
50
|
-
end.parse!
|
|
51
|
-
|
|
52
|
-
b = BCC.new(text: BPF_TEXT)
|
|
53
|
-
b.attach_kprobe(
|
|
54
|
-
event: b.get_syscall_fnname('execve'),
|
|
55
|
-
fn_name: 'trace_execve'
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
hash_map = b['pin_hash_map']
|
|
59
|
-
array_map = b['pin_array_map']
|
|
60
|
-
|
|
61
|
-
# Initialize global counter slot.
|
|
62
|
-
array_map[0] = 0
|
|
63
|
-
|
|
64
|
-
FileUtils.mkdir_p(options[:pin_dir])
|
|
65
|
-
hash_path = File.join(options[:pin_dir], 'pin_hash_map')
|
|
66
|
-
array_path = File.join(options[:pin_dir], 'pin_array_map')
|
|
67
|
-
|
|
68
|
-
File.unlink(hash_path) if File.exist?(hash_path)
|
|
69
|
-
File.unlink(array_path) if File.exist?(array_path)
|
|
70
|
-
|
|
71
|
-
BCC.pin!(hash_map.map_fd, hash_path)
|
|
72
|
-
BCC.pin!(array_map.map_fd, array_path)
|
|
73
|
-
|
|
74
|
-
puts 'Pinned maps created.'
|
|
75
|
-
puts " hash map: #{hash_path}"
|
|
76
|
-
puts " array map: #{array_path}"
|
|
77
|
-
puts 'kprobe attached to execve. Run some commands in another terminal.'
|
|
78
|
-
puts 'Press Ctrl-C to stop Program A.'
|
|
79
|
-
|
|
80
|
-
begin
|
|
81
|
-
loop do
|
|
82
|
-
sleep 1
|
|
83
|
-
total = array_map[0]&.to_bcc_value || 0
|
|
84
|
-
puts "execve total count: #{total}"
|
|
85
|
-
end
|
|
86
|
-
rescue Interrupt
|
|
87
|
-
puts '\nStopping Program A...'
|
|
88
|
-
end
|
data/examples/pin_maps_b.rb
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# pin_maps_b.rb
|
|
4
|
-
# Program B: open pinned HashMap/ArrayMap with from_pin and read/update values.
|
|
5
|
-
#
|
|
6
|
-
# Usage (root):
|
|
7
|
-
# sudo ruby examples/pin_maps_b.rb --pin-dir /sys/fs/bpf/rbbcc_pin_demo
|
|
8
|
-
|
|
9
|
-
require 'rbbcc'
|
|
10
|
-
require 'optparse'
|
|
11
|
-
|
|
12
|
-
include RbBCC
|
|
13
|
-
|
|
14
|
-
options = {
|
|
15
|
-
pin_dir: '/sys/fs/bpf/rbbcc_pin_demo'
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
OptionParser.new do |opts|
|
|
19
|
-
opts.banner = 'Usage: pin_maps_b.rb [options]'
|
|
20
|
-
|
|
21
|
-
opts.on('--pin-dir DIR', 'Pin directory under bpffs') do |v|
|
|
22
|
-
options[:pin_dir] = v
|
|
23
|
-
end
|
|
24
|
-
end.parse!
|
|
25
|
-
|
|
26
|
-
hash_path = File.join(options[:pin_dir], 'pin_hash_map')
|
|
27
|
-
array_path = File.join(options[:pin_dir], 'pin_array_map')
|
|
28
|
-
|
|
29
|
-
unless File.exist?(hash_path) && File.exist?(array_path)
|
|
30
|
-
abort("Pinned map files are missing. Run pin_maps_a.rb first: #{options[:pin_dir]}")
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Explicitly pass key/leaf type and size; no type detection is performed.
|
|
34
|
-
hash_map = HashTable.from_pin(
|
|
35
|
-
hash_path,
|
|
36
|
-
'unsigned int',
|
|
37
|
-
'unsigned long long',
|
|
38
|
-
keysize: 4,
|
|
39
|
-
leafsize: 8
|
|
40
|
-
)
|
|
41
|
-
array_map = ArrayTable.from_pin(
|
|
42
|
-
array_path,
|
|
43
|
-
'unsigned int',
|
|
44
|
-
'unsigned long long',
|
|
45
|
-
keysize: 4,
|
|
46
|
-
leafsize: 8
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
puts 'Loaded pinned maps.'
|
|
50
|
-
puts " hash map fd: #{hash_map.map_fd}"
|
|
51
|
-
puts " array map fd: #{array_map.map_fd}"
|
|
52
|
-
puts " hash ttype: #{hash_map.ttype}"
|
|
53
|
-
puts " array ttype: #{array_map.ttype}"
|
|
54
|
-
|
|
55
|
-
puts 'Read existing values:'
|
|
56
|
-
puts " hash[1] = #{hash_map[1]&.to_bcc_value.inspect}"
|
|
57
|
-
puts " hash[2] = #{hash_map[2]&.to_bcc_value.inspect}"
|
|
58
|
-
puts " array[0] = #{array_map[0]&.to_bcc_value.inspect}"
|
|
59
|
-
puts " array[1] = #{array_map[1]&.to_bcc_value.inspect}"
|
|
60
|
-
|
|
61
|
-
hash_map[3] = 1
|
|
62
|
-
array_map[0] = (array_map[0]&.to_bcc_value || 0) + 1
|
|
63
|
-
|
|
64
|
-
puts 'Updated values:'
|
|
65
|
-
puts " hash[3] = #{hash_map[3]&.to_bcc_value.inspect}"
|
|
66
|
-
puts " array[0] = #{array_map[0]&.to_bcc_value.inspect}"
|
|
67
|
-
|
|
68
|
-
puts 'Iterate hash entries:'
|
|
69
|
-
hash_map.each_pair do |k, v|
|
|
70
|
-
puts " #{k.to_bcc_value} => #{v.to_bcc_value}"
|
|
71
|
-
end
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
from bcc import BPF, lib
|
|
2
|
-
import socket
|
|
3
|
-
import ctypes
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
# 1. C言語側のプログラム
|
|
7
|
-
program = r"""
|
|
8
|
-
#include <linux/lsm_hooks.h>
|
|
9
|
-
#include <linux/socket.h>
|
|
10
|
-
#include <uapi/asm-generic/errno-base.h>
|
|
11
|
-
|
|
12
|
-
struct data_t {
|
|
13
|
-
u32 pid;
|
|
14
|
-
int family;
|
|
15
|
-
int type;
|
|
16
|
-
int is_warning;
|
|
17
|
-
int is_blocked;
|
|
18
|
-
char comm[16];
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
BPF_PERF_OUTPUT(events);
|
|
22
|
-
|
|
23
|
-
// モード保存用マップ (Index 0 を使用)
|
|
24
|
-
// 1: blockモード, 0: previewモード
|
|
25
|
-
BPF_ARRAY(config_map, u32, 1);
|
|
26
|
-
|
|
27
|
-
LSM_PROBE(socket_create, int family, int type, int protocol, int kern)
|
|
28
|
-
{
|
|
29
|
-
u32 pid = bpf_get_current_pid_tgid() >> 32;
|
|
30
|
-
struct data_t data = {};
|
|
31
|
-
|
|
32
|
-
// マップから現在のモードを取得
|
|
33
|
-
u32 key = 0;
|
|
34
|
-
u32 *mode = config_map.lookup(&key);
|
|
35
|
-
int is_block_mode = (mode && *mode == 1);
|
|
36
|
-
|
|
37
|
-
data.pid = pid;
|
|
38
|
-
data.family = family;
|
|
39
|
-
data.type = type;
|
|
40
|
-
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
|
41
|
-
|
|
42
|
-
if (family == AF_ALG) {
|
|
43
|
-
data.is_blocked = is_block_mode;
|
|
44
|
-
data.is_warning = 1;
|
|
45
|
-
|
|
46
|
-
// ログデータを送信
|
|
47
|
-
events.perf_submit(ctx, &data, sizeof(data));
|
|
48
|
-
|
|
49
|
-
// blockモードならエラーを返してシステムコールを失敗させる
|
|
50
|
-
if (is_block_mode) {
|
|
51
|
-
return -EPERM; // -1 (Operation not permitted)
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
data.is_blocked = 0;
|
|
55
|
-
data.is_warning = 0;
|
|
56
|
-
|
|
57
|
-
// ログデータを送信
|
|
58
|
-
events.perf_submit(ctx, &data, sizeof(data));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return 0;
|
|
62
|
-
}
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
|
-
# 定数解決用
|
|
66
|
-
families = {getattr(socket, n): n for n in dir(socket) if n.startswith('AF_')}
|
|
67
|
-
types = {getattr(socket, n): n for n in dir(socket) if n.startswith('SOCK_')}
|
|
68
|
-
|
|
69
|
-
def print_event(cpu, data, size):
|
|
70
|
-
event = b["events"].event(data)
|
|
71
|
-
|
|
72
|
-
family_str = families.get(event.family, f"AF_UNKNOWN({event.family})")
|
|
73
|
-
type_str = types.get(event.type, f"SOCK_UNKNOWN({event.type})")
|
|
74
|
-
|
|
75
|
-
print(f"PID: {event.pid:<7} | COMM: {event.comm.decode('utf-8'):<15} | "
|
|
76
|
-
f"FAMILY: {family_str:<12} | TYPE: {type_str}")
|
|
77
|
-
|
|
78
|
-
if event.is_warning:
|
|
79
|
-
mode_str = "BLOCK" if event.is_blocked else "PREVIEW"
|
|
80
|
-
status = "!! REJECTED !!" if event.is_blocked else "WARNING"
|
|
81
|
-
|
|
82
|
-
print(f"[{mode_str}] {status}: PID {event.pid} ({event.comm.decode()}) "
|
|
83
|
-
f"tried to create AF_ALG socket.")
|
|
84
|
-
|
|
85
|
-
# 2. ロードと設定
|
|
86
|
-
try:
|
|
87
|
-
b = BPF(text=program)
|
|
88
|
-
|
|
89
|
-
# --- モード設定 ---
|
|
90
|
-
# 1 を書き込むと blockモード、0 だと previewモード
|
|
91
|
-
mode = 0
|
|
92
|
-
config_table = b.get_table("config_map")
|
|
93
|
-
config_table[ctypes.c_uint32(0)] = ctypes.c_uint32(mode)
|
|
94
|
-
|
|
95
|
-
# Mapの永続化 - ユーザ空間からモードを変更できるようにするため
|
|
96
|
-
map_path = "/sys/fs/bpf/my_config_map"
|
|
97
|
-
if os.path.exists(map_path):
|
|
98
|
-
os.remove(map_path)
|
|
99
|
-
print(f"Pinning config map to -> {map_path}")
|
|
100
|
-
map_fd = config_table.get_fd()
|
|
101
|
-
res = lib.bpf_obj_pin(map_fd, ctypes.c_char_p(map_path.encode()))
|
|
102
|
-
if res != 0:
|
|
103
|
-
raise Exception(f"Failed to pin map to {map_path}: {os.strerror(-res)}")
|
|
104
|
-
|
|
105
|
-
# -----------------
|
|
106
|
-
|
|
107
|
-
print(f"LSM BPF started in {'BLOCK' if mode == 1 else 'PREVIEW'} mode.")
|
|
108
|
-
print("Tracing AF_ALG creation... Press Ctrl-C to exit.")
|
|
109
|
-
|
|
110
|
-
b["events"].open_perf_buffer(print_event)
|
|
111
|
-
|
|
112
|
-
while True:
|
|
113
|
-
try:
|
|
114
|
-
b.perf_buffer_poll()
|
|
115
|
-
except KeyboardInterrupt:
|
|
116
|
-
exit()
|
|
117
|
-
|
|
118
|
-
except Exception as e:
|
|
119
|
-
print(f"Failed: {e}")
|
data/examples/ringbuf_pin_a.rb
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
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
|
data/examples/ringbuf_pin_b.rb
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
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
|
data/examples/ruby_usdt.rb
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# To run this example, please build the target ruby with an `--enable-dtrace` option in advance.
|
|
3
|
-
# To build via rbenv, sample command is:
|
|
4
|
-
# $ RUBY_CONFIGURE_OPTS='--enable-dtrace' rbenv install 2.7.0
|
|
5
|
-
#
|
|
6
|
-
# Example autput:
|
|
7
|
-
# # bundle exec ruby examples/ruby_usdt.rb $(pidof irb)
|
|
8
|
-
# TIME(s) COMM KLASS PATH
|
|
9
|
-
# 0.000000000 irb Struct::Key /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline.rb
|
|
10
|
-
# 0.000055206 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
|
11
|
-
# 0.000088588 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
12
|
-
# 0.000117740 irb Ripper::Lexer::Elem /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
13
|
-
# 0.000126697 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
14
|
-
# 0.000213388 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
|
15
|
-
# 0.000225678 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
16
|
-
# 0.000243638 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
|
17
|
-
# 0.000254680 irb Range /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb/ruby-lex.rb
|
|
18
|
-
# 0.000264707 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
19
|
-
# 0.000275579 irb Ripper::Lexer::Elem /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
20
|
-
# 0.000282438 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
21
|
-
# 0.000326136 irb String /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb.rb
|
|
22
|
-
# 0.001353621 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
|
23
|
-
# 0.001385320 irb IRB::Color::SymbolState /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb/color.rb
|
|
24
|
-
# 0.001397043 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb/color.rb
|
|
25
|
-
# 0.001416420 irb Ripper::Lexer::Elem /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
26
|
-
# 0.001423861 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
27
|
-
# 0.001462010 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
28
|
-
# 0.001478995 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
|
29
|
-
# 0.001487499 irb Range /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb/ruby-lex.rb
|
|
30
|
-
# 0.001496666 irb Ripper::Lexer /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
31
|
-
# 0.001508224 irb Ripper::Lexer::Elem /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
32
|
-
# 0.001515143 irb Ripper::Lexer::State /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/ripper/lexer.rb
|
|
33
|
-
# 0.001556170 irb String /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/irb.rb
|
|
34
|
-
# 0.001726273 irb String /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
|
35
|
-
# 0.001946948 irb Array /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline/line_editor.rb
|
|
36
|
-
# 0.001956585 irb String /root/.rbenv/versions/2.7.0/lib/ruby/2.7.0/reline.rb
|
|
37
|
-
|
|
38
|
-
require 'rbbcc'
|
|
39
|
-
include RbBCC
|
|
40
|
-
|
|
41
|
-
pid = ARGV[0] || begin
|
|
42
|
-
puts("USAGE: #{$0} PID")
|
|
43
|
-
exit()
|
|
44
|
-
end
|
|
45
|
-
debug = !!ENV['DEBUG']
|
|
46
|
-
|
|
47
|
-
bpf_text = <<BPF
|
|
48
|
-
#include <uapi/linux/ptrace.h>
|
|
49
|
-
#include <linux/sched.h>
|
|
50
|
-
|
|
51
|
-
struct data_t {
|
|
52
|
-
u64 ts;
|
|
53
|
-
char comm[TASK_COMM_LEN];
|
|
54
|
-
char klass[64];
|
|
55
|
-
char path[256];
|
|
56
|
-
};
|
|
57
|
-
BPF_PERF_OUTPUT(events);
|
|
58
|
-
|
|
59
|
-
int do_trace_create_object(struct pt_regs *ctx) {
|
|
60
|
-
struct data_t data = {};
|
|
61
|
-
uint64_t addr, addr2;
|
|
62
|
-
|
|
63
|
-
data.ts = bpf_ktime_get_ns();
|
|
64
|
-
|
|
65
|
-
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
|
66
|
-
bpf_usdt_readarg_p(1, ctx, &data.klass, sizeof(data.klass));
|
|
67
|
-
bpf_usdt_readarg_p(2, ctx, &data.path, sizeof(data.path));
|
|
68
|
-
|
|
69
|
-
events.perf_submit(ctx, &data, sizeof(data));
|
|
70
|
-
|
|
71
|
-
return 0;
|
|
72
|
-
};
|
|
73
|
-
BPF
|
|
74
|
-
|
|
75
|
-
u = USDT.new(pid: pid.to_i)
|
|
76
|
-
u.enable_probe(probe: "object__create", fn_name: "do_trace_create_object")
|
|
77
|
-
if debug
|
|
78
|
-
puts(u.get_text)
|
|
79
|
-
puts(bpf_text)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# initialize BPF
|
|
83
|
-
b = BCC.new(text: bpf_text, usdt_contexts: [u])
|
|
84
|
-
|
|
85
|
-
puts("%-18s %-6s %-24s %s" % ["TIME(s)", "COMM", "KLASS", "PATH"])
|
|
86
|
-
|
|
87
|
-
# process event
|
|
88
|
-
start = 0
|
|
89
|
-
b["events"].open_perf_buffer do |cpu, data, size|
|
|
90
|
-
event = b["events"].event(data)
|
|
91
|
-
if start == 0
|
|
92
|
-
start = event.ts
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
time_s = ((event.ts - start).to_f) / 1000000000
|
|
96
|
-
puts(
|
|
97
|
-
"%-18.9f %-6s %-24s %s" %
|
|
98
|
-
[time_s, event.comm, event.klass, event.path]
|
|
99
|
-
)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
Signal.trap(:INT) { puts "\nDone."; exit }
|
|
103
|
-
loop do
|
|
104
|
-
b.perf_buffer_poll()
|
|
105
|
-
end
|
data/examples/sbrk_trace.rb
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# Trace example for libc's USDT:
|
|
3
|
-
# - memory_sbrk_more
|
|
4
|
-
# - memory_sbrk_less
|
|
5
|
-
# - memory_mallopt_free_dyn_thresholds
|
|
6
|
-
# Description is here: https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Probes.html
|
|
7
|
-
#
|
|
8
|
-
# Example output:
|
|
9
|
-
# bundle exec ruby examples/sbrk_trace.rb -c ruby
|
|
10
|
-
# !! Trace start.
|
|
11
|
-
# [ 0.000000000] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x55f34b979000 size=135168
|
|
12
|
-
# [ 0.036549804] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9760000 size=135168
|
|
13
|
-
# [ 0.036804183] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9781000 size=143360
|
|
14
|
-
# [ 0.036855378] pid=32756 comm=ruby probe=memory_sbrk_less addr=0x557fd97a0000 size=16384
|
|
15
|
-
# [ 0.036931376] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd97a0000 size=147456
|
|
16
|
-
# [ 0.036940382] pid=32756 comm=ruby probe=memory_sbrk_less addr=0x557fd97c0000 size=16384
|
|
17
|
-
# [ 0.037022971] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd97c0000 size=151552
|
|
18
|
-
# [ 0.038602464] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd97e5000 size=204800
|
|
19
|
-
# [ 0.039398297] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9817000 size=135168
|
|
20
|
-
# [ 0.039909594] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9838000 size=135168
|
|
21
|
-
# [ 0.040536005] pid=32756 comm=ruby probe=memory_sbrk_more addr=0x557fd9859000 size=163840
|
|
22
|
-
# ...
|
|
23
|
-
|
|
24
|
-
require 'rbbcc'
|
|
25
|
-
include RbBCC
|
|
26
|
-
|
|
27
|
-
def usage
|
|
28
|
-
puts("USAGE: #{$0} [-p PID|-c COMM]")
|
|
29
|
-
exit()
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def find_libc_location
|
|
33
|
-
if File.exist?('/lib/x86_64-linux-gnu/libc.so.6')
|
|
34
|
-
'/lib/x86_64-linux-gnu/libc.so.6'
|
|
35
|
-
else
|
|
36
|
-
`find /lib/ -name 'libc.so*' | tail -1`.chomp
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
usage if ARGV.size != 0 && ARGV.size != 2
|
|
41
|
-
|
|
42
|
-
pid = comm = nil
|
|
43
|
-
path = find_libc_location
|
|
44
|
-
case ARGV[0]
|
|
45
|
-
when '-p', '--pid'
|
|
46
|
-
pid = ARGV[1].to_i
|
|
47
|
-
when '-c', '--comm'
|
|
48
|
-
comm = ARGV[1]
|
|
49
|
-
when nil
|
|
50
|
-
# nop
|
|
51
|
-
else
|
|
52
|
-
usage
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
debug = !!ENV['DEBUG']
|
|
56
|
-
|
|
57
|
-
bpf_text = <<BPF
|
|
58
|
-
#include <uapi/linux/ptrace.h>
|
|
59
|
-
#include <linux/sched.h>
|
|
60
|
-
|
|
61
|
-
struct data_t {
|
|
62
|
-
u32 type;
|
|
63
|
-
u64 ts;
|
|
64
|
-
u32 pid;
|
|
65
|
-
char comm[TASK_COMM_LEN];
|
|
66
|
-
u64 addr;
|
|
67
|
-
u32 sbrk_size;
|
|
68
|
-
u32 adjusted_mmap;
|
|
69
|
-
u32 trim_thresholds;
|
|
70
|
-
};
|
|
71
|
-
BPF_PERF_OUTPUT(events);
|
|
72
|
-
|
|
73
|
-
static inline bool streq(uintptr_t str) {
|
|
74
|
-
char needle[] = "{{NEEDLE}}";
|
|
75
|
-
char haystack[sizeof(needle)];
|
|
76
|
-
bpf_probe_read(&haystack, sizeof(haystack), (void *)str);
|
|
77
|
-
for (int i = 0; i < sizeof(needle) - 1; ++i) {
|
|
78
|
-
if (needle[i] != haystack[i]) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
#define PROBE_TYPE_more 1
|
|
86
|
-
#define PROBE_TYPE_less 2
|
|
87
|
-
#define PROBE_TYPE_free 3
|
|
88
|
-
|
|
89
|
-
{{FUNC_MORE}}
|
|
90
|
-
|
|
91
|
-
{{FUNC_LESS}}
|
|
92
|
-
|
|
93
|
-
int trace_memory_free(struct pt_regs *ctx) {
|
|
94
|
-
struct data_t data = {};
|
|
95
|
-
long buf;
|
|
96
|
-
|
|
97
|
-
data.type = PROBE_TYPE_free;
|
|
98
|
-
data.ts = bpf_ktime_get_ns();
|
|
99
|
-
data.pid = bpf_get_current_pid_tgid();
|
|
100
|
-
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
|
101
|
-
|
|
102
|
-
{{NEEDLE_START}}
|
|
103
|
-
bpf_usdt_readarg(1, ctx, &buf);
|
|
104
|
-
data.adjusted_mmap = buf;
|
|
105
|
-
|
|
106
|
-
bpf_usdt_readarg(2, ctx, &buf);
|
|
107
|
-
data.trim_thresholds = buf;
|
|
108
|
-
|
|
109
|
-
events.perf_submit(ctx, &data, sizeof(data));
|
|
110
|
-
{{NEEDLE_END}}
|
|
111
|
-
|
|
112
|
-
return 0;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
BPF
|
|
116
|
-
|
|
117
|
-
trace_fun_sbrk = <<FUNC
|
|
118
|
-
int trace_memory_sbrk_{{TYPE}}(struct pt_regs *ctx) {
|
|
119
|
-
struct data_t data = {};
|
|
120
|
-
long buf;
|
|
121
|
-
|
|
122
|
-
data.type = PROBE_TYPE_{{TYPE}};
|
|
123
|
-
data.ts = bpf_ktime_get_ns();
|
|
124
|
-
data.pid = bpf_get_current_pid_tgid();
|
|
125
|
-
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
|
126
|
-
|
|
127
|
-
{{NEEDLE_START}}
|
|
128
|
-
bpf_usdt_readarg(1, ctx, &buf);
|
|
129
|
-
data.addr = buf;
|
|
130
|
-
|
|
131
|
-
bpf_usdt_readarg(2, ctx, &buf);
|
|
132
|
-
data.sbrk_size = buf;
|
|
133
|
-
|
|
134
|
-
events.perf_submit(ctx, &data, sizeof(data));
|
|
135
|
-
{{NEEDLE_END}}
|
|
136
|
-
|
|
137
|
-
return 0;
|
|
138
|
-
};
|
|
139
|
-
FUNC
|
|
140
|
-
|
|
141
|
-
PROBE_TYPE_more = 1
|
|
142
|
-
PROBE_TYPE_less = 2
|
|
143
|
-
PROBE_TYPE_free = 3
|
|
144
|
-
PROBE_MAP = {
|
|
145
|
-
PROBE_TYPE_more => 'memory_sbrk_more',
|
|
146
|
-
PROBE_TYPE_less => 'memory_sbrk_less',
|
|
147
|
-
PROBE_TYPE_free => 'memory_mallopt_free_dyn_thresholds'
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
bpf_text.sub!('{{FUNC_MORE}}', trace_fun_sbrk.gsub('{{TYPE}}', 'more'))
|
|
151
|
-
bpf_text.sub!('{{FUNC_LESS}}', trace_fun_sbrk.gsub('{{TYPE}}', 'less'))
|
|
152
|
-
|
|
153
|
-
if comm
|
|
154
|
-
bpf_text.sub!('{{NEEDLE}}', comm)
|
|
155
|
-
bpf_text.gsub!('{{NEEDLE_START}}', "if(streq((uintptr_t)data.comm)) {")
|
|
156
|
-
bpf_text.gsub!('{{NEEDLE_END}}', "}")
|
|
157
|
-
else
|
|
158
|
-
bpf_text.sub!('{{NEEDLE}}', "")
|
|
159
|
-
bpf_text.gsub!('{{NEEDLE_START}}', "")
|
|
160
|
-
bpf_text.gsub!('{{NEEDLE_END}}', "")
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
u = USDT.new(pid: pid, path: path)
|
|
164
|
-
u.enable_probe(probe: "memory_sbrk_more", fn_name: "trace_memory_sbrk_more")
|
|
165
|
-
u.enable_probe(probe: "memory_sbrk_less", fn_name: "trace_memory_sbrk_less")
|
|
166
|
-
if pid
|
|
167
|
-
# FIXME: Only available when PID is specified
|
|
168
|
-
# otherwise got an error:
|
|
169
|
-
# bpf: Failed to load program: Invalid argument
|
|
170
|
-
# last insn is not an exit or jmp
|
|
171
|
-
# It seems libbcc won't generate proper readarg helper
|
|
172
|
-
u.enable_probe(probe: "memory_mallopt_free_dyn_thresholds", fn_name: "trace_memory_free")
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
# initialize BPF
|
|
176
|
-
b = BCC.new(text: bpf_text, usdt_contexts: [u])
|
|
177
|
-
|
|
178
|
-
puts "!! Trace start."
|
|
179
|
-
# process event
|
|
180
|
-
start = 0
|
|
181
|
-
b["events"].open_perf_buffer do |cpu, data, size|
|
|
182
|
-
event = b["events"].event(data)
|
|
183
|
-
if start == 0
|
|
184
|
-
start = event.ts
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
time_s = ((event.ts - start).to_f) / 1000000000
|
|
188
|
-
if [PROBE_TYPE_more, PROBE_TYPE_less].include?(event.type)
|
|
189
|
-
puts(
|
|
190
|
-
"[%18.9f] pid=%d comm=%s probe=%s addr=%#x size=%d" %
|
|
191
|
-
[time_s, event.pid, event.comm, PROBE_MAP[event.type], event.addr, event.sbrk_size]
|
|
192
|
-
)
|
|
193
|
-
else
|
|
194
|
-
puts(
|
|
195
|
-
"[%18.9f] pid=%d comm=%s probe=%s adjusted_mmap=%d trim_thresholds=%d" %
|
|
196
|
-
[time_s, event.pid, event.comm, PROBE_MAP[event.type], event.adjusted_mmap, event.trim_thresholds]
|
|
197
|
-
)
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
Signal.trap(:INT) { puts "\n!! Done."; exit }
|
|
202
|
-
loop do
|
|
203
|
-
b.perf_buffer_poll()
|
|
204
|
-
end
|