11b69346eSAdrian Hunter // SPDX-License-Identifier: GPL-2.0 21b69346eSAdrian Hunter #include <linux/compiler.h> 31b69346eSAdrian Hunter #include <linux/string.h> 41b69346eSAdrian Hunter #include <sys/mman.h> 51b69346eSAdrian Hunter #include <limits.h> 61b69346eSAdrian Hunter #include "debug.h" 71b69346eSAdrian Hunter #include "dso.h" 8*e4810663SIan Rogers #include "env.h" 91b69346eSAdrian Hunter #include "machine.h" 101b69346eSAdrian Hunter #include "thread.h" 111b69346eSAdrian Hunter #include "symbol.h" 121b69346eSAdrian Hunter #include "map.h" 131b69346eSAdrian Hunter #include "util.h" 141b69346eSAdrian Hunter #include "tests.h" 151b69346eSAdrian Hunter 161b69346eSAdrian Hunter struct test_info { 17*e4810663SIan Rogers struct perf_env host_env; 181b69346eSAdrian Hunter struct machine *machine; 191b69346eSAdrian Hunter struct thread *thread; 201b69346eSAdrian Hunter }; 211b69346eSAdrian Hunter 221b69346eSAdrian Hunter static int init_test_info(struct test_info *ti) 231b69346eSAdrian Hunter { 24*e4810663SIan Rogers perf_env__init(&ti->host_env); 25*e4810663SIan Rogers ti->machine = machine__new_host(&ti->host_env); 261b69346eSAdrian Hunter if (!ti->machine) { 271b69346eSAdrian Hunter pr_debug("machine__new_host() failed!\n"); 28*e4810663SIan Rogers perf_env__exit(&ti->host_env); 291b69346eSAdrian Hunter return TEST_FAIL; 301b69346eSAdrian Hunter } 311b69346eSAdrian Hunter 321b69346eSAdrian Hunter /* Create a dummy thread */ 331b69346eSAdrian Hunter ti->thread = machine__findnew_thread(ti->machine, 100, 100); 341b69346eSAdrian Hunter if (!ti->thread) { 351b69346eSAdrian Hunter pr_debug("machine__findnew_thread() failed!\n"); 36*e4810663SIan Rogers perf_env__exit(&ti->host_env); 371b69346eSAdrian Hunter return TEST_FAIL; 381b69346eSAdrian Hunter } 391b69346eSAdrian Hunter 401b69346eSAdrian Hunter return TEST_OK; 411b69346eSAdrian Hunter } 421b69346eSAdrian Hunter 431b69346eSAdrian Hunter static void exit_test_info(struct test_info *ti) 441b69346eSAdrian Hunter { 451b69346eSAdrian Hunter thread__put(ti->thread); 461b69346eSAdrian Hunter machine__delete(ti->machine); 47*e4810663SIan Rogers perf_env__exit(&ti->host_env); 481b69346eSAdrian Hunter } 491b69346eSAdrian Hunter 506f04d664SAdrian Hunter struct dso_map { 516f04d664SAdrian Hunter struct dso *dso; 526f04d664SAdrian Hunter struct map *map; 536f04d664SAdrian Hunter }; 546f04d664SAdrian Hunter 556f04d664SAdrian Hunter static int find_map_cb(struct map *map, void *d) 566f04d664SAdrian Hunter { 576f04d664SAdrian Hunter struct dso_map *data = d; 586f04d664SAdrian Hunter 596f04d664SAdrian Hunter if (map__dso(map) != data->dso) 606f04d664SAdrian Hunter return 0; 616f04d664SAdrian Hunter data->map = map; 626f04d664SAdrian Hunter return 1; 636f04d664SAdrian Hunter } 646f04d664SAdrian Hunter 656f04d664SAdrian Hunter static struct map *find_module_map(struct machine *machine, struct dso *dso) 666f04d664SAdrian Hunter { 676f04d664SAdrian Hunter struct dso_map data = { .dso = dso }; 686f04d664SAdrian Hunter 696f04d664SAdrian Hunter machine__for_each_kernel_map(machine, find_map_cb, &data); 706f04d664SAdrian Hunter 716f04d664SAdrian Hunter return data.map; 726f04d664SAdrian Hunter } 736f04d664SAdrian Hunter 741b69346eSAdrian Hunter static void get_test_dso_filename(char *filename, size_t max_sz) 751b69346eSAdrian Hunter { 761b69346eSAdrian Hunter if (dso_to_test) 771b69346eSAdrian Hunter strlcpy(filename, dso_to_test, max_sz); 781b69346eSAdrian Hunter else 791b69346eSAdrian Hunter perf_exe(filename, max_sz); 801b69346eSAdrian Hunter } 811b69346eSAdrian Hunter 821b69346eSAdrian Hunter static int create_map(struct test_info *ti, char *filename, struct map **map_p) 831b69346eSAdrian Hunter { 846f04d664SAdrian Hunter struct dso *dso = machine__findnew_dso(ti->machine, filename); 856f04d664SAdrian Hunter 866f04d664SAdrian Hunter /* 876f04d664SAdrian Hunter * If 'filename' matches a current kernel module, must use a kernel 886f04d664SAdrian Hunter * map. Find the one that already exists. 896f04d664SAdrian Hunter */ 90ee756ef7SIan Rogers if (dso && dso__kernel(dso) != DSO_SPACE__USER) { 916f04d664SAdrian Hunter *map_p = find_module_map(ti->machine, dso); 926f04d664SAdrian Hunter dso__put(dso); 936f04d664SAdrian Hunter if (!*map_p) { 94eb94225eSColin Ian King pr_debug("Failed to find map for current kernel module %s", 956f04d664SAdrian Hunter filename); 966f04d664SAdrian Hunter return TEST_FAIL; 976f04d664SAdrian Hunter } 986f04d664SAdrian Hunter map__get(*map_p); 996f04d664SAdrian Hunter return TEST_OK; 1006f04d664SAdrian Hunter } 1016f04d664SAdrian Hunter 1026f04d664SAdrian Hunter dso__put(dso); 1036f04d664SAdrian Hunter 1041b69346eSAdrian Hunter /* Create a dummy map at 0x100000 */ 105d9f2ecbcSIan Rogers *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, &dso_id_empty, 106d9f2ecbcSIan Rogers PROT_EXEC, /*flags=*/0, filename, ti->thread); 1071b69346eSAdrian Hunter if (!*map_p) { 1081b69346eSAdrian Hunter pr_debug("Failed to create map!"); 1091b69346eSAdrian Hunter return TEST_FAIL; 1101b69346eSAdrian Hunter } 1111b69346eSAdrian Hunter 1121b69346eSAdrian Hunter return TEST_OK; 1131b69346eSAdrian Hunter } 1141b69346eSAdrian Hunter 1151b69346eSAdrian Hunter static int test_dso(struct dso *dso) 1161b69346eSAdrian Hunter { 1171b69346eSAdrian Hunter struct symbol *last_sym = NULL; 1181b69346eSAdrian Hunter struct rb_node *nd; 1191b69346eSAdrian Hunter int ret = TEST_OK; 1201b69346eSAdrian Hunter 1211b69346eSAdrian Hunter /* dso__fprintf() prints all the symbols */ 1221b69346eSAdrian Hunter if (verbose > 1) 1231b69346eSAdrian Hunter dso__fprintf(dso, stderr); 1241b69346eSAdrian Hunter 125ee756ef7SIan Rogers for (nd = rb_first_cached(dso__symbols(dso)); nd; nd = rb_next(nd)) { 1261b69346eSAdrian Hunter struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 1271b69346eSAdrian Hunter 1281b69346eSAdrian Hunter if (sym->type != STT_FUNC && sym->type != STT_GNU_IFUNC) 1291b69346eSAdrian Hunter continue; 1301b69346eSAdrian Hunter 1311b69346eSAdrian Hunter /* Check for overlapping function symbols */ 1321b69346eSAdrian Hunter if (last_sym && sym->start < last_sym->end) { 1331b69346eSAdrian Hunter pr_debug("Overlapping symbols:\n"); 1341b69346eSAdrian Hunter symbol__fprintf(last_sym, stderr); 1351b69346eSAdrian Hunter symbol__fprintf(sym, stderr); 1361b69346eSAdrian Hunter ret = TEST_FAIL; 1371b69346eSAdrian Hunter } 1381b69346eSAdrian Hunter /* Check for zero-length function symbol */ 1391b69346eSAdrian Hunter if (sym->start == sym->end) { 1401b69346eSAdrian Hunter pr_debug("Zero-length symbol:\n"); 1411b69346eSAdrian Hunter symbol__fprintf(sym, stderr); 1421b69346eSAdrian Hunter ret = TEST_FAIL; 1431b69346eSAdrian Hunter } 1441b69346eSAdrian Hunter last_sym = sym; 1451b69346eSAdrian Hunter } 1461b69346eSAdrian Hunter 1471b69346eSAdrian Hunter return ret; 1481b69346eSAdrian Hunter } 1491b69346eSAdrian Hunter 1506f04d664SAdrian Hunter static int subdivided_dso_cb(struct dso *dso, struct machine *machine __maybe_unused, void *d) 1516f04d664SAdrian Hunter { 1526f04d664SAdrian Hunter struct dso *text_dso = d; 1536f04d664SAdrian Hunter 154ee756ef7SIan Rogers if (dso != text_dso && strstarts(dso__short_name(dso), dso__short_name(text_dso))) 1556f04d664SAdrian Hunter if (test_dso(dso) != TEST_OK) 1566f04d664SAdrian Hunter return -1; 1576f04d664SAdrian Hunter 1586f04d664SAdrian Hunter return 0; 1596f04d664SAdrian Hunter } 1606f04d664SAdrian Hunter 1616f04d664SAdrian Hunter static int process_subdivided_dso(struct machine *machine, struct dso *dso) 1626f04d664SAdrian Hunter { 1636f04d664SAdrian Hunter int ret; 1646f04d664SAdrian Hunter 1656f04d664SAdrian Hunter ret = machine__for_each_dso(machine, subdivided_dso_cb, dso); 1666f04d664SAdrian Hunter 1676f04d664SAdrian Hunter return ret < 0 ? TEST_FAIL : TEST_OK; 1686f04d664SAdrian Hunter } 1696f04d664SAdrian Hunter 1701b69346eSAdrian Hunter static int test_file(struct test_info *ti, char *filename) 1711b69346eSAdrian Hunter { 1721b69346eSAdrian Hunter struct map *map = NULL; 1731b69346eSAdrian Hunter int ret, nr; 17463df0e4bSIan Rogers struct dso *dso; 1751b69346eSAdrian Hunter 1761b69346eSAdrian Hunter pr_debug("Testing %s\n", filename); 1771b69346eSAdrian Hunter 1781b69346eSAdrian Hunter ret = create_map(ti, filename, &map); 1791b69346eSAdrian Hunter if (ret != TEST_OK) 1801b69346eSAdrian Hunter return ret; 1811b69346eSAdrian Hunter 18263df0e4bSIan Rogers dso = map__dso(map); 18363df0e4bSIan Rogers nr = dso__load(dso, map); 1841b69346eSAdrian Hunter if (nr < 0) { 1851b69346eSAdrian Hunter pr_debug("dso__load() failed!\n"); 1861b69346eSAdrian Hunter ret = TEST_FAIL; 1871b69346eSAdrian Hunter goto out_put; 1881b69346eSAdrian Hunter } 1891b69346eSAdrian Hunter 1901b69346eSAdrian Hunter if (nr == 0) { 1911b69346eSAdrian Hunter pr_debug("DSO has no symbols!\n"); 1921b69346eSAdrian Hunter ret = TEST_SKIP; 1931b69346eSAdrian Hunter goto out_put; 1941b69346eSAdrian Hunter } 1951b69346eSAdrian Hunter 19663df0e4bSIan Rogers ret = test_dso(dso); 1976f04d664SAdrian Hunter 1986f04d664SAdrian Hunter /* Module dso is split into many dsos by section */ 199ee756ef7SIan Rogers if (ret == TEST_OK && dso__kernel(dso) != DSO_SPACE__USER) 2006f04d664SAdrian Hunter ret = process_subdivided_dso(ti->machine, dso); 2011b69346eSAdrian Hunter out_put: 2021b69346eSAdrian Hunter map__put(map); 2031b69346eSAdrian Hunter 2041b69346eSAdrian Hunter return ret; 2051b69346eSAdrian Hunter } 2061b69346eSAdrian Hunter 2071b69346eSAdrian Hunter static int test__symbols(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 2081b69346eSAdrian Hunter { 2091b69346eSAdrian Hunter char filename[PATH_MAX]; 2101b69346eSAdrian Hunter struct test_info ti; 2111b69346eSAdrian Hunter int ret; 2121b69346eSAdrian Hunter 2131b69346eSAdrian Hunter ret = init_test_info(&ti); 2141b69346eSAdrian Hunter if (ret != TEST_OK) 2151b69346eSAdrian Hunter return ret; 2161b69346eSAdrian Hunter 2171b69346eSAdrian Hunter get_test_dso_filename(filename, sizeof(filename)); 2181b69346eSAdrian Hunter 2191b69346eSAdrian Hunter ret = test_file(&ti, filename); 2201b69346eSAdrian Hunter 2211b69346eSAdrian Hunter exit_test_info(&ti); 2221b69346eSAdrian Hunter 2231b69346eSAdrian Hunter return ret; 2241b69346eSAdrian Hunter } 2251b69346eSAdrian Hunter 2261b69346eSAdrian Hunter DEFINE_SUITE("Symbols", symbols); 227