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" 81b69346eSAdrian Hunter #include "machine.h" 91b69346eSAdrian Hunter #include "thread.h" 101b69346eSAdrian Hunter #include "symbol.h" 111b69346eSAdrian Hunter #include "map.h" 121b69346eSAdrian Hunter #include "util.h" 131b69346eSAdrian Hunter #include "tests.h" 141b69346eSAdrian Hunter 151b69346eSAdrian Hunter struct test_info { 161b69346eSAdrian Hunter struct machine *machine; 171b69346eSAdrian Hunter struct thread *thread; 181b69346eSAdrian Hunter }; 191b69346eSAdrian Hunter 201b69346eSAdrian Hunter static int init_test_info(struct test_info *ti) 211b69346eSAdrian Hunter { 221b69346eSAdrian Hunter ti->machine = machine__new_host(); 231b69346eSAdrian Hunter if (!ti->machine) { 241b69346eSAdrian Hunter pr_debug("machine__new_host() failed!\n"); 251b69346eSAdrian Hunter return TEST_FAIL; 261b69346eSAdrian Hunter } 271b69346eSAdrian Hunter 281b69346eSAdrian Hunter /* Create a dummy thread */ 291b69346eSAdrian Hunter ti->thread = machine__findnew_thread(ti->machine, 100, 100); 301b69346eSAdrian Hunter if (!ti->thread) { 311b69346eSAdrian Hunter pr_debug("machine__findnew_thread() failed!\n"); 321b69346eSAdrian Hunter return TEST_FAIL; 331b69346eSAdrian Hunter } 341b69346eSAdrian Hunter 351b69346eSAdrian Hunter return TEST_OK; 361b69346eSAdrian Hunter } 371b69346eSAdrian Hunter 381b69346eSAdrian Hunter static void exit_test_info(struct test_info *ti) 391b69346eSAdrian Hunter { 401b69346eSAdrian Hunter thread__put(ti->thread); 4182c6d83bSIan Rogers machine__delete_threads(ti->machine); 421b69346eSAdrian Hunter machine__delete(ti->machine); 431b69346eSAdrian Hunter } 441b69346eSAdrian Hunter 451b69346eSAdrian Hunter static void get_test_dso_filename(char *filename, size_t max_sz) 461b69346eSAdrian Hunter { 471b69346eSAdrian Hunter if (dso_to_test) 481b69346eSAdrian Hunter strlcpy(filename, dso_to_test, max_sz); 491b69346eSAdrian Hunter else 501b69346eSAdrian Hunter perf_exe(filename, max_sz); 511b69346eSAdrian Hunter } 521b69346eSAdrian Hunter 531b69346eSAdrian Hunter static int create_map(struct test_info *ti, char *filename, struct map **map_p) 541b69346eSAdrian Hunter { 551b69346eSAdrian Hunter /* Create a dummy map at 0x100000 */ 561b69346eSAdrian Hunter *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, NULL, 571b69346eSAdrian Hunter PROT_EXEC, 0, NULL, filename, ti->thread); 581b69346eSAdrian Hunter if (!*map_p) { 591b69346eSAdrian Hunter pr_debug("Failed to create map!"); 601b69346eSAdrian Hunter return TEST_FAIL; 611b69346eSAdrian Hunter } 621b69346eSAdrian Hunter 631b69346eSAdrian Hunter return TEST_OK; 641b69346eSAdrian Hunter } 651b69346eSAdrian Hunter 661b69346eSAdrian Hunter static int test_dso(struct dso *dso) 671b69346eSAdrian Hunter { 681b69346eSAdrian Hunter struct symbol *last_sym = NULL; 691b69346eSAdrian Hunter struct rb_node *nd; 701b69346eSAdrian Hunter int ret = TEST_OK; 711b69346eSAdrian Hunter 721b69346eSAdrian Hunter /* dso__fprintf() prints all the symbols */ 731b69346eSAdrian Hunter if (verbose > 1) 741b69346eSAdrian Hunter dso__fprintf(dso, stderr); 751b69346eSAdrian Hunter 761b69346eSAdrian Hunter for (nd = rb_first_cached(&dso->symbols); nd; nd = rb_next(nd)) { 771b69346eSAdrian Hunter struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 781b69346eSAdrian Hunter 791b69346eSAdrian Hunter if (sym->type != STT_FUNC && sym->type != STT_GNU_IFUNC) 801b69346eSAdrian Hunter continue; 811b69346eSAdrian Hunter 821b69346eSAdrian Hunter /* Check for overlapping function symbols */ 831b69346eSAdrian Hunter if (last_sym && sym->start < last_sym->end) { 841b69346eSAdrian Hunter pr_debug("Overlapping symbols:\n"); 851b69346eSAdrian Hunter symbol__fprintf(last_sym, stderr); 861b69346eSAdrian Hunter symbol__fprintf(sym, stderr); 871b69346eSAdrian Hunter ret = TEST_FAIL; 881b69346eSAdrian Hunter } 891b69346eSAdrian Hunter /* Check for zero-length function symbol */ 901b69346eSAdrian Hunter if (sym->start == sym->end) { 911b69346eSAdrian Hunter pr_debug("Zero-length symbol:\n"); 921b69346eSAdrian Hunter symbol__fprintf(sym, stderr); 931b69346eSAdrian Hunter ret = TEST_FAIL; 941b69346eSAdrian Hunter } 951b69346eSAdrian Hunter last_sym = sym; 961b69346eSAdrian Hunter } 971b69346eSAdrian Hunter 981b69346eSAdrian Hunter return ret; 991b69346eSAdrian Hunter } 1001b69346eSAdrian Hunter 1011b69346eSAdrian Hunter static int test_file(struct test_info *ti, char *filename) 1021b69346eSAdrian Hunter { 1031b69346eSAdrian Hunter struct map *map = NULL; 1041b69346eSAdrian Hunter int ret, nr; 10563df0e4bSIan Rogers struct dso *dso; 1061b69346eSAdrian Hunter 1071b69346eSAdrian Hunter pr_debug("Testing %s\n", filename); 1081b69346eSAdrian Hunter 1091b69346eSAdrian Hunter ret = create_map(ti, filename, &map); 1101b69346eSAdrian Hunter if (ret != TEST_OK) 1111b69346eSAdrian Hunter return ret; 1121b69346eSAdrian Hunter 11363df0e4bSIan Rogers dso = map__dso(map); 11463df0e4bSIan Rogers nr = dso__load(dso, map); 1151b69346eSAdrian Hunter if (nr < 0) { 1161b69346eSAdrian Hunter pr_debug("dso__load() failed!\n"); 1171b69346eSAdrian Hunter ret = TEST_FAIL; 1181b69346eSAdrian Hunter goto out_put; 1191b69346eSAdrian Hunter } 1201b69346eSAdrian Hunter 1211b69346eSAdrian Hunter if (nr == 0) { 1221b69346eSAdrian Hunter pr_debug("DSO has no symbols!\n"); 1231b69346eSAdrian Hunter ret = TEST_SKIP; 1241b69346eSAdrian Hunter goto out_put; 1251b69346eSAdrian Hunter } 1261b69346eSAdrian Hunter 12763df0e4bSIan Rogers ret = test_dso(dso); 1281b69346eSAdrian Hunter out_put: 1291b69346eSAdrian Hunter map__put(map); 1301b69346eSAdrian Hunter 1311b69346eSAdrian Hunter return ret; 1321b69346eSAdrian Hunter } 1331b69346eSAdrian Hunter 1341b69346eSAdrian Hunter static int test__symbols(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 1351b69346eSAdrian Hunter { 1361b69346eSAdrian Hunter char filename[PATH_MAX]; 1371b69346eSAdrian Hunter struct test_info ti; 1381b69346eSAdrian Hunter int ret; 1391b69346eSAdrian Hunter 1401b69346eSAdrian Hunter ret = init_test_info(&ti); 1411b69346eSAdrian Hunter if (ret != TEST_OK) 1421b69346eSAdrian Hunter return ret; 1431b69346eSAdrian Hunter 1441b69346eSAdrian Hunter get_test_dso_filename(filename, sizeof(filename)); 1451b69346eSAdrian Hunter 1461b69346eSAdrian Hunter ret = test_file(&ti, filename); 1471b69346eSAdrian Hunter 1481b69346eSAdrian Hunter exit_test_info(&ti); 1491b69346eSAdrian Hunter 1501b69346eSAdrian Hunter return ret; 1511b69346eSAdrian Hunter } 1521b69346eSAdrian Hunter 1531b69346eSAdrian Hunter DEFINE_SUITE("Symbols", symbols); 154