Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Add support to display uprobe_multi links

Adding support to display details for uprobe_multi links,
both plain:

# bpftool link -p
...
24: uprobe_multi prog 126
uprobe.multi path /home/jolsa/bpf/test_progs func_cnt 3 pid 4143
offset ref_ctr_offset cookies
0xd1f88 0xf5d5a8 0xdead
0xd1f8f 0xf5d5aa 0xbeef
0xd1f96 0xf5d5ac 0xcafe

and json:

# bpftool link -p
[{
...
},{
"id": 24,
"type": "uprobe_multi",
"prog_id": 126,
"retprobe": false,
"path": "/home/jolsa/bpf/test_progs",
"func_cnt": 3,
"pid": 4143,
"funcs": [{
"offset": 860040,
"ref_ctr_offset": 16111016,
"cookie": 57005
},{
"offset": 860047,
"ref_ctr_offset": 16111018,
"cookie": 48879
},{
"offset": 860054,
"ref_ctr_offset": 16111020,
"cookie": 51966
}
]
}
]

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Acked-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/bpf/20231125193130.834322-7-jolsa@kernel.org

authored by

Jiri Olsa and committed by
Andrii Nakryiko
a7795698 147c6930

+103 -2
+103 -2
tools/bpf/bpftool/link.c
··· 294 294 jsonw_end_array(json_wtr); 295 295 } 296 296 297 + static __u64 *u64_to_arr(__u64 val) 298 + { 299 + return (__u64 *) u64_to_ptr(val); 300 + } 301 + 302 + static void 303 + show_uprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) 304 + { 305 + __u32 i; 306 + 307 + jsonw_bool_field(json_wtr, "retprobe", 308 + info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN); 309 + jsonw_string_field(json_wtr, "path", (char *) u64_to_ptr(info->uprobe_multi.path)); 310 + jsonw_uint_field(json_wtr, "func_cnt", info->uprobe_multi.count); 311 + jsonw_int_field(json_wtr, "pid", (int) info->uprobe_multi.pid); 312 + jsonw_name(json_wtr, "funcs"); 313 + jsonw_start_array(json_wtr); 314 + 315 + for (i = 0; i < info->uprobe_multi.count; i++) { 316 + jsonw_start_object(json_wtr); 317 + jsonw_uint_field(json_wtr, "offset", 318 + u64_to_arr(info->uprobe_multi.offsets)[i]); 319 + jsonw_uint_field(json_wtr, "ref_ctr_offset", 320 + u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i]); 321 + jsonw_uint_field(json_wtr, "cookie", 322 + u64_to_arr(info->uprobe_multi.cookies)[i]); 323 + jsonw_end_object(json_wtr); 324 + } 325 + jsonw_end_array(json_wtr); 326 + } 327 + 297 328 static void 298 329 show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr) 299 330 { ··· 495 464 break; 496 465 case BPF_LINK_TYPE_KPROBE_MULTI: 497 466 show_kprobe_multi_json(info, json_wtr); 467 + break; 468 + case BPF_LINK_TYPE_UPROBE_MULTI: 469 + show_uprobe_multi_json(info, json_wtr); 498 470 break; 499 471 case BPF_LINK_TYPE_PERF_EVENT: 500 472 switch (info->perf_event.type) { ··· 708 674 } 709 675 } 710 676 677 + static void show_uprobe_multi_plain(struct bpf_link_info *info) 678 + { 679 + __u32 i; 680 + 681 + if (!info->uprobe_multi.count) 682 + return; 683 + 684 + if (info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN) 685 + printf("\n\turetprobe.multi "); 686 + else 687 + printf("\n\tuprobe.multi "); 688 + 689 + printf("path %s ", (char *) u64_to_ptr(info->uprobe_multi.path)); 690 + printf("func_cnt %u ", info->uprobe_multi.count); 691 + 692 + if (info->uprobe_multi.pid) 693 + printf("pid %d ", info->uprobe_multi.pid); 694 + 695 + printf("\n\t%-16s %-16s %-16s", "offset", "ref_ctr_offset", "cookies"); 696 + for (i = 0; i < info->uprobe_multi.count; i++) { 697 + printf("\n\t0x%-16llx 0x%-16llx 0x%-16llx", 698 + u64_to_arr(info->uprobe_multi.offsets)[i], 699 + u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i], 700 + u64_to_arr(info->uprobe_multi.cookies)[i]); 701 + } 702 + } 703 + 711 704 static void show_perf_event_kprobe_plain(struct bpf_link_info *info) 712 705 { 713 706 const char *buf; ··· 868 807 case BPF_LINK_TYPE_KPROBE_MULTI: 869 808 show_kprobe_multi_plain(info); 870 809 break; 810 + case BPF_LINK_TYPE_UPROBE_MULTI: 811 + show_uprobe_multi_plain(info); 812 + break; 871 813 case BPF_LINK_TYPE_PERF_EVENT: 872 814 switch (info->perf_event.type) { 873 815 case BPF_PERF_EVENT_EVENT: ··· 910 846 911 847 static int do_show_link(int fd) 912 848 { 849 + __u64 *ref_ctr_offsets = NULL, *offsets = NULL, *cookies = NULL; 913 850 struct bpf_link_info info; 914 851 __u32 len = sizeof(info); 852 + char path_buf[PATH_MAX]; 915 853 __u64 *addrs = NULL; 916 854 char buf[PATH_MAX]; 917 855 int count; ··· 955 889 goto again; 956 890 } 957 891 } 892 + if (info.type == BPF_LINK_TYPE_UPROBE_MULTI && 893 + !info.uprobe_multi.offsets) { 894 + count = info.uprobe_multi.count; 895 + if (count) { 896 + offsets = calloc(count, sizeof(__u64)); 897 + if (!offsets) { 898 + p_err("mem alloc failed"); 899 + close(fd); 900 + return -ENOMEM; 901 + } 902 + info.uprobe_multi.offsets = ptr_to_u64(offsets); 903 + ref_ctr_offsets = calloc(count, sizeof(__u64)); 904 + if (!ref_ctr_offsets) { 905 + p_err("mem alloc failed"); 906 + free(offsets); 907 + close(fd); 908 + return -ENOMEM; 909 + } 910 + info.uprobe_multi.ref_ctr_offsets = ptr_to_u64(ref_ctr_offsets); 911 + cookies = calloc(count, sizeof(__u64)); 912 + if (!cookies) { 913 + p_err("mem alloc failed"); 914 + free(cookies); 915 + free(offsets); 916 + close(fd); 917 + return -ENOMEM; 918 + } 919 + info.uprobe_multi.cookies = ptr_to_u64(cookies); 920 + info.uprobe_multi.path = ptr_to_u64(path_buf); 921 + info.uprobe_multi.path_size = sizeof(path_buf); 922 + goto again; 923 + } 924 + } 958 925 if (info.type == BPF_LINK_TYPE_PERF_EVENT) { 959 926 switch (info.perf_event.type) { 960 927 case BPF_PERF_EVENT_TRACEPOINT: ··· 1023 924 else 1024 925 show_link_close_plain(fd, &info); 1025 926 1026 - if (addrs) 1027 - free(addrs); 927 + free(ref_ctr_offsets); 928 + free(cookies); 929 + free(offsets); 930 + free(addrs); 1028 931 close(fd); 1029 932 return 0; 1030 933 }