1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/compiler.h> 3 #include <linux/string.h> 4 #include <sys/mman.h> 5 #include <limits.h> 6 #include "debug.h" 7 #include "dso.h" 8 #include "machine.h" 9 #include "thread.h" 10 #include "symbol.h" 11 #include "map.h" 12 #include "util.h" 13 #include "tests.h" 14 15 struct test_info { 16 struct machine *machine; 17 struct thread *thread; 18 }; 19 20 static int init_test_info(struct test_info *ti) 21 { 22 ti->machine = machine__new_host(); 23 if (!ti->machine) { 24 pr_debug("machine__new_host() failed!\n"); 25 return TEST_FAIL; 26 } 27 28 /* Create a dummy thread */ 29 ti->thread = machine__findnew_thread(ti->machine, 100, 100); 30 if (!ti->thread) { 31 pr_debug("machine__findnew_thread() failed!\n"); 32 return TEST_FAIL; 33 } 34 35 return TEST_OK; 36 } 37 38 static void exit_test_info(struct test_info *ti) 39 { 40 thread__put(ti->thread); 41 machine__delete_threads(ti->machine); 42 machine__delete(ti->machine); 43 } 44 45 static void get_test_dso_filename(char *filename, size_t max_sz) 46 { 47 if (dso_to_test) 48 strlcpy(filename, dso_to_test, max_sz); 49 else 50 perf_exe(filename, max_sz); 51 } 52 53 static int create_map(struct test_info *ti, char *filename, struct map **map_p) 54 { 55 /* Create a dummy map at 0x100000 */ 56 *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, NULL, 57 PROT_EXEC, 0, NULL, filename, ti->thread); 58 if (!*map_p) { 59 pr_debug("Failed to create map!"); 60 return TEST_FAIL; 61 } 62 63 return TEST_OK; 64 } 65 66 static int test_dso(struct dso *dso) 67 { 68 struct symbol *last_sym = NULL; 69 struct rb_node *nd; 70 int ret = TEST_OK; 71 72 /* dso__fprintf() prints all the symbols */ 73 if (verbose > 1) 74 dso__fprintf(dso, stderr); 75 76 for (nd = rb_first_cached(&dso->symbols); nd; nd = rb_next(nd)) { 77 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 78 79 if (sym->type != STT_FUNC && sym->type != STT_GNU_IFUNC) 80 continue; 81 82 /* Check for overlapping function symbols */ 83 if (last_sym && sym->start < last_sym->end) { 84 pr_debug("Overlapping symbols:\n"); 85 symbol__fprintf(last_sym, stderr); 86 symbol__fprintf(sym, stderr); 87 ret = TEST_FAIL; 88 } 89 /* Check for zero-length function symbol */ 90 if (sym->start == sym->end) { 91 pr_debug("Zero-length symbol:\n"); 92 symbol__fprintf(sym, stderr); 93 ret = TEST_FAIL; 94 } 95 last_sym = sym; 96 } 97 98 return ret; 99 } 100 101 static int test_file(struct test_info *ti, char *filename) 102 { 103 struct map *map = NULL; 104 int ret, nr; 105 struct dso *dso; 106 107 pr_debug("Testing %s\n", filename); 108 109 ret = create_map(ti, filename, &map); 110 if (ret != TEST_OK) 111 return ret; 112 113 dso = map__dso(map); 114 nr = dso__load(dso, map); 115 if (nr < 0) { 116 pr_debug("dso__load() failed!\n"); 117 ret = TEST_FAIL; 118 goto out_put; 119 } 120 121 if (nr == 0) { 122 pr_debug("DSO has no symbols!\n"); 123 ret = TEST_SKIP; 124 goto out_put; 125 } 126 127 ret = test_dso(dso); 128 out_put: 129 map__put(map); 130 131 return ret; 132 } 133 134 static int test__symbols(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 135 { 136 char filename[PATH_MAX]; 137 struct test_info ti; 138 int ret; 139 140 ret = init_test_info(&ti); 141 if (ret != TEST_OK) 142 return ret; 143 144 get_test_dso_filename(filename, sizeof(filename)); 145 146 ret = test_file(&ti, filename); 147 148 exit_test_info(&ti); 149 150 return ret; 151 } 152 153 DEFINE_SUITE("Symbols", symbols); 154