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(ti->machine); 42 } 43 44 static void get_test_dso_filename(char *filename, size_t max_sz) 45 { 46 if (dso_to_test) 47 strlcpy(filename, dso_to_test, max_sz); 48 else 49 perf_exe(filename, max_sz); 50 } 51 52 static int create_map(struct test_info *ti, char *filename, struct map **map_p) 53 { 54 /* Create a dummy map at 0x100000 */ 55 *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, NULL, 56 PROT_EXEC, 0, NULL, filename, ti->thread); 57 if (!*map_p) { 58 pr_debug("Failed to create map!"); 59 return TEST_FAIL; 60 } 61 62 return TEST_OK; 63 } 64 65 static int test_dso(struct dso *dso) 66 { 67 struct symbol *last_sym = NULL; 68 struct rb_node *nd; 69 int ret = TEST_OK; 70 71 /* dso__fprintf() prints all the symbols */ 72 if (verbose > 1) 73 dso__fprintf(dso, stderr); 74 75 for (nd = rb_first_cached(&dso->symbols); nd; nd = rb_next(nd)) { 76 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 77 78 if (sym->type != STT_FUNC && sym->type != STT_GNU_IFUNC) 79 continue; 80 81 /* Check for overlapping function symbols */ 82 if (last_sym && sym->start < last_sym->end) { 83 pr_debug("Overlapping symbols:\n"); 84 symbol__fprintf(last_sym, stderr); 85 symbol__fprintf(sym, stderr); 86 ret = TEST_FAIL; 87 } 88 /* Check for zero-length function symbol */ 89 if (sym->start == sym->end) { 90 pr_debug("Zero-length symbol:\n"); 91 symbol__fprintf(sym, stderr); 92 ret = TEST_FAIL; 93 } 94 last_sym = sym; 95 } 96 97 return ret; 98 } 99 100 static int test_file(struct test_info *ti, char *filename) 101 { 102 struct map *map = NULL; 103 int ret, nr; 104 struct dso *dso; 105 106 pr_debug("Testing %s\n", filename); 107 108 ret = create_map(ti, filename, &map); 109 if (ret != TEST_OK) 110 return ret; 111 112 dso = map__dso(map); 113 nr = dso__load(dso, map); 114 if (nr < 0) { 115 pr_debug("dso__load() failed!\n"); 116 ret = TEST_FAIL; 117 goto out_put; 118 } 119 120 if (nr == 0) { 121 pr_debug("DSO has no symbols!\n"); 122 ret = TEST_SKIP; 123 goto out_put; 124 } 125 126 ret = test_dso(dso); 127 out_put: 128 map__put(map); 129 130 return ret; 131 } 132 133 static int test__symbols(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 134 { 135 char filename[PATH_MAX]; 136 struct test_info ti; 137 int ret; 138 139 ret = init_test_info(&ti); 140 if (ret != TEST_OK) 141 return ret; 142 143 get_test_dso_filename(filename, sizeof(filename)); 144 145 ret = test_file(&ti, filename); 146 147 exit_test_info(&ti); 148 149 return ret; 150 } 151 152 DEFINE_SUITE("Symbols", symbols); 153