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