* Request for comments version (still needs polishing). * Based on Andrii Nakryiko's suggestion. * Using bpf_program__set_priv in attach_kprobe() for kprobe cleanup. Signed-off-by: Rafael David Tinoco <rafaeldtinoco@xxxxxxxxxx> --- src/libbpf.c | 100 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 10 deletions(-) diff --git a/src/libbpf.c b/src/libbpf.c index 2f351d3..4dc09d3 100644 --- a/src/libbpf.c +++ b/src/libbpf.c @@ -9677,8 +9677,14 @@ static int parse_uint_from_file(const char *file, const char *fmt) static int determine_kprobe_perf_type(void) { + int ret = 0; + struct stat s; const char *file = "/sys/bus/event_source/devices/kprobe/type"; + ret = stat(file, &s); + if (ret < 0) + return -errno; + return parse_uint_from_file(file, "%d\n"); } @@ -9703,25 +9709,87 @@ static int determine_uprobe_retprobe_bit(void) return parse_uint_from_file(file, "config:%d\n"); } +static int determine_kprobe_perf_type_legacy(const char *func_name) +{ + char file[256]; + const char *fname = "/sys/kernel/debug/tracing/events/kprobes/%s/id"; + + snprintf(file, sizeof(file), fname, func_name); + + return parse_uint_from_file(file, "%d\n"); +} + +static int poke_kprobe_events(bool add, const char *name, bool kretprobe) +{ + int fd, ret = 0; + char given[256], buf[256]; + const char *file = "/sys/kernel/debug/tracing/kprobe_events"; + + if (kretprobe && add) + snprintf(given, sizeof(given), "kprobes/%s_ret", name); + else + snprintf(given, sizeof(given), "kprobes/%s", name); + if (add) + snprintf(buf, sizeof(buf),"%c:%s %s\n", kretprobe ? 'r' : 'p', given, name); + else + snprintf(buf, sizeof(buf), "-:%s\n", given); + + fd = open(file, O_WRONLY|O_APPEND, 0); + if (!fd) + return -errno; + ret = write(fd, buf, strlen(buf)); + if (ret < 0) { + ret = -errno; + } + close(fd); + + return ret; +} + +static inline int add_kprobe_event_legacy(const char* func_name, bool kretprobe) +{ + return poke_kprobe_events(true /*add*/, func_name, kretprobe); +} + +static inline int remove_kprobe_event_legacy(const char* func_name, bool kretprobe) +{ + return poke_kprobe_events(false /*remove*/, func_name, kretprobe); +} + static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, uint64_t offset, int pid) { struct perf_event_attr attr = {}; char errmsg[STRERR_BUFSIZE]; int type, pfd, err; + bool legacy = false; type = uprobe ? determine_uprobe_perf_type() : determine_kprobe_perf_type(); if (type < 0) { - pr_warn("failed to determine %s perf type: %s\n", - uprobe ? "uprobe" : "kprobe", - libbpf_strerror_r(type, errmsg, sizeof(errmsg))); - return type; + if (uprobe) { + pr_warn("failed to determine %s perf type: %s\n", + uprobe ? "uprobe" : "kprobe", + libbpf_strerror_r(type, errmsg, sizeof(errmsg))); + return type; + } + err = add_kprobe_event_legacy(name, retprobe); + if (err < 0) { + pr_warn("failed to add legacy kprobe events: %s\n", + libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + return err; + } + type = uprobe ? type : determine_kprobe_perf_type_legacy(name); + if (type < 0) { + remove_kprobe_event_legacy(name, retprobe); + pr_warn("failed to determine kprobe perf type: %s\n", + libbpf_strerror_r(type, errmsg, sizeof(errmsg))); + } + legacy = true; } - if (retprobe) { + if (retprobe && !legacy) { int bit = uprobe ? determine_uprobe_retprobe_bit() : determine_kprobe_retprobe_bit(); - if (bit < 0) { pr_warn("failed to determine %s retprobe bit: %s\n", uprobe ? "uprobe" : "kprobe", @@ -9731,10 +9799,14 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, attr.config |= 1 << bit; } attr.size = sizeof(attr); - attr.type = type; - attr.config1 = ptr_to_u64(name); /* kprobe_func or uprobe_path */ - attr.config2 = offset; /* kprobe_addr or probe_offset */ - + if (!legacy) { + attr.type = type; + attr.config1 = ptr_to_u64(name); /* kprobe_func or uprobe_path */ + attr.config2 = offset; /* kprobe_addr or probe_offset */ + } else { + attr.config = type; + attr.type = PERF_TYPE_TRACEPOINT; + } /* pid filter is meaningful only for uprobes */ pfd = syscall(__NR_perf_event_open, &attr, pid < 0 ? -1 : pid /* pid */, @@ -9750,6 +9822,11 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, return pfd; } +void bpf_program__detach_kprobe_legacy(struct bpf_program *prog, void *retprobe) +{ + remove_kprobe_event_legacy(prog->name, (bool) retprobe); +} + struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog, bool retprobe, const char *func_name) @@ -9766,6 +9843,9 @@ struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog, libbpf_strerror_r(pfd, errmsg, sizeof(errmsg))); return ERR_PTR(pfd); } + + bpf_program__set_priv(prog, (void *) retprobe, bpf_program__detach_kprobe_legacy); + link = bpf_program__attach_perf_event(prog, pfd); if (IS_ERR(link)) { close(pfd); -- 2.27.0