]> git.ipfire.org Git - thirdparty/gcc.git/blob - libbacktrace/btest.c
[Ada] Use new API when creating a special SPARK heap entity
[thirdparty/gcc.git] / libbacktrace / btest.c
1 /* btest.c -- Test for libbacktrace library
2 Copyright (C) 2012-2020 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
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
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE. */
32
33 /* This program tests the externally visible interfaces of the
34 libbacktrace library. */
35
36 #include <assert.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include "filenames.h"
43
44 #include "backtrace.h"
45 #include "backtrace-supported.h"
46
47 #include "testlib.h"
48
49 /* Test the backtrace function with non-inlined functions. */
50
51 static int test1 (void) __attribute__ ((noinline, noclone, unused));
52 static int f2 (int) __attribute__ ((noinline, noclone));
53 static int f3 (int, int) __attribute__ ((noinline, noclone));
54
55 static int
56 test1 (void)
57 {
58 /* Returning a value here and elsewhere avoids a tailcall which
59 would mess up the backtrace. */
60 return f2 (__LINE__) + 1;
61 }
62
63 static int
64 f2 (int f1line)
65 {
66 return f3 (f1line, __LINE__) + 2;
67 }
68
69 static int
70 f3 (int f1line, int f2line)
71 {
72 struct info all[20];
73 struct bdata data;
74 int f3line;
75 int i;
76
77 data.all = &all[0];
78 data.index = 0;
79 data.max = 20;
80 data.failed = 0;
81
82 f3line = __LINE__ + 1;
83 i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
84
85 if (i != 0)
86 {
87 fprintf (stderr, "test1: unexpected return value %d\n", i);
88 data.failed = 1;
89 }
90
91 if (data.index < 3)
92 {
93 fprintf (stderr,
94 "test1: not enough frames; got %zu, expected at least 3\n",
95 data.index);
96 data.failed = 1;
97 }
98
99 check ("test1", 0, all, f3line, "f3", "btest.c", &data.failed);
100 check ("test1", 1, all, f2line, "f2", "btest.c", &data.failed);
101 check ("test1", 2, all, f1line, "test1", "btest.c", &data.failed);
102
103 printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
104
105 if (data.failed)
106 ++failures;
107
108 return failures;
109 }
110
111 /* Test the backtrace function with inlined functions. */
112
113 static inline int test2 (void) __attribute__ ((always_inline, unused));
114 static inline int f12 (int) __attribute__ ((always_inline));
115 static inline int f13 (int, int) __attribute__ ((always_inline));
116
117 static inline int
118 test2 (void)
119 {
120 return f12 (__LINE__) + 1;
121 }
122
123 static inline int
124 f12 (int f1line)
125 {
126 return f13 (f1line, __LINE__) + 2;
127 }
128
129 static inline int
130 f13 (int f1line, int f2line)
131 {
132 struct info all[20];
133 struct bdata data;
134 int f3line;
135 int i;
136
137 data.all = &all[0];
138 data.index = 0;
139 data.max = 20;
140 data.failed = 0;
141
142 f3line = __LINE__ + 1;
143 i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
144
145 if (i != 0)
146 {
147 fprintf (stderr, "test2: unexpected return value %d\n", i);
148 data.failed = 1;
149 }
150
151 check ("test2", 0, all, f3line, "f13", "btest.c", &data.failed);
152 check ("test2", 1, all, f2line, "f12", "btest.c", &data.failed);
153 check ("test2", 2, all, f1line, "test2", "btest.c", &data.failed);
154
155 printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
156
157 if (data.failed)
158 ++failures;
159
160 return failures;
161 }
162
163 /* Test the backtrace_simple function with non-inlined functions. */
164
165 static int test3 (void) __attribute__ ((noinline, noclone, unused));
166 static int f22 (int) __attribute__ ((noinline, noclone));
167 static int f23 (int, int) __attribute__ ((noinline, noclone));
168
169 static int
170 test3 (void)
171 {
172 return f22 (__LINE__) + 1;
173 }
174
175 static int
176 f22 (int f1line)
177 {
178 return f23 (f1line, __LINE__) + 2;
179 }
180
181 static int
182 f23 (int f1line, int f2line)
183 {
184 uintptr_t addrs[20];
185 struct sdata data;
186 int f3line;
187 int i;
188
189 data.addrs = &addrs[0];
190 data.index = 0;
191 data.max = 20;
192 data.failed = 0;
193
194 f3line = __LINE__ + 1;
195 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
196
197 if (i != 0)
198 {
199 fprintf (stderr, "test3: unexpected return value %d\n", i);
200 data.failed = 1;
201 }
202
203 if (!data.failed)
204 {
205 struct info all[20];
206 struct bdata bdata;
207 int j;
208
209 bdata.all = &all[0];
210 bdata.index = 0;
211 bdata.max = 20;
212 bdata.failed = 0;
213
214 for (j = 0; j < 3; ++j)
215 {
216 i = backtrace_pcinfo (state, addrs[j], callback_one,
217 error_callback_one, &bdata);
218 if (i != 0)
219 {
220 fprintf (stderr,
221 ("test3: unexpected return value "
222 "from backtrace_pcinfo %d\n"),
223 i);
224 bdata.failed = 1;
225 }
226 if (!bdata.failed && bdata.index != (size_t) (j + 1))
227 {
228 fprintf (stderr,
229 ("wrong number of calls from backtrace_pcinfo "
230 "got %u expected %d\n"),
231 (unsigned int) bdata.index, j + 1);
232 bdata.failed = 1;
233 }
234 }
235
236 check ("test3", 0, all, f3line, "f23", "btest.c", &bdata.failed);
237 check ("test3", 1, all, f2line, "f22", "btest.c", &bdata.failed);
238 check ("test3", 2, all, f1line, "test3", "btest.c", &bdata.failed);
239
240 if (bdata.failed)
241 data.failed = 1;
242
243 for (j = 0; j < 3; ++j)
244 {
245 struct symdata symdata;
246
247 symdata.name = NULL;
248 symdata.val = 0;
249 symdata.size = 0;
250 symdata.failed = 0;
251
252 i = backtrace_syminfo (state, addrs[j], callback_three,
253 error_callback_three, &symdata);
254 if (i == 0)
255 {
256 fprintf (stderr,
257 ("test3: [%d]: unexpected return value "
258 "from backtrace_syminfo %d\n"),
259 j, i);
260 symdata.failed = 1;
261 }
262
263 if (!symdata.failed)
264 {
265 const char *expected;
266
267 switch (j)
268 {
269 case 0:
270 expected = "f23";
271 break;
272 case 1:
273 expected = "f22";
274 break;
275 case 2:
276 expected = "test3";
277 break;
278 default:
279 assert (0);
280 }
281
282 if (symdata.name == NULL)
283 {
284 fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
285 symdata.failed = 1;
286 }
287 /* Use strncmp, not strcmp, because GCC might create a
288 clone. */
289 else if (strncmp (symdata.name, expected, strlen (expected))
290 != 0)
291 {
292 fprintf (stderr,
293 ("test3: [%d]: unexpected syminfo name "
294 "got %s expected %s\n"),
295 j, symdata.name, expected);
296 symdata.failed = 1;
297 }
298 }
299
300 if (symdata.failed)
301 data.failed = 1;
302 }
303 }
304
305 printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
306
307 if (data.failed)
308 ++failures;
309
310 return failures;
311 }
312
313 /* Test the backtrace_simple function with inlined functions. */
314
315 static inline int test4 (void) __attribute__ ((always_inline, unused));
316 static inline int f32 (int) __attribute__ ((always_inline));
317 static inline int f33 (int, int) __attribute__ ((always_inline));
318
319 static inline int
320 test4 (void)
321 {
322 return f32 (__LINE__) + 1;
323 }
324
325 static inline int
326 f32 (int f1line)
327 {
328 return f33 (f1line, __LINE__) + 2;
329 }
330
331 static inline int
332 f33 (int f1line, int f2line)
333 {
334 uintptr_t addrs[20];
335 struct sdata data;
336 int f3line;
337 int i;
338
339 data.addrs = &addrs[0];
340 data.index = 0;
341 data.max = 20;
342 data.failed = 0;
343
344 f3line = __LINE__ + 1;
345 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
346
347 if (i != 0)
348 {
349 fprintf (stderr, "test3: unexpected return value %d\n", i);
350 data.failed = 1;
351 }
352
353 if (!data.failed)
354 {
355 struct info all[20];
356 struct bdata bdata;
357
358 bdata.all = &all[0];
359 bdata.index = 0;
360 bdata.max = 20;
361 bdata.failed = 0;
362
363 i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
364 &bdata);
365 if (i != 0)
366 {
367 fprintf (stderr,
368 ("test4: unexpected return value "
369 "from backtrace_pcinfo %d\n"),
370 i);
371 bdata.failed = 1;
372 }
373
374 check ("test4", 0, all, f3line, "f33", "btest.c", &bdata.failed);
375 check ("test4", 1, all, f2line, "f32", "btest.c", &bdata.failed);
376 check ("test4", 2, all, f1line, "test4", "btest.c", &bdata.failed);
377
378 if (bdata.failed)
379 data.failed = 1;
380 }
381
382 printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
383
384 if (data.failed)
385 ++failures;
386
387 return failures;
388 }
389
390 static int test5 (void) __attribute__ ((unused));
391
392 int global = 1;
393
394 static int
395 test5 (void)
396 {
397 struct symdata symdata;
398 int i;
399 uintptr_t addr = (uintptr_t) &global;
400
401 if (sizeof (global) > 1)
402 addr += 1;
403
404 symdata.name = NULL;
405 symdata.val = 0;
406 symdata.size = 0;
407 symdata.failed = 0;
408
409 i = backtrace_syminfo (state, addr, callback_three,
410 error_callback_three, &symdata);
411 if (i == 0)
412 {
413 fprintf (stderr,
414 "test5: unexpected return value from backtrace_syminfo %d\n",
415 i);
416 symdata.failed = 1;
417 }
418
419 if (!symdata.failed)
420 {
421 if (symdata.name == NULL)
422 {
423 fprintf (stderr, "test5: NULL syminfo name\n");
424 symdata.failed = 1;
425 }
426 else if (!(strncmp (symdata.name, "global", 6) == 0
427 && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
428 {
429 fprintf (stderr,
430 "test5: unexpected syminfo name got %s expected %s\n",
431 symdata.name, "global");
432 symdata.failed = 1;
433 }
434 else if (symdata.val != (uintptr_t) &global)
435 {
436 fprintf (stderr,
437 "test5: unexpected syminfo value got %lx expected %lx\n",
438 (unsigned long) symdata.val,
439 (unsigned long) (uintptr_t) &global);
440 symdata.failed = 1;
441 }
442 else if (symdata.size != sizeof (global))
443 {
444 fprintf (stderr,
445 "test5: unexpected syminfo size got %lx expected %lx\n",
446 (unsigned long) symdata.size,
447 (unsigned long) sizeof (global));
448 symdata.failed = 1;
449 }
450 }
451
452 printf ("%s: backtrace_syminfo variable\n",
453 symdata.failed ? "FAIL" : "PASS");
454
455 if (symdata.failed)
456 ++failures;
457
458 return failures;
459 }
460
461 /* Check that are no files left open. */
462
463 static void
464 check_open_files (void)
465 {
466 int i;
467
468 for (i = 3; i < 10; i++)
469 {
470 if (close (i) == 0)
471 {
472 fprintf (stderr,
473 "ERROR: descriptor %d still open after tests complete\n",
474 i);
475 ++failures;
476 }
477 }
478 }
479
480 /* Run all the tests. */
481
482 int
483 main (int argc ATTRIBUTE_UNUSED, char **argv)
484 {
485 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
486 error_callback_create, NULL);
487
488 #if BACKTRACE_SUPPORTED
489 test1 ();
490 test2 ();
491 test3 ();
492 test4 ();
493 #if BACKTRACE_SUPPORTS_DATA
494 test5 ();
495 #endif
496 #endif
497
498 check_open_files ();
499
500 exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
501 }