From 420b96ae1e34751cd084393170bdb1ee63506944 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 26 Sep 2023 11:08:33 -0700 Subject: [PATCH] examples/c: demo how to get IP for uprobe and uretprobe Show how it's possible to fetch user-space function's address from uprobe and uretprobe BPF programs. When uprobe example is run, you'll see: ``` Triggering user function test_func, addr 0x402bc2... ``` in the console output. And corresponding: ``` uprobe-1805730 [036] ....1 674139.123096: bpf_trace_printk: UPROBE IP 0x402bc2. uprobe-1805730 [036] ....1 674139.123110: bpf_trace_printk: URETPROBE IP 0x402bc2. ``` in /sys/kernel/debug/tracing/trace_pipe. As you can see, those IPs match exactly. ARM might need a bit of adjustment, I'm not sure, I think ARM can have uprobe/uretprobe breakpoint installed not at the very first byte offset within user space function. Signed-off-by: Andrii Nakryiko --- examples/c/uprobe.bpf.c | 24 ++++++++++++++++++------ examples/c/uprobe.c | 2 ++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/examples/c/uprobe.bpf.c b/examples/c/uprobe.bpf.c index 94a6db57..01914fe0 100644 --- a/examples/c/uprobe.bpf.c +++ b/examples/c/uprobe.bpf.c @@ -3,33 +3,45 @@ #include "vmlinux.h" #include #include +#include char LICENSE[] SEC("license") = "Dual BSD/GPL"; SEC("uprobe") -int BPF_KPROBE(uprobe_add, int a, int b) +int BPF_UPROBE(uprobe_add, int a, int b) { - bpf_printk("uprobed_add ENTRY: a = %d, b = %d", a, b); + long ip; + + ip = PT_REGS_IP(ctx); + bpf_printk("UPROBE IP 0x%lx.", ip); return 0; } SEC("uretprobe") -int BPF_KRETPROBE(uretprobe_add, int ret) +int BPF_URETPROBE(uretprobe_add, int ret) { - bpf_printk("uprobed_add EXIT: return = %d", ret); + struct task_struct *t = (void *)bpf_get_current_task(); + struct uprobe_dispatch_data *ud; + long ip; + + ud = (void *)BPF_CORE_READ(t, utask, vaddr); + ip = BPF_CORE_READ(ud, bp_addr); + bpf_printk("URETPROBE IP 0x%lx.", ip); return 0; } +/* SEC("uprobe//proc/self/exe:uprobed_sub") -int BPF_KPROBE(uprobe_sub, int a, int b) +int BPF_UPROBE(uprobe_sub, int a, int b) { bpf_printk("uprobed_sub ENTRY: a = %d, b = %d", a, b); return 0; } SEC("uretprobe//proc/self/exe:uprobed_sub") -int BPF_KRETPROBE(uretprobe_sub, int ret) +int BPF_URETPROBE(uretprobe_sub, int ret) { bpf_printk("uprobed_sub EXIT: return = %d", ret); return 0; } +*/ diff --git a/examples/c/uprobe.c b/examples/c/uprobe.c index f7ea1b4b..1621aff4 100644 --- a/examples/c/uprobe.c +++ b/examples/c/uprobe.c @@ -15,6 +15,8 @@ static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va /* It's a global function to make sure compiler doesn't inline it. */ int uprobed_add(int a, int b) { + printf("Triggering user function test_func, addr %p...\n", + (const void *)&uprobed_add); return a + b; }