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