1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <stdio.h> 4 #include <string.h> 5 #include <stdbool.h> 6 #include <stdint.h> 7 #include <sys/mman.h> 8 #include <unistd.h> 9 #include <sdt.h> 10 11 #ifndef MADV_POPULATE_READ 12 #define MADV_POPULATE_READ 22 13 #endif 14 15 int __attribute__((weak)) uprobe(void) 16 { 17 return 0; 18 } 19 20 #define __PASTE(a, b) a##b 21 #define PASTE(a, b) __PASTE(a, b) 22 23 #define NAME(name, idx) PASTE(name, idx) 24 25 #define DEF(name, idx) int __attribute__((weak)) NAME(name, idx)(void) { return 0; } 26 #define CALL(name, idx) NAME(name, idx)(); 27 28 #define F(body, name, idx) body(name, idx) 29 30 #define F10(body, name, idx) \ 31 F(body, PASTE(name, idx), 0) F(body, PASTE(name, idx), 1) F(body, PASTE(name, idx), 2) \ 32 F(body, PASTE(name, idx), 3) F(body, PASTE(name, idx), 4) F(body, PASTE(name, idx), 5) \ 33 F(body, PASTE(name, idx), 6) F(body, PASTE(name, idx), 7) F(body, PASTE(name, idx), 8) \ 34 F(body, PASTE(name, idx), 9) 35 36 #define F100(body, name, idx) \ 37 F10(body, PASTE(name, idx), 0) F10(body, PASTE(name, idx), 1) F10(body, PASTE(name, idx), 2) \ 38 F10(body, PASTE(name, idx), 3) F10(body, PASTE(name, idx), 4) F10(body, PASTE(name, idx), 5) \ 39 F10(body, PASTE(name, idx), 6) F10(body, PASTE(name, idx), 7) F10(body, PASTE(name, idx), 8) \ 40 F10(body, PASTE(name, idx), 9) 41 42 #define F1000(body, name, idx) \ 43 F100(body, PASTE(name, idx), 0) F100(body, PASTE(name, idx), 1) F100(body, PASTE(name, idx), 2) \ 44 F100(body, PASTE(name, idx), 3) F100(body, PASTE(name, idx), 4) F100(body, PASTE(name, idx), 5) \ 45 F100(body, PASTE(name, idx), 6) F100(body, PASTE(name, idx), 7) F100(body, PASTE(name, idx), 8) \ 46 F100(body, PASTE(name, idx), 9) 47 48 #define F10000(body, name, idx) \ 49 F1000(body, PASTE(name, idx), 0) F1000(body, PASTE(name, idx), 1) F1000(body, PASTE(name, idx), 2) \ 50 F1000(body, PASTE(name, idx), 3) F1000(body, PASTE(name, idx), 4) F1000(body, PASTE(name, idx), 5) \ 51 F1000(body, PASTE(name, idx), 6) F1000(body, PASTE(name, idx), 7) F1000(body, PASTE(name, idx), 8) \ 52 F1000(body, PASTE(name, idx), 9) 53 54 F10000(DEF, uprobe_multi_func_, 0) 55 F10000(DEF, uprobe_multi_func_, 1) 56 F10000(DEF, uprobe_multi_func_, 2) 57 F10000(DEF, uprobe_multi_func_, 3) 58 F10000(DEF, uprobe_multi_func_, 4) 59 60 static int bench(void) 61 { 62 F10000(CALL, uprobe_multi_func_, 0) 63 F10000(CALL, uprobe_multi_func_, 1) 64 F10000(CALL, uprobe_multi_func_, 2) 65 F10000(CALL, uprobe_multi_func_, 3) 66 F10000(CALL, uprobe_multi_func_, 4) 67 return 0; 68 } 69 70 #define PROBE STAP_PROBE(test, usdt); 71 72 #define PROBE10 PROBE PROBE PROBE PROBE PROBE \ 73 PROBE PROBE PROBE PROBE PROBE 74 #define PROBE100 PROBE10 PROBE10 PROBE10 PROBE10 PROBE10 \ 75 PROBE10 PROBE10 PROBE10 PROBE10 PROBE10 76 #define PROBE1000 PROBE100 PROBE100 PROBE100 PROBE100 PROBE100 \ 77 PROBE100 PROBE100 PROBE100 PROBE100 PROBE100 78 #define PROBE10000 PROBE1000 PROBE1000 PROBE1000 PROBE1000 PROBE1000 \ 79 PROBE1000 PROBE1000 PROBE1000 PROBE1000 PROBE1000 80 81 static int usdt(void) 82 { 83 PROBE10000 84 PROBE10000 85 PROBE10000 86 PROBE10000 87 PROBE10000 88 return 0; 89 } 90 91 extern char build_id_start[]; 92 extern char build_id_end[]; 93 94 int __attribute__((weak)) trigger_uprobe(bool build_id_resident) 95 { 96 int page_sz = sysconf(_SC_PAGESIZE); 97 void *addr; 98 99 /* page-align build ID start */ 100 addr = (void *)((uintptr_t)&build_id_start & ~(page_sz - 1)); 101 102 /* to guarantee MADV_PAGEOUT work reliably, we need to ensure that 103 * memory range is mapped into current process, so we unconditionally 104 * do MADV_POPULATE_READ, and then MADV_PAGEOUT, if necessary 105 */ 106 madvise(addr, page_sz, MADV_POPULATE_READ); 107 if (!build_id_resident) 108 madvise(addr, page_sz, MADV_PAGEOUT); 109 110 (void)uprobe(); 111 112 return 0; 113 } 114 115 int main(int argc, char **argv) 116 { 117 if (argc != 2) 118 goto error; 119 120 if (!strcmp("bench", argv[1])) 121 return bench(); 122 if (!strcmp("usdt", argv[1])) 123 return usdt(); 124 if (!strcmp("uprobe-paged-out", argv[1])) 125 return trigger_uprobe(false /* page-out build ID */); 126 if (!strcmp("uprobe-paged-in", argv[1])) 127 return trigger_uprobe(true /* page-in build ID */); 128 129 error: 130 fprintf(stderr, "usage: %s <bench|usdt>\n", argv[0]); 131 return -1; 132 } 133