xref: /netbsd-src/external/gpl3/gcc.old/dist/libbacktrace/btest.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* btest.c -- Test for libbacktrace library
2    Copyright (C) 2012-2015 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 int global = 1;
620 
621 static int
622 test5 (void)
623 {
624   struct symdata symdata;
625   int i;
626   uintptr_t addr = (uintptr_t) &global;
627 
628   if (sizeof (global) > 1)
629     addr += 1;
630 
631   symdata.name = NULL;
632   symdata.val = 0;
633   symdata.size = 0;
634   symdata.failed = 0;
635 
636   i = backtrace_syminfo (state, addr, callback_three,
637 			 error_callback_three, &symdata);
638   if (i == 0)
639     {
640       fprintf (stderr,
641 	       "test5: unexpected return value from backtrace_syminfo %d\n",
642 	       i);
643       symdata.failed = 1;
644     }
645 
646   if (!symdata.failed)
647     {
648       if (symdata.name == NULL)
649 	{
650 	  fprintf (stderr, "test5: NULL syminfo name\n");
651 	  symdata.failed = 1;
652 	}
653       else if (strcmp (symdata.name, "global") != 0)
654 	{
655 	  fprintf (stderr,
656 		   "test5: unexpected syminfo name got %s expected %s\n",
657 		   symdata.name, "global");
658 	  symdata.failed = 1;
659 	}
660       else if (symdata.val != (uintptr_t) &global)
661 	{
662 	  fprintf (stderr,
663 		   "test5: unexpected syminfo value got %lx expected %lx\n",
664 		   (unsigned long) symdata.val,
665 		   (unsigned long) (uintptr_t) &global);
666 	  symdata.failed = 1;
667 	}
668       else if (symdata.size != sizeof (global))
669 	{
670 	  fprintf (stderr,
671 		   "test5: unexpected syminfo size got %lx expected %lx\n",
672 		   (unsigned long) symdata.size,
673 		   (unsigned long) sizeof (global));
674 	  symdata.failed = 1;
675 	}
676     }
677 
678   printf ("%s: backtrace_syminfo variable\n",
679 	  symdata.failed ? "FAIL" : "PASS");
680 
681   if (symdata.failed)
682     ++failures;
683 
684   return failures;
685 }
686 
687 static void
688 error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
689 		       int errnum)
690 {
691   fprintf (stderr, "%s", msg);
692   if (errnum > 0)
693     fprintf (stderr, ": %s", strerror (errnum));
694   fprintf (stderr, "\n");
695   exit (EXIT_FAILURE);
696 }
697 
698 /* Run all the tests.  */
699 
700 int
701 main (int argc ATTRIBUTE_UNUSED, char **argv)
702 {
703   state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
704 				  error_callback_create, NULL);
705 
706 #if BACKTRACE_SUPPORTED
707   test1 ();
708   test2 ();
709   test3 ();
710   test4 ();
711   test5 ();
712 #endif
713 
714   exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
715 }
716