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 void 381 show_uprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) 382 { 383 __u32 i; 384 385 jsonw_bool_field(json_wtr, "retprobe", 386 info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN); 387 jsonw_string_field(json_wtr, "path", (char *) u64_to_ptr(info->uprobe_multi.path)); 388 jsonw_uint_field(json_wtr, "func_cnt", info->uprobe_multi.count); 389 jsonw_int_field(json_wtr, "pid", (int) info->uprobe_multi.pid); 390 jsonw_name(json_wtr, "funcs"); 391 jsonw_start_array(json_wtr); 392 393 for (i = 0; i < info->uprobe_multi.count; i++) { 394 jsonw_start_object(json_wtr); 395 jsonw_uint_field(json_wtr, "offset", 396 u64_to_arr(info->uprobe_multi.offsets)[i]); 397 jsonw_uint_field(json_wtr, "ref_ctr_offset", 398 u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i]); 399 jsonw_uint_field(json_wtr, "cookie", 400 u64_to_arr(info->uprobe_multi.cookies)[i]); 401 jsonw_end_object(json_wtr); 402 } 403 jsonw_end_array(json_wtr); 404 } 405 406 static void 407 show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr) 408 { 409 jsonw_bool_field(wtr, "retprobe", info->perf_event.type == BPF_PERF_EVENT_KRETPROBE); 410 jsonw_uint_field(wtr, "addr", info->perf_event.kprobe.addr); 411 jsonw_string_field(wtr, "func", 412 u64_to_ptr(info->perf_event.kprobe.func_name)); 413 jsonw_uint_field(wtr, "offset", info->perf_event.kprobe.offset); 414 jsonw_uint_field(wtr, "missed", info->perf_event.kprobe.missed); 415 jsonw_uint_field(wtr, "cookie", info->perf_event.kprobe.cookie); 416 } 417 418 static void 419 show_perf_event_uprobe_json(struct bpf_link_info *info, json_writer_t *wtr) 420 { 421 jsonw_bool_field(wtr, "retprobe", info->perf_event.type == BPF_PERF_EVENT_URETPROBE); 422 jsonw_string_field(wtr, "file", 423 u64_to_ptr(info->perf_event.uprobe.file_name)); 424 jsonw_uint_field(wtr, "offset", info->perf_event.uprobe.offset); 425 jsonw_uint_field(wtr, "cookie", info->perf_event.uprobe.cookie); 426 jsonw_uint_field(wtr, "ref_ctr_offset", info->perf_event.uprobe.ref_ctr_offset); 427 } 428 429 static void 430 show_perf_event_tracepoint_json(struct bpf_link_info *info, json_writer_t *wtr) 431 { 432 jsonw_string_field(wtr, "tracepoint", 433 u64_to_ptr(info->perf_event.tracepoint.tp_name)); 434 jsonw_uint_field(wtr, "cookie", info->perf_event.tracepoint.cookie); 435 } 436 437 static char *perf_config_hw_cache_str(__u64 config) 438 { 439 const char *hw_cache, *result, *op; 440 char *str = malloc(PERF_HW_CACHE_LEN); 441 442 if (!str) { 443 p_err("mem alloc failed"); 444 return NULL; 445 } 446 447 hw_cache = perf_event_name(evsel__hw_cache, config & 0xff); 448 if (hw_cache) 449 snprintf(str, PERF_HW_CACHE_LEN, "%s-", hw_cache); 450 else 451 snprintf(str, PERF_HW_CACHE_LEN, "%llu-", config & 0xff); 452 453 op = perf_event_name(evsel__hw_cache_op, (config >> 8) & 0xff); 454 if (op) 455 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 456 "%s-", op); 457 else 458 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 459 "%llu-", (config >> 8) & 0xff); 460 461 result = perf_event_name(evsel__hw_cache_result, config >> 16); 462 if (result) 463 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 464 "%s", result); 465 else 466 snprintf(str + strlen(str), PERF_HW_CACHE_LEN - strlen(str), 467 "%llu", config >> 16); 468 return str; 469 } 470 471 static const char *perf_config_str(__u32 type, __u64 config) 472 { 473 const char *perf_config; 474 475 switch (type) { 476 case PERF_TYPE_HARDWARE: 477 perf_config = perf_event_name(event_symbols_hw, config); 478 break; 479 case PERF_TYPE_SOFTWARE: 480 perf_config = perf_event_name(event_symbols_sw, config); 481 break; 482 case PERF_TYPE_HW_CACHE: 483 perf_config = perf_config_hw_cache_str(config); 484 break; 485 default: 486 perf_config = NULL; 487 break; 488 } 489 return perf_config; 490 } 491 492 static void 493 show_perf_event_event_json(struct bpf_link_info *info, json_writer_t *wtr) 494 { 495 __u64 config = info->perf_event.event.config; 496 __u32 type = info->perf_event.event.type; 497 const char *perf_type, *perf_config; 498 499 perf_type = perf_event_name(perf_type_name, type); 500 if (perf_type) 501 jsonw_string_field(wtr, "event_type", perf_type); 502 else 503 jsonw_uint_field(wtr, "event_type", type); 504 505 perf_config = perf_config_str(type, config); 506 if (perf_config) 507 jsonw_string_field(wtr, "event_config", perf_config); 508 else 509 jsonw_uint_field(wtr, "event_config", config); 510 511 jsonw_uint_field(wtr, "cookie", info->perf_event.event.cookie); 512 513 if (type == PERF_TYPE_HW_CACHE && perf_config) 514 free((void *)perf_config); 515 } 516 517 static int show_link_close_json(int fd, struct bpf_link_info *info) 518 { 519 struct bpf_prog_info prog_info; 520 const char *prog_type_str; 521 int err; 522 523 jsonw_start_object(json_wtr); 524 525 show_link_header_json(info, json_wtr); 526 527 switch (info->type) { 528 case BPF_LINK_TYPE_RAW_TRACEPOINT: 529 jsonw_string_field(json_wtr, "tp_name", 530 u64_to_ptr(info->raw_tracepoint.tp_name)); 531 jsonw_uint_field(json_wtr, "cookie", info->raw_tracepoint.cookie); 532 break; 533 case BPF_LINK_TYPE_TRACING: 534 err = get_prog_info(info->prog_id, &prog_info); 535 if (err) 536 return err; 537 538 prog_type_str = libbpf_bpf_prog_type_str(prog_info.type); 539 /* libbpf will return NULL for variants unknown to it. */ 540 if (prog_type_str) 541 jsonw_string_field(json_wtr, "prog_type", prog_type_str); 542 else 543 jsonw_uint_field(json_wtr, "prog_type", prog_info.type); 544 545 show_link_attach_type_json(info->tracing.attach_type, 546 json_wtr); 547 jsonw_uint_field(json_wtr, "target_obj_id", info->tracing.target_obj_id); 548 jsonw_uint_field(json_wtr, "target_btf_id", info->tracing.target_btf_id); 549 jsonw_uint_field(json_wtr, "cookie", info->tracing.cookie); 550 break; 551 case BPF_LINK_TYPE_CGROUP: 552 jsonw_lluint_field(json_wtr, "cgroup_id", 553 info->cgroup.cgroup_id); 554 show_link_attach_type_json(info->cgroup.attach_type, json_wtr); 555 break; 556 case BPF_LINK_TYPE_ITER: 557 show_iter_json(info, json_wtr); 558 break; 559 case BPF_LINK_TYPE_NETNS: 560 jsonw_uint_field(json_wtr, "netns_ino", 561 info->netns.netns_ino); 562 show_link_attach_type_json(info->netns.attach_type, json_wtr); 563 break; 564 case BPF_LINK_TYPE_NETFILTER: 565 netfilter_dump_json(info, json_wtr); 566 break; 567 case BPF_LINK_TYPE_TCX: 568 show_link_ifindex_json(info->tcx.ifindex, json_wtr); 569 show_link_attach_type_json(info->tcx.attach_type, json_wtr); 570 break; 571 case BPF_LINK_TYPE_NETKIT: 572 show_link_ifindex_json(info->netkit.ifindex, json_wtr); 573 show_link_attach_type_json(info->netkit.attach_type, json_wtr); 574 break; 575 case BPF_LINK_TYPE_SOCKMAP: 576 jsonw_uint_field(json_wtr, "map_id", info->sockmap.map_id); 577 show_link_attach_type_json(info->sockmap.attach_type, json_wtr); 578 break; 579 case BPF_LINK_TYPE_XDP: 580 show_link_ifindex_json(info->xdp.ifindex, json_wtr); 581 break; 582 case BPF_LINK_TYPE_STRUCT_OPS: 583 jsonw_uint_field(json_wtr, "map_id", 584 info->struct_ops.map_id); 585 break; 586 case BPF_LINK_TYPE_KPROBE_MULTI: 587 show_kprobe_multi_json(info, json_wtr); 588 break; 589 case BPF_LINK_TYPE_UPROBE_MULTI: 590 show_uprobe_multi_json(info, json_wtr); 591 break; 592 case BPF_LINK_TYPE_PERF_EVENT: 593 switch (info->perf_event.type) { 594 case BPF_PERF_EVENT_EVENT: 595 show_perf_event_event_json(info, json_wtr); 596 break; 597 case BPF_PERF_EVENT_TRACEPOINT: 598 show_perf_event_tracepoint_json(info, json_wtr); 599 break; 600 case BPF_PERF_EVENT_KPROBE: 601 case BPF_PERF_EVENT_KRETPROBE: 602 show_perf_event_kprobe_json(info, json_wtr); 603 break; 604 case BPF_PERF_EVENT_UPROBE: 605 case BPF_PERF_EVENT_URETPROBE: 606 show_perf_event_uprobe_json(info, json_wtr); 607 break; 608 default: 609 break; 610 } 611 break; 612 default: 613 break; 614 } 615 616 if (!hashmap__empty(link_table)) { 617 struct hashmap_entry *entry; 618 619 jsonw_name(json_wtr, "pinned"); 620 jsonw_start_array(json_wtr); 621 hashmap__for_each_key_entry(link_table, entry, info->id) 622 jsonw_string(json_wtr, entry->pvalue); 623 jsonw_end_array(json_wtr); 624 } 625 626 emit_obj_refs_json(refs_table, info->id, json_wtr); 627 628 jsonw_end_object(json_wtr); 629 630 return 0; 631 } 632 633 static void show_link_header_plain(struct bpf_link_info *info) 634 { 635 const char *link_type_str; 636 637 printf("%u: ", info->id); 638 link_type_str = libbpf_bpf_link_type_str(info->type); 639 if (link_type_str) 640 printf("%s ", link_type_str); 641 else 642 printf("type %u ", info->type); 643 644 if (info->type == BPF_LINK_TYPE_STRUCT_OPS) 645 printf("map %u ", info->struct_ops.map_id); 646 else 647 printf("prog %u ", info->prog_id); 648 } 649 650 static void show_link_attach_type_plain(__u32 attach_type) 651 { 652 const char *attach_type_str; 653 654 attach_type_str = libbpf_bpf_attach_type_str(attach_type); 655 if (attach_type_str) 656 printf("attach_type %s ", attach_type_str); 657 else 658 printf("attach_type %u ", attach_type); 659 } 660 661 static void show_link_ifindex_plain(__u32 ifindex) 662 { 663 char devname[IF_NAMESIZE * 2] = "(unknown)"; 664 char tmpname[IF_NAMESIZE]; 665 char *ret = NULL; 666 667 if (ifindex) 668 ret = if_indextoname(ifindex, tmpname); 669 else 670 snprintf(devname, sizeof(devname), "(detached)"); 671 if (ret) 672 snprintf(devname, sizeof(devname), "%s(%u)", 673 tmpname, ifindex); 674 printf("ifindex %s ", devname); 675 } 676 677 static void show_iter_plain(struct bpf_link_info *info) 678 { 679 const char *target_name = u64_to_ptr(info->iter.target_name); 680 681 printf("target_name %s ", target_name); 682 683 if (is_iter_map_target(target_name)) 684 printf("map_id %u ", info->iter.map.map_id); 685 else if (is_iter_task_target(target_name)) { 686 if (info->iter.task.tid) 687 printf("tid %u ", info->iter.task.tid); 688 else if (info->iter.task.pid) 689 printf("pid %u ", info->iter.task.pid); 690 } 691 692 if (is_iter_cgroup_target(target_name)) { 693 printf("cgroup_id %llu ", info->iter.cgroup.cgroup_id); 694 printf("order %s ", 695 cgroup_order_string(info->iter.cgroup.order)); 696 } 697 } 698 699 static const char * const pf2name[] = { 700 [NFPROTO_INET] = "inet", 701 [NFPROTO_IPV4] = "ip", 702 [NFPROTO_ARP] = "arp", 703 [NFPROTO_NETDEV] = "netdev", 704 [NFPROTO_BRIDGE] = "bridge", 705 [NFPROTO_IPV6] = "ip6", 706 }; 707 708 static const char * const inethook2name[] = { 709 [NF_INET_PRE_ROUTING] = "prerouting", 710 [NF_INET_LOCAL_IN] = "input", 711 [NF_INET_FORWARD] = "forward", 712 [NF_INET_LOCAL_OUT] = "output", 713 [NF_INET_POST_ROUTING] = "postrouting", 714 }; 715 716 static const char * const arphook2name[] = { 717 [NF_ARP_IN] = "input", 718 [NF_ARP_OUT] = "output", 719 }; 720 721 void netfilter_dump_plain(const struct bpf_link_info *info) 722 { 723 const char *hookname = NULL, *pfname = NULL; 724 unsigned int hook = info->netfilter.hooknum; 725 unsigned int pf = info->netfilter.pf; 726 727 if (pf < ARRAY_SIZE(pf2name)) 728 pfname = pf2name[pf]; 729 730 switch (pf) { 731 case NFPROTO_BRIDGE: /* bridge shares numbers with enum nf_inet_hooks */ 732 case NFPROTO_IPV4: 733 case NFPROTO_IPV6: 734 case NFPROTO_INET: 735 if (hook < ARRAY_SIZE(inethook2name)) 736 hookname = inethook2name[hook]; 737 break; 738 case NFPROTO_ARP: 739 if (hook < ARRAY_SIZE(arphook2name)) 740 hookname = arphook2name[hook]; 741 default: 742 break; 743 } 744 745 if (pfname) 746 printf("\n\t%s", pfname); 747 else 748 printf("\n\tpf: %u", pf); 749 750 if (hookname) 751 printf(" %s", hookname); 752 else 753 printf(", hook %u,", hook); 754 755 printf(" prio %d", info->netfilter.priority); 756 757 if (info->netfilter.flags) 758 printf(" flags 0x%x", info->netfilter.flags); 759 } 760 761 static void show_kprobe_multi_plain(struct bpf_link_info *info) 762 { 763 struct addr_cookie *data; 764 __u32 i, j = 0; 765 bool is_ibt_enabled; 766 767 if (!info->kprobe_multi.count) 768 return; 769 770 if (info->kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN) 771 printf("\n\tkretprobe.multi "); 772 else 773 printf("\n\tkprobe.multi "); 774 printf("func_cnt %u ", info->kprobe_multi.count); 775 if (info->kprobe_multi.missed) 776 printf("missed %llu ", info->kprobe_multi.missed); 777 data = get_addr_cookie_array(u64_to_ptr(info->kprobe_multi.addrs), 778 u64_to_ptr(info->kprobe_multi.cookies), 779 info->kprobe_multi.count); 780 if (!data) 781 return; 782 783 /* Load it once for all. */ 784 if (!dd.sym_count) 785 kernel_syms_load(&dd); 786 if (!dd.sym_count) 787 goto error; 788 789 is_ibt_enabled = is_x86_ibt_enabled(); 790 printf("\n\t%-16s %-16s %s", "addr", "cookie", "func [module]"); 791 for (i = 0; i < dd.sym_count; i++) { 792 if (!symbol_matches_target(dd.sym_mapping[i].address, 793 data[j].addr, is_ibt_enabled)) 794 continue; 795 printf("\n\t%016lx %-16llx %s", 796 (unsigned long)data[j].addr, data[j].cookie, dd.sym_mapping[i].name); 797 if (dd.sym_mapping[i].module[0] != '\0') 798 printf(" [%s] ", dd.sym_mapping[i].module); 799 else 800 printf(" "); 801 802 if (j++ == info->kprobe_multi.count) 803 break; 804 } 805 error: 806 free(data); 807 } 808 809 static void show_uprobe_multi_plain(struct bpf_link_info *info) 810 { 811 __u32 i; 812 813 if (!info->uprobe_multi.count) 814 return; 815 816 if (info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN) 817 printf("\n\turetprobe.multi "); 818 else 819 printf("\n\tuprobe.multi "); 820 821 printf("path %s ", (char *) u64_to_ptr(info->uprobe_multi.path)); 822 printf("func_cnt %u ", info->uprobe_multi.count); 823 824 if (info->uprobe_multi.pid) 825 printf("pid %u ", info->uprobe_multi.pid); 826 827 printf("\n\t%-16s %-16s %-16s", "offset", "ref_ctr_offset", "cookies"); 828 for (i = 0; i < info->uprobe_multi.count; i++) { 829 printf("\n\t0x%-16llx 0x%-16llx 0x%-16llx", 830 u64_to_arr(info->uprobe_multi.offsets)[i], 831 u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i], 832 u64_to_arr(info->uprobe_multi.cookies)[i]); 833 } 834 } 835 836 static void show_perf_event_kprobe_plain(struct bpf_link_info *info) 837 { 838 const char *buf; 839 840 buf = u64_to_ptr(info->perf_event.kprobe.func_name); 841 if (buf[0] == '\0' && !info->perf_event.kprobe.addr) 842 return; 843 844 if (info->perf_event.type == BPF_PERF_EVENT_KRETPROBE) 845 printf("\n\tkretprobe "); 846 else 847 printf("\n\tkprobe "); 848 if (info->perf_event.kprobe.addr) 849 printf("%llx ", info->perf_event.kprobe.addr); 850 printf("%s", buf); 851 if (info->perf_event.kprobe.offset) 852 printf("+%#x", info->perf_event.kprobe.offset); 853 if (info->perf_event.kprobe.missed) 854 printf(" missed %llu", info->perf_event.kprobe.missed); 855 if (info->perf_event.kprobe.cookie) 856 printf(" cookie %llu", info->perf_event.kprobe.cookie); 857 printf(" "); 858 } 859 860 static void show_perf_event_uprobe_plain(struct bpf_link_info *info) 861 { 862 const char *buf; 863 864 buf = u64_to_ptr(info->perf_event.uprobe.file_name); 865 if (buf[0] == '\0') 866 return; 867 868 if (info->perf_event.type == BPF_PERF_EVENT_URETPROBE) 869 printf("\n\turetprobe "); 870 else 871 printf("\n\tuprobe "); 872 printf("%s+%#x ", buf, info->perf_event.uprobe.offset); 873 if (info->perf_event.uprobe.cookie) 874 printf("cookie %llu ", info->perf_event.uprobe.cookie); 875 if (info->perf_event.uprobe.ref_ctr_offset) 876 printf("ref_ctr_offset 0x%llx ", info->perf_event.uprobe.ref_ctr_offset); 877 } 878 879 static void show_perf_event_tracepoint_plain(struct bpf_link_info *info) 880 { 881 const char *buf; 882 883 buf = u64_to_ptr(info->perf_event.tracepoint.tp_name); 884 if (buf[0] == '\0') 885 return; 886 887 printf("\n\ttracepoint %s ", buf); 888 if (info->perf_event.tracepoint.cookie) 889 printf("cookie %llu ", info->perf_event.tracepoint.cookie); 890 } 891 892 static void show_perf_event_event_plain(struct bpf_link_info *info) 893 { 894 __u64 config = info->perf_event.event.config; 895 __u32 type = info->perf_event.event.type; 896 const char *perf_type, *perf_config; 897 898 printf("\n\tevent "); 899 perf_type = perf_event_name(perf_type_name, type); 900 if (perf_type) 901 printf("%s:", perf_type); 902 else 903 printf("%u :", type); 904 905 perf_config = perf_config_str(type, config); 906 if (perf_config) 907 printf("%s ", perf_config); 908 else 909 printf("%llu ", config); 910 911 if (info->perf_event.event.cookie) 912 printf("cookie %llu ", info->perf_event.event.cookie); 913 914 if (type == PERF_TYPE_HW_CACHE && perf_config) 915 free((void *)perf_config); 916 } 917 918 static int show_link_close_plain(int fd, struct bpf_link_info *info) 919 { 920 struct bpf_prog_info prog_info; 921 const char *prog_type_str; 922 int err; 923 924 show_link_header_plain(info); 925 926 switch (info->type) { 927 case BPF_LINK_TYPE_RAW_TRACEPOINT: 928 printf("\n\ttp '%s' ", 929 (const char *)u64_to_ptr(info->raw_tracepoint.tp_name)); 930 if (info->raw_tracepoint.cookie) 931 printf("cookie %llu ", info->raw_tracepoint.cookie); 932 break; 933 case BPF_LINK_TYPE_TRACING: 934 err = get_prog_info(info->prog_id, &prog_info); 935 if (err) 936 return err; 937 938 prog_type_str = libbpf_bpf_prog_type_str(prog_info.type); 939 /* libbpf will return NULL for variants unknown to it. */ 940 if (prog_type_str) 941 printf("\n\tprog_type %s ", prog_type_str); 942 else 943 printf("\n\tprog_type %u ", prog_info.type); 944 945 show_link_attach_type_plain(info->tracing.attach_type); 946 if (info->tracing.target_obj_id || info->tracing.target_btf_id) 947 printf("\n\ttarget_obj_id %u target_btf_id %u ", 948 info->tracing.target_obj_id, 949 info->tracing.target_btf_id); 950 if (info->tracing.cookie) 951 printf("\n\tcookie %llu ", info->tracing.cookie); 952 break; 953 case BPF_LINK_TYPE_CGROUP: 954 printf("\n\tcgroup_id %zu ", (size_t)info->cgroup.cgroup_id); 955 show_link_attach_type_plain(info->cgroup.attach_type); 956 break; 957 case BPF_LINK_TYPE_ITER: 958 show_iter_plain(info); 959 break; 960 case BPF_LINK_TYPE_NETNS: 961 printf("\n\tnetns_ino %u ", info->netns.netns_ino); 962 show_link_attach_type_plain(info->netns.attach_type); 963 break; 964 case BPF_LINK_TYPE_NETFILTER: 965 netfilter_dump_plain(info); 966 break; 967 case BPF_LINK_TYPE_TCX: 968 printf("\n\t"); 969 show_link_ifindex_plain(info->tcx.ifindex); 970 show_link_attach_type_plain(info->tcx.attach_type); 971 break; 972 case BPF_LINK_TYPE_NETKIT: 973 printf("\n\t"); 974 show_link_ifindex_plain(info->netkit.ifindex); 975 show_link_attach_type_plain(info->netkit.attach_type); 976 break; 977 case BPF_LINK_TYPE_SOCKMAP: 978 printf("\n\t"); 979 printf("map_id %u ", info->sockmap.map_id); 980 show_link_attach_type_plain(info->sockmap.attach_type); 981 break; 982 case BPF_LINK_TYPE_XDP: 983 printf("\n\t"); 984 show_link_ifindex_plain(info->xdp.ifindex); 985 break; 986 case BPF_LINK_TYPE_KPROBE_MULTI: 987 show_kprobe_multi_plain(info); 988 break; 989 case BPF_LINK_TYPE_UPROBE_MULTI: 990 show_uprobe_multi_plain(info); 991 break; 992 case BPF_LINK_TYPE_PERF_EVENT: 993 switch (info->perf_event.type) { 994 case BPF_PERF_EVENT_EVENT: 995 show_perf_event_event_plain(info); 996 break; 997 case BPF_PERF_EVENT_TRACEPOINT: 998 show_perf_event_tracepoint_plain(info); 999 break; 1000 case BPF_PERF_EVENT_KPROBE: 1001 case BPF_PERF_EVENT_KRETPROBE: 1002 show_perf_event_kprobe_plain(info); 1003 break; 1004 case BPF_PERF_EVENT_UPROBE: 1005 case BPF_PERF_EVENT_URETPROBE: 1006 show_perf_event_uprobe_plain(info); 1007 break; 1008 default: 1009 break; 1010 } 1011 break; 1012 default: 1013 break; 1014 } 1015 1016 if (!hashmap__empty(link_table)) { 1017 struct hashmap_entry *entry; 1018 1019 hashmap__for_each_key_entry(link_table, entry, info->id) 1020 printf("\n\tpinned %s", (char *)entry->pvalue); 1021 } 1022 emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 1023 1024 printf("\n"); 1025 1026 return 0; 1027 } 1028 1029 static int do_show_link(int fd) 1030 { 1031 __u64 *ref_ctr_offsets = NULL, *offsets = NULL, *cookies = NULL; 1032 struct bpf_link_info info; 1033 __u32 len = sizeof(info); 1034 char path_buf[PATH_MAX]; 1035 __u64 *addrs = NULL; 1036 char buf[PATH_MAX]; 1037 int count; 1038 int err; 1039 1040 memset(&info, 0, sizeof(info)); 1041 buf[0] = '\0'; 1042 again: 1043 err = bpf_link_get_info_by_fd(fd, &info, &len); 1044 if (err) { 1045 p_err("can't get link info: %s", 1046 strerror(errno)); 1047 close(fd); 1048 return err; 1049 } 1050 if (info.type == BPF_LINK_TYPE_RAW_TRACEPOINT && 1051 !info.raw_tracepoint.tp_name) { 1052 info.raw_tracepoint.tp_name = ptr_to_u64(&buf); 1053 info.raw_tracepoint.tp_name_len = sizeof(buf); 1054 goto again; 1055 } 1056 if (info.type == BPF_LINK_TYPE_ITER && 1057 !info.iter.target_name) { 1058 info.iter.target_name = ptr_to_u64(&buf); 1059 info.iter.target_name_len = sizeof(buf); 1060 goto again; 1061 } 1062 if (info.type == BPF_LINK_TYPE_KPROBE_MULTI && 1063 !info.kprobe_multi.addrs) { 1064 count = info.kprobe_multi.count; 1065 if (count) { 1066 addrs = calloc(count, sizeof(__u64)); 1067 if (!addrs) { 1068 p_err("mem alloc failed"); 1069 close(fd); 1070 return -ENOMEM; 1071 } 1072 info.kprobe_multi.addrs = ptr_to_u64(addrs); 1073 cookies = calloc(count, sizeof(__u64)); 1074 if (!cookies) { 1075 p_err("mem alloc failed"); 1076 free(addrs); 1077 close(fd); 1078 return -ENOMEM; 1079 } 1080 info.kprobe_multi.cookies = ptr_to_u64(cookies); 1081 goto again; 1082 } 1083 } 1084 if (info.type == BPF_LINK_TYPE_UPROBE_MULTI && 1085 !info.uprobe_multi.offsets) { 1086 count = info.uprobe_multi.count; 1087 if (count) { 1088 offsets = calloc(count, sizeof(__u64)); 1089 if (!offsets) { 1090 p_err("mem alloc failed"); 1091 close(fd); 1092 return -ENOMEM; 1093 } 1094 info.uprobe_multi.offsets = ptr_to_u64(offsets); 1095 ref_ctr_offsets = calloc(count, sizeof(__u64)); 1096 if (!ref_ctr_offsets) { 1097 p_err("mem alloc failed"); 1098 free(offsets); 1099 close(fd); 1100 return -ENOMEM; 1101 } 1102 info.uprobe_multi.ref_ctr_offsets = ptr_to_u64(ref_ctr_offsets); 1103 cookies = calloc(count, sizeof(__u64)); 1104 if (!cookies) { 1105 p_err("mem alloc failed"); 1106 free(ref_ctr_offsets); 1107 free(offsets); 1108 close(fd); 1109 return -ENOMEM; 1110 } 1111 info.uprobe_multi.cookies = ptr_to_u64(cookies); 1112 info.uprobe_multi.path = ptr_to_u64(path_buf); 1113 info.uprobe_multi.path_size = sizeof(path_buf); 1114 goto again; 1115 } 1116 } 1117 if (info.type == BPF_LINK_TYPE_PERF_EVENT) { 1118 switch (info.perf_event.type) { 1119 case BPF_PERF_EVENT_TRACEPOINT: 1120 if (!info.perf_event.tracepoint.tp_name) { 1121 info.perf_event.tracepoint.tp_name = ptr_to_u64(&buf); 1122 info.perf_event.tracepoint.name_len = sizeof(buf); 1123 goto again; 1124 } 1125 break; 1126 case BPF_PERF_EVENT_KPROBE: 1127 case BPF_PERF_EVENT_KRETPROBE: 1128 if (!info.perf_event.kprobe.func_name) { 1129 info.perf_event.kprobe.func_name = ptr_to_u64(&buf); 1130 info.perf_event.kprobe.name_len = sizeof(buf); 1131 goto again; 1132 } 1133 break; 1134 case BPF_PERF_EVENT_UPROBE: 1135 case BPF_PERF_EVENT_URETPROBE: 1136 if (!info.perf_event.uprobe.file_name) { 1137 info.perf_event.uprobe.file_name = ptr_to_u64(&buf); 1138 info.perf_event.uprobe.name_len = sizeof(buf); 1139 goto again; 1140 } 1141 break; 1142 default: 1143 break; 1144 } 1145 } 1146 1147 if (json_output) 1148 show_link_close_json(fd, &info); 1149 else 1150 show_link_close_plain(fd, &info); 1151 1152 free(ref_ctr_offsets); 1153 free(cookies); 1154 free(offsets); 1155 free(addrs); 1156 close(fd); 1157 return 0; 1158 } 1159 1160 static int do_show(int argc, char **argv) 1161 { 1162 __u32 id = 0; 1163 int err, fd; 1164 1165 if (show_pinned) { 1166 link_table = hashmap__new(hash_fn_for_key_as_id, 1167 equal_fn_for_key_as_id, NULL); 1168 if (IS_ERR(link_table)) { 1169 p_err("failed to create hashmap for pinned paths"); 1170 return -1; 1171 } 1172 build_pinned_obj_table(link_table, BPF_OBJ_LINK); 1173 } 1174 build_obj_refs_table(&refs_table, BPF_OBJ_LINK); 1175 1176 if (argc == 2) { 1177 fd = link_parse_fd(&argc, &argv); 1178 if (fd < 0) 1179 return fd; 1180 do_show_link(fd); 1181 goto out; 1182 } 1183 1184 if (argc) 1185 return BAD_ARG(); 1186 1187 if (json_output) 1188 jsonw_start_array(json_wtr); 1189 while (true) { 1190 err = bpf_link_get_next_id(id, &id); 1191 if (err) { 1192 if (errno == ENOENT) 1193 break; 1194 p_err("can't get next link: %s%s", strerror(errno), 1195 errno == EINVAL ? " -- kernel too old?" : ""); 1196 break; 1197 } 1198 1199 fd = bpf_link_get_fd_by_id(id); 1200 if (fd < 0) { 1201 if (errno == ENOENT) 1202 continue; 1203 p_err("can't get link by id (%u): %s", 1204 id, strerror(errno)); 1205 break; 1206 } 1207 1208 err = do_show_link(fd); 1209 if (err) 1210 break; 1211 } 1212 if (json_output) 1213 jsonw_end_array(json_wtr); 1214 1215 delete_obj_refs_table(refs_table); 1216 1217 if (show_pinned) 1218 delete_pinned_obj_table(link_table); 1219 1220 out: 1221 if (dd.sym_count) 1222 kernel_syms_destroy(&dd); 1223 return errno == ENOENT ? 0 : -1; 1224 } 1225 1226 static int do_pin(int argc, char **argv) 1227 { 1228 int err; 1229 1230 err = do_pin_any(argc, argv, link_parse_fd); 1231 if (!err && json_output) 1232 jsonw_null(json_wtr); 1233 return err; 1234 } 1235 1236 static int do_detach(int argc, char **argv) 1237 { 1238 int err, fd; 1239 1240 if (argc != 2) { 1241 p_err("link specifier is invalid or missing\n"); 1242 return 1; 1243 } 1244 1245 fd = link_parse_fd(&argc, &argv); 1246 if (fd < 0) 1247 return 1; 1248 1249 err = bpf_link_detach(fd); 1250 if (err) 1251 err = -errno; 1252 close(fd); 1253 if (err) { 1254 p_err("failed link detach: %s", strerror(-err)); 1255 return 1; 1256 } 1257 1258 if (json_output) 1259 jsonw_null(json_wtr); 1260 1261 return 0; 1262 } 1263 1264 static int do_help(int argc, char **argv) 1265 { 1266 if (json_output) { 1267 jsonw_null(json_wtr); 1268 return 0; 1269 } 1270 1271 fprintf(stderr, 1272 "Usage: %1$s %2$s { show | list } [LINK]\n" 1273 " %1$s %2$s pin LINK FILE\n" 1274 " %1$s %2$s detach LINK\n" 1275 " %1$s %2$s help\n" 1276 "\n" 1277 " " HELP_SPEC_LINK "\n" 1278 " " HELP_SPEC_OPTIONS " |\n" 1279 " {-f|--bpffs} | {-n|--nomount} }\n" 1280 "", 1281 bin_name, argv[-2]); 1282 1283 return 0; 1284 } 1285 1286 static const struct cmd cmds[] = { 1287 { "show", do_show }, 1288 { "list", do_show }, 1289 { "help", do_help }, 1290 { "pin", do_pin }, 1291 { "detach", do_detach }, 1292 { 0 } 1293 }; 1294 1295 int do_link(int argc, char **argv) 1296 { 1297 return cmd_select(cmds, argc, argv, do_help); 1298 } 1299