BPF List
 help / color / mirror / Atom feed
From: Jiri Olsa <olsajiri@gmail.com>
To: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	bpf@vger.kernel.org, Martin KaFai Lau <martin.lau@linux.dev>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Song Liu <songliubraving@fb.com>, Yonghong Song <yhs@fb.com>,
	Quentin Monnet <qmo@kernel.org>
Subject: Re: [PATCHv2 bpf-next 3/3] bpftool: Add tracing_multi link info output
Date: Wed, 24 Jun 2026 13:32:01 +0200	[thread overview]
Message-ID: <ajvAMSeIxsHGBXOw@krava> (raw)
In-Reply-To: <CAEf4BzaCnTNo5dmYGRVWGWn+tUCP279Owbg54MuVqQrZTx=rQQ@mail.gmail.com>

On Tue, Jun 23, 2026 at 02:11:34PM -0700, Andrii Nakryiko wrote:
> On Tue, Jun 23, 2026 at 7:24 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Adding bpftool support to show tracing_multi link details,
> > the new output looks like:
> >
> >   # bpftool link
> >   ...
> >   27: tracing_multi  prog 93
> >           attach_type trace_fentry_multi  obj_id 1  count 3
> >           btf_id           addr             cookie           func [module]
> >           91984            ffffffff824f4a24 a                bpf_fentry_test1
> >           91986            ffffffff824f6a84 1e               bpf_fentry_test2
> >           91987            ffffffff824f6a94 14               bpf_fentry_test3
> >           pids test_progs(1462)
> >
> > Assisted-by: Codex:GPT-5
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  tools/bpf/bpftool/link.c | 137 +++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 137 insertions(+)
> >
> > diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
> > index bdcd717b0348..db780ee39820 100644
> > --- a/tools/bpf/bpftool/link.c
> > +++ b/tools/bpf/bpftool/link.c
> > @@ -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);
> 
> if is_ibt_enabled, can we match addr with kernel_syms_search at all?
> I.e., can addr sometimes be resolvable without - 4 adjustment? If not,
> why is this not if/else and instead "try this, if not, try that"?

I followed the symbol_matches_target logic and assumed we could have functions
with and without endbr instruction at the entry.. but I can't find any example
of such traceable function

> 
> > +
> > +       return sym;
> > +}
> > +
> >  static void
> >  show_uprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr)
> >  {
> > @@ -403,6 +422,47 @@ 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;
> > +       __u32 i;
> > +
> > +       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, "obj_id", info->tracing_multi.obj_id);
> > +       jsonw_name(wtr, "funcs");
> > +
> > +       jsonw_start_array(wtr);
> > +
> > +       for (i = 0; i < info->tracing_multi.count; i++) {
> > +               __u64 addr = u64_to_arr(info->tracing_multi.addrs)[i];
> > +               struct kernel_sym *sym;
> > +
> > +               sym = show_symbol ? find_kernel_sym_by_addr(addr, is_ibt_enabled) : NULL;
> > +
> > +               jsonw_start_object(wtr);
> > +               jsonw_uint_field(wtr, "id", u64_to_u32_arr(info->tracing_multi.ids)[i]);
> 
> nit, here and for cookies, do the cast outside of the loop into local
> variable? seems cleaner as an approach

ok

> 
> > +               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);
> 
> just curious, is it cleaner to have "module: null" instead of just not
> emitting "module:" field at all?

I followed what we do for kprobe_multi, not sure what's preffered,
but I think it's better to be consistent.. at least somewhere ;-)

> 
> > +                       } else {
> > +                               jsonw_string_field(wtr, "module", sym->module);
> > +                       }
> > +               }
> > +               jsonw_uint_field(wtr, "cookie", u64_to_arr(info->tracing_multi.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 +649,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 +896,42 @@ 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;
> > +       __u32 i;
> > +
> > +       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("obj_id %u  ", info->tracing_multi.obj_id);
> > +       printf("count %u  ", info->tracing_multi.count);
> > +
> > +       printf("\n\t%-16s %-16s %-16s %s",
> > +              "btf_id", "addr", "cookie", "func [module]");
> > +       for (i = 0; i < info->tracing_multi.count; i++) {
> > +               __u64 addr = u64_to_arr(info->tracing_multi.addrs)[i];
> > +               struct kernel_sym *sym;
> > +
> > +               sym = show_symbol ? find_kernel_sym_by_addr(addr, is_ibt_enabled) : NULL;
> > +
> > +               printf("\n\t%-16u %016llx %-16llx",
> > +                      u64_to_u32_arr(info->tracing_multi.ids)[i],
> > +                      addr, u64_to_arr(info->tracing_multi.cookies)[i]);
> 
> As I mentioned, it surprised me that we emit cookie as hex. Kernel
> doesn't in fdinfo output. And at least in my experience cookie is some
> small compact index into some additional lookup array, so decimal
> makes most sense. I see now that we have hex for uprobe_multi, but
> decimal for perf link, so ugh, goodbye consistency. But still, decimal
> will be much more useful in practice, IMO.

agreed

> 
> > +               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 +1088,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 +1131,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 +1217,39 @@ static int do_show_link(int fd)
> >                         goto again;
> >                 }
> >         }
> > +       if (info.type == BPF_LINK_TYPE_TRACING_MULTI &&
> > +           !info.tracing_multi.ids) {
> 
> why wrap?

I followed the previous code style

> 
> > +               count = info.tracing_multi.count;
> > +               if (count) {
> > +                       ids = calloc(count, sizeof(__u32));
> > +                       if (!ids) {
> > +                               p_err("mem alloc failed");
> > +                               close(fd);
> > +                               return -ENOMEM;
> > +                       }
> > +                       info.tracing_multi.ids = ptr_to_u64(ids);
> > +
> > +                       addrs = calloc(count, sizeof(__u64));
> > +                       if (!addrs) {
> > +                               p_err("mem alloc failed");
> > +                               free(ids);
> > +                               close(fd);
> > +                               return -ENOMEM;
> > +                       }
> > +                       info.tracing_multi.addrs = ptr_to_u64(addrs);
> > +
> > +                       cookies = calloc(count, sizeof(__u64));
> > +                       if (!cookies) {
> > +                               p_err("mem alloc failed");
> > +                               free(addrs);
> > +                               free(ids);
> > +                               close(fd);
> > +                               return -ENOMEM;
> > +                       }
> 
> ugh... do three calloc()s in a row, check that all succeeded, if not -
> free and close(fd)? shorter and just as good

ah right.. I guess I followed the previous kprobe/uprobe code style,
but as you said, we can simplify the error path, will change

thanks,
jirka

  reply	other threads:[~2026-06-24 11:32 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-23 14:24 [PATCHv2 bpf-next 0/3] bpf: tracing_multi link info support Jiri Olsa
2026-06-23 14:24 ` [PATCHv2 bpf-next 1/3] bpf: Add " Jiri Olsa
2026-06-23 15:32   ` Leon Hwang
2026-06-23 21:01   ` Andrii Nakryiko
2026-06-24  9:36     ` Jiri Olsa
2026-06-23 14:24 ` [PATCHv2 bpf-next 2/3] selftests/bpf: Add tracing_multi link info tests Jiri Olsa
2026-06-23 14:39   ` sashiko-bot
2026-06-23 14:24 ` [PATCHv2 bpf-next 3/3] bpftool: Add tracing_multi link info output Jiri Olsa
2026-06-23 14:38   ` sashiko-bot
2026-06-23 21:11   ` Andrii Nakryiko
2026-06-24 11:32     ` Jiri Olsa [this message]
2026-06-23 20:51 ` [PATCHv2 bpf-next 0/3] bpf: tracing_multi link info support Andrii Nakryiko
2026-06-24  9:29   ` Jiri Olsa

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ajvAMSeIxsHGBXOw@krava \
    --to=olsajiri@gmail.com \
    --cc=andrii.nakryiko@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=martin.lau@linux.dev \
    --cc=qmo@kernel.org \
    --cc=songliubraving@fb.com \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox