Commit 8058eb13 authored by Sasha Goldshtein's avatar Sasha Goldshtein

Added ret probes

parent 4cd70632
...@@ -33,6 +33,9 @@ int PROBENAME(struct pt_regs *ctx SIGNATURE) ...@@ -33,6 +33,9 @@ int PROBENAME(struct pt_regs *ctx SIGNATURE)
if len(parts) < 3 or len(parts) > 6: if len(parts) < 3 or len(parts) > 6:
raise ValueError("invalid specifier format") raise ValueError("invalid specifier format")
self.type = parts[0] # hist or raw self.type = parts[0] # hist or raw
self.is_ret_probe = self.type.endswith("-ret")
if self.is_ret_probe:
self.type = self.type[:-len("-ret")]
if self.type != "hist" and self.type != "raw": if self.type != "hist" and self.type != "raw":
raise ValueError("unrecognized probe type") raise ValueError("unrecognized probe type")
self.library = parts[1] self.library = parts[1]
...@@ -45,8 +48,11 @@ int PROBENAME(struct pt_regs *ctx SIGNATURE) ...@@ -45,8 +48,11 @@ int PROBENAME(struct pt_regs *ctx SIGNATURE)
self.expr_type = parts[3] self.expr_type = parts[3]
self.expr = parts[4] self.expr = parts[4]
else: else:
self.expr_type = "u64" self.expr_type = \
self.expr = "1" "u64" if not self.is_ret_probe else "int"
self.expr = "1" if not self.is_ret_probe else "@retval"
self.expr = self.expr.replace("@retval",
"(%s)ctx->ax" % self.expr_type)
self.filter = None if len(parts) != 6 else parts[5] self.filter = None if len(parts) != 6 else parts[5]
self.pid = pid self.pid = pid
self.probe_func_name = self.function + "_probe" self.probe_func_name = self.function + "_probe"
...@@ -95,13 +101,23 @@ bpf_probe_read(&__key.key, sizeof(__key.key), %s); ...@@ -95,13 +101,23 @@ bpf_probe_read(&__key.key, sizeof(__key.key), %s);
def attach(self, bpf): def attach(self, bpf):
self.bpf = bpf self.bpf = bpf
if len(self.library) > 0: if len(self.library) > 0:
bpf.attach_uprobe(name=self.library, if self.is_ret_probe:
sym=self.function, bpf.attach_uretprobe(name=self.library,
fn_name=self.probe_func_name, sym=self.function,
pid=self.pid or -1) fn_name=self.probe_func_name,
pid=self.pid or -1)
else:
bpf.attach_uprobe(name=self.library,
sym=self.function,
fn_name=self.probe_func_name,
pid=self.pid or -1)
else: else:
bpf.attach_kprobe(event=self.function, if self.is_ret_probe:
fn_name=self.probe_func_name) bpf.attach_kretprobe(event=self.function,
fn_name=self.probe_func_name)
else:
bpf.attach_kprobe(event=self.function,
fn_name=self.probe_func_name)
def display(self): def display(self):
print(self.raw_spec) print(self.raw_spec)
...@@ -121,9 +137,10 @@ bpf_probe_read(&__key.key, sizeof(__key.key), %s); ...@@ -121,9 +137,10 @@ bpf_probe_read(&__key.key, sizeof(__key.key), %s);
examples = """ examples = """
Probe specifier syntax: Probe specifier syntax:
<raw|hist>:[library]:function(signature)[:type:expr[:filter]] <raw|hist>[-ret]:[library]:function(signature)[:type:expr[:filter]]
Where: Where:
<raw|hist> -- collect raw data or a histogram of values <raw|hist> -- collect raw data or a histogram of values
ret -- probe at function exit, only @retval is accessible
library -- the library that contains the function library -- the library that contains the function
(leave empty for kernel functions) (leave empty for kernel functions)
function -- the function name to trace function -- the function name to trace
...@@ -141,10 +158,16 @@ gentrace.py -p 1005 -s "raw:c:malloc(size_t size):size_t:size:size==16" ...@@ -141,10 +158,16 @@ gentrace.py -p 1005 -s "raw:c:malloc(size_t size):size_t:size:size==16"
Print a raw count of how many times process 1005 called malloc with Print a raw count of how many times process 1005 called malloc with
an allocation size of 16 bytes an allocation size of 16 bytes
gentrace.py -s "raw-ret:c:gets():char*:@retval"
Snoop on all strings returned by gets()
gentrace.py -p 1005 -s "raw:c:write(int fd):int:fd" gentrace.py -p 1005 -s "raw:c:write(int fd):int:fd"
Print raw counts of how many times writes were issued to a particular Print raw counts of how many times writes were issued to a particular
file descriptor number, in process 1005 file descriptor number, in process 1005
gentrace.py -p 1005 -s "hist-ret:c:read()"
Print a histogram of error codes returned by read() in process 1005
gentrace.py -s "hist:c:write(int fd, const void *buf, size_t count):size_t:count:fd==1" gentrace.py -s "hist:c:write(int fd, const void *buf, size_t count):size_t:count:fd==1"
Print a histogram of buffer sizes passed to write() across all Print a histogram of buffer sizes passed to write() across all
processes, where the file descriptor was 1 (STDOUT) processes, where the file descriptor was 1 (STDOUT)
......
...@@ -152,11 +152,40 @@ raw:c:puts(char *str):char*:str ...@@ -152,11 +152,40 @@ raw:c:puts(char *str):char*:str
It looks like the message "Press ENTER to start." was printed twice during the It looks like the message "Press ENTER to start." was printed twice during the
10 seconds we were tracing. 10 seconds we were tracing.
What about reads? You could trace gets() across the system and print the
strings input by the user:
# ./gentrace.py 10 1 -s "raw-ret:c:gets():char*:@retval"
[02:12:23]
raw-ret:c:gets():char*:@retval
COUNT EVENT
1 (char*)ctx->ax = hi there
1 (char*)ctx->ax = sasha
1 (char*)ctx->ax = hello
Similarly, we could get a histogram of the error codes returned by read():
# ./gentrace.py 10 1 -s "hist-ret:c:read()"
[02:15:36]
hist-ret:c:read()
(int)ctx->ax : count distribution
0 -> 1 : 29 |****************************************|
2 -> 3 : 11 |*************** |
4 -> 7 : 0 | |
8 -> 15 : 3 |**** |
16 -> 31 : 2 |** |
32 -> 63 : 22 |****************************** |
64 -> 127 : 5 |****** |
128 -> 255 : 0 | |
256 -> 511 : 1 |* |
512 -> 1023 : 1 |* |
1024 -> 2047 : 0 | |
2048 -> 4095 : 2 |** |
USAGE message: USAGE message:
# ./gentrace.py -h # ./gentrace.py -h
usage: gentrace.py [-h] [-p PID] [-z STRING_SIZE] usage: gentrace.py [-h] [-p PID] [-z STRING_SIZE]
[-s SPECIFIERS [SPECIFIERS ...]] [-s SPECIFIERS [SPECIFIERS ...]]
[interval] [count] [interval] [count]
...@@ -176,9 +205,10 @@ optional arguments: ...@@ -176,9 +205,10 @@ optional arguments:
the probe specifiers (see examples below) the probe specifiers (see examples below)
Probe specifier syntax: Probe specifier syntax:
<raw|hist>:[library]:function(signature)[:type:expr[:filter]] <raw|hist>[-ret]:[library]:function(signature)[:type:expr[:filter]]
Where: Where:
<raw|hist> -- collect raw data or a histogram of values <raw|hist> -- collect raw data or a histogram of values
ret -- probe at function exit, only @retval is accessible
library -- the library that contains the function library -- the library that contains the function
(leave empty for kernel functions) (leave empty for kernel functions)
function -- the function name to trace function -- the function name to trace
...@@ -196,10 +226,16 @@ gentrace.py -p 1005 -s "raw:c:malloc(size_t size):size_t:size:size==16" ...@@ -196,10 +226,16 @@ gentrace.py -p 1005 -s "raw:c:malloc(size_t size):size_t:size:size==16"
Print a raw count of how many times process 1005 called malloc with Print a raw count of how many times process 1005 called malloc with
an allocation size of 16 bytes an allocation size of 16 bytes
gentrace.py -s "raw-ret:c:gets():char*:@retval"
Snoop on all strings returned by gets()
gentrace.py -p 1005 -s "raw:c:write(int fd):int:fd" gentrace.py -p 1005 -s "raw:c:write(int fd):int:fd"
Print raw counts of how many times writes were issued to a particular Print raw counts of how many times writes were issued to a particular
file descriptor number, in process 1005 file descriptor number, in process 1005
gentrace.py -p 1005 -s "hist-ret:c:read()"
Print a histogram of error codes returned by read() in process 1005
gentrace.py -s "hist:c:write(int fd, const void *buf, size_t count):size_t:count:fd==1" gentrace.py -s "hist:c:write(int fd, const void *buf, size_t count):size_t:count:fd==1"
Print a histogram of buffer sizes passed to write() across all Print a histogram of buffer sizes passed to write() across all
processes, where the file descriptor was 1 (STDOUT) processes, where the file descriptor was 1 (STDOUT)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment