Commit b7d1af37 authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'bpf-add-cookies-retrieval-for-perf-kprobe-multi-links'

Jiri Olsa says:

====================
bpf: Add cookies retrieval for perf/kprobe multi links

hi,
this patchset adds support to retrieve cookies from existing tracing
links that still did not support it plus changes to bpftool to display
them. It's leftover we discussed some time ago [1].

thanks,
jirka

v2 changes:
 - added review/ack tags
 - fixed memory leak [Quentin]
 - align the uapi fields properly [Yafang Shao]

[1] https://lore.kernel.org/bpf/CALOAHbAZ6=A9j3VFCLoAC_WhgQKU7injMf06=cM2sU4Hi4Sx+Q@mail.gmail.com/Reviewed-by: default avatarQuentin Monnet <quentin@isovalent.com>
---
====================
Reviewed-by: default avatarQuentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/r/20240119110505.400573-1-jolsa@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents bbc094b3 b0dc0373
...@@ -6563,6 +6563,7 @@ struct bpf_link_info { ...@@ -6563,6 +6563,7 @@ struct bpf_link_info {
__u32 count; /* in/out: kprobe_multi function count */ __u32 count; /* in/out: kprobe_multi function count */
__u32 flags; __u32 flags;
__u64 missed; __u64 missed;
__aligned_u64 cookies;
} kprobe_multi; } kprobe_multi;
struct { struct {
__aligned_u64 path; __aligned_u64 path;
...@@ -6582,6 +6583,7 @@ struct bpf_link_info { ...@@ -6582,6 +6583,7 @@ struct bpf_link_info {
__aligned_u64 file_name; /* in/out */ __aligned_u64 file_name; /* in/out */
__u32 name_len; __u32 name_len;
__u32 offset; /* offset from file_name */ __u32 offset; /* offset from file_name */
__u64 cookie;
} uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */ } uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */
struct { struct {
__aligned_u64 func_name; /* in/out */ __aligned_u64 func_name; /* in/out */
...@@ -6589,14 +6591,19 @@ struct bpf_link_info { ...@@ -6589,14 +6591,19 @@ struct bpf_link_info {
__u32 offset; /* offset from func_name */ __u32 offset; /* offset from func_name */
__u64 addr; __u64 addr;
__u64 missed; __u64 missed;
__u64 cookie;
} kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */ } kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */
struct { struct {
__aligned_u64 tp_name; /* in/out */ __aligned_u64 tp_name; /* in/out */
__u32 name_len; __u32 name_len;
__u32 :32;
__u64 cookie;
} tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */ } tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */
struct { struct {
__u64 config; __u64 config;
__u32 type; __u32 type;
__u32 :32;
__u64 cookie;
} event; /* BPF_PERF_EVENT_EVENT */ } event; /* BPF_PERF_EVENT_EVENT */
}; };
} perf_event; } perf_event;
......
...@@ -3501,6 +3501,7 @@ static int bpf_perf_link_fill_kprobe(const struct perf_event *event, ...@@ -3501,6 +3501,7 @@ static int bpf_perf_link_fill_kprobe(const struct perf_event *event,
if (!kallsyms_show_value(current_cred())) if (!kallsyms_show_value(current_cred()))
addr = 0; addr = 0;
info->perf_event.kprobe.addr = addr; info->perf_event.kprobe.addr = addr;
info->perf_event.kprobe.cookie = event->bpf_cookie;
return 0; return 0;
} }
#endif #endif
...@@ -3526,6 +3527,7 @@ static int bpf_perf_link_fill_uprobe(const struct perf_event *event, ...@@ -3526,6 +3527,7 @@ static int bpf_perf_link_fill_uprobe(const struct perf_event *event,
else else
info->perf_event.type = BPF_PERF_EVENT_UPROBE; info->perf_event.type = BPF_PERF_EVENT_UPROBE;
info->perf_event.uprobe.offset = offset; info->perf_event.uprobe.offset = offset;
info->perf_event.uprobe.cookie = event->bpf_cookie;
return 0; return 0;
} }
#endif #endif
...@@ -3553,6 +3555,7 @@ static int bpf_perf_link_fill_tracepoint(const struct perf_event *event, ...@@ -3553,6 +3555,7 @@ static int bpf_perf_link_fill_tracepoint(const struct perf_event *event,
uname = u64_to_user_ptr(info->perf_event.tracepoint.tp_name); uname = u64_to_user_ptr(info->perf_event.tracepoint.tp_name);
ulen = info->perf_event.tracepoint.name_len; ulen = info->perf_event.tracepoint.name_len;
info->perf_event.type = BPF_PERF_EVENT_TRACEPOINT; info->perf_event.type = BPF_PERF_EVENT_TRACEPOINT;
info->perf_event.tracepoint.cookie = event->bpf_cookie;
return bpf_perf_link_fill_common(event, uname, ulen, NULL, NULL, NULL, NULL); return bpf_perf_link_fill_common(event, uname, ulen, NULL, NULL, NULL, NULL);
} }
...@@ -3561,6 +3564,7 @@ static int bpf_perf_link_fill_perf_event(const struct perf_event *event, ...@@ -3561,6 +3564,7 @@ static int bpf_perf_link_fill_perf_event(const struct perf_event *event,
{ {
info->perf_event.event.type = event->attr.type; info->perf_event.event.type = event->attr.type;
info->perf_event.event.config = event->attr.config; info->perf_event.event.config = event->attr.config;
info->perf_event.event.cookie = event->bpf_cookie;
info->perf_event.type = BPF_PERF_EVENT_EVENT; info->perf_event.type = BPF_PERF_EVENT_EVENT;
return 0; return 0;
} }
......
...@@ -2679,6 +2679,7 @@ static void bpf_kprobe_multi_link_dealloc(struct bpf_link *link) ...@@ -2679,6 +2679,7 @@ static void bpf_kprobe_multi_link_dealloc(struct bpf_link *link)
static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link, static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link,
struct bpf_link_info *info) struct bpf_link_info *info)
{ {
u64 __user *ucookies = u64_to_user_ptr(info->kprobe_multi.cookies);
u64 __user *uaddrs = u64_to_user_ptr(info->kprobe_multi.addrs); u64 __user *uaddrs = u64_to_user_ptr(info->kprobe_multi.addrs);
struct bpf_kprobe_multi_link *kmulti_link; struct bpf_kprobe_multi_link *kmulti_link;
u32 ucount = info->kprobe_multi.count; u32 ucount = info->kprobe_multi.count;
...@@ -2686,6 +2687,8 @@ static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link, ...@@ -2686,6 +2687,8 @@ static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link,
if (!uaddrs ^ !ucount) if (!uaddrs ^ !ucount)
return -EINVAL; return -EINVAL;
if (ucookies && !ucount)
return -EINVAL;
kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link); kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link);
info->kprobe_multi.count = kmulti_link->cnt; info->kprobe_multi.count = kmulti_link->cnt;
...@@ -2699,6 +2702,18 @@ static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link, ...@@ -2699,6 +2702,18 @@ static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link,
else else
ucount = kmulti_link->cnt; ucount = kmulti_link->cnt;
if (ucookies) {
if (kmulti_link->cookies) {
if (copy_to_user(ucookies, kmulti_link->cookies, ucount * sizeof(u64)))
return -EFAULT;
} else {
for (i = 0; i < ucount; i++) {
if (put_user(0, ucookies + i))
return -EFAULT;
}
}
}
if (kallsyms_show_value(current_cred())) { if (kallsyms_show_value(current_cred())) {
if (copy_to_user(uaddrs, kmulti_link->addrs, ucount * sizeof(u64))) if (copy_to_user(uaddrs, kmulti_link->addrs, ucount * sizeof(u64)))
return -EFAULT; return -EFAULT;
......
...@@ -249,18 +249,44 @@ static int get_prog_info(int prog_id, struct bpf_prog_info *info) ...@@ -249,18 +249,44 @@ static int get_prog_info(int prog_id, struct bpf_prog_info *info)
return err; return err;
} }
static int cmp_u64(const void *A, const void *B) struct addr_cookie {
__u64 addr;
__u64 cookie;
};
static int cmp_addr_cookie(const void *A, const void *B)
{ {
const __u64 *a = A, *b = B; const struct addr_cookie *a = A, *b = B;
return *a - *b; if (a->addr == b->addr)
return 0;
return a->addr < b->addr ? -1 : 1;
}
static struct addr_cookie *
get_addr_cookie_array(__u64 *addrs, __u64 *cookies, __u32 count)
{
struct addr_cookie *data;
__u32 i;
data = calloc(count, sizeof(data[0]));
if (!data) {
p_err("mem alloc failed");
return NULL;
}
for (i = 0; i < count; i++) {
data[i].addr = addrs[i];
data[i].cookie = cookies[i];
}
qsort(data, count, sizeof(data[0]), cmp_addr_cookie);
return data;
} }
static void static void
show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
{ {
struct addr_cookie *data;
__u32 i, j = 0; __u32 i, j = 0;
__u64 *addrs;
jsonw_bool_field(json_wtr, "retprobe", jsonw_bool_field(json_wtr, "retprobe",
info->kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN); info->kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN);
...@@ -268,14 +294,20 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) ...@@ -268,14 +294,20 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
jsonw_uint_field(json_wtr, "missed", info->kprobe_multi.missed); jsonw_uint_field(json_wtr, "missed", info->kprobe_multi.missed);
jsonw_name(json_wtr, "funcs"); jsonw_name(json_wtr, "funcs");
jsonw_start_array(json_wtr); jsonw_start_array(json_wtr);
addrs = u64_to_ptr(info->kprobe_multi.addrs); data = get_addr_cookie_array(u64_to_ptr(info->kprobe_multi.addrs),
qsort(addrs, info->kprobe_multi.count, sizeof(addrs[0]), cmp_u64); u64_to_ptr(info->kprobe_multi.cookies),
info->kprobe_multi.count);
if (!data)
return;
/* Load it once for all. */ /* Load it once for all. */
if (!dd.sym_count) if (!dd.sym_count)
kernel_syms_load(&dd); kernel_syms_load(&dd);
if (!dd.sym_count)
goto error;
for (i = 0; i < dd.sym_count; i++) { for (i = 0; i < dd.sym_count; i++) {
if (dd.sym_mapping[i].address != addrs[j]) if (dd.sym_mapping[i].address != data[j].addr)
continue; continue;
jsonw_start_object(json_wtr); jsonw_start_object(json_wtr);
jsonw_uint_field(json_wtr, "addr", dd.sym_mapping[i].address); jsonw_uint_field(json_wtr, "addr", dd.sym_mapping[i].address);
...@@ -287,11 +319,14 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) ...@@ -287,11 +319,14 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
} else { } else {
jsonw_string_field(json_wtr, "module", dd.sym_mapping[i].module); jsonw_string_field(json_wtr, "module", dd.sym_mapping[i].module);
} }
jsonw_uint_field(json_wtr, "cookie", data[j].cookie);
jsonw_end_object(json_wtr); jsonw_end_object(json_wtr);
if (j++ == info->kprobe_multi.count) if (j++ == info->kprobe_multi.count)
break; break;
} }
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
error:
free(data);
} }
static __u64 *u64_to_arr(__u64 val) static __u64 *u64_to_arr(__u64 val)
...@@ -334,6 +369,7 @@ show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr) ...@@ -334,6 +369,7 @@ show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr)
u64_to_ptr(info->perf_event.kprobe.func_name)); u64_to_ptr(info->perf_event.kprobe.func_name));
jsonw_uint_field(wtr, "offset", info->perf_event.kprobe.offset); jsonw_uint_field(wtr, "offset", info->perf_event.kprobe.offset);
jsonw_uint_field(wtr, "missed", info->perf_event.kprobe.missed); jsonw_uint_field(wtr, "missed", info->perf_event.kprobe.missed);
jsonw_uint_field(wtr, "cookie", info->perf_event.kprobe.cookie);
} }
static void static void
...@@ -343,6 +379,7 @@ show_perf_event_uprobe_json(struct bpf_link_info *info, json_writer_t *wtr) ...@@ -343,6 +379,7 @@ show_perf_event_uprobe_json(struct bpf_link_info *info, json_writer_t *wtr)
jsonw_string_field(wtr, "file", jsonw_string_field(wtr, "file",
u64_to_ptr(info->perf_event.uprobe.file_name)); u64_to_ptr(info->perf_event.uprobe.file_name));
jsonw_uint_field(wtr, "offset", info->perf_event.uprobe.offset); jsonw_uint_field(wtr, "offset", info->perf_event.uprobe.offset);
jsonw_uint_field(wtr, "cookie", info->perf_event.uprobe.cookie);
} }
static void static void
...@@ -350,6 +387,7 @@ show_perf_event_tracepoint_json(struct bpf_link_info *info, json_writer_t *wtr) ...@@ -350,6 +387,7 @@ show_perf_event_tracepoint_json(struct bpf_link_info *info, json_writer_t *wtr)
{ {
jsonw_string_field(wtr, "tracepoint", jsonw_string_field(wtr, "tracepoint",
u64_to_ptr(info->perf_event.tracepoint.tp_name)); u64_to_ptr(info->perf_event.tracepoint.tp_name));
jsonw_uint_field(wtr, "cookie", info->perf_event.tracepoint.cookie);
} }
static char *perf_config_hw_cache_str(__u64 config) static char *perf_config_hw_cache_str(__u64 config)
...@@ -426,6 +464,8 @@ show_perf_event_event_json(struct bpf_link_info *info, json_writer_t *wtr) ...@@ -426,6 +464,8 @@ show_perf_event_event_json(struct bpf_link_info *info, json_writer_t *wtr)
else else
jsonw_uint_field(wtr, "event_config", config); jsonw_uint_field(wtr, "event_config", config);
jsonw_uint_field(wtr, "cookie", info->perf_event.event.cookie);
if (type == PERF_TYPE_HW_CACHE && perf_config) if (type == PERF_TYPE_HW_CACHE && perf_config)
free((void *)perf_config); free((void *)perf_config);
} }
...@@ -670,8 +710,8 @@ void netfilter_dump_plain(const struct bpf_link_info *info) ...@@ -670,8 +710,8 @@ void netfilter_dump_plain(const struct bpf_link_info *info)
static void show_kprobe_multi_plain(struct bpf_link_info *info) static void show_kprobe_multi_plain(struct bpf_link_info *info)
{ {
struct addr_cookie *data;
__u32 i, j = 0; __u32 i, j = 0;
__u64 *addrs;
if (!info->kprobe_multi.count) if (!info->kprobe_multi.count)
return; return;
...@@ -683,21 +723,24 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info) ...@@ -683,21 +723,24 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info)
printf("func_cnt %u ", info->kprobe_multi.count); printf("func_cnt %u ", info->kprobe_multi.count);
if (info->kprobe_multi.missed) if (info->kprobe_multi.missed)
printf("missed %llu ", info->kprobe_multi.missed); printf("missed %llu ", info->kprobe_multi.missed);
addrs = (__u64 *)u64_to_ptr(info->kprobe_multi.addrs); data = get_addr_cookie_array(u64_to_ptr(info->kprobe_multi.addrs),
qsort(addrs, info->kprobe_multi.count, sizeof(__u64), cmp_u64); u64_to_ptr(info->kprobe_multi.cookies),
info->kprobe_multi.count);
if (!data)
return;
/* Load it once for all. */ /* Load it once for all. */
if (!dd.sym_count) if (!dd.sym_count)
kernel_syms_load(&dd); kernel_syms_load(&dd);
if (!dd.sym_count) if (!dd.sym_count)
return; goto error;
printf("\n\t%-16s %s", "addr", "func [module]"); printf("\n\t%-16s %-16s %s", "addr", "cookie", "func [module]");
for (i = 0; i < dd.sym_count; i++) { for (i = 0; i < dd.sym_count; i++) {
if (dd.sym_mapping[i].address != addrs[j]) if (dd.sym_mapping[i].address != data[j].addr)
continue; continue;
printf("\n\t%016lx %s", printf("\n\t%016lx %-16llx %s",
dd.sym_mapping[i].address, dd.sym_mapping[i].name); dd.sym_mapping[i].address, data[j].cookie, dd.sym_mapping[i].name);
if (dd.sym_mapping[i].module[0] != '\0') if (dd.sym_mapping[i].module[0] != '\0')
printf(" [%s] ", dd.sym_mapping[i].module); printf(" [%s] ", dd.sym_mapping[i].module);
else else
...@@ -706,6 +749,8 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info) ...@@ -706,6 +749,8 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info)
if (j++ == info->kprobe_multi.count) if (j++ == info->kprobe_multi.count)
break; break;
} }
error:
free(data);
} }
static void show_uprobe_multi_plain(struct bpf_link_info *info) static void show_uprobe_multi_plain(struct bpf_link_info *info)
...@@ -754,6 +799,8 @@ static void show_perf_event_kprobe_plain(struct bpf_link_info *info) ...@@ -754,6 +799,8 @@ static void show_perf_event_kprobe_plain(struct bpf_link_info *info)
printf("+%#x", info->perf_event.kprobe.offset); printf("+%#x", info->perf_event.kprobe.offset);
if (info->perf_event.kprobe.missed) if (info->perf_event.kprobe.missed)
printf(" missed %llu", info->perf_event.kprobe.missed); printf(" missed %llu", info->perf_event.kprobe.missed);
if (info->perf_event.kprobe.cookie)
printf(" cookie %llu", info->perf_event.kprobe.cookie);
printf(" "); printf(" ");
} }
...@@ -770,6 +817,8 @@ static void show_perf_event_uprobe_plain(struct bpf_link_info *info) ...@@ -770,6 +817,8 @@ static void show_perf_event_uprobe_plain(struct bpf_link_info *info)
else else
printf("\n\tuprobe "); printf("\n\tuprobe ");
printf("%s+%#x ", buf, info->perf_event.uprobe.offset); printf("%s+%#x ", buf, info->perf_event.uprobe.offset);
if (info->perf_event.uprobe.cookie)
printf("cookie %llu ", info->perf_event.uprobe.cookie);
} }
static void show_perf_event_tracepoint_plain(struct bpf_link_info *info) static void show_perf_event_tracepoint_plain(struct bpf_link_info *info)
...@@ -781,6 +830,8 @@ static void show_perf_event_tracepoint_plain(struct bpf_link_info *info) ...@@ -781,6 +830,8 @@ static void show_perf_event_tracepoint_plain(struct bpf_link_info *info)
return; return;
printf("\n\ttracepoint %s ", buf); printf("\n\ttracepoint %s ", buf);
if (info->perf_event.tracepoint.cookie)
printf("cookie %llu ", info->perf_event.tracepoint.cookie);
} }
static void show_perf_event_event_plain(struct bpf_link_info *info) static void show_perf_event_event_plain(struct bpf_link_info *info)
...@@ -802,6 +853,9 @@ static void show_perf_event_event_plain(struct bpf_link_info *info) ...@@ -802,6 +853,9 @@ static void show_perf_event_event_plain(struct bpf_link_info *info)
else else
printf("%llu ", config); printf("%llu ", config);
if (info->perf_event.event.cookie)
printf("cookie %llu ", info->perf_event.event.cookie);
if (type == PERF_TYPE_HW_CACHE && perf_config) if (type == PERF_TYPE_HW_CACHE && perf_config)
free((void *)perf_config); free((void *)perf_config);
} }
...@@ -952,6 +1006,14 @@ static int do_show_link(int fd) ...@@ -952,6 +1006,14 @@ static int do_show_link(int fd)
return -ENOMEM; return -ENOMEM;
} }
info.kprobe_multi.addrs = ptr_to_u64(addrs); info.kprobe_multi.addrs = ptr_to_u64(addrs);
cookies = calloc(count, sizeof(__u64));
if (!cookies) {
p_err("mem alloc failed");
free(addrs);
close(fd);
return -ENOMEM;
}
info.kprobe_multi.cookies = ptr_to_u64(cookies);
goto again; goto again;
} }
} }
...@@ -977,7 +1039,7 @@ static int do_show_link(int fd) ...@@ -977,7 +1039,7 @@ static int do_show_link(int fd)
cookies = calloc(count, sizeof(__u64)); cookies = calloc(count, sizeof(__u64));
if (!cookies) { if (!cookies) {
p_err("mem alloc failed"); p_err("mem alloc failed");
free(cookies); free(ref_ctr_offsets);
free(offsets); free(offsets);
close(fd); close(fd);
return -ENOMEM; return -ENOMEM;
......
...@@ -6563,6 +6563,7 @@ struct bpf_link_info { ...@@ -6563,6 +6563,7 @@ struct bpf_link_info {
__u32 count; /* in/out: kprobe_multi function count */ __u32 count; /* in/out: kprobe_multi function count */
__u32 flags; __u32 flags;
__u64 missed; __u64 missed;
__aligned_u64 cookies;
} kprobe_multi; } kprobe_multi;
struct { struct {
__aligned_u64 path; __aligned_u64 path;
...@@ -6582,6 +6583,7 @@ struct bpf_link_info { ...@@ -6582,6 +6583,7 @@ struct bpf_link_info {
__aligned_u64 file_name; /* in/out */ __aligned_u64 file_name; /* in/out */
__u32 name_len; __u32 name_len;
__u32 offset; /* offset from file_name */ __u32 offset; /* offset from file_name */
__u64 cookie;
} uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */ } uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */
struct { struct {
__aligned_u64 func_name; /* in/out */ __aligned_u64 func_name; /* in/out */
...@@ -6589,14 +6591,19 @@ struct bpf_link_info { ...@@ -6589,14 +6591,19 @@ struct bpf_link_info {
__u32 offset; /* offset from func_name */ __u32 offset; /* offset from func_name */
__u64 addr; __u64 addr;
__u64 missed; __u64 missed;
__u64 cookie;
} kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */ } kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */
struct { struct {
__aligned_u64 tp_name; /* in/out */ __aligned_u64 tp_name; /* in/out */
__u32 name_len; __u32 name_len;
__u32 :32;
__u64 cookie;
} tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */ } tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */
struct { struct {
__u64 config; __u64 config;
__u32 type; __u32 type;
__u32 :32;
__u64 cookie;
} event; /* BPF_PERF_EVENT_EVENT */ } event; /* BPF_PERF_EVENT_EVENT */
}; };
} perf_event; } perf_event;
......
...@@ -19,6 +19,7 @@ static const char *kmulti_syms[] = { ...@@ -19,6 +19,7 @@ static const char *kmulti_syms[] = {
}; };
#define KMULTI_CNT ARRAY_SIZE(kmulti_syms) #define KMULTI_CNT ARRAY_SIZE(kmulti_syms)
static __u64 kmulti_addrs[KMULTI_CNT]; static __u64 kmulti_addrs[KMULTI_CNT];
static __u64 kmulti_cookies[] = { 3, 1, 2 };
#define KPROBE_FUNC "bpf_fentry_test1" #define KPROBE_FUNC "bpf_fentry_test1"
static __u64 kprobe_addr; static __u64 kprobe_addr;
...@@ -31,6 +32,8 @@ static noinline void uprobe_func(void) ...@@ -31,6 +32,8 @@ static noinline void uprobe_func(void)
asm volatile (""); asm volatile ("");
} }
#define PERF_EVENT_COOKIE 0xdeadbeef
static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long addr, static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long addr,
ssize_t offset, ssize_t entry_offset) ssize_t offset, ssize_t entry_offset)
{ {
...@@ -62,6 +65,8 @@ static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long add ...@@ -62,6 +65,8 @@ static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long add
ASSERT_EQ(info.perf_event.kprobe.addr, addr + entry_offset, ASSERT_EQ(info.perf_event.kprobe.addr, addr + entry_offset,
"kprobe_addr"); "kprobe_addr");
ASSERT_EQ(info.perf_event.kprobe.cookie, PERF_EVENT_COOKIE, "kprobe_cookie");
if (!info.perf_event.kprobe.func_name) { if (!info.perf_event.kprobe.func_name) {
ASSERT_EQ(info.perf_event.kprobe.name_len, 0, "name_len"); ASSERT_EQ(info.perf_event.kprobe.name_len, 0, "name_len");
info.perf_event.kprobe.func_name = ptr_to_u64(&buf); info.perf_event.kprobe.func_name = ptr_to_u64(&buf);
...@@ -81,6 +86,8 @@ static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long add ...@@ -81,6 +86,8 @@ static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long add
goto again; goto again;
} }
ASSERT_EQ(info.perf_event.tracepoint.cookie, PERF_EVENT_COOKIE, "tracepoint_cookie");
err = strncmp(u64_to_ptr(info.perf_event.tracepoint.tp_name), TP_NAME, err = strncmp(u64_to_ptr(info.perf_event.tracepoint.tp_name), TP_NAME,
strlen(TP_NAME)); strlen(TP_NAME));
ASSERT_EQ(err, 0, "cmp_tp_name"); ASSERT_EQ(err, 0, "cmp_tp_name");
...@@ -96,10 +103,17 @@ static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long add ...@@ -96,10 +103,17 @@ static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long add
goto again; goto again;
} }
ASSERT_EQ(info.perf_event.uprobe.cookie, PERF_EVENT_COOKIE, "uprobe_cookie");
err = strncmp(u64_to_ptr(info.perf_event.uprobe.file_name), UPROBE_FILE, err = strncmp(u64_to_ptr(info.perf_event.uprobe.file_name), UPROBE_FILE,
strlen(UPROBE_FILE)); strlen(UPROBE_FILE));
ASSERT_EQ(err, 0, "cmp_file_name"); ASSERT_EQ(err, 0, "cmp_file_name");
break; break;
case BPF_PERF_EVENT_EVENT:
ASSERT_EQ(info.perf_event.event.type, PERF_TYPE_SOFTWARE, "event_type");
ASSERT_EQ(info.perf_event.event.config, PERF_COUNT_SW_PAGE_FAULTS, "event_config");
ASSERT_EQ(info.perf_event.event.cookie, PERF_EVENT_COOKIE, "event_cookie");
break;
default: default:
err = -1; err = -1;
break; break;
...@@ -139,6 +153,7 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel, ...@@ -139,6 +153,7 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel,
DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts, DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts,
.attach_mode = PROBE_ATTACH_MODE_LINK, .attach_mode = PROBE_ATTACH_MODE_LINK,
.retprobe = type == BPF_PERF_EVENT_KRETPROBE, .retprobe = type == BPF_PERF_EVENT_KRETPROBE,
.bpf_cookie = PERF_EVENT_COOKIE,
); );
ssize_t entry_offset = 0; ssize_t entry_offset = 0;
struct bpf_link *link; struct bpf_link *link;
...@@ -163,10 +178,13 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel, ...@@ -163,10 +178,13 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel,
static void test_tp_fill_link_info(struct test_fill_link_info *skel) static void test_tp_fill_link_info(struct test_fill_link_info *skel)
{ {
DECLARE_LIBBPF_OPTS(bpf_tracepoint_opts, opts,
.bpf_cookie = PERF_EVENT_COOKIE,
);
struct bpf_link *link; struct bpf_link *link;
int link_fd, err; int link_fd, err;
link = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME); link = bpf_program__attach_tracepoint_opts(skel->progs.tp_run, TP_CAT, TP_NAME, &opts);
if (!ASSERT_OK_PTR(link, "attach_tp")) if (!ASSERT_OK_PTR(link, "attach_tp"))
return; return;
...@@ -176,16 +194,53 @@ static void test_tp_fill_link_info(struct test_fill_link_info *skel) ...@@ -176,16 +194,53 @@ static void test_tp_fill_link_info(struct test_fill_link_info *skel)
bpf_link__destroy(link); bpf_link__destroy(link);
} }
static void test_event_fill_link_info(struct test_fill_link_info *skel)
{
DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, opts,
.bpf_cookie = PERF_EVENT_COOKIE,
);
struct bpf_link *link;
int link_fd, err, pfd;
struct perf_event_attr attr = {
.type = PERF_TYPE_SOFTWARE,
.config = PERF_COUNT_SW_PAGE_FAULTS,
.freq = 1,
.sample_freq = 1,
.size = sizeof(struct perf_event_attr),
};
pfd = syscall(__NR_perf_event_open, &attr, -1 /* pid */, 0 /* cpu 0 */,
-1 /* group id */, 0 /* flags */);
if (!ASSERT_GE(pfd, 0, "perf_event_open"))
return;
link = bpf_program__attach_perf_event_opts(skel->progs.event_run, pfd, &opts);
if (!ASSERT_OK_PTR(link, "attach_event"))
goto error;
link_fd = bpf_link__fd(link);
err = verify_perf_link_info(link_fd, BPF_PERF_EVENT_EVENT, 0, 0, 0);
ASSERT_OK(err, "verify_perf_link_info");
bpf_link__destroy(link);
error:
close(pfd);
}
static void test_uprobe_fill_link_info(struct test_fill_link_info *skel, static void test_uprobe_fill_link_info(struct test_fill_link_info *skel,
enum bpf_perf_event_type type) enum bpf_perf_event_type type)
{ {
DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, opts,
.retprobe = type == BPF_PERF_EVENT_URETPROBE,
.bpf_cookie = PERF_EVENT_COOKIE,
);
struct bpf_link *link; struct bpf_link *link;
int link_fd, err; int link_fd, err;
link = bpf_program__attach_uprobe(skel->progs.uprobe_run, link = bpf_program__attach_uprobe_opts(skel->progs.uprobe_run,
type == BPF_PERF_EVENT_URETPROBE, 0, /* self pid */
0, /* self pid */ UPROBE_FILE, uprobe_offset,
UPROBE_FILE, uprobe_offset); &opts);
if (!ASSERT_OK_PTR(link, "attach_uprobe")) if (!ASSERT_OK_PTR(link, "attach_uprobe"))
return; return;
...@@ -195,11 +250,11 @@ static void test_uprobe_fill_link_info(struct test_fill_link_info *skel, ...@@ -195,11 +250,11 @@ static void test_uprobe_fill_link_info(struct test_fill_link_info *skel,
bpf_link__destroy(link); bpf_link__destroy(link);
} }
static int verify_kmulti_link_info(int fd, bool retprobe) static int verify_kmulti_link_info(int fd, bool retprobe, bool has_cookies)
{ {
__u64 addrs[KMULTI_CNT], cookies[KMULTI_CNT];
struct bpf_link_info info; struct bpf_link_info info;
__u32 len = sizeof(info); __u32 len = sizeof(info);
__u64 addrs[KMULTI_CNT];
int flags, i, err; int flags, i, err;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
...@@ -221,18 +276,22 @@ static int verify_kmulti_link_info(int fd, bool retprobe) ...@@ -221,18 +276,22 @@ static int verify_kmulti_link_info(int fd, bool retprobe)
if (!info.kprobe_multi.addrs) { if (!info.kprobe_multi.addrs) {
info.kprobe_multi.addrs = ptr_to_u64(addrs); info.kprobe_multi.addrs = ptr_to_u64(addrs);
info.kprobe_multi.cookies = ptr_to_u64(cookies);
goto again; goto again;
} }
for (i = 0; i < KMULTI_CNT; i++) for (i = 0; i < KMULTI_CNT; i++) {
ASSERT_EQ(addrs[i], kmulti_addrs[i], "kmulti_addrs"); ASSERT_EQ(addrs[i], kmulti_addrs[i], "kmulti_addrs");
ASSERT_EQ(cookies[i], has_cookies ? kmulti_cookies[i] : 0,
"kmulti_cookies_value");
}
return 0; return 0;
} }
static void verify_kmulti_invalid_user_buffer(int fd) static void verify_kmulti_invalid_user_buffer(int fd)
{ {
__u64 addrs[KMULTI_CNT], cookies[KMULTI_CNT];
struct bpf_link_info info; struct bpf_link_info info;
__u32 len = sizeof(info); __u32 len = sizeof(info);
__u64 addrs[KMULTI_CNT];
int err, i; int err, i;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
...@@ -266,7 +325,20 @@ static void verify_kmulti_invalid_user_buffer(int fd) ...@@ -266,7 +325,20 @@ static void verify_kmulti_invalid_user_buffer(int fd)
info.kprobe_multi.count = KMULTI_CNT; info.kprobe_multi.count = KMULTI_CNT;
info.kprobe_multi.addrs = 0x1; /* invalid addr */ info.kprobe_multi.addrs = 0x1; /* invalid addr */
err = bpf_link_get_info_by_fd(fd, &info, &len); err = bpf_link_get_info_by_fd(fd, &info, &len);
ASSERT_EQ(err, -EFAULT, "invalid_buff"); ASSERT_EQ(err, -EFAULT, "invalid_buff_addrs");
info.kprobe_multi.count = KMULTI_CNT;
info.kprobe_multi.addrs = ptr_to_u64(addrs);
info.kprobe_multi.cookies = 0x1; /* invalid addr */
err = bpf_link_get_info_by_fd(fd, &info, &len);
ASSERT_EQ(err, -EFAULT, "invalid_buff_cookies");
/* cookies && !count */
info.kprobe_multi.count = 0;
info.kprobe_multi.addrs = ptr_to_u64(NULL);
info.kprobe_multi.cookies = ptr_to_u64(cookies);
err = bpf_link_get_info_by_fd(fd, &info, &len);
ASSERT_EQ(err, -EINVAL, "invalid_cookies_count");
} }
static int symbols_cmp_r(const void *a, const void *b) static int symbols_cmp_r(const void *a, const void *b)
...@@ -278,13 +350,15 @@ static int symbols_cmp_r(const void *a, const void *b) ...@@ -278,13 +350,15 @@ static int symbols_cmp_r(const void *a, const void *b)
} }
static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel, static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel,
bool retprobe, bool invalid) bool retprobe, bool cookies,
bool invalid)
{ {
LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
struct bpf_link *link; struct bpf_link *link;
int link_fd, err; int link_fd, err;
opts.syms = kmulti_syms; opts.syms = kmulti_syms;
opts.cookies = cookies ? kmulti_cookies : NULL;
opts.cnt = KMULTI_CNT; opts.cnt = KMULTI_CNT;
opts.retprobe = retprobe; opts.retprobe = retprobe;
link = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run, NULL, &opts); link = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run, NULL, &opts);
...@@ -293,7 +367,7 @@ static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel, ...@@ -293,7 +367,7 @@ static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel,
link_fd = bpf_link__fd(link); link_fd = bpf_link__fd(link);
if (!invalid) { if (!invalid) {
err = verify_kmulti_link_info(link_fd, retprobe); err = verify_kmulti_link_info(link_fd, retprobe, cookies);
ASSERT_OK(err, "verify_kmulti_link_info"); ASSERT_OK(err, "verify_kmulti_link_info");
} else { } else {
verify_kmulti_invalid_user_buffer(link_fd); verify_kmulti_invalid_user_buffer(link_fd);
...@@ -513,6 +587,8 @@ void test_fill_link_info(void) ...@@ -513,6 +587,8 @@ void test_fill_link_info(void)
test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KPROBE, true); test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KPROBE, true);
if (test__start_subtest("tracepoint_link_info")) if (test__start_subtest("tracepoint_link_info"))
test_tp_fill_link_info(skel); test_tp_fill_link_info(skel);
if (test__start_subtest("event_link_info"))
test_event_fill_link_info(skel);
uprobe_offset = get_uprobe_offset(&uprobe_func); uprobe_offset = get_uprobe_offset(&uprobe_func);
if (test__start_subtest("uprobe_link_info")) if (test__start_subtest("uprobe_link_info"))
...@@ -523,12 +599,16 @@ void test_fill_link_info(void) ...@@ -523,12 +599,16 @@ void test_fill_link_info(void)
qsort(kmulti_syms, KMULTI_CNT, sizeof(kmulti_syms[0]), symbols_cmp_r); qsort(kmulti_syms, KMULTI_CNT, sizeof(kmulti_syms[0]), symbols_cmp_r);
for (i = 0; i < KMULTI_CNT; i++) for (i = 0; i < KMULTI_CNT; i++)
kmulti_addrs[i] = ksym_get_addr(kmulti_syms[i]); kmulti_addrs[i] = ksym_get_addr(kmulti_syms[i]);
if (test__start_subtest("kprobe_multi_link_info")) if (test__start_subtest("kprobe_multi_link_info")) {
test_kprobe_multi_fill_link_info(skel, false, false); test_kprobe_multi_fill_link_info(skel, false, false, false);
if (test__start_subtest("kretprobe_multi_link_info")) test_kprobe_multi_fill_link_info(skel, false, true, false);
test_kprobe_multi_fill_link_info(skel, true, false); }
if (test__start_subtest("kretprobe_multi_link_info")) {
test_kprobe_multi_fill_link_info(skel, true, false, false);
test_kprobe_multi_fill_link_info(skel, true, true, false);
}
if (test__start_subtest("kprobe_multi_invalid_ubuff")) if (test__start_subtest("kprobe_multi_invalid_ubuff"))
test_kprobe_multi_fill_link_info(skel, true, true); test_kprobe_multi_fill_link_info(skel, true, true, true);
if (test__start_subtest("uprobe_multi_link_info")) if (test__start_subtest("uprobe_multi_link_info"))
test_uprobe_multi_fill_link_info(skel, false, false); test_uprobe_multi_fill_link_info(skel, false, false);
......
...@@ -33,6 +33,12 @@ int BPF_PROG(tp_run) ...@@ -33,6 +33,12 @@ int BPF_PROG(tp_run)
return 0; return 0;
} }
SEC("perf_event")
int event_run(void *ctx)
{
return 0;
}
SEC("kprobe.multi") SEC("kprobe.multi")
int BPF_PROG(kmulti_run) int BPF_PROG(kmulti_run)
{ {
......
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