Permalink
Browse files

Remove dynamic generation of opensnoop.c.

Instead of changing the generated C code for opensnoop.c
based on the --pid and --tid flags, create a BPF array
that stores the values of the --pid and --tid arguments.

The flag values are written by the client and read by the
probe. By parameterizing the BPF program this way, we could
potentially rewrite opensnoop.c in Rust and use the
techniques discussed in https://github.com/bolinfest/rust-ebpf-demo/
to create a pure-Rust implementation of opensnoop powered by BPF.

The primary downside is that now every call to trace_entry()
makes two calls to lookup_or_init() whereas previously it made zero.
(I plan to get this down to one call in the next commit.)
I haven't had a chance to diff the BPF bytecode before and after this
change.
  • Loading branch information...
bolinfest committed Sep 11, 2018
1 parent 03e6e2b commit b60e496af5f76f3ea43a4dc2df4ed08d2b911285
Showing with 41 additions and 10 deletions.
  1. +41 −10 tools/opensnoop.py
View
@@ -74,6 +74,12 @@
char fname[NAME_MAX];
};
// If a[0] == 0, then there is nothing to filter.
// If a[0] == 1, then filter by the pid in a[1].
// If a[0] == 2, then filter by the tid in a[2].
// TODO(mbolin): Use a single u64 to store this data.
BPF_ARRAY(filter, u32, 3);
BPF_HASH(infotmp, u64, struct val_t);
BPF_PERF_OUTPUT(events);
@@ -84,7 +90,25 @@
u32 pid = id >> 32; // PID is higher part
u32 tid = id; // Cast and get the lower part
FILTER
u32 zero_index = 0;
u32 one_index = 1;
u32 two_index = 2;
u32 zero = 0;
u32 *filter_index = filter.lookup_or_init(&zero_index, &zero);
if (*filter_index == 1) {
u32 *filter_pid = filter.lookup_or_init(&one_index, &zero);
if (pid != *filter_pid) {
return 0;
}
} else if (*filter_index == 2) {
u32 *filter_tid = filter.lookup_or_init(&two_index, &zero);
if (tid != *filter_tid) {
return 0;
}
}
if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) {
val.id = id;
val.ts = bpf_ktime_get_ns();
@@ -120,21 +144,28 @@
return 0;
}
"""
if args.tid: # TID trumps PID
bpf_text = bpf_text.replace('FILTER',
'if (tid != %s) { return 0; }' % args.tid)
elif args.pid:
bpf_text = bpf_text.replace('FILTER',
'if (pid != %s) { return 0; }' % args.pid)
else:
bpf_text = bpf_text.replace('FILTER', '')
if debug or args.ebpf:
print(bpf_text)
if args.ebpf:
exit()
# initialize BPF
b = BPF(text=bpf_text)
b = BPF(text=bpf_text, debug=0)
if args.tid:
b["filter"][ct.c_int(0)] = ct.c_int(2)
b["filter"][ct.c_int(1)] = ct.c_int(0)
b["filter"][ct.c_int(2)] = ct.c_int(int(args.tid))
elif args.pid:
b["filter"][ct.c_int(0)] = ct.c_int(1)
b["filter"][ct.c_int(1)] = ct.c_int(int(args.pid))
b["filter"][ct.c_int(2)] = ct.c_int(0)
else:
b["filter"][ct.c_int(0)] = ct.c_int(0)
b["filter"][ct.c_int(1)] = ct.c_int(0)
b["filter"][ct.c_int(2)] = ct.c_int(0)
b.attach_kprobe(event="do_sys_open", fn_name="trace_entry")
b.attach_kretprobe(event="do_sys_open", fn_name="trace_return")

0 comments on commit b60e496

Please sign in to comment.