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

perf test: Add kallsyms split test

Create a fake root directory for /proc/{version,modules,kallsyms} in
/tmp for testing. The kallsyms has a bad symbol in the module and it
causes the main map splitted. The test ensures it only has two maps -
kernel and the module and it finds the initial map after the module
without creating the split maps like [kernel].0 and so on.

$ perf test -vv "split kallsyms"
69: split kallsyms:
--- start ---
test child forked, pid 1016196
try to create fake root directory
create kernel maps from the fake root directory
maps__set_modules_path_dir: cannot open /tmp/perf-test.Zrv6Sy/lib/modules/X.Y.Z dir
Problems setting modules path maps, continuing anyway...
Failed to open /tmp/perf-test.Zrv6Sy/proc/kcore. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.
Using /tmp/perf-test.Zrv6Sy/proc/kallsyms for symbols
kernel map loaded - check symbol and map
---- end(0) ----
69: split kallsyms : Ok

Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

+159
+1
tools/perf/tests/Build
··· 69 69 perf-test-y += hwmon_pmu.o 70 70 perf-test-y += tool_pmu.o 71 71 perf-test-y += subcmd-help.o 72 + perf-test-y += kallsyms-split.o 72 73 73 74 ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc)) 74 75 perf-test-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
+1
tools/perf/tests/builtin-test.c
··· 140 140 &suite__symbols, 141 141 &suite__util, 142 142 &suite__subcmd_help, 143 + &suite__kallsyms_split, 143 144 NULL, 144 145 }; 145 146
+156
tools/perf/tests/kallsyms-split.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/compiler.h> 3 + #include <fcntl.h> 4 + #include <signal.h> 5 + #include <unistd.h> 6 + #include <sys/stat.h> 7 + #include "util/dso.h" 8 + #include "util/map.h" 9 + #include "util/symbol.h" 10 + #include "util/debug.h" 11 + #include "util/machine.h" 12 + #include "tests.h" 13 + 14 + /* 15 + * This test is to check whether a bad symbol in a module won't split kallsyms maps. 16 + * The main_symbol[1-3] should belong to the main [kernel.kallsyms] map even if the 17 + * bad_symbol from the module is found in the middle. 18 + */ 19 + static char root_template[] = "/tmp/perf-test.XXXXXX"; 20 + static char *root_dir; 21 + 22 + static const char proc_version[] = "Linux version X.Y.Z (just for perf test)\n"; 23 + static const char proc_modules[] = "module 4096 1 - Live 0xffffffffcd000000\n"; 24 + static const char proc_kallsyms[] = 25 + "ffffffffab200000 T _stext\n" 26 + "ffffffffab200010 T good_symbol\n" 27 + "ffffffffab200020 t bad_symbol\n" 28 + "ffffffffab200030 t main_symbol1\n" 29 + "ffffffffab200040 t main_symbol2\n" 30 + "ffffffffab200050 t main_symbol3\n" 31 + "ffffffffab200060 T _etext\n" 32 + "ffffffffcd000000 T start_module\t[module]\n" 33 + "ffffffffab200020 u bad_symbol\t[module]\n" 34 + "ffffffffcd000040 T end_module\t[module]\n"; 35 + 36 + static struct { 37 + const char *name; 38 + const char *contents; 39 + long len; 40 + } proc_files[] = { 41 + { "version", proc_version, sizeof(proc_version) - 1 }, 42 + { "modules", proc_modules, sizeof(proc_modules) - 1 }, 43 + { "kallsyms", proc_kallsyms, sizeof(proc_kallsyms) - 1 }, 44 + }; 45 + 46 + static void remove_proc_dir(int sig __maybe_unused) 47 + { 48 + char buf[128]; 49 + 50 + if (root_dir == NULL) 51 + return; 52 + 53 + for (unsigned i = 0; i < ARRAY_SIZE(proc_files); i++) { 54 + scnprintf(buf, sizeof(buf), "%s/proc/%s", root_dir, proc_files[i].name); 55 + remove(buf); 56 + } 57 + 58 + scnprintf(buf, sizeof(buf), "%s/proc", root_dir); 59 + rmdir(buf); 60 + 61 + rmdir(root_dir); 62 + root_dir = NULL; 63 + } 64 + 65 + static int create_proc_dir(void) 66 + { 67 + char buf[128]; 68 + 69 + root_dir = mkdtemp(root_template); 70 + if (root_dir == NULL) 71 + return -1; 72 + 73 + scnprintf(buf, sizeof(buf), "%s/proc", root_dir); 74 + if (mkdir(buf, 0700) < 0) 75 + goto err; 76 + 77 + for (unsigned i = 0; i < ARRAY_SIZE(proc_files); i++) { 78 + int fd, len; 79 + 80 + scnprintf(buf, sizeof(buf), "%s/proc/%s", root_dir, proc_files[i].name); 81 + fd = open(buf, O_RDWR | O_CREAT, 0600); 82 + if (fd < 0) 83 + goto err; 84 + 85 + len = write(fd, proc_files[i].contents, proc_files[i].len); 86 + close(fd); 87 + if (len != proc_files[i].len) 88 + goto err; 89 + } 90 + return 0; 91 + 92 + err: 93 + remove_proc_dir(0); 94 + return -1; 95 + } 96 + 97 + static int test__kallsyms_split(struct test_suite *test __maybe_unused, 98 + int subtest __maybe_unused) 99 + { 100 + struct machine m; 101 + struct map *map = NULL; 102 + int ret = TEST_FAIL; 103 + 104 + pr_debug("try to create fake root directory\n"); 105 + if (create_proc_dir() < 0) { 106 + pr_debug("SKIP: cannot create a fake root directory\n"); 107 + return TEST_SKIP; 108 + } 109 + 110 + signal(SIGINT, remove_proc_dir); 111 + signal(SIGPIPE, remove_proc_dir); 112 + signal(SIGSEGV, remove_proc_dir); 113 + signal(SIGTERM, remove_proc_dir); 114 + 115 + pr_debug("create kernel maps from the fake root directory\n"); 116 + machine__init(&m, root_dir, HOST_KERNEL_ID); 117 + if (machine__create_kernel_maps(&m) < 0) { 118 + pr_debug("FAIL: failed to create kernel maps\n"); 119 + goto out; 120 + } 121 + 122 + /* force to use /proc/kallsyms */ 123 + symbol_conf.ignore_vmlinux = true; 124 + symbol_conf.ignore_vmlinux_buildid = true; 125 + symbol_conf.allow_aliases = true; 126 + 127 + if (map__load(machine__kernel_map(&m)) < 0) { 128 + pr_debug("FAIL: failed to load kallsyms\n"); 129 + goto out; 130 + } 131 + 132 + pr_debug("kernel map loaded - check symbol and map\n"); 133 + if (maps__nr_maps(machine__kernel_maps(&m)) != 2) { 134 + pr_debug("FAIL: it should have the kernel and a module, but has %u maps\n", 135 + maps__nr_maps(machine__kernel_maps(&m))); 136 + goto out; 137 + } 138 + 139 + if (machine__find_kernel_symbol_by_name(&m, "main_symbol3", &map) == NULL) { 140 + pr_debug("FAIL: failed to find a symbol\n"); 141 + goto out; 142 + } 143 + 144 + if (!RC_CHK_EQUAL(map, machine__kernel_map(&m))) { 145 + pr_debug("FAIL: the symbol is not in the kernel map\n"); 146 + goto out; 147 + } 148 + ret = TEST_OK; 149 + 150 + out: 151 + remove_proc_dir(0); 152 + machine__exit(&m); 153 + return ret; 154 + } 155 + 156 + DEFINE_SUITE("split kallsyms", kallsyms_split);
+1
tools/perf/tests/tests.h
··· 178 178 DECLARE_SUITE(symbols); 179 179 DECLARE_SUITE(util); 180 180 DECLARE_SUITE(subcmd_help); 181 + DECLARE_SUITE(kallsyms_split); 181 182 182 183 /* 183 184 * PowerPC and S390 do not support creation of instruction breakpoints using the