diff --git a/examples/hello_world.py b/examples/hello_world.py index 73a105ed25fa3c0a2016bd26525593b02c758817..2ad21c6905ff2351babc7c60171a5054aba3f2b3 100755 --- a/examples/hello_world.py +++ b/examples/hello_world.py @@ -6,14 +6,13 @@ # sudo ./hello_world.py" from bpf import BPF -from subprocess import call prog = """ int hello(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; -}; +} """ b = BPF(text=prog) b.attach_kprobe(event="sys_clone", fn_name="hello") -b.trace_print() +b.trace_print(fmt="{1} {5}") diff --git a/src/python/bpf/__init__.py b/src/python/bpf/__init__.py index f05e38da88edb35aa347a930f92d69a6be798402..10ee07d1b1d93956c6cfcec7a12118ce542a6a85 100644 --- a/src/python/bpf/__init__.py +++ b/src/python/bpf/__init__.py @@ -389,7 +389,7 @@ class BPF(object): if res < 0: raise Exception("Failed to attach BPF to kprobe") open_kprobes[ev_name] = res - return res + return self @staticmethod def detach_kprobe(event): @@ -412,7 +412,7 @@ class BPF(object): if res < 0: raise Exception("Failed to attach BPF to kprobe") open_kprobes[ev_name] = res - return res + return self @staticmethod def detach_kretprobe(event): @@ -437,14 +437,33 @@ class BPF(object): if not tracefile: tracefile = open("%s/trace_pipe" % TRACEFS) if nonblocking: - fd = trace.fileno() + fd = tracefile.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) return tracefile @staticmethod - def trace_readline(nonblocking=True): - """trace_readline(nonblocking=True) + def trace_readline_fields(nonblocking=False): + """trace_readline_fields(nonblocking=False) + + Read from the kernel debug trace pipe and return a tuple of the + fields (task, pid, cpu, flags, timestamp, msg) or None if no + line was read (nonblocking=True) + """ + line = BPF.trace_readline(nonblocking) + if line: + task = line[:16].lstrip() + line = line[17:] + ts_end = line.find(":") + pid, cpu, flags, ts = line[:ts_end].split() + cpu = cpu[1:-1] + msg = line[ts_end + 4:] + return (task, int(pid), int(cpu), flags, float(ts), msg) + return + + @staticmethod + def trace_readline(nonblocking=False): + """trace_readline(nonblocking=False) Read from the kernel debug trace pipe and return one line If nonblocking is False, this will block until ctrl-C is pressed. @@ -454,17 +473,28 @@ class BPF(object): line = None try: - line = trace.readline(128).rstrip() - except BlockingIOError: + line = trace.readline(1024).rstrip() + except IOError: pass + except KeyboardInterrupt: + exit() return line @staticmethod - def trace_print(): - try: - while True: + def trace_print(fmt=None): + """trace_print(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_readline_fields for the members of the tuple + example: trace_print(fmt="pid {1}, msg = {5}") + """ + + while True: + if fmt: + fields = BPF.trace_readline_fields(nonblocking=False) + line = fmt.format(*fields) + else: line = BPF.trace_readline(nonblocking=False) - print(line) - sys.stdout.flush() - except KeyboardInterrupt: - exit() + print(line) + sys.stdout.flush()