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

selftests/bpf: move get_ksyms and get_addrs to trace_helpers.c

We need to get all the kernel function that can be traced sometimes, so we
move the get_syms() and get_addrs() in kprobe_multi_test.c to
trace_helpers.c and rename it to bpf_get_ksyms() and bpf_get_addrs().

Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
Link: https://lore.kernel.org/r/20250904021011.14069-2-dongml2@chinatelecom.cn
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Menglong Dong and committed by
Alexei Starovoitov
8bad31ed c9110e6f

+220 -217
+3 -217
tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
··· 422 422 kprobe_multi__destroy(skel); 423 423 } 424 424 425 - static size_t symbol_hash(long key, void *ctx __maybe_unused) 426 - { 427 - return str_hash((const char *) key); 428 - } 429 - 430 - static bool symbol_equal(long key1, long key2, void *ctx __maybe_unused) 431 - { 432 - return strcmp((const char *) key1, (const char *) key2) == 0; 433 - } 434 - 435 - static bool is_invalid_entry(char *buf, bool kernel) 436 - { 437 - if (kernel && strchr(buf, '[')) 438 - return true; 439 - if (!kernel && !strchr(buf, '[')) 440 - return true; 441 - return false; 442 - } 443 - 444 - static bool skip_entry(char *name) 445 - { 446 - /* 447 - * We attach to almost all kernel functions and some of them 448 - * will cause 'suspicious RCU usage' when fprobe is attached 449 - * to them. Filter out the current culprits - arch_cpu_idle 450 - * default_idle and rcu_* functions. 451 - */ 452 - if (!strcmp(name, "arch_cpu_idle")) 453 - return true; 454 - if (!strcmp(name, "default_idle")) 455 - return true; 456 - if (!strncmp(name, "rcu_", 4)) 457 - return true; 458 - if (!strcmp(name, "bpf_dispatcher_xdp_func")) 459 - return true; 460 - if (!strncmp(name, "__ftrace_invalid_address__", 461 - sizeof("__ftrace_invalid_address__") - 1)) 462 - return true; 463 - return false; 464 - } 465 - 466 - /* Do comparison by ignoring '.llvm.<hash>' suffixes. */ 467 - static int compare_name(const char *name1, const char *name2) 468 - { 469 - const char *res1, *res2; 470 - int len1, len2; 471 - 472 - res1 = strstr(name1, ".llvm."); 473 - res2 = strstr(name2, ".llvm."); 474 - len1 = res1 ? res1 - name1 : strlen(name1); 475 - len2 = res2 ? res2 - name2 : strlen(name2); 476 - 477 - if (len1 == len2) 478 - return strncmp(name1, name2, len1); 479 - if (len1 < len2) 480 - return strncmp(name1, name2, len1) <= 0 ? -1 : 1; 481 - return strncmp(name1, name2, len2) >= 0 ? 1 : -1; 482 - } 483 - 484 - static int load_kallsyms_compare(const void *p1, const void *p2) 485 - { 486 - return compare_name(((const struct ksym *)p1)->name, ((const struct ksym *)p2)->name); 487 - } 488 - 489 - static int search_kallsyms_compare(const void *p1, const struct ksym *p2) 490 - { 491 - return compare_name(p1, p2->name); 492 - } 493 - 494 - static int get_syms(char ***symsp, size_t *cntp, bool kernel) 495 - { 496 - size_t cap = 0, cnt = 0; 497 - char *name = NULL, *ksym_name, **syms = NULL; 498 - struct hashmap *map; 499 - struct ksyms *ksyms; 500 - struct ksym *ks; 501 - char buf[256]; 502 - FILE *f; 503 - int err = 0; 504 - 505 - ksyms = load_kallsyms_custom_local(load_kallsyms_compare); 506 - if (!ASSERT_OK_PTR(ksyms, "load_kallsyms_custom_local")) 507 - return -EINVAL; 508 - 509 - /* 510 - * The available_filter_functions contains many duplicates, 511 - * but other than that all symbols are usable in kprobe multi 512 - * interface. 513 - * Filtering out duplicates by using hashmap__add, which won't 514 - * add existing entry. 515 - */ 516 - 517 - if (access("/sys/kernel/tracing/trace", F_OK) == 0) 518 - f = fopen("/sys/kernel/tracing/available_filter_functions", "r"); 519 - else 520 - f = fopen("/sys/kernel/debug/tracing/available_filter_functions", "r"); 521 - 522 - if (!f) 523 - return -EINVAL; 524 - 525 - map = hashmap__new(symbol_hash, symbol_equal, NULL); 526 - if (IS_ERR(map)) { 527 - err = libbpf_get_error(map); 528 - goto error; 529 - } 530 - 531 - while (fgets(buf, sizeof(buf), f)) { 532 - if (is_invalid_entry(buf, kernel)) 533 - continue; 534 - 535 - free(name); 536 - if (sscanf(buf, "%ms$*[^\n]\n", &name) != 1) 537 - continue; 538 - if (skip_entry(name)) 539 - continue; 540 - 541 - ks = search_kallsyms_custom_local(ksyms, name, search_kallsyms_compare); 542 - if (!ks) { 543 - err = -EINVAL; 544 - goto error; 545 - } 546 - 547 - ksym_name = ks->name; 548 - err = hashmap__add(map, ksym_name, 0); 549 - if (err == -EEXIST) { 550 - err = 0; 551 - continue; 552 - } 553 - if (err) 554 - goto error; 555 - 556 - err = libbpf_ensure_mem((void **) &syms, &cap, 557 - sizeof(*syms), cnt + 1); 558 - if (err) 559 - goto error; 560 - 561 - syms[cnt++] = ksym_name; 562 - } 563 - 564 - *symsp = syms; 565 - *cntp = cnt; 566 - 567 - error: 568 - free(name); 569 - fclose(f); 570 - hashmap__free(map); 571 - if (err) 572 - free(syms); 573 - return err; 574 - } 575 - 576 - static int get_addrs(unsigned long **addrsp, size_t *cntp, bool kernel) 577 - { 578 - unsigned long *addr, *addrs, *tmp_addrs; 579 - int err = 0, max_cnt, inc_cnt; 580 - char *name = NULL; 581 - size_t cnt = 0; 582 - char buf[256]; 583 - FILE *f; 584 - 585 - if (access("/sys/kernel/tracing/trace", F_OK) == 0) 586 - f = fopen("/sys/kernel/tracing/available_filter_functions_addrs", "r"); 587 - else 588 - f = fopen("/sys/kernel/debug/tracing/available_filter_functions_addrs", "r"); 589 - 590 - if (!f) 591 - return -ENOENT; 592 - 593 - /* In my local setup, the number of entries is 50k+ so Let us initially 594 - * allocate space to hold 64k entries. If 64k is not enough, incrementally 595 - * increase 1k each time. 596 - */ 597 - max_cnt = 65536; 598 - inc_cnt = 1024; 599 - addrs = malloc(max_cnt * sizeof(long)); 600 - if (addrs == NULL) { 601 - err = -ENOMEM; 602 - goto error; 603 - } 604 - 605 - while (fgets(buf, sizeof(buf), f)) { 606 - if (is_invalid_entry(buf, kernel)) 607 - continue; 608 - 609 - free(name); 610 - if (sscanf(buf, "%p %ms$*[^\n]\n", &addr, &name) != 2) 611 - continue; 612 - if (skip_entry(name)) 613 - continue; 614 - 615 - if (cnt == max_cnt) { 616 - max_cnt += inc_cnt; 617 - tmp_addrs = realloc(addrs, max_cnt); 618 - if (!tmp_addrs) { 619 - err = -ENOMEM; 620 - goto error; 621 - } 622 - addrs = tmp_addrs; 623 - } 624 - 625 - addrs[cnt++] = (unsigned long)addr; 626 - } 627 - 628 - *addrsp = addrs; 629 - *cntp = cnt; 630 - 631 - error: 632 - free(name); 633 - fclose(f); 634 - if (err) 635 - free(addrs); 636 - return err; 637 - } 638 - 639 425 static void do_bench_test(struct kprobe_multi_empty *skel, struct bpf_kprobe_multi_opts *opts) 640 426 { 641 427 long attach_start_ns, attach_end_ns; ··· 456 670 char **syms = NULL; 457 671 size_t cnt = 0; 458 672 459 - if (!ASSERT_OK(get_syms(&syms, &cnt, kernel), "get_syms")) 673 + if (!ASSERT_OK(bpf_get_ksyms(&syms, &cnt, kernel), "bpf_get_ksyms")) 460 674 return; 461 675 462 676 skel = kprobe_multi_empty__open_and_load(); ··· 482 696 size_t cnt = 0; 483 697 int err; 484 698 485 - err = get_addrs(&addrs, &cnt, kernel); 699 + err = bpf_get_addrs(&addrs, &cnt, kernel); 486 700 if (err == -ENOENT) { 487 701 test__skip(); 488 702 return; 489 703 } 490 704 491 - if (!ASSERT_OK(err, "get_addrs")) 705 + if (!ASSERT_OK(err, "bpf_get_addrs")) 492 706 return; 493 707 494 708 skel = kprobe_multi_empty__open_and_load();
+214
tools/testing/selftests/bpf/trace_helpers.c
··· 17 17 #include <linux/limits.h> 18 18 #include <libelf.h> 19 19 #include <gelf.h> 20 + #include "bpf/hashmap.h" 20 21 #include "bpf/libbpf_internal.h" 21 22 22 23 #define TRACEFS_PIPE "/sys/kernel/tracing/trace_pipe" ··· 519 518 void read_trace_pipe(void) 520 519 { 521 520 read_trace_pipe_iter(trace_pipe_cb, NULL, 0); 521 + } 522 + 523 + static size_t symbol_hash(long key, void *ctx __maybe_unused) 524 + { 525 + return str_hash((const char *) key); 526 + } 527 + 528 + static bool symbol_equal(long key1, long key2, void *ctx __maybe_unused) 529 + { 530 + return strcmp((const char *) key1, (const char *) key2) == 0; 531 + } 532 + 533 + static bool is_invalid_entry(char *buf, bool kernel) 534 + { 535 + if (kernel && strchr(buf, '[')) 536 + return true; 537 + if (!kernel && !strchr(buf, '[')) 538 + return true; 539 + return false; 540 + } 541 + 542 + static bool skip_entry(char *name) 543 + { 544 + /* 545 + * We attach to almost all kernel functions and some of them 546 + * will cause 'suspicious RCU usage' when fprobe is attached 547 + * to them. Filter out the current culprits - arch_cpu_idle 548 + * default_idle and rcu_* functions. 549 + */ 550 + if (!strcmp(name, "arch_cpu_idle")) 551 + return true; 552 + if (!strcmp(name, "default_idle")) 553 + return true; 554 + if (!strncmp(name, "rcu_", 4)) 555 + return true; 556 + if (!strcmp(name, "bpf_dispatcher_xdp_func")) 557 + return true; 558 + if (!strncmp(name, "__ftrace_invalid_address__", 559 + sizeof("__ftrace_invalid_address__") - 1)) 560 + return true; 561 + return false; 562 + } 563 + 564 + /* Do comparison by ignoring '.llvm.<hash>' suffixes. */ 565 + static int compare_name(const char *name1, const char *name2) 566 + { 567 + const char *res1, *res2; 568 + int len1, len2; 569 + 570 + res1 = strstr(name1, ".llvm."); 571 + res2 = strstr(name2, ".llvm."); 572 + len1 = res1 ? res1 - name1 : strlen(name1); 573 + len2 = res2 ? res2 - name2 : strlen(name2); 574 + 575 + if (len1 == len2) 576 + return strncmp(name1, name2, len1); 577 + if (len1 < len2) 578 + return strncmp(name1, name2, len1) <= 0 ? -1 : 1; 579 + return strncmp(name1, name2, len2) >= 0 ? 1 : -1; 580 + } 581 + 582 + static int load_kallsyms_compare(const void *p1, const void *p2) 583 + { 584 + return compare_name(((const struct ksym *)p1)->name, ((const struct ksym *)p2)->name); 585 + } 586 + 587 + static int search_kallsyms_compare(const void *p1, const struct ksym *p2) 588 + { 589 + return compare_name(p1, p2->name); 590 + } 591 + 592 + int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel) 593 + { 594 + size_t cap = 0, cnt = 0; 595 + char *name = NULL, *ksym_name, **syms = NULL; 596 + struct hashmap *map; 597 + struct ksyms *ksyms; 598 + struct ksym *ks; 599 + char buf[256]; 600 + FILE *f; 601 + int err = 0; 602 + 603 + ksyms = load_kallsyms_custom_local(load_kallsyms_compare); 604 + if (!ksyms) 605 + return -EINVAL; 606 + 607 + /* 608 + * The available_filter_functions contains many duplicates, 609 + * but other than that all symbols are usable to trace. 610 + * Filtering out duplicates by using hashmap__add, which won't 611 + * add existing entry. 612 + */ 613 + 614 + if (access("/sys/kernel/tracing/trace", F_OK) == 0) 615 + f = fopen("/sys/kernel/tracing/available_filter_functions", "r"); 616 + else 617 + f = fopen("/sys/kernel/debug/tracing/available_filter_functions", "r"); 618 + 619 + if (!f) 620 + return -EINVAL; 621 + 622 + map = hashmap__new(symbol_hash, symbol_equal, NULL); 623 + if (IS_ERR(map)) { 624 + err = libbpf_get_error(map); 625 + goto error; 626 + } 627 + 628 + while (fgets(buf, sizeof(buf), f)) { 629 + if (is_invalid_entry(buf, kernel)) 630 + continue; 631 + 632 + free(name); 633 + if (sscanf(buf, "%ms$*[^\n]\n", &name) != 1) 634 + continue; 635 + if (skip_entry(name)) 636 + continue; 637 + 638 + ks = search_kallsyms_custom_local(ksyms, name, search_kallsyms_compare); 639 + if (!ks) { 640 + err = -EINVAL; 641 + goto error; 642 + } 643 + 644 + ksym_name = ks->name; 645 + err = hashmap__add(map, ksym_name, 0); 646 + if (err == -EEXIST) { 647 + err = 0; 648 + continue; 649 + } 650 + if (err) 651 + goto error; 652 + 653 + err = libbpf_ensure_mem((void **) &syms, &cap, 654 + sizeof(*syms), cnt + 1); 655 + if (err) 656 + goto error; 657 + 658 + syms[cnt++] = ksym_name; 659 + } 660 + 661 + *symsp = syms; 662 + *cntp = cnt; 663 + 664 + error: 665 + free(name); 666 + fclose(f); 667 + hashmap__free(map); 668 + if (err) 669 + free(syms); 670 + return err; 671 + } 672 + 673 + int bpf_get_addrs(unsigned long **addrsp, size_t *cntp, bool kernel) 674 + { 675 + unsigned long *addr, *addrs, *tmp_addrs; 676 + int err = 0, max_cnt, inc_cnt; 677 + char *name = NULL; 678 + size_t cnt = 0; 679 + char buf[256]; 680 + FILE *f; 681 + 682 + if (access("/sys/kernel/tracing/trace", F_OK) == 0) 683 + f = fopen("/sys/kernel/tracing/available_filter_functions_addrs", "r"); 684 + else 685 + f = fopen("/sys/kernel/debug/tracing/available_filter_functions_addrs", "r"); 686 + 687 + if (!f) 688 + return -ENOENT; 689 + 690 + /* In my local setup, the number of entries is 50k+ so Let us initially 691 + * allocate space to hold 64k entries. If 64k is not enough, incrementally 692 + * increase 1k each time. 693 + */ 694 + max_cnt = 65536; 695 + inc_cnt = 1024; 696 + addrs = malloc(max_cnt * sizeof(long)); 697 + if (addrs == NULL) { 698 + err = -ENOMEM; 699 + goto error; 700 + } 701 + 702 + while (fgets(buf, sizeof(buf), f)) { 703 + if (is_invalid_entry(buf, kernel)) 704 + continue; 705 + 706 + free(name); 707 + if (sscanf(buf, "%p %ms$*[^\n]\n", &addr, &name) != 2) 708 + continue; 709 + if (skip_entry(name)) 710 + continue; 711 + 712 + if (cnt == max_cnt) { 713 + max_cnt += inc_cnt; 714 + tmp_addrs = realloc(addrs, max_cnt); 715 + if (!tmp_addrs) { 716 + err = -ENOMEM; 717 + goto error; 718 + } 719 + addrs = tmp_addrs; 720 + } 721 + 722 + addrs[cnt++] = (unsigned long)addr; 723 + } 724 + 725 + *addrsp = addrs; 726 + *cntp = cnt; 727 + 728 + error: 729 + free(name); 730 + fclose(f); 731 + if (err) 732 + free(addrs); 733 + return err; 522 734 }
+3
tools/testing/selftests/bpf/trace_helpers.h
··· 41 41 42 42 int read_build_id(const char *path, char *build_id, size_t size); 43 43 44 + int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel); 45 + int bpf_get_addrs(unsigned long **addrsp, size_t *cntp, bool kernel); 46 + 44 47 #endif