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