We are trying to port an existing bcc solution to libbpf + c. The problem is we need to support older kernels too i.e. at least 5.5.
Functionality: uprobe for user executable with function pattern etc i.e. need bpf_program__attach_uprobe_multi
functionality. We have to achieve the same with bpf_program__attach_uprobe
Looked at examples in libbpf-bootstrap
and bcc/libbpf-tools/
, and all of them installed one function per uprobe handler.
We are trying to get the address of the traced function with bpf_get_func_ip(void *ctx)
but it is returning a zero ip, looks like works only for kprobes.
Is there any way to get the ip of a uprobe function that is traced?
Maybe cookies are the way to detect which user function is called.
Or should I read from this (void *)PT_REGS_IP(ctx)
?
Tried the following example. Is anything missing here? Is there any boilerplate example for the same?
int main(int argc, char **argv)
{
size_t offset1;
size_t offset2;
int err, i;
char filename[256];
pid_t pid;
struct bpf_object *obj = NULL;
struct bpf_program *prog[2];
static struct bpf_link *bpflinks[2];
static struct bpf_link *ubpflinks[2];
if (argc < 2) {
printf("Error return \n");
return 0;
}
pid = strtoul(argv[1], NULL, 10);
snprintf(filename, 256, "/proc/%d/exe", pid);
offset1 = get_elf_func_offset("/data/expr/operations", "op_add");
offset2 = get_elf_func_offset("/data/expr/operations", "op_sub");
snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]);
obj = bpf_object__open_file(filename, NULL);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
obj = NULL;
goto cleanup;
}
/* load BPF program */
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
}
prog[0] = bpf_object__find_program_by_name(obj, "handle_uprobe_ref_ctr");
// prog[1] = bpf_object__find_program_by_name(obj, "handle_uretprobe_ref_ctr");
ubpflinks[0] =
bpf_program__attach_uprobe(prog[0], false /* not uretprobe */,
pid, "/data/expr/operations" , offset1);
if (!ubpflinks[0])
printf("failed at link0\n");
ubpflinks[1] =
bpf_program__attach_uprobe(prog[0], false /* not uretprobe */,
pid, "/data/expr/operations" , offset2);
if (!ubpflinks[1])
printf("failed at link1\n");
// bpflinks[0] = bpf_program__attach(prog[0]); // do we need to attach program, already probes attached
getchar();
cleanup:
bpf_link__destroy(ubpflinks[0]);
bpf_link__destroy(ubpflinks[1]);
return -err;
}
char LICENSE[] SEC("license") = "Dual BSD/GPL";
SEC("uprobe")
int handle_uprobe_ref_ctr(struct pt_regs *ctx)
{
__u64 addr = bpf_get_func_ip(ctx);
const char fmt_str[] = "function fp %lld ip %lld\n";
bpf_trace_printk(fmt_str, sizeof(fmt_str), (void *)PT_REGS_FP(ctx), addr);
return 0;
}
SEC("uretprobe")
int handle_uretprobe_ref_ctr(struct pt_regs *ctx)
{
bpf_printk("handle_uretprobe_ref_ctr \n");
return 0;
}
some executable operations
void op_add(int a, int b)
{
}
void op_sub(int a, int b)
{
}
int main()
{
printf("pid %d\n",getpid());
for (int i = 0;; i++) {
/* trigger our BPF programs */
fprintf(stderr, ".");
op_add(i, i + 1);
op_sub(i * i, i);
sleep(1);
}
return 0;
}