]> git.cworth.org Git - vogl/blob - src/libbacktrace/btest.c
Make voglgen accept specdir as option
[vogl] / src / libbacktrace / btest.c
1 /* btest.c -- Test for libbacktrace library
2    Copyright (C) 2012-2014 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 }