bpftool: Add tracing_multi link info output

Adding bpftool support to show tracing_multi link details,
the new output looks like:

  # bpftool link
  ...
  61: tracing_multi  prog 167
          attach_type trace_fentry_multi  btf_obj_id 1  count 3
          btf_id           addr             cookie           func [module]
          92598            ffffffff825017c4 10               bpf_fentry_test1
          92600            ffffffff82503814 30               bpf_fentry_test2
          92601            ffffffff82503824 20               bpf_fentry_test3
          pids test_progs(1540)

Assisted-by: Codex:GPT-5

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260629212208.895962-4-jolsa@kernel.org
This commit is contained in:
Jiri Olsa
2026-06-29 23:22:08 +02:00
committed by Andrii Nakryiko
parent d36e4dd547
commit 37c1e353c9

View File

@@ -377,6 +377,25 @@ static __u64 *u64_to_arr(__u64 val)
return (__u64 *) u64_to_ptr(val);
}
static __u32 *u64_to_u32_arr(__u64 val)
{
return (__u32 *)u64_to_ptr(val);
}
static struct kernel_sym *find_kernel_sym_by_addr(__u64 addr, bool is_ibt_enabled)
{
struct kernel_sym *sym;
if (!addr)
return NULL;
sym = kernel_syms_search(&dd, addr);
if (!sym && is_ibt_enabled && addr >= 4)
sym = kernel_syms_search(&dd, addr - 4);
return sym;
}
static void
show_uprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
{
@@ -403,6 +422,52 @@ show_uprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
jsonw_end_array(json_wtr);
}
static void
show_tracing_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
{
bool is_ibt_enabled = is_x86_ibt_enabled(), show_symbol;
__u64 *addrs, *cookies;
__u32 i, *ids;
if (!dd.sym_count)
kernel_syms_load(&dd);
show_symbol = !!dd.sym_count;
show_link_attach_type_json(info->tracing_multi.attach_type, wtr);
jsonw_uint_field(wtr, "func_cnt", info->tracing_multi.count);
jsonw_uint_field(wtr, "btf_obj_id", info->tracing_multi.btf_obj_id);
jsonw_name(wtr, "funcs");
jsonw_start_array(wtr);
ids = u64_to_u32_arr(info->tracing_multi.ids);
addrs = u64_to_arr(info->tracing_multi.addrs);
cookies = u64_to_arr(info->tracing_multi.cookies);
for (i = 0; i < info->tracing_multi.count; i++) {
struct kernel_sym *sym;
__u64 addr = addrs[i];
sym = show_symbol ? find_kernel_sym_by_addr(addr, is_ibt_enabled) : NULL;
jsonw_start_object(wtr);
jsonw_uint_field(wtr, "id", ids[i]);
jsonw_uint_field(wtr, "addr", addr);
if (sym) {
jsonw_string_field(wtr, "func", sym->name);
if (sym->module[0] == '\0') {
jsonw_name(wtr, "module");
jsonw_null(wtr);
} else {
jsonw_string_field(wtr, "module", sym->module);
}
}
jsonw_uint_field(wtr, "cookie", cookies[i]);
jsonw_end_object(wtr);
}
jsonw_end_array(wtr);
}
static void
show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr)
{
@@ -589,6 +654,9 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
case BPF_LINK_TYPE_UPROBE_MULTI:
show_uprobe_multi_json(info, json_wtr);
break;
case BPF_LINK_TYPE_TRACING_MULTI:
show_tracing_multi_json(info, json_wtr);
break;
case BPF_LINK_TYPE_PERF_EVENT:
switch (info->perf_event.type) {
case BPF_PERF_EVENT_EVENT:
@@ -833,6 +901,46 @@ static void show_uprobe_multi_plain(struct bpf_link_info *info)
}
}
static void show_tracing_multi_plain(struct bpf_link_info *info)
{
bool is_ibt_enabled = is_x86_ibt_enabled(), show_symbol;
__u64 *addrs, *cookies;
__u32 i, *ids;
if (!info->tracing_multi.count)
return;
if (!dd.sym_count)
kernel_syms_load(&dd);
show_symbol = !!dd.sym_count;
printf("\n\t");
show_link_attach_type_plain(info->tracing_multi.attach_type);
printf("btf_obj_id %u ", info->tracing_multi.btf_obj_id);
printf("count %u ", info->tracing_multi.count);
printf("\n\t%-16s %-16s %-16s %s",
"btf_id", "addr", "cookie", "func [module]");
ids = u64_to_u32_arr(info->tracing_multi.ids);
addrs = u64_to_arr(info->tracing_multi.addrs);
cookies = u64_to_arr(info->tracing_multi.cookies);
for (i = 0; i < info->tracing_multi.count; i++) {
__u64 addr = addrs[i];
struct kernel_sym *sym;
sym = show_symbol ? find_kernel_sym_by_addr(addr, is_ibt_enabled) : NULL;
printf("\n\t%-16u %016llx %-16llu", ids[i], addr, cookies[i]);
if (sym) {
printf(" %s", sym->name);
if (sym->module[0] != '\0')
printf(" [%s]", sym->module);
}
}
}
static void show_perf_event_kprobe_plain(struct bpf_link_info *info)
{
const char *buf;
@@ -989,6 +1097,9 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
case BPF_LINK_TYPE_UPROBE_MULTI:
show_uprobe_multi_plain(info);
break;
case BPF_LINK_TYPE_TRACING_MULTI:
show_tracing_multi_plain(info);
break;
case BPF_LINK_TYPE_PERF_EVENT:
switch (info->perf_event.type) {
case BPF_PERF_EVENT_EVENT:
@@ -1029,6 +1140,7 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
static int do_show_link(int fd)
{
__u64 *ref_ctr_offsets = NULL, *offsets = NULL, *cookies = NULL;
__u32 *ids = NULL;
struct bpf_link_info info;
__u32 len = sizeof(info);
char path_buf[PATH_MAX];
@@ -1114,6 +1226,26 @@ static int do_show_link(int fd)
goto again;
}
}
if (info.type == BPF_LINK_TYPE_TRACING_MULTI && !info.tracing_multi.ids) {
count = info.tracing_multi.count;
if (count) {
ids = calloc(count, sizeof(__u32));
addrs = calloc(count, sizeof(__u64));
cookies = calloc(count, sizeof(__u64));
if (!ids || !addrs || !cookies) {
p_err("mem alloc failed");
close(fd);
free(cookies);
free(addrs);
free(ids);
return -ENOMEM;
}
info.tracing_multi.ids = ptr_to_u64(ids);
info.tracing_multi.addrs = ptr_to_u64(addrs);
info.tracing_multi.cookies = ptr_to_u64(cookies);
goto again;
}
}
if (info.type == BPF_LINK_TYPE_PERF_EVENT) {
switch (info.perf_event.type) {
case BPF_PERF_EVENT_TRACEPOINT:
@@ -1153,6 +1285,7 @@ static int do_show_link(int fd)
free(cookies);
free(offsets);
free(addrs);
free(ids);
close(fd);
return 0;
}