perf tests: Add option to run tests in parallel
[linux-2.6-microblaze.git] / tools / perf / tests / symbols.c
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(ti->machine);
42 }
43
44 struct dso_map {
45         struct dso *dso;
46         struct map *map;
47 };
48
49 static int find_map_cb(struct map *map, void *d)
50 {
51         struct dso_map *data = d;
52
53         if (map__dso(map) != data->dso)
54                 return 0;
55         data->map = map;
56         return 1;
57 }
58
59 static struct map *find_module_map(struct machine *machine, struct dso *dso)
60 {
61         struct dso_map data = { .dso = dso };
62
63         machine__for_each_kernel_map(machine, find_map_cb, &data);
64
65         return data.map;
66 }
67
68 static void get_test_dso_filename(char *filename, size_t max_sz)
69 {
70         if (dso_to_test)
71                 strlcpy(filename, dso_to_test, max_sz);
72         else
73                 perf_exe(filename, max_sz);
74 }
75
76 static int create_map(struct test_info *ti, char *filename, struct map **map_p)
77 {
78         struct dso *dso = machine__findnew_dso(ti->machine, filename);
79
80         /*
81          * If 'filename' matches a current kernel module, must use a kernel
82          * map. Find the one that already exists.
83          */
84         if (dso && dso->kernel) {
85                 *map_p = find_module_map(ti->machine, dso);
86                 dso__put(dso);
87                 if (!*map_p) {
88                         pr_debug("Failed to find map for curent kernel module %s",
89                                  filename);
90                         return TEST_FAIL;
91                 }
92                 map__get(*map_p);
93                 return TEST_OK;
94         }
95
96         dso__put(dso);
97
98         /* Create a dummy map at 0x100000 */
99         *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, NULL,
100                           PROT_EXEC, 0, NULL, filename, ti->thread);
101         if (!*map_p) {
102                 pr_debug("Failed to create map!");
103                 return TEST_FAIL;
104         }
105
106         return TEST_OK;
107 }
108
109 static int test_dso(struct dso *dso)
110 {
111         struct symbol *last_sym = NULL;
112         struct rb_node *nd;
113         int ret = TEST_OK;
114
115         /* dso__fprintf() prints all the symbols */
116         if (verbose > 1)
117                 dso__fprintf(dso, stderr);
118
119         for (nd = rb_first_cached(&dso->symbols); nd; nd = rb_next(nd)) {
120                 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
121
122                 if (sym->type != STT_FUNC && sym->type != STT_GNU_IFUNC)
123                         continue;
124
125                 /* Check for overlapping function symbols */
126                 if (last_sym && sym->start < last_sym->end) {
127                         pr_debug("Overlapping symbols:\n");
128                         symbol__fprintf(last_sym, stderr);
129                         symbol__fprintf(sym, stderr);
130                         ret = TEST_FAIL;
131                 }
132                 /* Check for zero-length function symbol */
133                 if (sym->start == sym->end) {
134                         pr_debug("Zero-length symbol:\n");
135                         symbol__fprintf(sym, stderr);
136                         ret = TEST_FAIL;
137                 }
138                 last_sym = sym;
139         }
140
141         return ret;
142 }
143
144 static int subdivided_dso_cb(struct dso *dso, struct machine *machine __maybe_unused, void *d)
145 {
146         struct dso *text_dso = d;
147
148         if (dso != text_dso && strstarts(dso->short_name, text_dso->short_name))
149                 if (test_dso(dso) != TEST_OK)
150                         return -1;
151
152         return 0;
153 }
154
155 static int process_subdivided_dso(struct machine *machine, struct dso *dso)
156 {
157         int ret;
158
159         ret = machine__for_each_dso(machine, subdivided_dso_cb, dso);
160
161         return ret < 0 ? TEST_FAIL : TEST_OK;
162 }
163
164 static int test_file(struct test_info *ti, char *filename)
165 {
166         struct map *map = NULL;
167         int ret, nr;
168         struct dso *dso;
169
170         pr_debug("Testing %s\n", filename);
171
172         ret = create_map(ti, filename, &map);
173         if (ret != TEST_OK)
174                 return ret;
175
176         dso = map__dso(map);
177         nr = dso__load(dso, map);
178         if (nr < 0) {
179                 pr_debug("dso__load() failed!\n");
180                 ret = TEST_FAIL;
181                 goto out_put;
182         }
183
184         if (nr == 0) {
185                 pr_debug("DSO has no symbols!\n");
186                 ret = TEST_SKIP;
187                 goto out_put;
188         }
189
190         ret = test_dso(dso);
191
192         /* Module dso is split into many dsos by section */
193         if (ret == TEST_OK && dso->kernel)
194                 ret = process_subdivided_dso(ti->machine, dso);
195 out_put:
196         map__put(map);
197
198         return ret;
199 }
200
201 static int test__symbols(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
202 {
203         char filename[PATH_MAX];
204         struct test_info ti;
205         int ret;
206
207         ret = init_test_info(&ti);
208         if (ret != TEST_OK)
209                 return ret;
210
211         get_test_dso_filename(filename, sizeof(filename));
212
213         ret = test_file(&ti, filename);
214
215         exit_test_info(&ti);
216
217         return ret;
218 }
219
220 DEFINE_SUITE("Symbols", symbols);