xref: /linux/tools/perf/tests/symbols.c (revision f4f346c3465949ebba80c6cc52cd8d2eeaa545fd)
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 
init_test_info(struct test_info * ti)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 
exit_test_info(struct test_info * ti)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 
find_map_cb(struct map * map,void * d)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 
find_module_map(struct machine * machine,struct dso * dso)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 
get_test_dso_filename(char * filename,size_t max_sz)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 
create_map(struct test_info * ti,char * filename,struct map ** map_p)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 
test_dso(struct dso * dso)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 
subdivided_dso_cb(struct dso * dso,struct machine * machine __maybe_unused,void * d)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 
process_subdivided_dso(struct machine * machine,struct dso * dso)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 
test_file(struct test_info * ti,char * filename)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 
test__symbols(struct test_suite * test __maybe_unused,int subtest __maybe_unused)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