1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (C) 2020 Facebook */ 3 4 #include <errno.h> 5 #include <linux/err.h> 6 #include <linux/netfilter.h> 7 #include <linux/netfilter_arp.h> 8 #include <linux/perf_event.h> 9 #include <net/if.h> 10 #include <stdio.h> 11 #include <unistd.h> 12 13 #include <bpf/bpf.h> 14 #include <bpf/hashmap.h> 15 16 #include "json_writer.h" 17 #include "main.h" 18 #include "xlated_dumper.h" 19 20 #define PERF_HW_CACHE_LEN 128 21 22 static struct hashmap *link_table; 23 static struct dump_data dd; 24 25 static const char *perf_type_name[PERF_TYPE_MAX] = { 26 [PERF_TYPE_HARDWARE] = "hardware", 27 [PERF_TYPE_SOFTWARE] = "software", 28 [PERF_TYPE_TRACEPOINT] = "tracepoint", 29 [PERF_TYPE_HW_CACHE] = "hw-cache", 30 [PERF_TYPE_RAW] = "raw", 31 [PERF_TYPE_BREAKPOINT] = "breakpoint", 32 }; 33 34 const char *event_symbols_hw[PERF_COUNT_HW_MAX] = { 35 [PERF_COUNT_HW_CPU_CYCLES] = "cpu-cycles", 36 [PERF_COUNT_HW_INSTRUCTIONS] = "instructions", 37 [PERF_COUNT_HW_CACHE_REFERENCES] = "cache-references", 38 [PERF_COUNT_HW_CACHE_MISSES] = "cache-misses", 39 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "branch-instructions", 40 [PERF_COUNT_HW_BRANCH_MISSES] = "branch-misses", 41 [PERF_COUNT_HW_BUS_CYCLES] = "bus-cycles", 42 [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = "stalled-cycles-frontend", 43 [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = "stalled-cycles-backend", 44 [PERF_COUNT_HW_REF_CPU_CYCLES] = "ref-cycles", 45 }; 46 47 const char *event_symbols_sw[PERF_COUNT_SW_MAX] = { 48 [PERF_COUNT_SW_CPU_CLOCK] = "cpu-clock", 49 [PERF_COUNT_SW_TASK_CLOCK] = "task-clock", 50 [PERF_COUNT_SW_PAGE_FAULTS] = "page-faults", 51 [PERF_COUNT_SW_CONTEXT_SWITCHES] = "context-switches", 52 [PERF_COUNT_SW_CPU_MIGRATIONS] = "cpu-migrations", 53 [PERF_COUNT_SW_PAGE_FAULTS_MIN] = "minor-faults", 54 [PERF_COUNT_SW_PAGE_FAULTS_MAJ] = "major-faults", 55 [PERF_COUNT_SW_ALIGNMENT_FAULTS] = "alignment-faults", 56 [PERF_COUNT_SW_EMULATION_FAULTS] = "emulation-faults", 57 [PERF_COUNT_SW_DUMMY] = "dummy", 58 [PERF_COUNT_SW_BPF_OUTPUT] = "bpf-output", 59 [PERF_COUNT_SW_CGROUP_SWITCHES] = "cgroup-switches", 60 }; 61 62 const char *evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] = { 63 [PERF_COUNT_HW_CACHE_L1D] = "L1-dcache", 64 [PERF_COUNT_HW_CACHE_L1I] = "L1-icache", 65 [PERF_COUNT_HW_CACHE_LL] = "LLC", 66 [PERF_COUNT_HW_CACHE_DTLB] = "dTLB", 67 [PERF_COUNT_HW_CACHE_ITLB] = "iTLB", 68 [PERF_COUNT_HW_CACHE_BPU] = "branch", 69 [PERF_COUNT_HW_CACHE_NODE] = "node", 70 }; 71 72 const char *evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] = { 73 [PERF_COUNT_HW_CACHE_OP_READ] = "load", 74 [PERF_COUNT_HW_CACHE_OP_WRITE] = "store", 75 [PERF_COUNT_HW_CACHE_OP_PREFETCH] = "prefetch", 76 }; 77 78 const char *evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] = { 79 [PERF_COUNT_HW_CACHE_RESULT_ACCESS] = "refs", 80 [PERF_COUNT_HW_CACHE_RESULT_MISS] = "misses", 81 }; 82 83 #define perf_event_name(array, id) ({ \ 84 const char *event_str = NULL; \ 85 \ 86 if ((id) < ARRAY_SIZE(array)) \ 87 event_str = array[id]; \ 88 event_str; \ 89 }) 90 91 static int link_parse_fd(int *argc, char ***argv) 92 { 93 int fd; 94 95 if (is_prefix(**argv, "id")) { 96 unsigned int id; 97 char *endptr; 98 99 NEXT_ARGP(); 100 101 id = strtoul(**argv, &endptr, 0); 102 if (*endptr) { 103 p_err("can't parse %s as ID", **argv); 104 return -1; 105 } 106 NEXT_ARGP(); 107 108 fd = bpf_link_get_fd_by_id(id); 109 if (fd < 0) 110 p_err("failed to get link with ID %u: %s", id, strerror(errno)); 111 return fd; 112 } else if (is_prefix(**argv, "pinned")) { 113 char *path; 114 115 NEXT_ARGP(); 116 117 path = **argv; 118 NEXT_ARGP(); 119 120 return open_obj_pinned_any(path, BPF_OBJ_LINK, NULL); 121 } 122 123 p_err("expected 'id' or 'pinned', got: '%s'?", **argv); 124 return -1; 125 } 126 127 static void 128 show_link_header_json(struct bpf_link_info *info, json_writer_t *wtr) 129 { 130 const char *link_type_str; 131 132 jsonw_uint_field(wtr, "id", info->id); 133 link_type_str = libbpf_bpf_link_type_str(info->type); 134 if (link_type_str) 135 jsonw_string_field(wtr, "type", link_type_str); 136 else 137 jsonw_uint_field(wtr, "type", info->type); 138 139 jsonw_uint_field(json_wtr, "prog_id", info->prog_id); 140 } 141 142 static void show_link_attach_type_json(__u32 attach_type, json_writer_t *wtr) 143 { 144 const char *attach_type_str; 145 146 attach_type_str = libbpf_bpf_attach_type_str(attach_type); 147 if (attach_type_str) 148 jsonw_string_field(wtr, "attach_type", attach_type_str); 149 else 150 jsonw_uint_field(wtr, "attach_type", attach_type); 151 } 152 153 static void show_link_ifindex_json(__u32 ifindex, json_writer_t *wtr) 154 { 155 char devname[IF_NAMESIZE] = "(unknown)"; 156 157 if (ifindex) 158 if_indextoname(ifindex, devname); 159 else 160 snprintf(devname, sizeof(devname), "(detached)"); 161 jsonw_string_field(wtr, "devname", devname); 162 jsonw_uint_field(wtr, "ifindex", ifindex); 163 } 164 165 static bool is_iter_map_target(const char *target_name) 166 { 167 return strcmp(target_name, "bpf_map_elem") == 0 || 168 strcmp(target_name, "bpf_sk_storage_map") == 0; 169 } 170 171 static bool is_iter_cgroup_target(const char *target_name) 172 { 173 return strcmp(target_name, "cgroup") == 0; 174 } 175 176 static const char *cgroup_order_string(__u32 order) 177 { 178 switch (order) { 179 case BPF_CGROUP_ITER_ORDER_UNSPEC: 180 return "order_unspec"; 181 case BPF_CGROUP_ITER_SELF_ONLY: 182 return "self_only"; 183 case BPF_CGROUP_ITER_DESCENDANTS_PRE: 184 return "descendants_pre"; 185 case BPF_CGROUP_ITER_DESCENDANTS_POST: 186 return "descendants_post"; 187 case BPF_CGROUP_ITER_ANCESTORS_UP: 188 return "ancestors_up"; 189 default: /* won't happen */ 190 return "unknown"; 191 } 192 } 193 194 static bool is_iter_task_target(const char *target_name) 195 { 196 return strcmp(target_name, "task") == 0 || 197 strcmp(target_name, "task_file") == 0 || 198 strcmp(target_name, "task_vma") == 0; 199 } 200 201 static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr) 202 { 203 const char *target_name = u64_to_ptr(info->iter.target_name); 204 205 jsonw_string_field(wtr, "target_name", target_name); 206 207 if (is_iter_map_target(target_name)) 208 jsonw_uint_field(wtr, "map_id", info->iter.map.map_id); 209 else if (is_iter_task_target(target_name)) { 210 if (info->iter.task.tid) 211 jsonw_uint_field(wtr, "tid", info->iter.task.tid); 212 else if (info->iter.task.pid) 213 jsonw_uint_field(wtr, "pid", info->iter.task.pid); 214 } 215 216 if (is_iter_cgroup_target(target_name)) { 217 jsonw_lluint_field(wtr, "cgroup_id", info->iter.cgroup.cgroup_id); 218 jsonw_string_field(wtr, "order", 219 cgroup_order_string(info->iter.cgroup.order)); 220 } 221 } 222 223 void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr) 224 { 225 jsonw_uint_field(json_wtr, "pf", 226 info->netfilter.pf); 227 jsonw_uint_field(json_wtr, "hook", 228 info->netfilter.hooknum); 229 jsonw_int_field(json_wtr, "prio", 230 info->netfilter.priority); 231 jsonw_uint_field(json_wtr, "flags", 232 info->netfilter.flags); 233 } 234 235 static int get_prog_info(int prog_id, struct bpf_prog_info *info) 236 { 237 __u32 len = sizeof(*info); 238 int err, prog_fd; 239 240 prog_fd = bpf_prog_get_fd_by_id(prog_id); 241 if (prog_fd < 0) 242 return prog_fd; 243 244 memset(info, 0, sizeof(*info)); 245 err = bpf_prog_get_info_by_fd(prog_fd, info, &len); 246 if (err) 247 p_err("can't get prog info: %s", strerror(errno)); 248 close(prog_fd); 249 return err; 250 } 251 252 struct addr_cookie { 253 __u64 addr; 254 __u64 cookie; 255 }; 256 257 static int cmp_addr_cookie(const void *A, const void *B) 258 { 259 const struct addr_cookie *a = A, *b = B; 260 261 if (a->addr == b->addr) 262 return 0; 263 return a->addr < b->addr ? -1 : 1; 264 } 265 266 static struct addr_cookie * 267 get_addr_cookie_array(__u64 *addrs, __u64 *cookies, __u32 count) 268 { 269 struct addr_cookie *data; 270 __u32 i; 271 272 data = calloc(count, sizeof(data[0])); 273 if (!data) { 274 p_err("mem alloc failed"); 275 return NULL; 276 } 277 for (i = 0; i < count; i++) { 278 data[i].addr = addrs[i]; 279 data[i].cookie = cookies[i]; 280 } 281 qsort(data, count, sizeof(data[0]), cmp_addr_cookie); 282 return data; 283 } 284 285 static bool is_x86_ibt_enabled(void) 286 { 287 #if defined(__x86_64__) 288 struct kernel_config_option options[] = { 289 { "CONFIG_X86_KERNEL_IBT", }, 290 }; 291 char *values[ARRAY_SIZE(options)] = { }; 292 bool ret; 293 294 if (read_kernel_config(options, ARRAY_SIZE(options), values, NULL)) 295 return false; 296 297 ret = !!values[0]; 298 free(values[0]); 299 return ret; 300 #else 301 return false; 302 #endif 303 } 304 305 static bool 306 symbol_matches_target(__u64 sym_addr, __u64 target_addr, bool is_ibt_enabled) 307 { 308 if (sym_addr == target_addr) 309 return true; 310 311 /* 312 * On x86_64 architectures with CET (Control-flow Enforcement Technology), 313 * function entry points have a 4-byte 'endbr' instruction prefix. 314 * This causes kprobe hooks to target the address *after* 'endbr' 315 * (symbol address + 4), preserving the CET instruction. 316 * Here we check if the symbol address matches the hook target address 317 * minus 4, indicating a CET-enabled function entry point. 318 */ 319 if (is_ibt_enabled && sym_addr == target_addr - 4) 320 return true; 321 322 return false; 323 } 324 325 static void 326 show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) 327 { 328 struct addr_cookie *data; 329 __u32 i, j = 0; 330 bool is_ibt_enabled; 331 332 jsonw_bool_field(json_wtr, "retprobe", 333 info->kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN); 334 jsonw_uint_field(json_wtr, "func_cnt", info->kprobe_multi.count); 335 jsonw_uint_field(json_wtr, "missed", info->kprobe_multi.missed); 336 jsonw_name(json_wtr, "funcs"); 337 jsonw_start_array(json_wtr); 338 data = get_addr_cookie_array(u64_to_ptr(info->kprobe_multi.addrs), 339 u64_to_ptr(info->kprobe_multi.cookies), 340 info->kprobe_multi.count); 341 if (!data) 342 return; 343 344 /* Load it once for all. */ 345 if (!dd.sym_count) 346 kernel_syms_load(&dd); 347 if (!dd.sym_count) 348 goto error; 349 350 is_ibt_enabled = is_x86_ibt_enabled(); 351 for (i = 0; i < dd.sym_count; i++) { 352 if (!symbol_matches_target(dd.sym_mapping[i].address, 353 data[j].addr, is_ibt_enabled)) 354 continue; 355 jsonw_start_object(json_wtr); 356 jsonw_uint_field(json_wtr, "addr", (unsigned long)data[j].addr); 357 jsonw_string_field(json_wtr, "func", dd.sym_mapping[i].name); 358 /* Print null if it is vmlinux */ 359 if (dd.sym_mapping[i].module[0] == '\0') { 360 jsonw_name(json_wtr, "module"); 361 jsonw_null(json_wtr); 362 } else { 363 jsonw_string_field(json_wtr, "module", dd.sym_mapping[i].module); 364 } 365 jsonw_uint_field(json_wtr, "cookie", data[j].cookie); 366 jsonw_end_object(json_wtr); 367 if (j++ == info->kprobe_multi.count) 368 break; 369 } 370 jsonw_end_array(json_wtr); 371 error: 372 free(data); 373 } 374 375 static __u64 *u64_to_arr(__u64 val) 376 { 377 return (__u64 *) u64_to_ptr(val); 378 } 379 380 static __u32 *u64_to_u32_arr(__u64 val) 381 { 382 return (__u32 *)u64_to_ptr(val); 383 } 384 385 static struct kernel_sym *find_kernel_sym_by_addr(__u64 addr, bool is_ibt_enabled) 386 { 387 struct kernel_sym *sym; 388 389 if (!addr) 390 return NULL; 391 392 sym = kernel_syms_search(&dd, addr); 393 if (!sym && is_ibt_enabled && addr >= 4) 394 sym = kernel_syms_search(&dd, addr - 4); 395 396 return sym; 397 } 398 399 static void 400 show_uprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) 401 { 402 __u32 i; 403 404 jsonw_bool_field(json_wtr, "retprobe", 405 info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN); 406 jsonw_string_field(json_wtr, "path", (char *) u64_to_ptr(info->uprobe_multi.path)); 407 jsonw_uint_field(json_wtr, "func_cnt", info->uprobe_multi.count); 408 jsonw_int_field(json_wtr, "pid", (int) info->uprobe_multi.pid); 409 jsonw_name(json_wtr, "funcs"); 410 jsonw_start_array(json_wtr); 411 412 for (i = 0; i < info->uprobe_multi.count; i++) { 413 jsonw_start_object(json_wtr); 414 jsonw_uint_field(json_wtr, "offset", 415 u64_to_arr(info->uprobe_multi.offsets)[i]); 416 jsonw_uint_field(json_wtr, "ref_ctr_offset", 417 u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i]); 418 jsonw_uint_field(json_wtr, "cookie", 419 u64_to_arr(info->uprobe_multi.cookies)[i]); 420 jsonw_end_object(json_wtr); 421 } 422 jsonw_end_array(json_wtr); 423 } 424 425 static void 426 show_tracing_multi_json(struct bpf_link_info *info, json_writer_t *wtr) 427 { 428 bool is_ibt_enabled = is_x86_ibt_enabled(), show_symbol; 429 __u64 *addrs, *cookies; 430 __u32 i, *ids; 431 432 if (!dd.sym_count) 433 kernel_syms_load(&dd); 434 show_symbol = !!dd.sym_count; 435 436 show_link_attach_type_json(info->tracing_multi.attach_type, wtr); 437 jsonw_uint_field(wtr, "func_cnt", info->tracing_multi.count); 438 jsonw_uint_field(wtr, "btf_obj_id", info->tracing_multi.btf_obj_id); 439 jsonw_name(wtr, "funcs"); 440 441 jsonw_start_array(wtr); 442 443 ids = u64_to_u32_arr(info->tracing_multi.ids); 444 addrs = u64_to_arr(info->tracing_multi.addrs); 445 cookies = u64_to_arr(info->tracing_multi.cookies); 446 447 for (i = 0; i < info->tracing_multi.count; i++) { 448 struct kernel_sym *sym; 449 __u64 addr = addrs[i]; 450 451 sym = show_symbol ? find_kernel_sym_by_addr(addr, is_ibt_enabled) : NULL; 452 453 jsonw_start_object(wtr); 454 jsonw_uint_field(wtr, "id", ids[i]); 455 jsonw_uint_field(wtr, "addr", addr); 456 if (sym) { 457 jsonw_string_field(wtr, "func", sym->name); 458 if (sym->module[0] == '\0') { 459 jsonw_name(wtr, "module"); 460 jsonw_null(wtr); 461 } else { 462 jsonw_string_field(wtr, "module", sym->module); 463 } 464 } 465 jsonw_uint_field(wtr, "cookie", cookies[i]); 466 jsonw_end_object(wtr); 467 } 468 jsonw_end_array(wtr); 469 } 470 471 static void 472 show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr) 473 { 474 jsonw_bool_field(wtr, "retprobe", info->perf_event.type == BPF_PERF_EVENT_KRETPROBE); 475 jsonw_uint_field(wtr, "addr", info->perf_event.kprobe.addr); 476 jsonw_string_field(wtr, "func", 477 u64_to_ptr(info->perf_event.kprobe.func_name)); 478 jsonw_uint_field(wtr, "offset", info->perf_event.kprobe.offset); 479 jsonw_uint_field(wtr, "missed", info->perf_event.kprobe.missed); 480 jsonw_uint_field(wtr, "cookie", info->perf_event.kprobe.cookie); 481 } 482 483 static void 484 show_perf_event_uprobe_json(struct bpf_link_info *info, json_writer_t *wtr) 485 { 486 jsonw_bool_field(wtr, "retprobe", info->perf_event.type == BPF_PERF_EVENT_URETPROBE); 487 jsonw_string_field(wtr, "file", 488 u64_to_ptr(info->perf_event.uprobe.file_name)); 489 jsonw_uint_field(wtr, "offset", info->perf_event.uprobe.offset); 490 jsonw_uint_field(wtr, "cookie", info->perf_event.uprobe.cookie); 491 jsonw_uint_field(wtr, "ref_ctr_offset", info->perf_event.uprobe.ref_ctr_offset); 492 } 493 494 static void 495 show_perf_event_tracepoint_json(struct bpf_link_info *info, json_writer_t *wtr) 496 { 497 jsonw_string_field(wtr, "tracepoint", 498 u64_to_ptr(info->perf_event.tracepoint.tp_name)); 499 jsonw_uint_field(wtr, "cookie", info->perf_event.tracepoint.cookie); 500 } 501 502 static char *perf_config_hw_cache_str(__u64 config) 503 { 504 const char *hw_cache, *result, *op; 505 char *str = malloc(PERF_HW_CACHE_LEN); 506 507 if (!str) { 508 p_err("mem alloc failed"); 509 return NULL; 510 } 511 512 hw_cache = perf_event_name(evsel__hw_cache, config & 0xff); 513 if (hw_cache) 514 snprintf(str, PERF_HW_CACHE_LEN, "%s-", hw_cache); 515 else 516 snprintf(str, PERF_HW_CACHE_LEN, "%llu-", config & 0xff); 517 518 op = perf_event_name(evsel__hw_cache_op, (config >> 8) & 0xff); 519 if (op) 520 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 521 "%s-", op); 522 else 523 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 524 "%llu-", (config >> 8) & 0xff); 525 526 result = perf_event_name(evsel__hw_cache_result, config >> 16); 527 if (result) 528 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 529 "%s", result); 530 else 531 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 532 "%llu", config >> 16); 533 return str; 534 } 535 536 static const char *perf_config_str(__u32 type, __u64 config) 537 { 538 const char *perf_config; 539 540 switch (type) { 541 case PERF_TYPE_HARDWARE: 542 perf_config = perf_event_name(event_symbols_hw, config); 543 break; 544 case PERF_TYPE_SOFTWARE: 545 perf_config = perf_event_name(event_symbols_sw, config); 546 break; 547 case PERF_TYPE_HW_CACHE: 548 perf_config = perf_config_hw_cache_str(config); 549 break; 550 default: 551 perf_config = NULL; 552 break; 553 } 554 return perf_config; 555 } 556 557 static void 558 show_perf_event_event_json(struct bpf_link_info *info, json_writer_t *wtr) 559 { 560 __u64 config = info->perf_event.event.config; 561 __u32 type = info->perf_event.event.type; 562 const char *perf_type, *perf_config; 563 564 perf_type = perf_event_name(perf_type_name, type); 565 if (perf_type) 566 jsonw_string_field(wtr, "event_type", perf_type); 567 else 568 jsonw_uint_field(wtr, "event_type", type); 569 570 perf_config = perf_config_str(type, config); 571 if (perf_config) 572 jsonw_string_field(wtr, "event_config", perf_config); 573 else 574 jsonw_uint_field(wtr, "event_config", config); 575 576 jsonw_uint_field(wtr, "cookie", info->perf_event.event.cookie); 577 578 if (type == PERF_TYPE_HW_CACHE && perf_config) 579 free((void *)perf_config); 580 } 581 582 static int show_link_close_json(int fd, struct bpf_link_info *info) 583 { 584 struct bpf_prog_info prog_info; 585 const char *prog_type_str; 586 int err; 587 588 jsonw_start_object(json_wtr); 589 590 show_link_header_json(info, json_wtr); 591 592 switch (info->type) { 593 case BPF_LINK_TYPE_RAW_TRACEPOINT: 594 jsonw_string_field(json_wtr, "tp_name", 595 u64_to_ptr(info->raw_tracepoint.tp_name)); 596 jsonw_uint_field(json_wtr, "cookie", info->raw_tracepoint.cookie); 597 break; 598 case BPF_LINK_TYPE_TRACING: 599 err = get_prog_info(info->prog_id, &prog_info); 600 if (err) 601 return err; 602 603 prog_type_str = libbpf_bpf_prog_type_str(prog_info.type); 604 /* libbpf will return NULL for variants unknown to it. */ 605 if (prog_type_str) 606 jsonw_string_field(json_wtr, "prog_type", prog_type_str); 607 else 608 jsonw_uint_field(json_wtr, "prog_type", prog_info.type); 609 610 show_link_attach_type_json(info->tracing.attach_type, 611 json_wtr); 612 jsonw_uint_field(json_wtr, "target_obj_id", info->tracing.target_obj_id); 613 jsonw_uint_field(json_wtr, "target_btf_id", info->tracing.target_btf_id); 614 jsonw_uint_field(json_wtr, "cookie", info->tracing.cookie); 615 break; 616 case BPF_LINK_TYPE_CGROUP: 617 jsonw_lluint_field(json_wtr, "cgroup_id", 618 info->cgroup.cgroup_id); 619 show_link_attach_type_json(info->cgroup.attach_type, json_wtr); 620 break; 621 case BPF_LINK_TYPE_ITER: 622 show_iter_json(info, json_wtr); 623 break; 624 case BPF_LINK_TYPE_NETNS: 625 jsonw_uint_field(json_wtr, "netns_ino", 626 info->netns.netns_ino); 627 show_link_attach_type_json(info->netns.attach_type, json_wtr); 628 break; 629 case BPF_LINK_TYPE_NETFILTER: 630 netfilter_dump_json(info, json_wtr); 631 break; 632 case BPF_LINK_TYPE_TCX: 633 show_link_ifindex_json(info->tcx.ifindex, json_wtr); 634 show_link_attach_type_json(info->tcx.attach_type, json_wtr); 635 break; 636 case BPF_LINK_TYPE_NETKIT: 637 show_link_ifindex_json(info->netkit.ifindex, json_wtr); 638 show_link_attach_type_json(info->netkit.attach_type, json_wtr); 639 break; 640 case BPF_LINK_TYPE_SOCKMAP: 641 jsonw_uint_field(json_wtr, "map_id", info->sockmap.map_id); 642 show_link_attach_type_json(info->sockmap.attach_type, json_wtr); 643 break; 644 case BPF_LINK_TYPE_XDP: 645 show_link_ifindex_json(info->xdp.ifindex, json_wtr); 646 break; 647 case BPF_LINK_TYPE_STRUCT_OPS: 648 jsonw_uint_field(json_wtr, "map_id", 649 info->struct_ops.map_id); 650 break; 651 case BPF_LINK_TYPE_KPROBE_MULTI: 652 show_kprobe_multi_json(info, json_wtr); 653 break; 654 case BPF_LINK_TYPE_UPROBE_MULTI: 655 show_uprobe_multi_json(info, json_wtr); 656 break; 657 case BPF_LINK_TYPE_TRACING_MULTI: 658 show_tracing_multi_json(info, json_wtr); 659 break; 660 case BPF_LINK_TYPE_PERF_EVENT: 661 switch (info->perf_event.type) { 662 case BPF_PERF_EVENT_EVENT: 663 show_perf_event_event_json(info, json_wtr); 664 break; 665 case BPF_PERF_EVENT_TRACEPOINT: 666 show_perf_event_tracepoint_json(info, json_wtr); 667 break; 668 case BPF_PERF_EVENT_KPROBE: 669 case BPF_PERF_EVENT_KRETPROBE: 670 show_perf_event_kprobe_json(info, json_wtr); 671 break; 672 case BPF_PERF_EVENT_UPROBE: 673 case BPF_PERF_EVENT_URETPROBE: 674 show_perf_event_uprobe_json(info, json_wtr); 675 break; 676 default: 677 break; 678 } 679 break; 680 default: 681 break; 682 } 683 684 if (!hashmap__empty(link_table)) { 685 struct hashmap_entry *entry; 686 687 jsonw_name(json_wtr, "pinned"); 688 jsonw_start_array(json_wtr); 689 hashmap__for_each_key_entry(link_table, entry, info->id) 690 jsonw_string(json_wtr, entry->pvalue); 691 jsonw_end_array(json_wtr); 692 } 693 694 emit_obj_refs_json(refs_table, info->id, json_wtr); 695 696 jsonw_end_object(json_wtr); 697 698 return 0; 699 } 700 701 static void show_link_header_plain(struct bpf_link_info *info) 702 { 703 const char *link_type_str; 704 705 printf("%u: ", info->id); 706 link_type_str = libbpf_bpf_link_type_str(info->type); 707 if (link_type_str) 708 printf("%s ", link_type_str); 709 else 710 printf("type %u ", info->type); 711 712 if (info->type == BPF_LINK_TYPE_STRUCT_OPS) 713 printf("map %u ", info->struct_ops.map_id); 714 else 715 printf("prog %u ", info->prog_id); 716 } 717 718 static void show_link_attach_type_plain(__u32 attach_type) 719 { 720 const char *attach_type_str; 721 722 attach_type_str = libbpf_bpf_attach_type_str(attach_type); 723 if (attach_type_str) 724 printf("attach_type %s ", attach_type_str); 725 else 726 printf("attach_type %u ", attach_type); 727 } 728 729 static void show_link_ifindex_plain(__u32 ifindex) 730 { 731 char devname[IF_NAMESIZE * 2] = "(unknown)"; 732 char tmpname[IF_NAMESIZE]; 733 char *ret = NULL; 734 735 if (ifindex) 736 ret = if_indextoname(ifindex, tmpname); 737 else 738 snprintf(devname, sizeof(devname), "(detached)"); 739 if (ret) 740 snprintf(devname, sizeof(devname), "%s(%u)", 741 tmpname, ifindex); 742 printf("ifindex %s ", devname); 743 } 744 745 static void show_iter_plain(struct bpf_link_info *info) 746 { 747 const char *target_name = u64_to_ptr(info->iter.target_name); 748 749 printf("target_name %s ", target_name); 750 751 if (is_iter_map_target(target_name)) 752 printf("map_id %u ", info->iter.map.map_id); 753 else if (is_iter_task_target(target_name)) { 754 if (info->iter.task.tid) 755 printf("tid %u ", info->iter.task.tid); 756 else if (info->iter.task.pid) 757 printf("pid %u ", info->iter.task.pid); 758 } 759 760 if (is_iter_cgroup_target(target_name)) { 761 printf("cgroup_id %llu ", info->iter.cgroup.cgroup_id); 762 printf("order %s ", 763 cgroup_order_string(info->iter.cgroup.order)); 764 } 765 } 766 767 static const char * const pf2name[] = { 768 [NFPROTO_INET] = "inet", 769 [NFPROTO_IPV4] = "ip", 770 [NFPROTO_ARP] = "arp", 771 [NFPROTO_NETDEV] = "netdev", 772 [NFPROTO_BRIDGE] = "bridge", 773 [NFPROTO_IPV6] = "ip6", 774 }; 775 776 static const char * const inethook2name[] = { 777 [NF_INET_PRE_ROUTING] = "prerouting", 778 [NF_INET_LOCAL_IN] = "input", 779 [NF_INET_FORWARD] = "forward", 780 [NF_INET_LOCAL_OUT] = "output", 781 [NF_INET_POST_ROUTING] = "postrouting", 782 }; 783 784 static const char * const arphook2name[] = { 785 [NF_ARP_IN] = "input", 786 [NF_ARP_OUT] = "output", 787 }; 788 789 void netfilter_dump_plain(const struct bpf_link_info *info) 790 { 791 const char *hookname = NULL, *pfname = NULL; 792 unsigned int hook = info->netfilter.hooknum; 793 unsigned int pf = info->netfilter.pf; 794 795 if (pf < ARRAY_SIZE(pf2name)) 796 pfname = pf2name[pf]; 797 798 switch (pf) { 799 case NFPROTO_BRIDGE: /* bridge shares numbers with enum nf_inet_hooks */ 800 case NFPROTO_IPV4: 801 case NFPROTO_IPV6: 802 case NFPROTO_INET: 803 if (hook < ARRAY_SIZE(inethook2name)) 804 hookname = inethook2name[hook]; 805 break; 806 case NFPROTO_ARP: 807 if (hook < ARRAY_SIZE(arphook2name)) 808 hookname = arphook2name[hook]; 809 default: 810 break; 811 } 812 813 if (pfname) 814 printf("\n\t%s", pfname); 815 else 816 printf("\n\tpf: %u", pf); 817 818 if (hookname) 819 printf(" %s", hookname); 820 else 821 printf(", hook %u,", hook); 822 823 printf(" prio %d", info->netfilter.priority); 824 825 if (info->netfilter.flags) 826 printf(" flags 0x%x", info->netfilter.flags); 827 } 828 829 static void show_kprobe_multi_plain(struct bpf_link_info *info) 830 { 831 struct addr_cookie *data; 832 __u32 i, j = 0; 833 bool is_ibt_enabled; 834 835 if (!info->kprobe_multi.count) 836 return; 837 838 if (info->kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN) 839 printf("\n\tkretprobe.multi "); 840 else 841 printf("\n\tkprobe.multi "); 842 printf("func_cnt %u ", info->kprobe_multi.count); 843 if (info->kprobe_multi.missed) 844 printf("missed %llu ", info->kprobe_multi.missed); 845 data = get_addr_cookie_array(u64_to_ptr(info->kprobe_multi.addrs), 846 u64_to_ptr(info->kprobe_multi.cookies), 847 info->kprobe_multi.count); 848 if (!data) 849 return; 850 851 /* Load it once for all. */ 852 if (!dd.sym_count) 853 kernel_syms_load(&dd); 854 if (!dd.sym_count) 855 goto error; 856 857 is_ibt_enabled = is_x86_ibt_enabled(); 858 printf("\n\t%-16s %-16s %s", "addr", "cookie", "func [module]"); 859 for (i = 0; i < dd.sym_count; i++) { 860 if (!symbol_matches_target(dd.sym_mapping[i].address, 861 data[j].addr, is_ibt_enabled)) 862 continue; 863 printf("\n\t%016lx %-16llx %s", 864 (unsigned long)data[j].addr, data[j].cookie, dd.sym_mapping[i].name); 865 if (dd.sym_mapping[i].module[0] != '\0') 866 printf(" [%s] ", dd.sym_mapping[i].module); 867 else 868 printf(" "); 869 870 if (j++ == info->kprobe_multi.count) 871 break; 872 } 873 error: 874 free(data); 875 } 876 877 static void show_uprobe_multi_plain(struct bpf_link_info *info) 878 { 879 __u32 i; 880 881 if (!info->uprobe_multi.count) 882 return; 883 884 if (info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN) 885 printf("\n\turetprobe.multi "); 886 else 887 printf("\n\tuprobe.multi "); 888 889 printf("path %s ", (char *) u64_to_ptr(info->uprobe_multi.path)); 890 printf("func_cnt %u ", info->uprobe_multi.count); 891 892 if (info->uprobe_multi.pid) 893 printf("pid %u ", info->uprobe_multi.pid); 894 895 printf("\n\t%-16s %-16s %-16s", "offset", "ref_ctr_offset", "cookies"); 896 for (i = 0; i < info->uprobe_multi.count; i++) { 897 printf("\n\t0x%-16llx 0x%-16llx 0x%-16llx", 898 u64_to_arr(info->uprobe_multi.offsets)[i], 899 u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i], 900 u64_to_arr(info->uprobe_multi.cookies)[i]); 901 } 902 } 903 904 static void show_tracing_multi_plain(struct bpf_link_info *info) 905 { 906 bool is_ibt_enabled = is_x86_ibt_enabled(), show_symbol; 907 __u64 *addrs, *cookies; 908 __u32 i, *ids; 909 910 if (!info->tracing_multi.count) 911 return; 912 913 if (!dd.sym_count) 914 kernel_syms_load(&dd); 915 show_symbol = !!dd.sym_count; 916 917 printf("\n\t"); 918 show_link_attach_type_plain(info->tracing_multi.attach_type); 919 printf("btf_obj_id %u ", info->tracing_multi.btf_obj_id); 920 printf("count %u ", info->tracing_multi.count); 921 922 printf("\n\t%-16s %-16s %-16s %s", 923 "btf_id", "addr", "cookie", "func [module]"); 924 925 ids = u64_to_u32_arr(info->tracing_multi.ids); 926 addrs = u64_to_arr(info->tracing_multi.addrs); 927 cookies = u64_to_arr(info->tracing_multi.cookies); 928 929 for (i = 0; i < info->tracing_multi.count; i++) { 930 __u64 addr = addrs[i]; 931 struct kernel_sym *sym; 932 933 sym = show_symbol ? find_kernel_sym_by_addr(addr, is_ibt_enabled) : NULL; 934 935 printf("\n\t%-16u %016llx %-16llu", ids[i], addr, cookies[i]); 936 if (sym) { 937 printf(" %s", sym->name); 938 if (sym->module[0] != '\0') 939 printf(" [%s]", sym->module); 940 } 941 } 942 } 943 944 static void show_perf_event_kprobe_plain(struct bpf_link_info *info) 945 { 946 const char *buf; 947 948 buf = u64_to_ptr(info->perf_event.kprobe.func_name); 949 if (buf[0] == '\0' && !info->perf_event.kprobe.addr) 950 return; 951 952 if (info->perf_event.type == BPF_PERF_EVENT_KRETPROBE) 953 printf("\n\tkretprobe "); 954 else 955 printf("\n\tkprobe "); 956 if (info->perf_event.kprobe.addr) 957 printf("%llx ", info->perf_event.kprobe.addr); 958 printf("%s", buf); 959 if (info->perf_event.kprobe.offset) 960 printf("+%#x", info->perf_event.kprobe.offset); 961 if (info->perf_event.kprobe.missed) 962 printf(" missed %llu", info->perf_event.kprobe.missed); 963 if (info->perf_event.kprobe.cookie) 964 printf(" cookie %llu", info->perf_event.kprobe.cookie); 965 printf(" "); 966 } 967 968 static void show_perf_event_uprobe_plain(struct bpf_link_info *info) 969 { 970 const char *buf; 971 972 buf = u64_to_ptr(info->perf_event.uprobe.file_name); 973 if (buf[0] == '\0') 974 return; 975 976 if (info->perf_event.type == BPF_PERF_EVENT_URETPROBE) 977 printf("\n\turetprobe "); 978 else 979 printf("\n\tuprobe "); 980 printf("%s+%#x ", buf, info->perf_event.uprobe.offset); 981 if (info->perf_event.uprobe.cookie) 982 printf("cookie %llu ", info->perf_event.uprobe.cookie); 983 if (info->perf_event.uprobe.ref_ctr_offset) 984 printf("ref_ctr_offset 0x%llx ", info->perf_event.uprobe.ref_ctr_offset); 985 } 986 987 static void show_perf_event_tracepoint_plain(struct bpf_link_info *info) 988 { 989 const char *buf; 990 991 buf = u64_to_ptr(info->perf_event.tracepoint.tp_name); 992 if (buf[0] == '\0') 993 return; 994 995 printf("\n\ttracepoint %s ", buf); 996 if (info->perf_event.tracepoint.cookie) 997 printf("cookie %llu ", info->perf_event.tracepoint.cookie); 998 } 999 1000 static void show_perf_event_event_plain(struct bpf_link_info *info) 1001 { 1002 __u64 config = info->perf_event.event.config; 1003 __u32 type = info->perf_event.event.type; 1004 const char *perf_type, *perf_config; 1005 1006 printf("\n\tevent "); 1007 perf_type = perf_event_name(perf_type_name, type); 1008 if (perf_type) 1009 printf("%s:", perf_type); 1010 else 1011 printf("%u :", type); 1012 1013 perf_config = perf_config_str(type, config); 1014 if (perf_config) 1015 printf("%s ", perf_config); 1016 else 1017 printf("%llu ", config); 1018 1019 if (info->perf_event.event.cookie) 1020 printf("cookie %llu ", info->perf_event.event.cookie); 1021 1022 if (type == PERF_TYPE_HW_CACHE && perf_config) 1023 free((void *)perf_config); 1024 } 1025 1026 static int show_link_close_plain(int fd, struct bpf_link_info *info) 1027 { 1028 struct bpf_prog_info prog_info; 1029 const char *prog_type_str; 1030 int err; 1031 1032 show_link_header_plain(info); 1033 1034 switch (info->type) { 1035 case BPF_LINK_TYPE_RAW_TRACEPOINT: 1036 printf("\n\ttp '%s' ", 1037 (const char *)u64_to_ptr(info->raw_tracepoint.tp_name)); 1038 if (info->raw_tracepoint.cookie) 1039 printf("cookie %llu ", info->raw_tracepoint.cookie); 1040 break; 1041 case BPF_LINK_TYPE_TRACING: 1042 err = get_prog_info(info->prog_id, &prog_info); 1043 if (err) 1044 return err; 1045 1046 prog_type_str = libbpf_bpf_prog_type_str(prog_info.type); 1047 /* libbpf will return NULL for variants unknown to it. */ 1048 if (prog_type_str) 1049 printf("\n\tprog_type %s ", prog_type_str); 1050 else 1051 printf("\n\tprog_type %u ", prog_info.type); 1052 1053 show_link_attach_type_plain(info->tracing.attach_type); 1054 if (info->tracing.target_obj_id || info->tracing.target_btf_id) 1055 printf("\n\ttarget_obj_id %u target_btf_id %u ", 1056 info->tracing.target_obj_id, 1057 info->tracing.target_btf_id); 1058 if (info->tracing.cookie) 1059 printf("\n\tcookie %llu ", info->tracing.cookie); 1060 break; 1061 case BPF_LINK_TYPE_CGROUP: 1062 printf("\n\tcgroup_id %zu ", (size_t)info->cgroup.cgroup_id); 1063 show_link_attach_type_plain(info->cgroup.attach_type); 1064 break; 1065 case BPF_LINK_TYPE_ITER: 1066 show_iter_plain(info); 1067 break; 1068 case BPF_LINK_TYPE_NETNS: 1069 printf("\n\tnetns_ino %u ", info->netns.netns_ino); 1070 show_link_attach_type_plain(info->netns.attach_type); 1071 break; 1072 case BPF_LINK_TYPE_NETFILTER: 1073 netfilter_dump_plain(info); 1074 break; 1075 case BPF_LINK_TYPE_TCX: 1076 printf("\n\t"); 1077 show_link_ifindex_plain(info->tcx.ifindex); 1078 show_link_attach_type_plain(info->tcx.attach_type); 1079 break; 1080 case BPF_LINK_TYPE_NETKIT: 1081 printf("\n\t"); 1082 show_link_ifindex_plain(info->netkit.ifindex); 1083 show_link_attach_type_plain(info->netkit.attach_type); 1084 break; 1085 case BPF_LINK_TYPE_SOCKMAP: 1086 printf("\n\t"); 1087 printf("map_id %u ", info->sockmap.map_id); 1088 show_link_attach_type_plain(info->sockmap.attach_type); 1089 break; 1090 case BPF_LINK_TYPE_XDP: 1091 printf("\n\t"); 1092 show_link_ifindex_plain(info->xdp.ifindex); 1093 break; 1094 case BPF_LINK_TYPE_KPROBE_MULTI: 1095 show_kprobe_multi_plain(info); 1096 break; 1097 case BPF_LINK_TYPE_UPROBE_MULTI: 1098 show_uprobe_multi_plain(info); 1099 break; 1100 case BPF_LINK_TYPE_TRACING_MULTI: 1101 show_tracing_multi_plain(info); 1102 break; 1103 case BPF_LINK_TYPE_PERF_EVENT: 1104 switch (info->perf_event.type) { 1105 case BPF_PERF_EVENT_EVENT: 1106 show_perf_event_event_plain(info); 1107 break; 1108 case BPF_PERF_EVENT_TRACEPOINT: 1109 show_perf_event_tracepoint_plain(info); 1110 break; 1111 case BPF_PERF_EVENT_KPROBE: 1112 case BPF_PERF_EVENT_KRETPROBE: 1113 show_perf_event_kprobe_plain(info); 1114 break; 1115 case BPF_PERF_EVENT_UPROBE: 1116 case BPF_PERF_EVENT_URETPROBE: 1117 show_perf_event_uprobe_plain(info); 1118 break; 1119 default: 1120 break; 1121 } 1122 break; 1123 default: 1124 break; 1125 } 1126 1127 if (!hashmap__empty(link_table)) { 1128 struct hashmap_entry *entry; 1129 1130 hashmap__for_each_key_entry(link_table, entry, info->id) 1131 printf("\n\tpinned %s", (char *)entry->pvalue); 1132 } 1133 emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 1134 1135 printf("\n"); 1136 1137 return 0; 1138 } 1139 1140 static int do_show_link(int fd) 1141 { 1142 __u64 *ref_ctr_offsets = NULL, *offsets = NULL, *cookies = NULL; 1143 __u32 *ids = NULL; 1144 struct bpf_link_info info; 1145 __u32 len = sizeof(info); 1146 char path_buf[PATH_MAX]; 1147 __u64 *addrs = NULL; 1148 char buf[PATH_MAX]; 1149 int count; 1150 int err; 1151 1152 memset(&info, 0, sizeof(info)); 1153 buf[0] = '\0'; 1154 again: 1155 err = bpf_link_get_info_by_fd(fd, &info, &len); 1156 if (err) { 1157 p_err("can't get link info: %s", 1158 strerror(errno)); 1159 close(fd); 1160 return err; 1161 } 1162 if (info.type == BPF_LINK_TYPE_RAW_TRACEPOINT && 1163 !info.raw_tracepoint.tp_name) { 1164 info.raw_tracepoint.tp_name = ptr_to_u64(&buf); 1165 info.raw_tracepoint.tp_name_len = sizeof(buf); 1166 goto again; 1167 } 1168 if (info.type == BPF_LINK_TYPE_ITER && 1169 !info.iter.target_name) { 1170 info.iter.target_name = ptr_to_u64(&buf); 1171 info.iter.target_name_len = sizeof(buf); 1172 goto again; 1173 } 1174 if (info.type == BPF_LINK_TYPE_KPROBE_MULTI && 1175 !info.kprobe_multi.addrs) { 1176 count = info.kprobe_multi.count; 1177 if (count) { 1178 addrs = calloc(count, sizeof(__u64)); 1179 if (!addrs) { 1180 p_err("mem alloc failed"); 1181 close(fd); 1182 return -ENOMEM; 1183 } 1184 info.kprobe_multi.addrs = ptr_to_u64(addrs); 1185 cookies = calloc(count, sizeof(__u64)); 1186 if (!cookies) { 1187 p_err("mem alloc failed"); 1188 free(addrs); 1189 close(fd); 1190 return -ENOMEM; 1191 } 1192 info.kprobe_multi.cookies = ptr_to_u64(cookies); 1193 goto again; 1194 } 1195 } 1196 if (info.type == BPF_LINK_TYPE_UPROBE_MULTI && 1197 !info.uprobe_multi.offsets) { 1198 count = info.uprobe_multi.count; 1199 if (count) { 1200 offsets = calloc(count, sizeof(__u64)); 1201 if (!offsets) { 1202 p_err("mem alloc failed"); 1203 close(fd); 1204 return -ENOMEM; 1205 } 1206 info.uprobe_multi.offsets = ptr_to_u64(offsets); 1207 ref_ctr_offsets = calloc(count, sizeof(__u64)); 1208 if (!ref_ctr_offsets) { 1209 p_err("mem alloc failed"); 1210 free(offsets); 1211 close(fd); 1212 return -ENOMEM; 1213 } 1214 info.uprobe_multi.ref_ctr_offsets = ptr_to_u64(ref_ctr_offsets); 1215 cookies = calloc(count, sizeof(__u64)); 1216 if (!cookies) { 1217 p_err("mem alloc failed"); 1218 free(ref_ctr_offsets); 1219 free(offsets); 1220 close(fd); 1221 return -ENOMEM; 1222 } 1223 info.uprobe_multi.cookies = ptr_to_u64(cookies); 1224 info.uprobe_multi.path = ptr_to_u64(path_buf); 1225 info.uprobe_multi.path_size = sizeof(path_buf); 1226 goto again; 1227 } 1228 } 1229 if (info.type == BPF_LINK_TYPE_TRACING_MULTI && !info.tracing_multi.ids) { 1230 count = info.tracing_multi.count; 1231 if (count) { 1232 ids = calloc(count, sizeof(__u32)); 1233 addrs = calloc(count, sizeof(__u64)); 1234 cookies = calloc(count, sizeof(__u64)); 1235 if (!ids || !addrs || !cookies) { 1236 p_err("mem alloc failed"); 1237 close(fd); 1238 free(cookies); 1239 free(addrs); 1240 free(ids); 1241 return -ENOMEM; 1242 } 1243 info.tracing_multi.ids = ptr_to_u64(ids); 1244 info.tracing_multi.addrs = ptr_to_u64(addrs); 1245 info.tracing_multi.cookies = ptr_to_u64(cookies); 1246 goto again; 1247 } 1248 } 1249 if (info.type == BPF_LINK_TYPE_PERF_EVENT) { 1250 switch (info.perf_event.type) { 1251 case BPF_PERF_EVENT_TRACEPOINT: 1252 if (!info.perf_event.tracepoint.tp_name) { 1253 info.perf_event.tracepoint.tp_name = ptr_to_u64(&buf); 1254 info.perf_event.tracepoint.name_len = sizeof(buf); 1255 goto again; 1256 } 1257 break; 1258 case BPF_PERF_EVENT_KPROBE: 1259 case BPF_PERF_EVENT_KRETPROBE: 1260 if (!info.perf_event.kprobe.func_name) { 1261 info.perf_event.kprobe.func_name = ptr_to_u64(&buf); 1262 info.perf_event.kprobe.name_len = sizeof(buf); 1263 goto again; 1264 } 1265 break; 1266 case BPF_PERF_EVENT_UPROBE: 1267 case BPF_PERF_EVENT_URETPROBE: 1268 if (!info.perf_event.uprobe.file_name) { 1269 info.perf_event.uprobe.file_name = ptr_to_u64(&buf); 1270 info.perf_event.uprobe.name_len = sizeof(buf); 1271 goto again; 1272 } 1273 break; 1274 default: 1275 break; 1276 } 1277 } 1278 1279 if (json_output) 1280 show_link_close_json(fd, &info); 1281 else 1282 show_link_close_plain(fd, &info); 1283 1284 free(ref_ctr_offsets); 1285 free(cookies); 1286 free(offsets); 1287 free(addrs); 1288 free(ids); 1289 close(fd); 1290 return 0; 1291 } 1292 1293 static int do_show(int argc, char **argv) 1294 { 1295 __u32 id = 0; 1296 int err, fd; 1297 1298 if (show_pinned) { 1299 link_table = hashmap__new(hash_fn_for_key_as_id, 1300 equal_fn_for_key_as_id, NULL); 1301 if (IS_ERR(link_table)) { 1302 p_err("failed to create hashmap for pinned paths"); 1303 return -1; 1304 } 1305 build_pinned_obj_table(link_table, BPF_OBJ_LINK); 1306 } 1307 build_obj_refs_table(&refs_table, BPF_OBJ_LINK); 1308 1309 if (argc == 2) { 1310 fd = link_parse_fd(&argc, &argv); 1311 if (fd < 0) 1312 return fd; 1313 do_show_link(fd); 1314 goto out; 1315 } 1316 1317 if (argc) 1318 return BAD_ARG(); 1319 1320 if (json_output) 1321 jsonw_start_array(json_wtr); 1322 while (true) { 1323 err = bpf_link_get_next_id(id, &id); 1324 if (err) { 1325 if (errno == ENOENT) 1326 break; 1327 p_err("can't get next link: %s%s", strerror(errno), 1328 errno == EINVAL ? " -- kernel too old?" : ""); 1329 break; 1330 } 1331 1332 fd = bpf_link_get_fd_by_id(id); 1333 if (fd < 0) { 1334 if (errno == ENOENT) 1335 continue; 1336 p_err("can't get link by id (%u): %s", 1337 id, strerror(errno)); 1338 break; 1339 } 1340 1341 err = do_show_link(fd); 1342 if (err) 1343 break; 1344 } 1345 if (json_output) 1346 jsonw_end_array(json_wtr); 1347 1348 delete_obj_refs_table(refs_table); 1349 1350 if (show_pinned) 1351 delete_pinned_obj_table(link_table); 1352 1353 out: 1354 if (dd.sym_count) 1355 kernel_syms_destroy(&dd); 1356 return errno == ENOENT ? 0 : -1; 1357 } 1358 1359 static int do_pin(int argc, char **argv) 1360 { 1361 int err; 1362 1363 err = do_pin_any(argc, argv, link_parse_fd); 1364 if (!err && json_output) 1365 jsonw_null(json_wtr); 1366 return err; 1367 } 1368 1369 static int do_detach(int argc, char **argv) 1370 { 1371 int err, fd; 1372 1373 if (argc != 2) { 1374 p_err("link specifier is invalid or missing\n"); 1375 return 1; 1376 } 1377 1378 fd = link_parse_fd(&argc, &argv); 1379 if (fd < 0) 1380 return 1; 1381 1382 err = bpf_link_detach(fd); 1383 if (err) 1384 err = -errno; 1385 close(fd); 1386 if (err) { 1387 p_err("failed link detach: %s", strerror(-err)); 1388 return 1; 1389 } 1390 1391 if (json_output) 1392 jsonw_null(json_wtr); 1393 1394 return 0; 1395 } 1396 1397 static int do_help(int argc, char **argv) 1398 { 1399 if (json_output) { 1400 jsonw_null(json_wtr); 1401 return 0; 1402 } 1403 1404 fprintf(stderr, 1405 "Usage: %1$s %2$s { show | list } [LINK]\n" 1406 " %1$s %2$s pin LINK FILE\n" 1407 " %1$s %2$s detach LINK\n" 1408 " %1$s %2$s help\n" 1409 "\n" 1410 " " HELP_SPEC_LINK "\n" 1411 " " HELP_SPEC_OPTIONS " |\n" 1412 " {-f|--bpffs} | {-n|--nomount} }\n" 1413 "", 1414 bin_name, argv[-2]); 1415 1416 return 0; 1417 } 1418 1419 static const struct cmd cmds[] = { 1420 { "show", do_show }, 1421 { "list", do_show }, 1422 { "help", do_help }, 1423 { "pin", do_pin }, 1424 { "detach", do_detach }, 1425 { 0 } 1426 }; 1427 1428 int do_link(int argc, char **argv) 1429 { 1430 return cmd_select(cmds, argc, argv, do_help); 1431 } 1432