bpftool: Display cookie for kprobe multi link
authorJiri Olsa <jolsa@kernel.org>
Fri, 19 Jan 2024 11:05:05 +0000 (12:05 +0100)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 24 Jan 2024 00:05:28 +0000 (16:05 -0800)
Displaying cookies for kprobe multi link, in plain mode:

  # bpftool link
  ...
  1397: kprobe_multi  prog 47532
          kretprobe.multi  func_cnt 3
          addr             cookie           func [module]
          ffffffff82b370c0 3                bpf_fentry_test1
          ffffffff82b39780 1                bpf_fentry_test2
          ffffffff82b397a0 2                bpf_fentry_test3

And in json mode:

  # bpftool link -j | jq
  ...
    {
      "id": 1397,
      "type": "kprobe_multi",
      "prog_id": 47532,
      "retprobe": true,
      "func_cnt": 3,
      "missed": 0,
      "funcs": [
        {
          "addr": 18446744071607382208,
          "func": "bpf_fentry_test1",
          "module": null,
          "cookie": 3
        },
        {
          "addr": 18446744071607392128,
          "func": "bpf_fentry_test2",
          "module": null,
          "cookie": 1
        },
        {
          "addr": 18446744071607392160,
          "func": "bpf_fentry_test3",
          "module": null,
          "cookie": 2
        }
      ]
    }

Cookie is attached to specific address, and because we sort addresses
before printing, we need to sort cookies the same way, hence adding
the struct addr_cookie to keep and sort them together.

Also adding missing dd.sym_count check to show_kprobe_multi_json.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20240119110505.400573-9-jolsa@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/bpf/bpftool/link.c

index b66a1598b87c4c76ed83c9c69b3cb1c93b664a49..afde9d0c2ea1912f65ceea07ee92dbaef587e38a 100644 (file)
@@ -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)
@@ -675,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;
@@ -688,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
@@ -711,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)
@@ -966,6 +1006,14 @@ again:
                                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;
                }
        }