Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | // SPDX-License-Identifier: GPL-2.0 #include <test_progs.h> #include "test_stacktrace_build_id.skel.h" static __u64 read_perf_max_sample_freq(void) { __u64 sample_freq = 5000; /* fallback to 5000 on error */ FILE *f; f = fopen("/proc/sys/kernel/perf_event_max_sample_rate", "r"); if (f == NULL) return sample_freq; fscanf(f, "%llu", &sample_freq); fclose(f); return sample_freq; } void test_stacktrace_build_id_nmi(void) { int control_map_fd, stackid_hmap_fd, stackmap_fd; struct test_stacktrace_build_id *skel; int err, pmu_fd; struct perf_event_attr attr = { .freq = 1, .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, }; __u32 key, previous_key, val, duration = 0; char buf[256]; int i, j; struct bpf_stack_build_id id_offs[PERF_MAX_STACK_DEPTH]; int build_id_matches = 0; int retry = 1; attr.sample_freq = read_perf_max_sample_freq(); retry: skel = test_stacktrace_build_id__open(); if (CHECK(!skel, "skel_open", "skeleton open failed\n")) return; /* override program type */ bpf_program__set_perf_event(skel->progs.oncpu); err = test_stacktrace_build_id__load(skel); if (CHECK(err, "skel_load", "skeleton load failed: %d\n", err)) goto cleanup; pmu_fd = syscall(__NR_perf_event_open, &attr, -1 /* pid */, 0 /* cpu 0 */, -1 /* group id */, 0 /* flags */); if (pmu_fd < 0 && errno == ENOENT) { printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n", __func__); test__skip(); goto cleanup; } if (CHECK(pmu_fd < 0, "perf_event_open", "err %d errno %d\n", pmu_fd, errno)) goto cleanup; skel->links.oncpu = bpf_program__attach_perf_event(skel->progs.oncpu, pmu_fd); if (CHECK(IS_ERR(skel->links.oncpu), "attach_perf_event", "err %ld\n", PTR_ERR(skel->links.oncpu))) { close(pmu_fd); goto cleanup; } /* find map fds */ control_map_fd = bpf_map__fd(skel->maps.control_map); stackid_hmap_fd = bpf_map__fd(skel->maps.stackid_hmap); stackmap_fd = bpf_map__fd(skel->maps.stackmap); if (CHECK_FAIL(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null"))) goto cleanup; if (CHECK_FAIL(system("taskset 0x1 ./urandom_read 100000"))) goto cleanup; /* disable stack trace collection */ key = 0; val = 1; bpf_map_update_elem(control_map_fd, &key, &val, 0); /* for every element in stackid_hmap, we can find a corresponding one * in stackmap, and vise versa. */ err = compare_map_keys(stackid_hmap_fd, stackmap_fd); if (CHECK(err, "compare_map_keys stackid_hmap vs. stackmap", "err %d errno %d\n", err, errno)) goto cleanup; err = compare_map_keys(stackmap_fd, stackid_hmap_fd); if (CHECK(err, "compare_map_keys stackmap vs. stackid_hmap", "err %d errno %d\n", err, errno)) goto cleanup; err = extract_build_id(buf, 256); if (CHECK(err, "get build_id with readelf", "err %d errno %d\n", err, errno)) goto cleanup; err = bpf_map_get_next_key(stackmap_fd, NULL, &key); if (CHECK(err, "get_next_key from stackmap", "err %d, errno %d\n", err, errno)) goto cleanup; do { char build_id[64]; err = bpf_map_lookup_elem(stackmap_fd, &key, id_offs); if (CHECK(err, "lookup_elem from stackmap", "err %d, errno %d\n", err, errno)) goto cleanup; for (i = 0; i < PERF_MAX_STACK_DEPTH; ++i) if (id_offs[i].status == BPF_STACK_BUILD_ID_VALID && id_offs[i].offset != 0) { for (j = 0; j < 20; ++j) sprintf(build_id + 2 * j, "%02x", id_offs[i].build_id[j] & 0xff); if (strstr(buf, build_id) != NULL) build_id_matches = 1; } previous_key = key; } while (bpf_map_get_next_key(stackmap_fd, &previous_key, &key) == 0); /* stack_map_get_build_id_offset() is racy and sometimes can return * BPF_STACK_BUILD_ID_IP instead of BPF_STACK_BUILD_ID_VALID; * try it one more time. */ if (build_id_matches < 1 && retry--) { test_stacktrace_build_id__destroy(skel); printf("%s:WARN:Didn't find expected build ID from the map, retrying\n", __func__); goto retry; } if (CHECK(build_id_matches < 1, "build id match", "Didn't find expected build ID from the map\n")) goto cleanup; /* * We intentionally skip compare_stack_ips(). This is because we * only support one in_nmi() ips-to-build_id translation per cpu * at any time, thus stack_amap here will always fallback to * BPF_STACK_BUILD_ID_IP; */ cleanup: test_stacktrace_build_id__destroy(skel); } |