xref: /netbsd-src/external/gpl3/gcc/dist/libbacktrace/btest.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
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;
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 {
243   struct symdata *data = (struct symdata *) vdata;
244 
245   if (symname == NULL)
246     data->name = NULL;
247   else
248     {
249       data->name = strdup (symname);
250       assert (data->name != NULL);
251     }
252   data->val = symval;
253 }
254 
255 /* The backtrace_syminfo error callback function.  */
256 
257 static void
258 error_callback_three (void *vdata, const char *msg, int errnum)
259 {
260   struct symdata *data = (struct symdata *) vdata;
261 
262   fprintf (stderr, "%s", msg);
263   if (errnum > 0)
264     fprintf (stderr, ": %s", strerror (errnum));
265   fprintf (stderr, "\n");
266   data->failed = 1;
267 }
268 
269 /* Test the backtrace function with non-inlined functions.  */
270 
271 static int test1 (void) __attribute__ ((noinline, unused));
272 static int f2 (int) __attribute__ ((noinline));
273 static int f3 (int, int) __attribute__ ((noinline));
274 
275 static int
276 test1 (void)
277 {
278   /* Returning a value here and elsewhere avoids a tailcall which
279      would mess up the backtrace.  */
280   return f2 (__LINE__) + 1;
281 }
282 
283 static int
284 f2 (int f1line)
285 {
286   return f3 (f1line, __LINE__) + 2;
287 }
288 
289 static int
290 f3 (int f1line, int f2line)
291 {
292   struct info all[20];
293   struct bdata data;
294   int f3line;
295   int i;
296 
297   data.all = &all[0];
298   data.index = 0;
299   data.max = 20;
300   data.failed = 0;
301 
302   f3line = __LINE__ + 1;
303   i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
304 
305   if (i != 0)
306     {
307       fprintf (stderr, "test1: unexpected return value %d\n", i);
308       data.failed = 1;
309     }
310 
311   check ("test1", 0, all, f3line, "f3", &data.failed);
312   check ("test1", 1, all, f2line, "f2", &data.failed);
313   check ("test1", 2, all, f1line, "test1", &data.failed);
314 
315   printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
316 
317   if (data.failed)
318     ++failures;
319 
320   return failures;
321 }
322 
323 /* Test the backtrace function with inlined functions.  */
324 
325 static inline int test2 (void) __attribute__ ((always_inline, unused));
326 static inline int f12 (int) __attribute__ ((always_inline));
327 static inline int f13 (int, int) __attribute__ ((always_inline));
328 
329 static inline int
330 test2 (void)
331 {
332   return f12 (__LINE__) + 1;
333 }
334 
335 static inline int
336 f12 (int f1line)
337 {
338   return f13 (f1line, __LINE__) + 2;
339 }
340 
341 static inline int
342 f13 (int f1line, int f2line)
343 {
344   struct info all[20];
345   struct bdata data;
346   int f3line;
347   int i;
348 
349   data.all = &all[0];
350   data.index = 0;
351   data.max = 20;
352   data.failed = 0;
353 
354   f3line = __LINE__ + 1;
355   i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
356 
357   if (i != 0)
358     {
359       fprintf (stderr, "test2: unexpected return value %d\n", i);
360       data.failed = 1;
361     }
362 
363   check ("test2", 0, all, f3line, "f13", &data.failed);
364   check ("test2", 1, all, f2line, "f12", &data.failed);
365   check ("test2", 2, all, f1line, "test2", &data.failed);
366 
367   printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
368 
369   if (data.failed)
370     ++failures;
371 
372   return failures;
373 }
374 
375 /* Test the backtrace_simple function with non-inlined functions.  */
376 
377 static int test3 (void) __attribute__ ((noinline, unused));
378 static int f22 (int) __attribute__ ((noinline));
379 static int f23 (int, int) __attribute__ ((noinline));
380 
381 static int
382 test3 (void)
383 {
384   return f22 (__LINE__) + 1;
385 }
386 
387 static int
388 f22 (int f1line)
389 {
390   return f23 (f1line, __LINE__) + 2;
391 }
392 
393 static int
394 f23 (int f1line, int f2line)
395 {
396   uintptr_t addrs[20];
397   struct sdata data;
398   int f3line;
399   int i;
400 
401   data.addrs = &addrs[0];
402   data.index = 0;
403   data.max = 20;
404   data.failed = 0;
405 
406   f3line = __LINE__ + 1;
407   i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
408 
409   if (i != 0)
410     {
411       fprintf (stderr, "test3: unexpected return value %d\n", i);
412       data.failed = 1;
413     }
414 
415   if (!data.failed)
416     {
417       struct info all[20];
418       struct bdata bdata;
419       int j;
420 
421       bdata.all = &all[0];
422       bdata.index = 0;
423       bdata.max = 20;
424       bdata.failed = 0;
425 
426       for (j = 0; j < 3; ++j)
427 	{
428 	  i = backtrace_pcinfo (state, addrs[j], callback_one,
429 				error_callback_one, &bdata);
430 	  if (i != 0)
431 	    {
432 	      fprintf (stderr,
433 		       ("test3: unexpected return value "
434 			"from backtrace_pcinfo %d\n"),
435 		       i);
436 	      bdata.failed = 1;
437 	    }
438 	  if (!bdata.failed && bdata.index != (size_t) (j + 1))
439 	    {
440 	      fprintf (stderr,
441 		       ("wrong number of calls from backtrace_pcinfo "
442 			"got %u expected %d\n"),
443 		       (unsigned int) bdata.index, j + 1);
444 	      bdata.failed = 1;
445 	    }
446 	}
447 
448       check ("test3", 0, all, f3line, "f23", &bdata.failed);
449       check ("test3", 1, all, f2line, "f22", &bdata.failed);
450       check ("test3", 2, all, f1line, "test3", &bdata.failed);
451 
452       if (bdata.failed)
453 	data.failed = 1;
454 
455       for (j = 0; j < 3; ++j)
456 	{
457 	  struct symdata symdata;
458 
459 	  symdata.name = NULL;
460 	  symdata.val = 0;
461 	  symdata.failed = 0;
462 
463 	  i = backtrace_syminfo (state, addrs[j], callback_three,
464 				 error_callback_three, &symdata);
465 	  if (i == 0)
466 	    {
467 	      fprintf (stderr,
468 		       ("test3: [%d]: unexpected return value "
469 			"from backtrace_syminfo %d\n"),
470 		       j, i);
471 	      symdata.failed = 1;
472 	    }
473 
474 	  if (!symdata.failed)
475 	    {
476 	      const char *expected;
477 
478 	      switch (j)
479 		{
480 		case 0:
481 		  expected = "f23";
482 		  break;
483 		case 1:
484 		  expected = "f22";
485 		  break;
486 		case 2:
487 		  expected = "test3";
488 		  break;
489 		default:
490 		  assert (0);
491 		}
492 
493 	      if (symdata.name == NULL)
494 		{
495 		  fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
496 		  symdata.failed = 1;
497 		}
498 	      /* Use strncmp, not strcmp, because GCC might create a
499 		 clone.  */
500 	      else if (strncmp (symdata.name, expected, strlen (expected))
501 		       != 0)
502 		{
503 		  fprintf (stderr,
504 			   ("test3: [%d]: unexpected syminfo name "
505 			    "got %s expected %s\n"),
506 			   j, symdata.name, expected);
507 		  symdata.failed = 1;
508 		}
509 	    }
510 
511 	  if (symdata.failed)
512 	    data.failed = 1;
513 	}
514     }
515 
516   printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
517 
518   if (data.failed)
519     ++failures;
520 
521   return failures;
522 }
523 
524 /* Test the backtrace_simple function with inlined functions.  */
525 
526 static inline int test4 (void) __attribute__ ((always_inline, unused));
527 static inline int f32 (int) __attribute__ ((always_inline));
528 static inline int f33 (int, int) __attribute__ ((always_inline));
529 
530 static inline int
531 test4 (void)
532 {
533   return f32 (__LINE__) + 1;
534 }
535 
536 static inline int
537 f32 (int f1line)
538 {
539   return f33 (f1line, __LINE__) + 2;
540 }
541 
542 static inline int
543 f33 (int f1line, int f2line)
544 {
545   uintptr_t addrs[20];
546   struct sdata data;
547   int f3line;
548   int i;
549 
550   data.addrs = &addrs[0];
551   data.index = 0;
552   data.max = 20;
553   data.failed = 0;
554 
555   f3line = __LINE__ + 1;
556   i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
557 
558   if (i != 0)
559     {
560       fprintf (stderr, "test3: unexpected return value %d\n", i);
561       data.failed = 1;
562     }
563 
564   if (!data.failed)
565     {
566       struct info all[20];
567       struct bdata bdata;
568 
569       bdata.all = &all[0];
570       bdata.index = 0;
571       bdata.max = 20;
572       bdata.failed = 0;
573 
574       i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
575 			    &bdata);
576       if (i != 0)
577 	{
578 	  fprintf (stderr,
579 		   ("test4: unexpected return value "
580 		    "from backtrace_pcinfo %d\n"),
581 		   i);
582 	  bdata.failed = 1;
583 	}
584 
585       check ("test4", 0, all, f3line, "f33", &bdata.failed);
586       check ("test4", 1, all, f2line, "f32", &bdata.failed);
587       check ("test4", 2, all, f1line, "test4", &bdata.failed);
588 
589       if (bdata.failed)
590 	data.failed = 1;
591     }
592 
593   printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
594 
595   if (data.failed)
596     ++failures;
597 
598   return failures;
599 }
600 
601 static void
602 error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
603 		       int errnum)
604 {
605   fprintf (stderr, "%s", msg);
606   if (errnum > 0)
607     fprintf (stderr, ": %s", strerror (errnum));
608   fprintf (stderr, "\n");
609   exit (EXIT_FAILURE);
610 }
611 
612 /* Run all the tests.  */
613 
614 int
615 main (int argc ATTRIBUTE_UNUSED, char **argv)
616 {
617   state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
618 				  error_callback_create, NULL);
619 
620 #if BACKTRACE_SUPPORTED
621   test1 ();
622   test2 ();
623   test3 ();
624   test4 ();
625 #endif
626 
627   exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
628 }
629