]> gcc.gnu.org Git - gcc.git/blame - libbacktrace/mtest.c
libbacktrace: support MiniDebugInfo
[gcc.git] / libbacktrace / mtest.c
CommitLineData
05f40bc4
ILT
1/* mtest.c -- Minidebug test for libbacktrace library
2 Copyright (C) 2020 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 (2) Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 (3) The name of the author may not be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31POSSIBILITY OF SUCH DAMAGE. */
32
33/* This program tests using libbacktrace with a program that uses the
34 minidebuginfo format in a .gnu_debugdata section. See
35 https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html
36 for a bit more information about minidebuginfo. What is relevant
37 for libbacktrace is that we have just a symbol table, with no debug
38 info, so we should be able to do a function backtrace, but we can't
39 do a file/line backtrace. */
40
41#include <assert.h>
42#include <stdlib.h>
43#include <string.h>
44
45#include "backtrace.h"
46#include "backtrace-supported.h"
47
48#include "testlib.h"
49
50static int test1 (void) __attribute__ ((noinline, noclone, unused));
51static int f2 (int) __attribute__ ((noinline, noclone));
52static int f3 (int, int) __attribute__ ((noinline, noclone));
53
54/* Collected PC values. */
55
56static uintptr_t addrs[20];
57
58/* The backtrace callback function. This is like callback_one in
59 testlib.c, but it saves the PC also. */
60
61static int
62callback_mtest (void *vdata, uintptr_t pc, const char *filename, int lineno,
63 const char *function)
64{
65 struct bdata *data = (struct bdata *) vdata;
66
67 if (data->index >= sizeof addrs / sizeof addrs[0])
68 {
69 fprintf (stderr, "callback_mtest: callback called too many times\n");
70 data->failed = 1;
71 return 1;
72 }
73
74 addrs[data->index] = pc;
75
76 return callback_one (vdata, pc, filename, lineno, function);
77}
78
79/* Test the backtrace function with non-inlined functions. (We don't
80 test with inlined functions because they won't work with minidebug
81 anyhow.) */
82
83static int
84test1 (void)
85{
86 /* Returning a value here and elsewhere avoids a tailcall which
87 would mess up the backtrace. */
88 return f2 (__LINE__) + 1;
89}
90
91static int
92f2 (int f1line)
93{
94 return f3 (f1line, __LINE__) + 2;
95}
96
97static int
98f3 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
99{
100 struct info all[20];
101 struct bdata data;
102 int i;
103 size_t j;
104
105 data.all = &all[0];
106 data.index = 0;
107 data.max = 20;
108 data.failed = 0;
109
110 i = backtrace_full (state, 0, callback_mtest, error_callback_one, &data);
111
112 if (i != 0)
113 {
114 fprintf (stderr, "test1: unexpected return value %d\n", i);
115 data.failed = 1;
116 }
117
118 if (data.index < 3)
119 {
120 fprintf (stderr,
121 "test1: not enough frames; got %zu, expected at least 3\n",
122 data.index);
123 data.failed = 1;
124 }
125
126 /* When using minidebug we don't expect the function name here. */
127
128 for (j = 0; j < 3 && j < data.index; j++)
129 {
130 if (all[j].function == NULL)
131 {
132 struct symdata symdata;
133
134 symdata.name = NULL;
135 symdata.val = 0;
136 symdata.size = 0;
137 symdata.failed = 0;
138
139 i = backtrace_syminfo (state, addrs[j], callback_three,
140 error_callback_three, &symdata);
141 if (i == 0)
142 {
143 fprintf (stderr,
144 ("test1: [%zu], unexpected return value from "
145 "backtrace_syminfo %d\n"),
146 j, i);
147 data.failed = 1;
148 }
149 else if (symdata.name == NULL)
150 {
151 fprintf (stderr, "test1: [%zu]: syminfo did not find name\n", j);
152 data.failed = 1;
153 }
154 else
155 all[j].function = strdup (symdata.name);
156 }
157 }
158
159 if (all[0].function == NULL)
160 {
161 fprintf (stderr, "test1: [0]: missing function name\n");
162 data.failed = 1;
163 }
164 else if (strcmp (all[0].function, "f3") != 0)
165 {
166 fprintf (stderr, "test1: [0]: got %s expected %s\n",
167 all[0].function, "f3");
168 data.failed = 1;
169 }
170
171 if (all[1].function == NULL)
172 {
173 fprintf (stderr, "test1: [1]: missing function name\n");
174 data.failed = 1;
175 }
176 else if (strcmp (all[1].function, "f2") != 0)
177 {
178 fprintf (stderr, "test1: [1]: got %s expected %s\n",
179 all[0].function, "f2");
180 data.failed = 1;
181 }
182
183 if (all[2].function == NULL)
184 {
185 fprintf (stderr, "test1: [2]: missing function name\n");
186 data.failed = 1;
187 }
188 else if (strcmp (all[2].function, "test1") != 0)
189 {
190 fprintf (stderr, "test1: [2]: got %s expected %s\n",
191 all[0].function, "test1");
192 data.failed = 1;
193 }
194
195 printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
196
197 if (data.failed)
198 ++failures;
199
200 return failures;
201}
202
203/* Test the backtrace_simple function with non-inlined functions. */
204
205static int test3 (void) __attribute__ ((noinline, noclone, unused));
206static int f22 (int) __attribute__ ((noinline, noclone));
207static int f23 (int, int) __attribute__ ((noinline, noclone));
208
209static int
210test3 (void)
211{
212 return f22 (__LINE__) + 1;
213}
214
215static int
216f22 (int f1line)
217{
218 return f23 (f1line, __LINE__) + 2;
219}
220
221static int
222f23 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
223{
224 uintptr_t addrs[20];
225 struct sdata data;
226 int i;
227
228 data.addrs = &addrs[0];
229 data.index = 0;
230 data.max = 20;
231 data.failed = 0;
232
233 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
234
235 if (i != 0)
236 {
237 fprintf (stderr, "test3: unexpected return value %d\n", i);
238 data.failed = 1;
239 }
240
241 if (!data.failed)
242 {
243 int j;
244
245 for (j = 0; j < 3; ++j)
246 {
247 struct symdata symdata;
248
249 symdata.name = NULL;
250 symdata.val = 0;
251 symdata.size = 0;
252 symdata.failed = 0;
253
254 i = backtrace_syminfo (state, addrs[j], callback_three,
255 error_callback_three, &symdata);
256 if (i == 0)
257 {
258 fprintf (stderr,
259 ("test3: [%d]: unexpected return value "
260 "from backtrace_syminfo %d\n"),
261 j, i);
262 symdata.failed = 1;
263 }
264
265 if (!symdata.failed)
266 {
267 const char *expected;
268
269 switch (j)
270 {
271 case 0:
272 expected = "f23";
273 break;
274 case 1:
275 expected = "f22";
276 break;
277 case 2:
278 expected = "test3";
279 break;
280 default:
281 assert (0);
282 }
283
284 if (symdata.name == NULL)
285 {
286 fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
287 symdata.failed = 1;
288 }
289 /* Use strncmp, not strcmp, because GCC might create a
290 clone. */
291 else if (strncmp (symdata.name, expected, strlen (expected))
292 != 0)
293 {
294 fprintf (stderr,
295 ("test3: [%d]: unexpected syminfo name "
296 "got %s expected %s\n"),
297 j, symdata.name, expected);
298 symdata.failed = 1;
299 }
300 }
301
302 if (symdata.failed)
303 data.failed = 1;
304 }
305 }
306
307 printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
308
309 if (data.failed)
310 ++failures;
311
312 return failures;
313}
314
315int test5 (void) __attribute__ ((unused));
316
317int global = 1;
318
319int
320test5 (void)
321{
322 struct symdata symdata;
323 int i;
324 uintptr_t addr = (uintptr_t) &global;
325
326 if (sizeof (global) > 1)
327 addr += 1;
328
329 symdata.name = NULL;
330 symdata.val = 0;
331 symdata.size = 0;
332 symdata.failed = 0;
333
334 i = backtrace_syminfo (state, addr, callback_three,
335 error_callback_three, &symdata);
336 if (i == 0)
337 {
338 fprintf (stderr,
339 "test5: unexpected return value from backtrace_syminfo %d\n",
340 i);
341 symdata.failed = 1;
342 }
343
344 if (!symdata.failed)
345 {
346 if (symdata.name == NULL)
347 {
348 fprintf (stderr, "test5: NULL syminfo name\n");
349 symdata.failed = 1;
350 }
351 else if (!(strncmp (symdata.name, "global", 6) == 0
352 && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
353 {
354 fprintf (stderr,
355 "test5: unexpected syminfo name got %s expected %s\n",
356 symdata.name, "global");
357 symdata.failed = 1;
358 }
359 else if (symdata.val != (uintptr_t) &global)
360 {
361 fprintf (stderr,
362 "test5: unexpected syminfo value got %lx expected %lx\n",
363 (unsigned long) symdata.val,
364 (unsigned long) (uintptr_t) &global);
365 symdata.failed = 1;
366 }
367 else if (symdata.size != sizeof (global))
368 {
369 fprintf (stderr,
370 "test5: unexpected syminfo size got %lx expected %lx\n",
371 (unsigned long) symdata.size,
372 (unsigned long) sizeof (global));
373 symdata.failed = 1;
374 }
375 }
376
377 printf ("%s: backtrace_syminfo variable\n",
378 symdata.failed ? "FAIL" : "PASS");
379
380 if (symdata.failed)
381 ++failures;
382
383 return failures;
384}
385
386int
387main (int argc ATTRIBUTE_UNUSED, char **argv)
388{
389 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
390 error_callback_create, NULL);
391
392#if BACKTRACE_SUPPORTED
393 test1 ();
394 test3 ();
395#if BACKTRACE_SUPPORTS_DATA
396 test5 ();
397#endif
398#endif
399
400 exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
401}
This page took 0.064484 seconds and 5 git commands to generate.