Remove dead FIXME
[gcc.git] / libbacktrace / btest.c
1 /* btest.c -- Test for libbacktrace library
2 Copyright (C) 2012-2016 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
41 #include "filenames.h"
42
43 #include "backtrace.h"
44 #include "backtrace-supported.h"
45
46 /* Portable attribute syntax. Actually some of these tests probably
47 won't work if the attributes are not recognized. */
48
49 #ifndef GCC_VERSION
50 # define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
51 #endif
52
53 #if (GCC_VERSION < 2007)
54 # define __attribute__(x)
55 #endif
56
57 #ifndef ATTRIBUTE_UNUSED
58 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
59 #endif
60
61 /* Used to collect backtrace info. */
62
63 struct info
64 {
65 char *filename;
66 int lineno;
67 char *function;
68 };
69
70 /* Passed to backtrace callback function. */
71
72 struct bdata
73 {
74 struct info *all;
75 size_t index;
76 size_t max;
77 int failed;
78 };
79
80 /* Passed to backtrace_simple callback function. */
81
82 struct sdata
83 {
84 uintptr_t *addrs;
85 size_t index;
86 size_t max;
87 int failed;
88 };
89
90 /* Passed to backtrace_syminfo callback function. */
91
92 struct symdata
93 {
94 const char *name;
95 uintptr_t val, size;
96 int failed;
97 };
98
99 /* The backtrace state. */
100
101 static void *state;
102
103 /* The number of failures. */
104
105 static int failures;
106
107 /* Return the base name in a path. */
108
109 static const char *
110 base (const char *p)
111 {
112 const char *last;
113 const char *s;
114
115 last = NULL;
116 for (s = p; *s != '\0'; ++s)
117 {
118 if (IS_DIR_SEPARATOR (*s))
119 last = s + 1;
120 }
121 return last != NULL ? last : p;
122 }
123
124 /* Check an entry in a struct info array. */
125
126 static void
127 check (const char *name, int index, const struct info *all, int want_lineno,
128 const char *want_function, int *failed)
129 {
130 if (*failed)
131 return;
132 if (all[index].filename == NULL || all[index].function == NULL)
133 {
134 fprintf (stderr, "%s: [%d]: missing file name or function name\n",
135 name, index);
136 *failed = 1;
137 return;
138 }
139 if (strcmp (base (all[index].filename), "btest.c") != 0)
140 {
141 fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
142 all[index].filename);
143 *failed = 1;
144 }
145 if (all[index].lineno != want_lineno)
146 {
147 fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
148 all[index].lineno, want_lineno);
149 *failed = 1;
150 }
151 if (strcmp (all[index].function, want_function) != 0)
152 {
153 fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
154 all[index].function, want_function);
155 *failed = 1;
156 }
157 }
158
159 /* The backtrace callback function. */
160
161 static int
162 callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
163 const char *filename, int lineno, const char *function)
164 {
165 struct bdata *data = (struct bdata *) vdata;
166 struct info *p;
167
168 if (data->index >= data->max)
169 {
170 fprintf (stderr, "callback_one: callback called too many times\n");
171 data->failed = 1;
172 return 1;
173 }
174
175 p = &data->all[data->index];
176 if (filename == NULL)
177 p->filename = NULL;
178 else
179 {
180 p->filename = strdup (filename);
181 assert (p->filename != NULL);
182 }
183 p->lineno = lineno;
184 if (function == NULL)
185 p->function = NULL;
186 else
187 {
188 p->function = strdup (function);
189 assert (p->function != NULL);
190 }
191 ++data->index;
192
193 return 0;
194 }
195
196 /* An error callback passed to backtrace. */
197
198 static void
199 error_callback_one (void *vdata, const char *msg, int errnum)
200 {
201 struct bdata *data = (struct bdata *) vdata;
202
203 fprintf (stderr, "%s", msg);
204 if (errnum > 0)
205 fprintf (stderr, ": %s", strerror (errnum));
206 fprintf (stderr, "\n");
207 data->failed = 1;
208 }
209
210 /* The backtrace_simple callback function. */
211
212 static int
213 callback_two (void *vdata, uintptr_t pc)
214 {
215 struct sdata *data = (struct sdata *) vdata;
216
217 if (data->index >= data->max)
218 {
219 fprintf (stderr, "callback_two: callback called too many times\n");
220 data->failed = 1;
221 return 1;
222 }
223
224 data->addrs[data->index] = pc;
225 ++data->index;
226
227 return 0;
228 }
229
230 /* An error callback passed to backtrace_simple. */
231
232 static void
233 error_callback_two (void *vdata, const char *msg, int errnum)
234 {
235 struct sdata *data = (struct sdata *) vdata;
236
237 fprintf (stderr, "%s", msg);
238 if (errnum > 0)
239 fprintf (stderr, ": %s", strerror (errnum));
240 fprintf (stderr, "\n");
241 data->failed = 1;
242 }
243
244 /* The backtrace_syminfo callback function. */
245
246 static void
247 callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
248 const char *symname, uintptr_t symval,
249 uintptr_t symsize)
250 {
251 struct symdata *data = (struct symdata *) vdata;
252
253 if (symname == NULL)
254 data->name = NULL;
255 else
256 {
257 data->name = strdup (symname);
258 assert (data->name != NULL);
259 }
260 data->val = symval;
261 data->size = symsize;
262 }
263
264 /* The backtrace_syminfo error callback function. */
265
266 static void
267 error_callback_three (void *vdata, const char *msg, int errnum)
268 {
269 struct symdata *data = (struct symdata *) vdata;
270
271 fprintf (stderr, "%s", msg);
272 if (errnum > 0)
273 fprintf (stderr, ": %s", strerror (errnum));
274 fprintf (stderr, "\n");
275 data->failed = 1;
276 }
277
278 /* Test the backtrace function with non-inlined functions. */
279
280 static int test1 (void) __attribute__ ((noinline, unused));
281 static int f2 (int) __attribute__ ((noinline));
282 static int f3 (int, int) __attribute__ ((noinline));
283
284 static int
285 test1 (void)
286 {
287 /* Returning a value here and elsewhere avoids a tailcall which
288 would mess up the backtrace. */
289 return f2 (__LINE__) + 1;
290 }
291
292 static int
293 f2 (int f1line)
294 {
295 return f3 (f1line, __LINE__) + 2;
296 }
297
298 static int
299 f3 (int f1line, int f2line)
300 {
301 struct info all[20];
302 struct bdata data;
303 int f3line;
304 int i;
305
306 data.all = &all[0];
307 data.index = 0;
308 data.max = 20;
309 data.failed = 0;
310
311 f3line = __LINE__ + 1;
312 i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
313
314 if (i != 0)
315 {
316 fprintf (stderr, "test1: unexpected return value %d\n", i);
317 data.failed = 1;
318 }
319
320 if (data.index < 3)
321 {
322 fprintf (stderr,
323 "test1: not enough frames; got %zu, expected at least 3\n",
324 data.index);
325 data.failed = 1;
326 }
327
328 check ("test1", 0, all, f3line, "f3", &data.failed);
329 check ("test1", 1, all, f2line, "f2", &data.failed);
330 check ("test1", 2, all, f1line, "test1", &data.failed);
331
332 printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
333
334 if (data.failed)
335 ++failures;
336
337 return failures;
338 }
339
340 /* Test the backtrace function with inlined functions. */
341
342 static inline int test2 (void) __attribute__ ((always_inline, unused));
343 static inline int f12 (int) __attribute__ ((always_inline));
344 static inline int f13 (int, int) __attribute__ ((always_inline));
345
346 static inline int
347 test2 (void)
348 {
349 return f12 (__LINE__) + 1;
350 }
351
352 static inline int
353 f12 (int f1line)
354 {
355 return f13 (f1line, __LINE__) + 2;
356 }
357
358 static inline int
359 f13 (int f1line, int f2line)
360 {
361 struct info all[20];
362 struct bdata data;
363 int f3line;
364 int i;
365
366 data.all = &all[0];
367 data.index = 0;
368 data.max = 20;
369 data.failed = 0;
370
371 f3line = __LINE__ + 1;
372 i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
373
374 if (i != 0)
375 {
376 fprintf (stderr, "test2: unexpected return value %d\n", i);
377 data.failed = 1;
378 }
379
380 check ("test2", 0, all, f3line, "f13", &data.failed);
381 check ("test2", 1, all, f2line, "f12", &data.failed);
382 check ("test2", 2, all, f1line, "test2", &data.failed);
383
384 printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
385
386 if (data.failed)
387 ++failures;
388
389 return failures;
390 }
391
392 /* Test the backtrace_simple function with non-inlined functions. */
393
394 static int test3 (void) __attribute__ ((noinline, unused));
395 static int f22 (int) __attribute__ ((noinline));
396 static int f23 (int, int) __attribute__ ((noinline));
397
398 static int
399 test3 (void)
400 {
401 return f22 (__LINE__) + 1;
402 }
403
404 static int
405 f22 (int f1line)
406 {
407 return f23 (f1line, __LINE__) + 2;
408 }
409
410 static int
411 f23 (int f1line, int f2line)
412 {
413 uintptr_t addrs[20];
414 struct sdata data;
415 int f3line;
416 int i;
417
418 data.addrs = &addrs[0];
419 data.index = 0;
420 data.max = 20;
421 data.failed = 0;
422
423 f3line = __LINE__ + 1;
424 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
425
426 if (i != 0)
427 {
428 fprintf (stderr, "test3: unexpected return value %d\n", i);
429 data.failed = 1;
430 }
431
432 if (!data.failed)
433 {
434 struct info all[20];
435 struct bdata bdata;
436 int j;
437
438 bdata.all = &all[0];
439 bdata.index = 0;
440 bdata.max = 20;
441 bdata.failed = 0;
442
443 for (j = 0; j < 3; ++j)
444 {
445 i = backtrace_pcinfo (state, addrs[j], callback_one,
446 error_callback_one, &bdata);
447 if (i != 0)
448 {
449 fprintf (stderr,
450 ("test3: unexpected return value "
451 "from backtrace_pcinfo %d\n"),
452 i);
453 bdata.failed = 1;
454 }
455 if (!bdata.failed && bdata.index != (size_t) (j + 1))
456 {
457 fprintf (stderr,
458 ("wrong number of calls from backtrace_pcinfo "
459 "got %u expected %d\n"),
460 (unsigned int) bdata.index, j + 1);
461 bdata.failed = 1;
462 }
463 }
464
465 check ("test3", 0, all, f3line, "f23", &bdata.failed);
466 check ("test3", 1, all, f2line, "f22", &bdata.failed);
467 check ("test3", 2, all, f1line, "test3", &bdata.failed);
468
469 if (bdata.failed)
470 data.failed = 1;
471
472 for (j = 0; j < 3; ++j)
473 {
474 struct symdata symdata;
475
476 symdata.name = NULL;
477 symdata.val = 0;
478 symdata.size = 0;
479 symdata.failed = 0;
480
481 i = backtrace_syminfo (state, addrs[j], callback_three,
482 error_callback_three, &symdata);
483 if (i == 0)
484 {
485 fprintf (stderr,
486 ("test3: [%d]: unexpected return value "
487 "from backtrace_syminfo %d\n"),
488 j, i);
489 symdata.failed = 1;
490 }
491
492 if (!symdata.failed)
493 {
494 const char *expected;
495
496 switch (j)
497 {
498 case 0:
499 expected = "f23";
500 break;
501 case 1:
502 expected = "f22";
503 break;
504 case 2:
505 expected = "test3";
506 break;
507 default:
508 assert (0);
509 }
510
511 if (symdata.name == NULL)
512 {
513 fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
514 symdata.failed = 1;
515 }
516 /* Use strncmp, not strcmp, because GCC might create a
517 clone. */
518 else if (strncmp (symdata.name, expected, strlen (expected))
519 != 0)
520 {
521 fprintf (stderr,
522 ("test3: [%d]: unexpected syminfo name "
523 "got %s expected %s\n"),
524 j, symdata.name, expected);
525 symdata.failed = 1;
526 }
527 }
528
529 if (symdata.failed)
530 data.failed = 1;
531 }
532 }
533
534 printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
535
536 if (data.failed)
537 ++failures;
538
539 return failures;
540 }
541
542 /* Test the backtrace_simple function with inlined functions. */
543
544 static inline int test4 (void) __attribute__ ((always_inline, unused));
545 static inline int f32 (int) __attribute__ ((always_inline));
546 static inline int f33 (int, int) __attribute__ ((always_inline));
547
548 static inline int
549 test4 (void)
550 {
551 return f32 (__LINE__) + 1;
552 }
553
554 static inline int
555 f32 (int f1line)
556 {
557 return f33 (f1line, __LINE__) + 2;
558 }
559
560 static inline int
561 f33 (int f1line, int f2line)
562 {
563 uintptr_t addrs[20];
564 struct sdata data;
565 int f3line;
566 int i;
567
568 data.addrs = &addrs[0];
569 data.index = 0;
570 data.max = 20;
571 data.failed = 0;
572
573 f3line = __LINE__ + 1;
574 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
575
576 if (i != 0)
577 {
578 fprintf (stderr, "test3: unexpected return value %d\n", i);
579 data.failed = 1;
580 }
581
582 if (!data.failed)
583 {
584 struct info all[20];
585 struct bdata bdata;
586
587 bdata.all = &all[0];
588 bdata.index = 0;
589 bdata.max = 20;
590 bdata.failed = 0;
591
592 i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
593 &bdata);
594 if (i != 0)
595 {
596 fprintf (stderr,
597 ("test4: unexpected return value "
598 "from backtrace_pcinfo %d\n"),
599 i);
600 bdata.failed = 1;
601 }
602
603 check ("test4", 0, all, f3line, "f33", &bdata.failed);
604 check ("test4", 1, all, f2line, "f32", &bdata.failed);
605 check ("test4", 2, all, f1line, "test4", &bdata.failed);
606
607 if (bdata.failed)
608 data.failed = 1;
609 }
610
611 printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
612
613 if (data.failed)
614 ++failures;
615
616 return failures;
617 }
618
619 #if BACKTRACE_SUPPORTS_DATA
620
621 int global = 1;
622
623 static int
624 test5 (void)
625 {
626 struct symdata symdata;
627 int i;
628 uintptr_t addr = (uintptr_t) &global;
629
630 if (sizeof (global) > 1)
631 addr += 1;
632
633 symdata.name = NULL;
634 symdata.val = 0;
635 symdata.size = 0;
636 symdata.failed = 0;
637
638 i = backtrace_syminfo (state, addr, callback_three,
639 error_callback_three, &symdata);
640 if (i == 0)
641 {
642 fprintf (stderr,
643 "test5: unexpected return value from backtrace_syminfo %d\n",
644 i);
645 symdata.failed = 1;
646 }
647
648 if (!symdata.failed)
649 {
650 if (symdata.name == NULL)
651 {
652 fprintf (stderr, "test5: NULL syminfo name\n");
653 symdata.failed = 1;
654 }
655 else if (strcmp (symdata.name, "global") != 0)
656 {
657 fprintf (stderr,
658 "test5: unexpected syminfo name got %s expected %s\n",
659 symdata.name, "global");
660 symdata.failed = 1;
661 }
662 else if (symdata.val != (uintptr_t) &global)
663 {
664 fprintf (stderr,
665 "test5: unexpected syminfo value got %lx expected %lx\n",
666 (unsigned long) symdata.val,
667 (unsigned long) (uintptr_t) &global);
668 symdata.failed = 1;
669 }
670 else if (symdata.size != sizeof (global))
671 {
672 fprintf (stderr,
673 "test5: unexpected syminfo size got %lx expected %lx\n",
674 (unsigned long) symdata.size,
675 (unsigned long) sizeof (global));
676 symdata.failed = 1;
677 }
678 }
679
680 printf ("%s: backtrace_syminfo variable\n",
681 symdata.failed ? "FAIL" : "PASS");
682
683 if (symdata.failed)
684 ++failures;
685
686 return failures;
687 }
688
689 #endif /* BACKTRACE_SUPPORTS_DATA */
690
691 static void
692 error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
693 int errnum)
694 {
695 fprintf (stderr, "%s", msg);
696 if (errnum > 0)
697 fprintf (stderr, ": %s", strerror (errnum));
698 fprintf (stderr, "\n");
699 exit (EXIT_FAILURE);
700 }
701
702 /* Run all the tests. */
703
704 int
705 main (int argc ATTRIBUTE_UNUSED, char **argv)
706 {
707 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
708 error_callback_create, NULL);
709
710 #if BACKTRACE_SUPPORTED
711 test1 ();
712 test2 ();
713 test3 ();
714 test4 ();
715 #if BACKTRACE_SUPPORTS_DATA
716 test5 ();
717 #endif
718 #endif
719
720 exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
721 }