xref: /openbmc/linux/tools/perf/tests/symbols.c (revision 7effbd18)
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 
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 	nr = dso__load(map->dso, map);
113 	if (nr < 0) {
114 		pr_debug("dso__load() failed!\n");
115 		ret = TEST_FAIL;
116 		goto out_put;
117 	}
118 
119 	if (nr == 0) {
120 		pr_debug("DSO has no symbols!\n");
121 		ret = TEST_SKIP;
122 		goto out_put;
123 	}
124 
125 	ret = test_dso(map->dso);
126 out_put:
127 	map__put(map);
128 
129 	return ret;
130 }
131 
132 static int test__symbols(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
133 {
134 	char filename[PATH_MAX];
135 	struct test_info ti;
136 	int ret;
137 
138 	ret = init_test_info(&ti);
139 	if (ret != TEST_OK)
140 		return ret;
141 
142 	get_test_dso_filename(filename, sizeof(filename));
143 
144 	ret = test_file(&ti, filename);
145 
146 	exit_test_info(&ti);
147 
148 	return ret;
149 }
150 
151 DEFINE_SUITE("Symbols", symbols);
152