1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3 #include <test_progs.h> 4 5 #include "test_build_id.skel.h" 6 7 static char build_id[BPF_BUILD_ID_SIZE]; 8 static int build_id_sz; 9 10 static void print_stack(struct bpf_stack_build_id *stack, int frame_cnt) 11 { 12 int i, j; 13 14 for (i = 0; i < frame_cnt; i++) { 15 printf("FRAME #%02d: ", i); 16 switch (stack[i].status) { 17 case BPF_STACK_BUILD_ID_EMPTY: 18 printf("<EMPTY>\n"); 19 break; 20 case BPF_STACK_BUILD_ID_VALID: 21 printf("BUILD ID = "); 22 for (j = 0; j < BPF_BUILD_ID_SIZE; j++) 23 printf("%02hhx", (unsigned)stack[i].build_id[j]); 24 printf(" OFFSET = %llx", (unsigned long long)stack[i].offset); 25 break; 26 case BPF_STACK_BUILD_ID_IP: 27 printf("IP = %llx", (unsigned long long)stack[i].ip); 28 break; 29 default: 30 printf("UNEXPECTED STATUS %d ", stack[i].status); 31 break; 32 } 33 printf("\n"); 34 } 35 } 36 37 static void subtest_nofault(bool build_id_resident) 38 { 39 struct test_build_id *skel; 40 struct bpf_stack_build_id *stack; 41 int frame_cnt; 42 43 skel = test_build_id__open_and_load(); 44 if (!ASSERT_OK_PTR(skel, "skel_open")) 45 return; 46 47 skel->links.uprobe_nofault = bpf_program__attach(skel->progs.uprobe_nofault); 48 if (!ASSERT_OK_PTR(skel->links.uprobe_nofault, "link")) 49 goto cleanup; 50 51 if (build_id_resident) 52 ASSERT_OK(system("./uprobe_multi uprobe-paged-in"), "trigger_uprobe"); 53 else 54 ASSERT_OK(system("./uprobe_multi uprobe-paged-out"), "trigger_uprobe"); 55 56 if (!ASSERT_GT(skel->bss->res_nofault, 0, "res")) 57 goto cleanup; 58 59 stack = skel->bss->stack_nofault; 60 frame_cnt = skel->bss->res_nofault / sizeof(struct bpf_stack_build_id); 61 if (env.verbosity >= VERBOSE_NORMAL) 62 print_stack(stack, frame_cnt); 63 64 if (build_id_resident) { 65 ASSERT_EQ(stack[0].status, BPF_STACK_BUILD_ID_VALID, "build_id_status"); 66 ASSERT_EQ(memcmp(stack[0].build_id, build_id, build_id_sz), 0, "build_id_match"); 67 } else { 68 ASSERT_EQ(stack[0].status, BPF_STACK_BUILD_ID_IP, "build_id_status"); 69 } 70 71 cleanup: 72 test_build_id__destroy(skel); 73 } 74 75 static void subtest_sleepable(void) 76 { 77 struct test_build_id *skel; 78 struct bpf_stack_build_id *stack; 79 int frame_cnt; 80 81 skel = test_build_id__open_and_load(); 82 if (!ASSERT_OK_PTR(skel, "skel_open")) 83 return; 84 85 skel->links.uprobe_sleepable = bpf_program__attach(skel->progs.uprobe_sleepable); 86 if (!ASSERT_OK_PTR(skel->links.uprobe_sleepable, "link")) 87 goto cleanup; 88 89 /* force build ID to not be paged in */ 90 ASSERT_OK(system("./uprobe_multi uprobe-paged-out"), "trigger_uprobe"); 91 92 if (!ASSERT_GT(skel->bss->res_sleepable, 0, "res")) 93 goto cleanup; 94 95 stack = skel->bss->stack_sleepable; 96 frame_cnt = skel->bss->res_sleepable / sizeof(struct bpf_stack_build_id); 97 if (env.verbosity >= VERBOSE_NORMAL) 98 print_stack(stack, frame_cnt); 99 100 ASSERT_EQ(stack[0].status, BPF_STACK_BUILD_ID_VALID, "build_id_status"); 101 ASSERT_EQ(memcmp(stack[0].build_id, build_id, build_id_sz), 0, "build_id_match"); 102 103 cleanup: 104 test_build_id__destroy(skel); 105 } 106 107 void serial_test_build_id(void) 108 { 109 build_id_sz = read_build_id("uprobe_multi", build_id, sizeof(build_id)); 110 ASSERT_EQ(build_id_sz, BPF_BUILD_ID_SIZE, "parse_build_id"); 111 112 if (test__start_subtest("nofault-paged-out")) 113 subtest_nofault(false /* not resident */); 114 if (test__start_subtest("nofault-paged-in")) 115 subtest_nofault(true /* resident */); 116 if (test__start_subtest("sleepable")) 117 subtest_sleepable(); 118 } 119