Commit b7d1af37 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

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.org


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents bbc094b3 b0dc0373
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -6563,6 +6563,7 @@ struct bpf_link_info {
			__u32 count; /* in/out: kprobe_multi function count */
			__u32 flags;
			__u64 missed;
			__aligned_u64 cookies;
		} kprobe_multi;
		struct {
			__aligned_u64 path;
@@ -6582,6 +6583,7 @@ struct bpf_link_info {
					__aligned_u64 file_name; /* in/out */
					__u32 name_len;
					__u32 offset; /* offset from file_name */
					__u64 cookie;
				} uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */
				struct {
					__aligned_u64 func_name; /* in/out */
@@ -6589,14 +6591,19 @@ struct bpf_link_info {
					__u32 offset; /* offset from func_name */
					__u64 addr;
					__u64 missed;
					__u64 cookie;
				} kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */
				struct {
					__aligned_u64 tp_name;   /* in/out */
					__u32 name_len;
					__u32 :32;
					__u64 cookie;
				} tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */
				struct {
					__u64 config;
					__u32 type;
					__u32 :32;
					__u64 cookie;
				} event; /* BPF_PERF_EVENT_EVENT */
			};
		} perf_event;
+4 −0
Original line number Diff line number Diff line
@@ -3501,6 +3501,7 @@ static int bpf_perf_link_fill_kprobe(const struct perf_event *event,
	if (!kallsyms_show_value(current_cred()))
		addr = 0;
	info->perf_event.kprobe.addr = addr;
	info->perf_event.kprobe.cookie = event->bpf_cookie;
	return 0;
}
#endif
@@ -3526,6 +3527,7 @@ static int bpf_perf_link_fill_uprobe(const struct perf_event *event,
	else
		info->perf_event.type = BPF_PERF_EVENT_UPROBE;
	info->perf_event.uprobe.offset = offset;
	info->perf_event.uprobe.cookie = event->bpf_cookie;
	return 0;
}
#endif
@@ -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);
	ulen = info->perf_event.tracepoint.name_len;
	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);
}

@@ -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.config = event->attr.config;
	info->perf_event.event.cookie = event->bpf_cookie;
	info->perf_event.type = BPF_PERF_EVENT_EVENT;
	return 0;
}
+15 −0
Original line number Diff line number Diff line
@@ -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,
						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);
	struct bpf_kprobe_multi_link *kmulti_link;
	u32 ucount = info->kprobe_multi.count;
@@ -2686,6 +2687,8 @@ static int bpf_kprobe_multi_link_fill_link_info(const struct bpf_link *link,

	if (!uaddrs ^ !ucount)
		return -EINVAL;
	if (ucookies && !ucount)
		return -EINVAL;

	kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link);
	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,
	else
		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 (copy_to_user(uaddrs, kmulti_link->addrs, ucount * sizeof(u64)))
			return -EFAULT;
+78 −16
Original line number Diff line number Diff line
@@ -249,18 +249,44 @@ static int get_prog_info(int prog_id, struct bpf_prog_info *info)
	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 struct addr_cookie *a = A, *b = 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)
{
	const __u64 *a = A, *b = B;
	struct addr_cookie *data;
	__u32 i;

	return *a - *b;
	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
show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
{
	struct addr_cookie *data;
	__u32 i, j = 0;
	__u64 *addrs;

	jsonw_bool_field(json_wtr, "retprobe",
			 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)
	jsonw_uint_field(json_wtr, "missed", info->kprobe_multi.missed);
	jsonw_name(json_wtr, "funcs");
	jsonw_start_array(json_wtr);
	addrs = u64_to_ptr(info->kprobe_multi.addrs);
	qsort(addrs, info->kprobe_multi.count, sizeof(addrs[0]), cmp_u64);
	data = get_addr_cookie_array(u64_to_ptr(info->kprobe_multi.addrs),
				     u64_to_ptr(info->kprobe_multi.cookies),
				     info->kprobe_multi.count);
	if (!data)
		return;

	/* Load it once for all. */
	if (!dd.sym_count)
		kernel_syms_load(&dd);
	if (!dd.sym_count)
		goto error;

	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;
		jsonw_start_object(json_wtr);
		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)
		} else {
			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);
		if (j++ == info->kprobe_multi.count)
			break;
	}
	jsonw_end_array(json_wtr);
error:
	free(data);
}

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)
			   u64_to_ptr(info->perf_event.kprobe.func_name));
	jsonw_uint_field(wtr, "offset", info->perf_event.kprobe.offset);
	jsonw_uint_field(wtr, "missed", info->perf_event.kprobe.missed);
	jsonw_uint_field(wtr, "cookie", info->perf_event.kprobe.cookie);
}

static void
@@ -343,6 +379,7 @@ show_perf_event_uprobe_json(struct bpf_link_info *info, json_writer_t *wtr)
	jsonw_string_field(wtr, "file",
			   u64_to_ptr(info->perf_event.uprobe.file_name));
	jsonw_uint_field(wtr, "offset", info->perf_event.uprobe.offset);
	jsonw_uint_field(wtr, "cookie", info->perf_event.uprobe.cookie);
}

static void
@@ -350,6 +387,7 @@ show_perf_event_tracepoint_json(struct bpf_link_info *info, json_writer_t *wtr)
{
	jsonw_string_field(wtr, "tracepoint",
			   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)
@@ -426,6 +464,8 @@ show_perf_event_event_json(struct bpf_link_info *info, json_writer_t *wtr)
	else
		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)
		free((void *)perf_config);
}
@@ -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)
{
	struct addr_cookie *data;
	__u32 i, j = 0;
	__u64 *addrs;

	if (!info->kprobe_multi.count)
		return;
@@ -683,21 +723,24 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info)
	printf("func_cnt %u  ", info->kprobe_multi.count);
	if (info->kprobe_multi.missed)
		printf("missed %llu  ", info->kprobe_multi.missed);
	addrs = (__u64 *)u64_to_ptr(info->kprobe_multi.addrs);
	qsort(addrs, info->kprobe_multi.count, sizeof(__u64), cmp_u64);
	data = get_addr_cookie_array(u64_to_ptr(info->kprobe_multi.addrs),
				     u64_to_ptr(info->kprobe_multi.cookies),
				     info->kprobe_multi.count);
	if (!data)
		return;

	/* Load it once for all. */
	if (!dd.sym_count)
		kernel_syms_load(&dd);
	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++) {
		if (dd.sym_mapping[i].address != addrs[j])
		if (dd.sym_mapping[i].address != data[j].addr)
			continue;
		printf("\n\t%016lx %s",
		       dd.sym_mapping[i].address, dd.sym_mapping[i].name);
		printf("\n\t%016lx %-16llx %s",
		       dd.sym_mapping[i].address, data[j].cookie, dd.sym_mapping[i].name);
		if (dd.sym_mapping[i].module[0] != '\0')
			printf(" [%s]  ", dd.sym_mapping[i].module);
		else
@@ -706,6 +749,8 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info)
		if (j++ == info->kprobe_multi.count)
			break;
	}
error:
	free(data);
}

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)
		printf("+%#x", info->perf_event.kprobe.offset);
	if (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("  ");
}

@@ -770,6 +817,8 @@ static void show_perf_event_uprobe_plain(struct bpf_link_info *info)
	else
		printf("\n\tuprobe ");
	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)
@@ -781,6 +830,8 @@ static void show_perf_event_tracepoint_plain(struct bpf_link_info *info)
		return;

	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)
@@ -802,6 +853,9 @@ static void show_perf_event_event_plain(struct bpf_link_info *info)
	else
		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)
		free((void *)perf_config);
}
@@ -952,6 +1006,14 @@ static int do_show_link(int fd)
				return -ENOMEM;
			}
			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;
		}
	}
@@ -977,7 +1039,7 @@ static int do_show_link(int fd)
			cookies = calloc(count, sizeof(__u64));
			if (!cookies) {
				p_err("mem alloc failed");
				free(cookies);
				free(ref_ctr_offsets);
				free(offsets);
				close(fd);
				return -ENOMEM;
+7 −0
Original line number Diff line number Diff line
@@ -6563,6 +6563,7 @@ struct bpf_link_info {
			__u32 count; /* in/out: kprobe_multi function count */
			__u32 flags;
			__u64 missed;
			__aligned_u64 cookies;
		} kprobe_multi;
		struct {
			__aligned_u64 path;
@@ -6582,6 +6583,7 @@ struct bpf_link_info {
					__aligned_u64 file_name; /* in/out */
					__u32 name_len;
					__u32 offset; /* offset from file_name */
					__u64 cookie;
				} uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */
				struct {
					__aligned_u64 func_name; /* in/out */
@@ -6589,14 +6591,19 @@ struct bpf_link_info {
					__u32 offset; /* offset from func_name */
					__u64 addr;
					__u64 missed;
					__u64 cookie;
				} kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */
				struct {
					__aligned_u64 tp_name;   /* in/out */
					__u32 name_len;
					__u32 :32;
					__u64 cookie;
				} tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */
				struct {
					__u64 config;
					__u32 type;
					__u32 :32;
					__u64 cookie;
				} event; /* BPF_PERF_EVENT_EVENT */
			};
		} perf_event;
Loading