Skip to content

Commit

Permalink
Support automatic kprobe event detection in common case
Browse files Browse the repository at this point in the history
* In the simple case, a user only creates 1 C function to be used with
  kprobes. Detect this common case and don't require the user to repeat
  themselves by passing the fn_name to attach_kprobe().
  e.g.: BPF(text='int sys_clone(void *ctx) {/*do stuff*/}').trace_print()

Signed-off-by: Brenden Blanco <[email protected]>
  • Loading branch information
Brenden Blanco committed Sep 9, 2015
1 parent 8d0425c commit 4fd308f
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 8 deletions.
4 changes: 1 addition & 3 deletions examples/hello_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,4 @@

from bcc import BPF

b = BPF(text='void hello(void *ctx) { bpf_trace_printk("Hello, World!\\n"); }')
b.attach_kprobe(event="sys_clone", fn_name="hello")
b.trace_print()
BPF(text='void sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); }').trace_print()
25 changes: 20 additions & 5 deletions src/python/bcc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
lib.bpf_module_license.argtypes = [ct.c_void_p]
lib.bpf_module_kern_version.restype = ct.c_uint
lib.bpf_module_kern_version.argtypes = [ct.c_void_p]
lib.bpf_num_functions.restype = ct.c_ulonglong
lib.bpf_num_functions.argtypes = [ct.c_void_p]
lib.bpf_function_name.restype = ct.c_char_p
lib.bpf_function_name.argtypes = [ct.c_void_p, ct.c_ulonglong]
lib.bpf_function_start.restype = ct.c_void_p
lib.bpf_function_start.argtypes = [ct.c_void_p, ct.c_char_p]
lib.bpf_function_size.restype = ct.c_size_t
Expand Down Expand Up @@ -345,6 +349,12 @@ def __init__(self, src_file="", hdr_file="", text=None, debug=0):
raise Exception("Failed to compile BPF module %s" % src_file)

def load_func(self, func_name, prog_type):
# empty func_name signifies auto-detection...works when only 1 fn exists
if not func_name:
if lib.bpf_num_functions(self.module) != 1:
raise Exception("Param func_name is None but num_functions > 1, ambiguous")
func_name = lib.bpf_function_name(self.module, 0).decode()

if func_name in self.funcs:
return self.funcs[func_name]

Expand Down Expand Up @@ -578,23 +588,28 @@ def trace_readline(nonblocking=False):
exit()
return line

@staticmethod
def trace_print(fmt=None):
"""trace_print(fmt=None)
def trace_print(self, fmt=None):
"""trace_print(self, fmt=None)
Read from the kernel debug trace pipe and print on stdout.
If fmt is specified, apply as a format string to the output. See
trace_fields for the members of the tuple
example: trace_print(fmt="pid {1}, msg = {5}")
"""

# Cater to one-liner case where attach_kprobe is omitted and C function
# name matches that of the kprobe.
if len(open_kprobes) == 0:
fn = self.load_func(None, BPF.KPROBE)
self.attach_kprobe(event=fn.name, fn_name=fn.name)

while True:
if fmt:
fields = BPF.trace_fields(nonblocking=False)
fields = self.trace_fields(nonblocking=False)
if not fields: continue
line = fmt.format(*fields)
else:
line = BPF.trace_readline(nonblocking=False)
line = self.trace_readline(nonblocking=False)
print(line)
sys.stdout.flush()

Expand Down

0 comments on commit 4fd308f

Please sign in to comment.