Skip to content

Commit

Permalink
introduce new BPF APIs to get kernel syscall entry func name/prefix
Browse files Browse the repository at this point in the history
As described in issue iovisor#1695, on 4.17 for syscalls on x86,
both sys_<fnname> and SyS_<fnname> are gone, the replacements
are __ia32_sys_sync and __x64_sys_sync.
The commit in Linus tree:
torvalds/linux@d5a0052

This patch introduced two APIs for python BPF object.
The API get_syscall_prefix() returns the prefix "sys_"/"__x64_sys_".
The API get_syscall_fnname(name) returns kernel function name for the syscall,
e.g., on x64, get_syscall_fnname("clone") will return "sys_clone" if kernel
has it, otherwise, "__x64_sys_clone".
get_syscall_prefix() is mostly useful for the regex func specifier of
attach_kprobe().

This patch only fixed the code using python API on examples and tests directory.

TOTO: python on tools directory, C++ and lua

Signed-off-by: Yonghong Song <[email protected]>
  • Loading branch information
yonghong-song committed Apr 24, 2018
1 parent 435dded commit 83b49ad
Show file tree
Hide file tree
Showing 14 changed files with 55 additions and 24 deletions.
1 change: 1 addition & 0 deletions examples/hello_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@

from bcc import BPF

# This may not work for 4.17 on x64, you need replace kprobe__sys_clone with kprobe____x64_sys_clone
BPF(text='int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }').trace_print()
2 changes: 1 addition & 1 deletion examples/tracing/hello_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

# load BPF program
b = BPF(text=prog)
b.attach_kprobe(event="sys_clone", fn_name="hello")
b.attach_kprobe(event=b.get_syscall_fnname("clone"), fn_name="hello")

# header
print("%-18s %-16s %-6s %s" % ("TIME(s)", "COMM", "PID", "MESSAGE"))
Expand Down
2 changes: 1 addition & 1 deletion examples/tracing/hello_perf_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

# load BPF program
b = BPF(text=prog)
b.attach_kprobe(event="sys_clone", fn_name="hello")
b.attach_kprobe(event=b.get_syscall_fnname("clone"), fn_name="hello")

# define output data structure in Python
TASK_COMM_LEN = 16 # linux/sched.h
Expand Down
2 changes: 1 addition & 1 deletion examples/tracing/sync_timing.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
}
""")

b.attach_kprobe(event="sys_sync", fn_name="do_trace")
b.attach_kprobe(event=b.get_syscall_fnname("sync"), fn_name="do_trace")
print("Tracing for quick sync's... Ctrl-C to end")

# format output
Expand Down
2 changes: 1 addition & 1 deletion examples/tracing/trace_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
}
"""
b = BPF(text=prog)
b.attach_kprobe(event="sys_clone", fn_name="hello")
b.attach_kprobe(event=b.get_syscall_fnname("clone"), fn_name="hello")
print "PID MESSAGE"
b.trace_print(fmt="{1} {5}")
6 changes: 4 additions & 2 deletions examples/tracing/trace_perf_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def cb(cpu, data, size):
prog = """
BPF_PERF_OUTPUT(events);
BPF_ARRAY(counters, u64, 10);
int kprobe__sys_clone(void *ctx) {
int do_sys_clone(void *ctx) {
struct {
u64 ts;
u64 magic;
Expand All @@ -40,6 +40,8 @@ def cb(cpu, data, size):
}
"""
b = BPF(text=prog)
event_name = b.get_syscall_fnname("clone")
b.attach_kprobe(event=event_name, fn_name="do_sys_clone")
b["events"].open_perf_buffer(cb)

@atexit.register
Expand All @@ -48,7 +50,7 @@ def print_counter():
global b
print("counter = %d vs %d" % (counter, b["counters"][ct.c_int(0)].value))

print("Tracing sys_write, try `dd if=/dev/zero of=/dev/null`")
print("Tracing " + event_name + ", try `dd if=/dev/zero of=/dev/null`")
print("Tracing... Hit Ctrl-C to end.")
while 1:
b.perf_buffer_poll()
13 changes: 13 additions & 0 deletions src/python/bcc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,19 @@ def _del_uprobe_fd(self, name):
global _num_open_probes
del self.uprobe_fds[name]
_num_open_probes -= 1

def get_syscall_prefix(self):
# test bpf syscall kernel func name
if self.ksymname("sys_bpf") != -1:
return "sys_"
if self.ksymname("__x64_sys_bpf") != -1:
return "__x64_sys_"
# none of them, just return "sys_", later API
# calls will return error
return "sys_"

def get_syscall_fnname(self, name):
return self.get_syscall_prefix() + name

def attach_kprobe(self, event=b"", fn_name=b"", event_re=b""):
event = _assert_is_bytes(event)
Expand Down
8 changes: 6 additions & 2 deletions tests/python/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def lost_cb(lost):

text = """
BPF_PERF_OUTPUT(events);
int kprobe__sys_nanosleep(void *ctx) {
int do_sys_nanosleep(void *ctx) {
struct {
u64 ts;
} data = {bpf_ktime_get_ns()};
Expand All @@ -63,6 +63,8 @@ def lost_cb(lost):
}
"""
b = BPF(text=text)
b.attach_kprobe(event=b.get_syscall_fnname("nanosleep"),
fn_name="do_sys_nanosleep")
b["events"].open_perf_buffer(cb, lost_cb=lost_cb)
time.sleep(0.1)
b.perf_buffer_poll()
Expand All @@ -85,7 +87,7 @@ def lost_cb(lost):

text = """
BPF_PERF_OUTPUT(events);
int kprobe__sys_nanosleep(void *ctx) {
int do_sys_nanosleep(void *ctx) {
struct {
u64 cpu;
} data = {bpf_get_smp_processor_id()};
Expand All @@ -94,6 +96,8 @@ def lost_cb(lost):
}
"""
b = BPF(text=text)
b.attach_kprobe(event=b.get_syscall_fnname("nanosleep"),
fn_name="do_sys_nanosleep")
b["events"].open_perf_buffer(cb, lost_cb=lost_cb)
online_cpus = get_online_cpus()
for cpu in online_cpus:
Expand Down
6 changes: 4 additions & 2 deletions tests/python/test_clang.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ def test_probe_struct_assign(self):
int flags;
int mode;
};
int kprobe__sys_open(struct pt_regs *ctx, const char *filename,
int do_sys_open(struct pt_regs *ctx, const char *filename,
int flags, int mode) {
struct args_t args = {};
args.filename = filename;
Expand All @@ -305,6 +305,8 @@ def test_probe_struct_assign(self):
return 0;
};
""")
b.attach_kprobe(event=b.get_syscall_fnname("open"),
fn_name="do_sys_open")

def test_task_switch(self):
b = BPF(text="""
Expand Down Expand Up @@ -599,7 +601,7 @@ def test_map_insert(self):
c_val = ct.c_ulong(1)
b["dummy"][ct.c_ulong(0)] = c_val
b["dummy"][ct.c_ulong(1)] = c_val
b.attach_kprobe(event="sys_sync", fn_name="do_trace")
b.attach_kprobe(event=b.get_syscall_fnname("sync"), fn_name="do_trace")
libc = ct.CDLL("libc.so.6")
libc.sync()
self.assertEqual(1, b["dummy"][ct.c_ulong(0)].value)
Expand Down
5 changes: 3 additions & 2 deletions tests/python/test_lru.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def test_lru_percpu_hash(self):
"""
b = BPF(text=test_prog1)
stats_map = b.get_table("stats")
b.attach_kprobe(event="sys_clone", fn_name="hello_world")
event_name = b.get_syscall_fnname("clone")
b.attach_kprobe(event=event_name, fn_name="hello_world")
ini = stats_map.Leaf()
for i in range(0, multiprocessing.cpu_count()):
ini[i] = 0
Expand All @@ -53,7 +54,7 @@ def test_lru_percpu_hash(self):
max = stats_map.max(stats_map.Key(0))
self.assertGreater(sum.value, 0L)
self.assertGreater(max.value, 0L)
b.detach_kprobe("sys_clone")
b.detach_kprobe(event_name)

if __name__ == "__main__":
unittest.main()
15 changes: 9 additions & 6 deletions tests/python/test_percpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ def test_u64(self):
"""
bpf_code = BPF(text=test_prog1)
stats_map = bpf_code.get_table("stats")
bpf_code.attach_kprobe(event="sys_clone", fn_name="hello_world")
event_name = bpf_code.get_syscall_fnname("clone")
bpf_code.attach_kprobe(event=event_name, fn_name="hello_world")
ini = stats_map.Leaf()
for i in range(0, multiprocessing.cpu_count()):
ini[i] = 0
Expand All @@ -50,7 +51,7 @@ def test_u64(self):
max = stats_map.max(stats_map.Key(0))
self.assertGreater(sum.value, int(0))
self.assertGreater(max.value, int(0))
bpf_code.detach_kprobe("sys_clone")
bpf_code.detach_kprobe(event_name)

def test_u32(self):
test_prog1 = """
Expand All @@ -65,7 +66,8 @@ def test_u32(self):
"""
bpf_code = BPF(text=test_prog1)
stats_map = bpf_code.get_table("stats")
bpf_code.attach_kprobe(event="sys_clone", fn_name="hello_world")
event_name = bpf_code.get_syscall_fnname("clone")
bpf_code.attach_kprobe(event=event_name, fn_name="hello_world")
ini = stats_map.Leaf()
for i in range(0, multiprocessing.cpu_count()):
ini[i] = 0
Expand All @@ -79,7 +81,7 @@ def test_u32(self):
max = stats_map.max(stats_map.Key(0))
self.assertGreater(sum.value, int(0))
self.assertGreater(max.value, int(0))
bpf_code.detach_kprobe("sys_clone")
bpf_code.detach_kprobe(event_name)

def test_struct_custom_func(self):
test_prog2 = """
Expand All @@ -100,7 +102,8 @@ def test_struct_custom_func(self):
bpf_code = BPF(text=test_prog2)
stats_map = bpf_code.get_table("stats",
reducer=lambda x,y: stats_map.sLeaf(x.c1+y.c1))
bpf_code.attach_kprobe(event="sys_clone", fn_name="hello_world")
event_name = bpf_code.get_syscall_fnname("clone")
bpf_code.attach_kprobe(event=event_name, fn_name="hello_world")
ini = stats_map.Leaf()
for i in ini:
i = stats_map.sLeaf(0,0)
Expand All @@ -110,7 +113,7 @@ def test_struct_custom_func(self):
self.assertEqual(len(stats_map),1)
k = stats_map[ stats_map.Key(0) ]
self.assertGreater(k.c1, int(0))
bpf_code.detach_kprobe("sys_clone")
bpf_code.detach_kprobe(event_name)


if __name__ == "__main__":
Expand Down
7 changes: 5 additions & 2 deletions tests/python/test_perf_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def test_cycles(self):
BPF_PERF_ARRAY(cnt1, NUM_CPUS);
BPF_ARRAY(prev, u64, NUM_CPUS);
BPF_HISTOGRAM(dist);
int kprobe__sys_getuid(void *ctx) {
int do_sys_getuid(void *ctx) {
u32 cpu = bpf_get_smp_processor_id();
u64 val = cnt1.perf_read(CUR_CPU_IDENTIFIER);
Expand All @@ -25,7 +25,7 @@ def test_cycles(self):
prev.update(&cpu, &val);
return 0;
}
int kretprobe__sys_getuid(void *ctx) {
int do_ret_sys_getuid(void *ctx) {
u32 cpu = bpf_get_smp_processor_id();
u64 val = cnt1.perf_read(CUR_CPU_IDENTIFIER);
Expand All @@ -40,6 +40,9 @@ def test_cycles(self):
"""
b = bcc.BPF(text=text, debug=0,
cflags=["-DNUM_CPUS=%d" % multiprocessing.cpu_count()])
event_name = b.get_syscall_fnname("getuid")
b.attach_kprobe(event=event_name, fn_name="do_sys_getuid")
b.attach_kretprobe(event=event_name, fn_name="do_ret_sys_getuid")
cnt1 = b["cnt1"]
try:
cnt1.open_perf_event(bcc.PerfType.HARDWARE, bcc.PerfHWConfig.CPU_CYCLES)
Expand Down
4 changes: 2 additions & 2 deletions tests/python/test_trace1.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class TestKprobe(TestCase):
def setUp(self):
b = BPF(arg1, arg2, debug=0)
self.stats = b.get_table("stats", Key, Leaf)
b.attach_kprobe(event="sys_write", fn_name="sys_wr")
b.attach_kprobe(event="sys_read", fn_name="sys_rd")
b.attach_kprobe(event=b.get_syscall_fnname("write"), fn_name="sys_wr")
b.attach_kprobe(event=b.get_syscall_fnname("read"), fn_name="sys_rd")
b.attach_kprobe(event="htab_map_get_next_key", fn_name="sys_rd")

def test_trace1(self):
Expand Down
6 changes: 4 additions & 2 deletions tests/python/test_trace4.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ def setUp(self):
return 0;
}
""")
self.b.attach_kprobe(event_re="^SyS_bp.*", fn_name="hello")
self.b.attach_kretprobe(event_re="^SyS_bp.*", fn_name="goodbye")
self.b.attach_kprobe(event_re="^" + self.b.get_syscall_prefix() + "bp.*",
fn_name="hello")
self.b.attach_kretprobe(event_re="^" + self.b.get_syscall_prefix() + "bp.*",
fn_name="goodbye")

def test_send1(self):
k1 = self.b["stats"].Key(1)
Expand Down

0 comments on commit 83b49ad

Please sign in to comment.