rbbcc 0.0.2 → 0.1.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 +4 -4
- data/.gitignore +4 -0
- data/Dockerfile +15 -0
- data/Dockerfile.dfm-example +9 -0
- data/Gemfile.lock +7 -1
- data/README.md +53 -0
- data/examples/bitehist.rb +46 -0
- data/examples/dddos.rb +112 -0
- data/examples/hello_perf_output.rb +64 -0
- data/lib/rbbcc/bcc.rb +56 -1
- data/lib/rbbcc/clib.rb +46 -1
- data/lib/rbbcc/cpu_helper.rb +29 -0
- data/lib/rbbcc/disp_helper.rb +98 -0
- data/lib/rbbcc/fiddle_ext.rb +15 -0
- data/lib/rbbcc/table.rb +329 -0
- data/lib/rbbcc/version.rb +1 -1
- data/lib/rbbcc.rb +1 -0
- data/misc/rbbcc-dfm-ruby +5 -0
- data/rbbcc.gemspec +1 -0
- metadata +26 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d39196324559279beb78acb224f5d1e4b8d327bec531a9f0fc821787c89703cf
|
4
|
+
data.tar.gz: 932e49ca5f9225eb7eaca7beea106efb7a54279a9c4570a12b4d2cc7da0fd1e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ab268845839b5b566b66a75bf0fefeea5fc6bda9cc0b451d5617f09d7a03d389be2075901924ef3bfaf05af840afb295721d878547a58d5d2d5404c1fbbe880
|
7
|
+
data.tar.gz: e387413acd3d1720e990f0cb11d69f4f5629559d37d46c784bd1e454a38badcae2997def0807dd512e486de0988fc1750dbffcba87a0d5a1b819380a64d066bf
|
data/.gitignore
CHANGED
data/Dockerfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
FROM rubylang/ruby:2.6.3-bionic
|
2
|
+
|
3
|
+
RUN set -ex; \
|
4
|
+
echo "deb [trusted=yes] http://repo.iovisor.org/apt/bionic bionic-nightly main" > /etc/apt/sources.list.d/iovisor.list; \
|
5
|
+
apt-get update -y; \
|
6
|
+
deps="auditd bcc-tools curl gcc git libelf1 libbcc-examples"; \
|
7
|
+
DEBIAN_FRONTEND=noninteractive apt-get install -y $deps; \
|
8
|
+
apt-get clean; \
|
9
|
+
rm -rf /var/lib/apt/lists/*;
|
10
|
+
|
11
|
+
RUN gem install rbbcc
|
12
|
+
COPY ./misc/rbbcc-dfm-ruby /usr/bin/rbbcc-dfm-ruby
|
13
|
+
RUN chmod a+x /usr/bin/rbbcc-dfm-ruby
|
14
|
+
|
15
|
+
ENTRYPOINT ["ruby"]
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rbbcc (0.0.
|
4
|
+
rbbcc (0.0.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
coderay (1.1.2)
|
10
|
+
method_source (0.9.2)
|
11
|
+
pry (0.12.2)
|
12
|
+
coderay (~> 1.1.0)
|
13
|
+
method_source (~> 0.9.0)
|
9
14
|
rake (10.5.0)
|
10
15
|
|
11
16
|
PLATFORMS
|
@@ -13,6 +18,7 @@ PLATFORMS
|
|
13
18
|
|
14
19
|
DEPENDENCIES
|
15
20
|
bundler (~> 2.0)
|
21
|
+
pry
|
16
22
|
rake (~> 10.0)
|
17
23
|
rbbcc!
|
18
24
|
|
data/README.md
CHANGED
@@ -41,6 +41,59 @@ RbBCC::BCC.new(text: code).trace_print
|
|
41
41
|
|
42
42
|
See examples (both in rbbcc and BCC)
|
43
43
|
|
44
|
+
## Trying with docker
|
45
|
+
|
46
|
+
[`udzura/rbbcc:${version}` is available.](https://hub.docker.com/r/udzura/rbbcc)
|
47
|
+
|
48
|
+
* On generic linux:
|
49
|
+
|
50
|
+
```console
|
51
|
+
$ docker run --privileged \
|
52
|
+
-v/lib/modules:/lib/modules \
|
53
|
+
-v/sys:/sys \
|
54
|
+
-v/usr/src:/usr/src \
|
55
|
+
-v`pwd`:/opt \
|
56
|
+
-ti \
|
57
|
+
udzura/rbbcc:0.0.2 /opt/hello_world.rb
|
58
|
+
Found fnc: kprobe__sys_clone
|
59
|
+
Attach: p_sys_clone
|
60
|
+
|
61
|
+
bash-20113 [000] .... 377.602655: 0x00000001: Hello, World!
|
62
|
+
bash-20113 [000] .... 385.367309: 0x00000001: Hello, World!
|
63
|
+
bash-20113 [000] .... 391.203779: 0x00000001: Hello, World!
|
64
|
+
curl-20316 [001] .... 391.218226: 0x00000001: Hello, World!
|
65
|
+
bash-20113 [000] .... 402.528271: 0x00000001: Hello, World!
|
66
|
+
docker-containe-20236 [000] .... 403.090058: 0x00000001: Hello, World!
|
67
|
+
...
|
68
|
+
```
|
69
|
+
|
70
|
+
* On Docker for Mac:
|
71
|
+
* Docker for Mac host does not have heders file in `/usr/src`, so you should extract headers in each container inside.
|
72
|
+
|
73
|
+
```console
|
74
|
+
### I have prepared an example Dockerfile
|
75
|
+
$ docker build -t udzura/rbbcc:0.0.2-dfm -f Dockerfile.dfm-example .
|
76
|
+
$ docker run --privileged \
|
77
|
+
-v/lib/modules:/lib/modules \
|
78
|
+
-v`pwd`/examples:/opt \
|
79
|
+
-ti \
|
80
|
+
udzura/rbbcc:0.0.2-dfm /opt/hello_world.rb
|
81
|
+
...
|
82
|
+
containerd-shim-4932 [002] d... 1237.795421: : Hello, World!
|
83
|
+
httpd-4958 [000] d... 1237.795666: : Hello, World!
|
84
|
+
httpd-4958 [000] d... 1237.795794: : Hello, World!
|
85
|
+
httpd-4967 [000] d... 1237.795988: : Hello, World!
|
86
|
+
httpd-4967 [000] d... 1237.796211: : Hello, World!
|
87
|
+
httpd-4967 [000] d... 1237.796289: : Hello, World!
|
88
|
+
httpd-4967 [000] d... 1237.796325: : Hello, World!
|
89
|
+
<...>-5025 [003] d... 1237.796956: : Hello, World!
|
90
|
+
runc-5025 [003] d... 1237.797133: : Hello, World!
|
91
|
+
httpd-4967 [000] d... 1237.797156: : Hello, World!
|
92
|
+
httpd-4967 [000] d... 1237.797198: : Hello, World!
|
93
|
+
httpd-4967 [000] d... 1237.797340: : Hello, World!
|
94
|
+
runc-5025 [003] d... 1237.797464: : Hello, World!
|
95
|
+
```
|
96
|
+
|
44
97
|
## Development
|
45
98
|
|
46
99
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# bitehist.rb, ported from bitehist.py. See license on that file
|
4
|
+
#
|
5
|
+
# Written as a basic example of using histograms to show a distribution.
|
6
|
+
#
|
7
|
+
# A Ctrl-C will print the gathered histogram then exit.
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'rbbcc'
|
11
|
+
include RbBCC
|
12
|
+
|
13
|
+
b = BCC.new(text: <<CLANG)
|
14
|
+
#include <uapi/linux/ptrace.h>
|
15
|
+
#include <linux/blkdev.h>
|
16
|
+
|
17
|
+
BPF_HISTOGRAM(dist);
|
18
|
+
BPF_HISTOGRAM(dist_linear);
|
19
|
+
|
20
|
+
int kprobe__blk_account_io_completion(struct pt_regs *ctx, struct request *req)
|
21
|
+
{
|
22
|
+
dist.increment(bpf_log2l(req->__data_len / 1024));
|
23
|
+
dist_linear.increment(req->__data_len / 1024);
|
24
|
+
return 0;
|
25
|
+
}
|
26
|
+
CLANG
|
27
|
+
|
28
|
+
puts "Tracing... Hit Ctrl-C to end."
|
29
|
+
|
30
|
+
loop do
|
31
|
+
begin
|
32
|
+
sleep 0.1
|
33
|
+
rescue Interrupt
|
34
|
+
puts
|
35
|
+
break
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "log2 histogram"
|
40
|
+
puts "~~~~~~~~~~~~~~"
|
41
|
+
b["dist"].print_log2_hist("kbytes")
|
42
|
+
|
43
|
+
puts
|
44
|
+
puts "linear histogram"
|
45
|
+
puts "~~~~~~~~~~~~~~~~"
|
46
|
+
b["dist_linear"].print_linear_hist("kbytes")
|
data/examples/dddos.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# dddos.rb DDOS dectection system, ported from python code.
|
4
|
+
#
|
5
|
+
# Written as a basic tracing example of using ePBF
|
6
|
+
# to detect a potential DDOS attack against a system.
|
7
|
+
#
|
8
|
+
# See Copyright and License on bcc project:
|
9
|
+
# examples/tracing/dddos.py
|
10
|
+
#
|
11
|
+
# 14-Jan-2019 Jugurtha BELKALEM Created dddos.py.
|
12
|
+
|
13
|
+
require 'rbbcc'
|
14
|
+
include RbBCC
|
15
|
+
|
16
|
+
prog = """
|
17
|
+
#include <linux/skbuff.h>
|
18
|
+
#include <uapi/linux/ip.h>
|
19
|
+
|
20
|
+
#define MAX_NB_PACKETS 1000
|
21
|
+
#define LEGAL_DIFF_TIMESTAMP_PACKETS 1000000
|
22
|
+
|
23
|
+
BPF_HASH(rcv_packets);
|
24
|
+
|
25
|
+
struct detectionPackets {
|
26
|
+
u64 nb_ddos_packets;
|
27
|
+
};
|
28
|
+
|
29
|
+
BPF_PERF_OUTPUT(events);
|
30
|
+
|
31
|
+
int detect_ddos(struct pt_regs *ctx, void *skb){
|
32
|
+
struct detectionPackets detectionPacket = {};
|
33
|
+
|
34
|
+
// Used to count number of received packets
|
35
|
+
u64 rcv_packets_nb_index = 0, rcv_packets_nb_inter=1, *rcv_packets_nb_ptr;
|
36
|
+
|
37
|
+
// Used to measure elapsed time between 2 successive received packets
|
38
|
+
u64 rcv_packets_ts_index = 1, rcv_packets_ts_inter=0, *rcv_packets_ts_ptr;
|
39
|
+
|
40
|
+
/* The algorithm analyses packets received by ip_rcv function
|
41
|
+
* and measures the difference in reception time between each packet.
|
42
|
+
* DDOS flooders send millions of packets such that difference of
|
43
|
+
* timestamp between 2 successive packets is so small
|
44
|
+
* (which is not like regular applications behaviour).
|
45
|
+
* This script looks for this difference in time and if it sees
|
46
|
+
* more than MAX_NB_PACKETS succesive packets with a difference
|
47
|
+
* of timestamp between each one of them less than
|
48
|
+
* LEGAL_DIFF_TIMESTAMP_PACKETS ns,
|
49
|
+
* ------------------ It Triggers an ALERT -----------------
|
50
|
+
* Those settings must be adapted depending on regular network traffic
|
51
|
+
* -------------------------------------------------------------------
|
52
|
+
* Important: this is a rudimentary intrusion detection system, one can
|
53
|
+
* test a real case attack using hping3. However; if regular network
|
54
|
+
* traffic increases above predefined detection settings, a false
|
55
|
+
* positive alert will be triggered (an example would be the
|
56
|
+
case of large file downloads).
|
57
|
+
*/
|
58
|
+
rcv_packets_nb_ptr = rcv_packets.lookup(&rcv_packets_nb_index);
|
59
|
+
rcv_packets_ts_ptr = rcv_packets.lookup(&rcv_packets_ts_index);
|
60
|
+
if(rcv_packets_nb_ptr != 0 && rcv_packets_ts_ptr != 0){
|
61
|
+
rcv_packets_nb_inter = *rcv_packets_nb_ptr;
|
62
|
+
rcv_packets_ts_inter = bpf_ktime_get_ns() - *rcv_packets_ts_ptr;
|
63
|
+
if(rcv_packets_ts_inter < LEGAL_DIFF_TIMESTAMP_PACKETS){
|
64
|
+
rcv_packets_nb_inter++;
|
65
|
+
} else {
|
66
|
+
rcv_packets_nb_inter = 0;
|
67
|
+
}
|
68
|
+
if(rcv_packets_nb_inter > MAX_NB_PACKETS){
|
69
|
+
detectionPacket.nb_ddos_packets = rcv_packets_nb_inter;
|
70
|
+
events.perf_submit(ctx, &detectionPacket, sizeof(detectionPacket));
|
71
|
+
}
|
72
|
+
}
|
73
|
+
rcv_packets_ts_inter = bpf_ktime_get_ns();
|
74
|
+
rcv_packets.update(&rcv_packets_nb_index, &rcv_packets_nb_inter);
|
75
|
+
rcv_packets.update(&rcv_packets_ts_index, &rcv_packets_ts_inter);
|
76
|
+
return 0;
|
77
|
+
}
|
78
|
+
"""
|
79
|
+
|
80
|
+
# Loads eBPF program
|
81
|
+
b = BCC.new(text: prog)
|
82
|
+
|
83
|
+
# Attach kprobe to kernel function and sets detect_ddos as kprobe handler
|
84
|
+
b.attach_kprobe(event: "ip_rcv", fn_name: "detect_ddos")
|
85
|
+
|
86
|
+
DetectionTimestamp = \
|
87
|
+
Fiddle::Importer.struct(["unsigned long long nb_ddos_packets"])
|
88
|
+
|
89
|
+
# Show message when ePBF stats
|
90
|
+
puts("DDOS detector started ... Hit Ctrl-C to end!")
|
91
|
+
|
92
|
+
puts("%-26s %-10s" % ["TIME(s)", "MESSAGE"])
|
93
|
+
|
94
|
+
trigger_alert_event = lambda { |cpu, data, size|
|
95
|
+
# data is raw Fiddle::Pointer instance
|
96
|
+
event = DetectionTimestamp.malloc
|
97
|
+
Fiddle::Pointer.new(event.to_ptr)[0, DetectionTimestamp.size] = data[0, DetectionTimestamp.size]
|
98
|
+
puts("%-26s %s %d" % [
|
99
|
+
Time.now,
|
100
|
+
"DDOS Attack => nb of packets up to now : ",
|
101
|
+
event.nb_ddos_packets])
|
102
|
+
}
|
103
|
+
|
104
|
+
# loop with callback to trigger_alert_event
|
105
|
+
b["events"].open_perf_buffer(&trigger_alert_event)
|
106
|
+
loop do
|
107
|
+
begin
|
108
|
+
b.perf_buffer_poll
|
109
|
+
rescue Interrupt
|
110
|
+
exit
|
111
|
+
end
|
112
|
+
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
|
+
// define output data structure in C
|
14
|
+
struct data_t {
|
15
|
+
u32 pid;
|
16
|
+
u64 ts;
|
17
|
+
char comm[TASK_COMM_LEN];
|
18
|
+
};
|
19
|
+
BPF_PERF_OUTPUT(events);
|
20
|
+
|
21
|
+
int hello(struct pt_regs *ctx) {
|
22
|
+
struct data_t data = {};
|
23
|
+
|
24
|
+
data.pid = bpf_get_current_pid_tgid();
|
25
|
+
data.ts = bpf_ktime_get_ns();
|
26
|
+
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
27
|
+
|
28
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
29
|
+
|
30
|
+
return 0;
|
31
|
+
}
|
32
|
+
"""
|
33
|
+
|
34
|
+
# load BPF program
|
35
|
+
b = BCC.new(text: prog)
|
36
|
+
b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
|
37
|
+
|
38
|
+
# header
|
39
|
+
puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
|
40
|
+
|
41
|
+
# process event
|
42
|
+
start = 0
|
43
|
+
print_event = lambda { |cpu, data, size|
|
44
|
+
event = b["events"].event(data)
|
45
|
+
if start == 0
|
46
|
+
start = event.ts
|
47
|
+
end
|
48
|
+
|
49
|
+
time_s = ((event.ts - start).to_f) / 1000000000
|
50
|
+
# event.comm.pack("c*").sprit
|
51
|
+
puts("%-18.9f %-16s %-6d %s" % [time_s, event.comm, event.pid,
|
52
|
+
"Hello, perf_output!"])
|
53
|
+
}
|
54
|
+
|
55
|
+
# loop with callback to print_event
|
56
|
+
b["events"].open_perf_buffer(&print_event)
|
57
|
+
|
58
|
+
loop do
|
59
|
+
begin
|
60
|
+
b.perf_buffer_poll()
|
61
|
+
rescue Interrupt
|
62
|
+
exit()
|
63
|
+
end
|
64
|
+
end
|
data/lib/rbbcc/bcc.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rbbcc/consts'
|
2
|
+
require 'rbbcc/table'
|
2
3
|
require 'rbbcc/symbol_cache'
|
3
4
|
|
4
5
|
module RbBCC
|
@@ -28,6 +29,8 @@ module RbBCC
|
|
28
29
|
allow_rlimit
|
29
30
|
)
|
30
31
|
@funcs = {}
|
32
|
+
@tables = {}
|
33
|
+
@perf_buffers = {}
|
31
34
|
|
32
35
|
unless @module
|
33
36
|
raise "BPF module not created"
|
@@ -43,7 +46,7 @@ module RbBCC
|
|
43
46
|
|
44
47
|
at_exit { self.cleanup }
|
45
48
|
end
|
46
|
-
attr_reader :module
|
49
|
+
attr_reader :module, :perf_buffers
|
47
50
|
|
48
51
|
def gen_args_from_usdt
|
49
52
|
ptr = Clib.bcc_usdt_genargs(@usdt_contexts.map(&:context).pack('J*'), @usdt_contexts.size)
|
@@ -177,6 +180,58 @@ module RbBCC
|
|
177
180
|
end
|
178
181
|
end
|
179
182
|
|
183
|
+
attr_reader :tables
|
184
|
+
def get_table(name, keytype: nil, leaftype: nil, reducer: nil)
|
185
|
+
map_id = Clib.bpf_table_id(@module, name)
|
186
|
+
map_fd = Clib.bpf_table_fd(@module, name)
|
187
|
+
|
188
|
+
raise KeyError, "map not found" if map_fd < 0
|
189
|
+
unless keytype
|
190
|
+
key_desc = Clib.bpf_table_key_desc(@module, name)
|
191
|
+
raise("Failed to load BPF Table #{name} key desc") if key_desc.null?
|
192
|
+
keytype = eval(key_desc.to_extracted_char_ptr) # XXX: parse as JSON?
|
193
|
+
end
|
194
|
+
|
195
|
+
unless leaftype
|
196
|
+
leaf_desc = Clib.bpf_table_leaf_desc(@module, name)
|
197
|
+
raise("Failed to load BPF Table #{name} leaf desc") if leaf_desc.null?
|
198
|
+
leaftype = eval(leaf_desc.to_extracted_char_ptr)
|
199
|
+
end
|
200
|
+
return Table.new(self, map_id, map_fd, keytype, leaftype, name, reducer: reducer)
|
201
|
+
end
|
202
|
+
|
203
|
+
def [](key)
|
204
|
+
self.tables[key] ||= get_table(key)
|
205
|
+
end
|
206
|
+
|
207
|
+
def []=(key, value)
|
208
|
+
self.tables[key] = value
|
209
|
+
end
|
210
|
+
|
211
|
+
def perf_buffer_poll(timeout=-1)
|
212
|
+
readers = self.perf_buffers.values
|
213
|
+
readers.each {|r| r.size = Clib::PerfReader.size }
|
214
|
+
pack = readers.map{|r| r[0, Clib::PerfReader.size] }.pack('p*')
|
215
|
+
Clib.perf_reader_poll(readers.size, pack, timeout)
|
216
|
+
end
|
217
|
+
|
218
|
+
def ksymname(name)
|
219
|
+
SymbolCache.resolve_global(name)
|
220
|
+
end
|
221
|
+
|
222
|
+
def get_syscall_prefix
|
223
|
+
SYSCALL_PREFIXES.each do |prefix|
|
224
|
+
if ksymname("%sbpf" % prefix)
|
225
|
+
return prefix
|
226
|
+
end
|
227
|
+
end
|
228
|
+
SYSCALL_PREFIXES[0]
|
229
|
+
end
|
230
|
+
|
231
|
+
def get_syscall_fnname(name)
|
232
|
+
get_syscall_prefix + name
|
233
|
+
end
|
234
|
+
|
180
235
|
private
|
181
236
|
def trace_autoload!
|
182
237
|
(0..Clib.bpf_num_functions(@module)).each do |i|
|
data/lib/rbbcc/clib.rb
CHANGED
@@ -13,7 +13,8 @@ module RbBCC
|
|
13
13
|
end
|
14
14
|
|
15
15
|
extend Fiddle::Importer
|
16
|
-
dlload "libbcc.so.0"
|
16
|
+
dlload "libbcc.so.0.10.0"
|
17
|
+
typealias "size_t", "int"
|
17
18
|
|
18
19
|
extern 'void * bpf_module_create_c_from_string(char *, unsigned int, char **, int, long)'
|
19
20
|
extern 'int bpf_num_functions(void *)'
|
@@ -25,6 +26,13 @@ module RbBCC
|
|
25
26
|
extern 'int bpf_function_size(void *, char *)'
|
26
27
|
extern 'char * bpf_module_license(void *)'
|
27
28
|
extern 'unsigned int bpf_module_kern_version(void *)'
|
29
|
+
extern 'int bpf_table_fd(void *, char *)'
|
30
|
+
extern 'int bpf_table_id(void *, char *)'
|
31
|
+
extern 'int bpf_table_type_id(void *, int)'
|
32
|
+
extern 'int bpf_table_flags_id(void *, int)'
|
33
|
+
extern 'char * bpf_table_key_desc(void *, char *)'
|
34
|
+
extern 'char * bpf_table_leaf_desc(void *, char *)'
|
35
|
+
extern 'int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags)'
|
28
36
|
|
29
37
|
extern 'int bpf_attach_kprobe(int, int, char *, char *, unsigned long, int)'
|
30
38
|
extern 'int bpf_detach_kprobe(char *)'
|
@@ -32,6 +40,35 @@ module RbBCC
|
|
32
40
|
extern 'int bpf_detach_uprobe(char *)'
|
33
41
|
extern 'int bpf_open_perf_event(unsigned int, unsigned long, int, int)'
|
34
42
|
extern 'int bpf_close_perf_event_fd(int)'
|
43
|
+
extern 'int bpf_get_first_key(int, void *, int)'
|
44
|
+
extern 'int bpf_get_next_key(int, void *, void *)'
|
45
|
+
extern 'int bpf_lookup_elem(int fd, void *key, void *value)'
|
46
|
+
extern 'size_t bpf_table_max_entries_id(void *program, size_t id)'
|
47
|
+
|
48
|
+
# FIXME: This size of struct will change in future version
|
49
|
+
# and no struct member info in header. This is hacky
|
50
|
+
PerfReader = struct(
|
51
|
+
[
|
52
|
+
"void * raw_cb",
|
53
|
+
"void * lost_cb",
|
54
|
+
"void * cb_cookie",
|
55
|
+
"void * buf",
|
56
|
+
"int buf_size",
|
57
|
+
"void * base",
|
58
|
+
"int rb_use_state",
|
59
|
+
"int rb_read_tid",
|
60
|
+
"int page_size",
|
61
|
+
"int page_cnt",
|
62
|
+
"int fd"
|
63
|
+
]
|
64
|
+
)
|
65
|
+
|
66
|
+
#typedef void (*perf_reader_raw_cb)(void *cb_cookie, void *raw, int raw_size);
|
67
|
+
#typedef void (*perf_reader_lost_cb)(void *cb_cookie, uint64_t lost);
|
68
|
+
extern 'void * bpf_open_perf_buffer(void *raw_cb, void *lost_cb, void *cb_cookie, int pid, int cpu, int page_cnt)'
|
69
|
+
extern 'int perf_reader_fd(void *reader)'
|
70
|
+
extern 'size_t bpf_perf_event_fields(void *program, const char *event)'
|
71
|
+
extern 'char * bpf_perf_event_field(void *program, const char *event, size_t i)'
|
35
72
|
|
36
73
|
extern 'void * bcc_usdt_new_frompid(int, char *)'
|
37
74
|
extern 'int bcc_usdt_enable_probe(void *, char *, char *)'
|
@@ -50,5 +87,13 @@ module RbBCC
|
|
50
87
|
extern 'int bcc_symcache_resolve(void *, unsigned long, void *)'
|
51
88
|
extern 'int bcc_symcache_resolve_no_demangle(void *, unsigned long, void *)'
|
52
89
|
extern 'int bcc_symcache_resolve_name(void *, char *, char *, unsigned long long *)'
|
90
|
+
|
91
|
+
extern 'int perf_reader_poll(int num_readers, struct perf_reader **readers, int timeout)'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class Fiddle::Pointer
|
96
|
+
def to_extracted_char_ptr
|
97
|
+
RbBCC::Clib.__extract_char(self)
|
53
98
|
end
|
54
99
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RbBCC
|
2
|
+
module CPUHelper
|
3
|
+
module_function
|
4
|
+
def get_online_cpus
|
5
|
+
return _read_cpu_range('/sys/devices/system/cpu/online')
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_possible_cpus
|
9
|
+
return _read_cpu_range('/sys/devices/system/cpu/possible')
|
10
|
+
end
|
11
|
+
|
12
|
+
# formatted like: '0,2-4,7-10'
|
13
|
+
def _read_cpu_range(path)
|
14
|
+
cpus = nil
|
15
|
+
File.open(path, 'r') do |f|
|
16
|
+
tmp = f.read.split(',').map do |range|
|
17
|
+
if range.include?('-')
|
18
|
+
start, end_ = *range.split('-')
|
19
|
+
(start.to_i..end_.to_i).to_a
|
20
|
+
else
|
21
|
+
range.to_i
|
22
|
+
end
|
23
|
+
end
|
24
|
+
cpus = tmp.flatten
|
25
|
+
end
|
26
|
+
cpus
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# FIXME: These should be class attributes?
|
2
|
+
$stars_max = 40
|
3
|
+
$log2_index_max = 65
|
4
|
+
$linear_index_max = 1025
|
5
|
+
|
6
|
+
module RbBCC
|
7
|
+
# They're directly ported from table.py
|
8
|
+
# They might be more looked like Ruby code
|
9
|
+
module DisplayHelper
|
10
|
+
def stars(val, val_max, width)
|
11
|
+
i = 0
|
12
|
+
text = ""
|
13
|
+
while true
|
14
|
+
break if (i > (width * val.to_f / val_max) - 1) || (i > width - 1)
|
15
|
+
text += "*"
|
16
|
+
i += 1
|
17
|
+
end
|
18
|
+
if val > val_max
|
19
|
+
text = text[0...-1] + "+"
|
20
|
+
end
|
21
|
+
return text
|
22
|
+
end
|
23
|
+
|
24
|
+
def print_log2_hist(vals, val_type, strip_leading_zero)
|
25
|
+
stars_max = $stars_max
|
26
|
+
log2_dist_max = 64
|
27
|
+
idx_max = -1
|
28
|
+
val_max = 0
|
29
|
+
|
30
|
+
vals.each_with_index do |v, i|
|
31
|
+
idx_max = i if v > 0
|
32
|
+
val_max = v if v > val_max
|
33
|
+
end
|
34
|
+
|
35
|
+
if idx_max <= 32
|
36
|
+
header = " %-19s : count distribution"
|
37
|
+
body = "%10d -> %-10d : %-8d |%-*s|"
|
38
|
+
stars = stars_max
|
39
|
+
else
|
40
|
+
header = " %-29s : count distribution"
|
41
|
+
body = "%20d -> %-20d : %-8d |%-*s|"
|
42
|
+
stars = stars_max / 2
|
43
|
+
end
|
44
|
+
|
45
|
+
if idx_max > 0
|
46
|
+
puts(header % val_type)
|
47
|
+
end
|
48
|
+
|
49
|
+
(1...(idx_max + 1)).each do |i|
|
50
|
+
low = (1 << i) >> 1
|
51
|
+
high = (1 << i) - 1
|
52
|
+
if (low == high)
|
53
|
+
low -= 1
|
54
|
+
end
|
55
|
+
val = vals[i]
|
56
|
+
|
57
|
+
if strip_leading_zero
|
58
|
+
if val
|
59
|
+
puts(body % [low, high, val, stars,
|
60
|
+
stars(val, val_max, stars)])
|
61
|
+
strip_leading_zero = false
|
62
|
+
end
|
63
|
+
else
|
64
|
+
puts(body % [low, high, val, stars,
|
65
|
+
stars(val, val_max, stars)])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def print_linear_hist(vals, val_type)
|
71
|
+
stars_max = $stars_max
|
72
|
+
log2_dist_max = 64
|
73
|
+
idx_max = -1
|
74
|
+
val_max = 0
|
75
|
+
|
76
|
+
vals.each_with_index do |v, i|
|
77
|
+
idx_max = i if v > 0
|
78
|
+
val_max = v if v > val_max
|
79
|
+
end
|
80
|
+
|
81
|
+
header = " %-13s : count distribution"
|
82
|
+
body = " %-10d : %-8d |%-*s|"
|
83
|
+
stars = stars_max
|
84
|
+
|
85
|
+
if idx_max >= 0
|
86
|
+
puts(header % val_type);
|
87
|
+
end
|
88
|
+
|
89
|
+
(0...(idx_max + 1)).each do |i|
|
90
|
+
val = vals[i]
|
91
|
+
puts(body % [i, val, stars,
|
92
|
+
stars(val, val_max, stars)])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
extend DisplayHelper
|
98
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fiddle'
|
2
|
+
require 'fiddle/import'
|
3
|
+
|
4
|
+
class Fiddle::Pointer
|
5
|
+
def to_bcc_value
|
6
|
+
case self.size
|
7
|
+
when Fiddle::Importer.sizeof("int")
|
8
|
+
self[0, self.size].unpack("i!").first
|
9
|
+
when Fiddle::Importer.sizeof("long")
|
10
|
+
self[0, self.size].unpack("l!").first
|
11
|
+
else
|
12
|
+
self[0, self.size].unpack("Z*").first
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/rbbcc/table.rb
ADDED
@@ -0,0 +1,329 @@
|
|
1
|
+
require 'rbbcc/clib'
|
2
|
+
require 'fiddle'
|
3
|
+
require 'enumerator'
|
4
|
+
require 'rbbcc/disp_helper'
|
5
|
+
require 'rbbcc/cpu_helper'
|
6
|
+
|
7
|
+
module RbBCC
|
8
|
+
module Table
|
9
|
+
BPF_MAP_TYPE_HASH = 1
|
10
|
+
BPF_MAP_TYPE_ARRAY = 2
|
11
|
+
BPF_MAP_TYPE_PROG_ARRAY = 3
|
12
|
+
BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4
|
13
|
+
BPF_MAP_TYPE_PERCPU_HASH = 5
|
14
|
+
BPF_MAP_TYPE_PERCPU_ARRAY = 6
|
15
|
+
BPF_MAP_TYPE_STACK_TRACE = 7
|
16
|
+
BPF_MAP_TYPE_CGROUP_ARRAY = 8
|
17
|
+
BPF_MAP_TYPE_LRU_HASH = 9
|
18
|
+
BPF_MAP_TYPE_LRU_PERCPU_HASH = 10
|
19
|
+
BPF_MAP_TYPE_LPM_TRIE = 11
|
20
|
+
BPF_MAP_TYPE_ARRAY_OF_MAPS = 12
|
21
|
+
BPF_MAP_TYPE_HASH_OF_MAPS = 13
|
22
|
+
BPF_MAP_TYPE_DEVMAP = 14
|
23
|
+
BPF_MAP_TYPE_SOCKMAP = 15
|
24
|
+
BPF_MAP_TYPE_CPUMAP = 16
|
25
|
+
BPF_MAP_TYPE_XSKMAP = 17
|
26
|
+
BPF_MAP_TYPE_SOCKHASH = 18
|
27
|
+
|
28
|
+
def self.new(bpf, map_id, map_fd, keytype, leaftype, name, **kwargs)
|
29
|
+
ttype = Clib.bpf_table_type_id(bpf.module, map_id)
|
30
|
+
case ttype
|
31
|
+
when BPF_MAP_TYPE_HASH
|
32
|
+
when BPF_MAP_TYPE_ARRAY
|
33
|
+
ArrayTable.new(bpf, map_id, map_fd, keytype, leaftype)
|
34
|
+
when BPF_MAP_TYPE_PERF_EVENT_ARRAY
|
35
|
+
PerfEventArray.new(bpf, map_id, map_fd, keytype, leaftype, name: name)
|
36
|
+
else
|
37
|
+
raise "Unknown table type #{ttype}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class TableBase
|
43
|
+
include Fiddle::Importer
|
44
|
+
include CPUHelper
|
45
|
+
include Enumerable
|
46
|
+
|
47
|
+
def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
|
48
|
+
@bpf, @map_id, @map_fd, @keysize, @leafsize = \
|
49
|
+
bpf, map_id, map_fd, sizeof(keytype), sizeof(leaftype)
|
50
|
+
@ttype = Clib.bpf_table_type_id(self.bpf.module, self.map_id)
|
51
|
+
@flags = Clib.bpf_table_flags_id(self.bpf.module, self.map_id)
|
52
|
+
@name = name
|
53
|
+
end
|
54
|
+
attr_reader :bpf, :map_id, :map_fd, :keysize, :leafsize, :ttype, :flags, :name
|
55
|
+
|
56
|
+
def next(key)
|
57
|
+
next_key = Fiddle::Pointer.malloc(self.keysize)
|
58
|
+
|
59
|
+
if !key
|
60
|
+
res = Clib.bpf_get_first_key(self.map_fd, next_key,
|
61
|
+
next_key.size)
|
62
|
+
else
|
63
|
+
unless key.is_a?(Fiddle::Pointer)
|
64
|
+
raise TypeError, key.inspect
|
65
|
+
end
|
66
|
+
res = Clib.bpf_get_next_key(self.map_fd, key,
|
67
|
+
next_key)
|
68
|
+
end
|
69
|
+
|
70
|
+
if res < 0
|
71
|
+
raise StopIteration
|
72
|
+
end
|
73
|
+
|
74
|
+
return next_key
|
75
|
+
end
|
76
|
+
|
77
|
+
def [](key)
|
78
|
+
leaf = Fiddle::Pointer.malloc(self.leafsize)
|
79
|
+
res = Clib.bpf_lookup_elem(self.map_fd, key, leaf)
|
80
|
+
if res < 0
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
return leaf
|
84
|
+
end
|
85
|
+
|
86
|
+
def fetch(key)
|
87
|
+
self[key] || raise(KeyError, "key not found")
|
88
|
+
end
|
89
|
+
|
90
|
+
def []=(key, leaf)
|
91
|
+
res = Clib.bpf_update_elem(self.map_fd, key, leaf, 0)
|
92
|
+
if res < 0
|
93
|
+
raise SystemCallError.new("Could not update table", Fiddle.last_error)
|
94
|
+
end
|
95
|
+
res
|
96
|
+
end
|
97
|
+
|
98
|
+
def each_key
|
99
|
+
k = nil
|
100
|
+
keys = []
|
101
|
+
loop do
|
102
|
+
k = self.next(k)
|
103
|
+
keys << k
|
104
|
+
yield k
|
105
|
+
end
|
106
|
+
keys
|
107
|
+
end
|
108
|
+
|
109
|
+
def each_value
|
110
|
+
each_key {|key| yield(self[key]) if self[key] }
|
111
|
+
end
|
112
|
+
|
113
|
+
def each_pair
|
114
|
+
each_key {|key| yield(key, self[key]) if self[key] }
|
115
|
+
end
|
116
|
+
alias each each_pair
|
117
|
+
|
118
|
+
def values
|
119
|
+
enum_for(:each_value).to_a
|
120
|
+
end
|
121
|
+
|
122
|
+
def items
|
123
|
+
enum_for(:each_pair).to_a
|
124
|
+
end
|
125
|
+
|
126
|
+
def print_log2_hist(val_type="value",
|
127
|
+
section_header: "Bucket ptr",
|
128
|
+
section_print_fn: nil,
|
129
|
+
bucket_fn: nil,
|
130
|
+
strip_leading_zero: false,
|
131
|
+
bucket_sort_fn: nil)
|
132
|
+
if structured_key?
|
133
|
+
raise NotImplementedError
|
134
|
+
else
|
135
|
+
vals = Array.new($log2_index_max) { 0 }
|
136
|
+
each_pair do |k, v|
|
137
|
+
vals[k.to_bcc_value] = v.to_bcc_value
|
138
|
+
end
|
139
|
+
RbBCC.print_log2_hist(vals, val_type, strip_leading_zero)
|
140
|
+
end
|
141
|
+
nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def print_linear_hist(val_type="value",
|
145
|
+
section_header: "Bucket ptr",
|
146
|
+
section_print_fn: nil,
|
147
|
+
bucket_fn: nil,
|
148
|
+
bucket_sort_fn: nil)
|
149
|
+
if structured_key?
|
150
|
+
raise NotImplementedError
|
151
|
+
else
|
152
|
+
vals = Array.new($linear_index_max) { 0 }
|
153
|
+
each_pair do |k, v|
|
154
|
+
vals[k.to_bcc_value] = v.to_bcc_value
|
155
|
+
end
|
156
|
+
RbBCC.print_linear_hist(vals, val_type)
|
157
|
+
end
|
158
|
+
nil
|
159
|
+
end
|
160
|
+
|
161
|
+
def structured_key?
|
162
|
+
false # TODO: implement me in the future
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
def byref(value, size=sizeof("int"))
|
167
|
+
pack_fmt = case size
|
168
|
+
when sizeof("int") ; "i!"
|
169
|
+
when sizeof("long"); "l!"
|
170
|
+
else ; "Z*"
|
171
|
+
end
|
172
|
+
ptr = Fiddle::Pointer.malloc(size)
|
173
|
+
ptr[0, size] = [value].pack(pack_fmt)
|
174
|
+
ptr
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
class ArrayTable < TableBase
|
179
|
+
def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
|
180
|
+
super
|
181
|
+
@max_entries = Clib.bpf_table_max_entries_id(bpf.module, map_id)
|
182
|
+
end
|
183
|
+
|
184
|
+
# We now emulate the Array class of Ruby
|
185
|
+
def size
|
186
|
+
@max_entries
|
187
|
+
end
|
188
|
+
alias length size
|
189
|
+
|
190
|
+
def [](key)
|
191
|
+
super(normalize_key(key))
|
192
|
+
end
|
193
|
+
|
194
|
+
def each(&b)
|
195
|
+
each_value do |v|
|
196
|
+
b.call(v.to_bcc_value)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
private
|
201
|
+
def normalize_key(key)
|
202
|
+
case key
|
203
|
+
when Fiddle::Pointer
|
204
|
+
key
|
205
|
+
when Integer
|
206
|
+
byref(key, keysize)
|
207
|
+
else
|
208
|
+
raise KeyError, "#{key.inspect} must be integer or pointor"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
class PerfEventArray < TableBase
|
214
|
+
def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
|
215
|
+
super
|
216
|
+
@open_key_fds = {}
|
217
|
+
@event_class = nil
|
218
|
+
@_cbs = {}
|
219
|
+
@_open_key_fds = {}
|
220
|
+
end
|
221
|
+
|
222
|
+
def event(data)
|
223
|
+
@event_class ||= get_event_class
|
224
|
+
ev = @event_class.malloc
|
225
|
+
Fiddle::Pointer.new(ev.to_ptr)[0, @event_class.size] = data[0, @event_class.size]
|
226
|
+
return ev
|
227
|
+
end
|
228
|
+
|
229
|
+
def open_perf_buffer(page_cnt: 8, lost_cb: nil, &callback)
|
230
|
+
if page_cnt & (page_cnt - 1) != 0
|
231
|
+
raise "Perf buffer page_cnt must be a power of two"
|
232
|
+
end
|
233
|
+
|
234
|
+
get_online_cpus.each do |i|
|
235
|
+
_open_perf_buffer(i, callback, page_cnt, lost_cb)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
private
|
240
|
+
def get_event_class
|
241
|
+
ct_mapping = {
|
242
|
+
's8': 'char',
|
243
|
+
'u8': 'unsined char',
|
244
|
+
's8 *': 'char *',
|
245
|
+
's16': 'short',
|
246
|
+
'u16': 'unsigned short',
|
247
|
+
's32': 'int',
|
248
|
+
'u32': 'unsigned int',
|
249
|
+
's64': 'long long',
|
250
|
+
'u64': 'unsigned long long'
|
251
|
+
}
|
252
|
+
|
253
|
+
array_type = /(.+) \[([0-9]+)\]$/
|
254
|
+
fields = []
|
255
|
+
num_fields = Clib.bpf_perf_event_fields(self.bpf.module, @name)
|
256
|
+
num_fields.times do |i|
|
257
|
+
field = Clib.__extract_char(Clib.bpf_perf_event_field(self.bpf.module, @name, i))
|
258
|
+
field_name, field_type = *field.split('#')
|
259
|
+
if field_type =~ /enum .*/
|
260
|
+
field_type = "int" #it is indeed enum...
|
261
|
+
end
|
262
|
+
if _field_type = ct_mapping[field_type.to_sym]
|
263
|
+
field_type = _field_type
|
264
|
+
end
|
265
|
+
|
266
|
+
m = array_type.match(field_type)
|
267
|
+
if m
|
268
|
+
field_type = "#{m[1]}[#{m[2]}]"
|
269
|
+
fields << [field_type, field_name].join(" ")
|
270
|
+
else
|
271
|
+
fields << [field_type, field_name].join(" ")
|
272
|
+
end
|
273
|
+
end
|
274
|
+
klass = Fiddle::Importer.struct(fields)
|
275
|
+
if fields.find {|f| f =~ /^char\[(\d+)\] ([_a-zA-Z0-9]+)/ }
|
276
|
+
size = $1
|
277
|
+
m = Module.new do
|
278
|
+
define_method $2 do
|
279
|
+
super().pack("c#{size}").sub(/\0+$/, "")
|
280
|
+
end
|
281
|
+
end
|
282
|
+
klass.prepend m
|
283
|
+
end
|
284
|
+
klass
|
285
|
+
end
|
286
|
+
|
287
|
+
def _open_perf_buffer(cpu, callback, page_cnt, lost_cb)
|
288
|
+
# bind("void raw_cb_callback(void *, void *, int)")
|
289
|
+
fn = Fiddle::Closure::BlockCaller.new(
|
290
|
+
Fiddle::TYPE_VOID,
|
291
|
+
[Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT]
|
292
|
+
) do |_dummy, data, size|
|
293
|
+
begin
|
294
|
+
callback.call(cpu, data, size)
|
295
|
+
rescue => e
|
296
|
+
if Fiddle.last_error == 32 # EPIPE
|
297
|
+
exit
|
298
|
+
else
|
299
|
+
raise e
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
lost_fn = Fiddle::Closure::BlockCaller.new(
|
304
|
+
Fiddle::TYPE_VOID,
|
305
|
+
[Fiddle::TYPE_VOIDP, Fiddle::TYPE_ULONG]
|
306
|
+
) do |_dummy, lost|
|
307
|
+
begin
|
308
|
+
lost_cb(lost)
|
309
|
+
rescue => e
|
310
|
+
if Fiddle.last_error == 32 # EPIPE
|
311
|
+
exit
|
312
|
+
else
|
313
|
+
raise e
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end if lost_cb
|
317
|
+
reader = Clib.bpf_open_perf_buffer(fn, lost_fn, nil, -1, cpu, page_cnt)
|
318
|
+
if !reader || reader.null?
|
319
|
+
raise "Could not open perf buffer"
|
320
|
+
end
|
321
|
+
fd = Clib.perf_reader_fd(reader)
|
322
|
+
|
323
|
+
self[byref(cpu, @keysize)] = byref(fd, @leafsize)
|
324
|
+
self.bpf.perf_buffers[[object_id, cpu]] = reader
|
325
|
+
@_cbs[cpu] = [fn, lost_fn]
|
326
|
+
@_open_key_fds[cpu] = -1
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
data/lib/rbbcc/version.rb
CHANGED
data/lib/rbbcc.rb
CHANGED
data/misc/rbbcc-dfm-ruby
ADDED
data/rbbcc.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbbcc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Uchio Kondo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: BCC port for MRI. See https://github.com/iovisor/bcc
|
42
56
|
email:
|
43
57
|
- udzura@udzura.jp
|
@@ -46,6 +60,8 @@ extensions: []
|
|
46
60
|
extra_rdoc_files: []
|
47
61
|
files:
|
48
62
|
- ".gitignore"
|
63
|
+
- Dockerfile
|
64
|
+
- Dockerfile.dfm-example
|
49
65
|
- Gemfile
|
50
66
|
- Gemfile.lock
|
51
67
|
- LICENSE
|
@@ -53,8 +69,11 @@ files:
|
|
53
69
|
- Rakefile
|
54
70
|
- bin/console
|
55
71
|
- bin/setup
|
72
|
+
- examples/bitehist.rb
|
73
|
+
- examples/dddos.rb
|
56
74
|
- examples/example.gif
|
57
75
|
- examples/extract_arg.rb
|
76
|
+
- examples/hello_perf_output.rb
|
58
77
|
- examples/hello_world.rb
|
59
78
|
- examples/usdt-test.rb
|
60
79
|
- examples/usdt.rb
|
@@ -62,9 +81,14 @@ files:
|
|
62
81
|
- lib/rbbcc/bcc.rb
|
63
82
|
- lib/rbbcc/clib.rb
|
64
83
|
- lib/rbbcc/consts.rb
|
84
|
+
- lib/rbbcc/cpu_helper.rb
|
85
|
+
- lib/rbbcc/disp_helper.rb
|
86
|
+
- lib/rbbcc/fiddle_ext.rb
|
65
87
|
- lib/rbbcc/symbol_cache.rb
|
88
|
+
- lib/rbbcc/table.rb
|
66
89
|
- lib/rbbcc/usdt.rb
|
67
90
|
- lib/rbbcc/version.rb
|
91
|
+
- misc/rbbcc-dfm-ruby
|
68
92
|
- rbbcc.gemspec
|
69
93
|
homepage: https://github.com/udzura/rbbcc
|
70
94
|
licenses: []
|