1 /* btest.c -- Test for libbacktrace library
2 Copyright (C) 2012-2014 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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
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.
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. */
33 /* This program tests the externally visible interfaces of the
34 libbacktrace library. */
41 #include "filenames.h"
43 #include "backtrace.h"
44 #include "backtrace-supported.h"
46 /* Portable attribute syntax. Actually some of these tests probably
47 won't work if the attributes are not recognized. */
50 # define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
53 #if (GCC_VERSION < 2007)
54 # define __attribute__(x)
57 #ifndef ATTRIBUTE_UNUSED
58 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
61 /* Used to collect backtrace info. */
70 /* Passed to backtrace callback function. */
80 /* Passed to backtrace_simple callback function. */
90 /* Passed to backtrace_syminfo callback function. */
99 /* The backtrace state. */
103 /* The number of failures. */
107 /* Return the base name in a path. */
116 for (s = p; *s != '\0'; ++s)
118 if (IS_DIR_SEPARATOR (*s))
121 return last != NULL ? last : p;
124 /* Check an entry in a struct info array. */
127 check (const char *name, int index, const struct info *all, int want_lineno,
128 const char *want_function, int *failed)
132 if (all[index].filename == NULL || all[index].function == NULL)
134 fprintf (stderr, "%s: [%d]: missing file name or function name\n",
139 if (strcmp (base (all[index].filename), "btest.c") != 0)
141 fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
142 all[index].filename);
145 if (all[index].lineno != want_lineno)
147 fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
148 all[index].lineno, want_lineno);
151 if (strcmp (all[index].function, want_function) != 0)
153 fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
154 all[index].function, want_function);
159 /* The backtrace callback function. */
162 callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
163 const char *filename, int lineno, const char *function)
165 struct bdata *data = (struct bdata *) vdata;
168 if (data->index >= data->max)
170 fprintf (stderr, "callback_one: callback called too many times\n");
175 p = &data->all[data->index];
176 if (filename == NULL)
180 p->filename = strdup (filename);
181 assert (p->filename != NULL);
184 if (function == NULL)
188 p->function = strdup (function);
189 assert (p->function != NULL);
196 /* An error callback passed to backtrace. */
199 error_callback_one (void *vdata, const char *msg, int errnum)
201 struct bdata *data = (struct bdata *) vdata;
203 fprintf (stderr, "%s", msg);
205 fprintf (stderr, ": %s", strerror (errnum));
206 fprintf (stderr, "\n");
210 /* The backtrace_simple callback function. */
213 callback_two (void *vdata, uintptr_t pc)
215 struct sdata *data = (struct sdata *) vdata;
217 if (data->index >= data->max)
219 fprintf (stderr, "callback_two: callback called too many times\n");
224 data->addrs[data->index] = pc;
230 /* An error callback passed to backtrace_simple. */
233 error_callback_two (void *vdata, const char *msg, int errnum)
235 struct sdata *data = (struct sdata *) vdata;
237 fprintf (stderr, "%s", msg);
239 fprintf (stderr, ": %s", strerror (errnum));
240 fprintf (stderr, "\n");
244 /* The backtrace_syminfo callback function. */
247 callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
248 const char *symname, uintptr_t symval,
251 struct symdata *data = (struct symdata *) vdata;
257 data->name = strdup (symname);
258 assert (data->name != NULL);
261 data->size = symsize;
264 /* The backtrace_syminfo error callback function. */
267 error_callback_three (void *vdata, const char *msg, int errnum)
269 struct symdata *data = (struct symdata *) vdata;
271 fprintf (stderr, "%s", msg);
273 fprintf (stderr, ": %s", strerror (errnum));
274 fprintf (stderr, "\n");
278 /* Test the backtrace function with non-inlined functions. */
280 static int test1 (void) __attribute__ ((noinline, unused));
281 static int f2 (int) __attribute__ ((noinline));
282 static int f3 (int, int) __attribute__ ((noinline));
287 /* Returning a value here and elsewhere avoids a tailcall which
288 would mess up the backtrace. */
289 return f2 (__LINE__) + 1;
295 return f3 (f1line, __LINE__) + 2;
299 f3 (int f1line, int f2line)
311 f3line = __LINE__ + 1;
312 i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
316 fprintf (stderr, "test1: unexpected return value %d\n", i);
323 "test1: not enough frames; got %zu, expected at least 3\n",
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);
332 printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
340 /* Test the backtrace function with inlined functions. */
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));
349 return f12 (__LINE__) + 1;
355 return f13 (f1line, __LINE__) + 2;
359 f13 (int f1line, int f2line)
371 f3line = __LINE__ + 1;
372 i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
376 fprintf (stderr, "test2: unexpected return value %d\n", i);
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);
384 printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
392 /* Test the backtrace_simple function with non-inlined functions. */
394 static int test3 (void) __attribute__ ((noinline, unused));
395 static int f22 (int) __attribute__ ((noinline));
396 static int f23 (int, int) __attribute__ ((noinline));
401 return f22 (__LINE__) + 1;
407 return f23 (f1line, __LINE__) + 2;
411 f23 (int f1line, int f2line)
418 data.addrs = &addrs[0];
423 f3line = __LINE__ + 1;
424 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
428 fprintf (stderr, "test3: unexpected return value %d\n", i);
443 for (j = 0; j < 3; ++j)
445 i = backtrace_pcinfo (state, addrs[j], callback_one,
446 error_callback_one, &bdata);
450 ("test3: unexpected return value "
451 "from backtrace_pcinfo %d\n"),
455 if (!bdata.failed && bdata.index != (size_t) (j + 1))
458 ("wrong number of calls from backtrace_pcinfo "
459 "got %u expected %d\n"),
460 (unsigned int) bdata.index, j + 1);
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);
472 for (j = 0; j < 3; ++j)
474 struct symdata symdata;
481 i = backtrace_syminfo (state, addrs[j], callback_three,
482 error_callback_three, &symdata);
486 ("test3: [%d]: unexpected return value "
487 "from backtrace_syminfo %d\n"),
494 const char *expected;
511 if (symdata.name == NULL)
513 fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
516 /* Use strncmp, not strcmp, because GCC might create a
518 else if (strncmp (symdata.name, expected, strlen (expected))
522 ("test3: [%d]: unexpected syminfo name "
523 "got %s expected %s\n"),
524 j, symdata.name, expected);
534 printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
542 /* Test the backtrace_simple function with inlined functions. */
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));
551 return f32 (__LINE__) + 1;
557 return f33 (f1line, __LINE__) + 2;
561 f33 (int f1line, int f2line)
568 data.addrs = &addrs[0];
573 f3line = __LINE__ + 1;
574 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
578 fprintf (stderr, "test3: unexpected return value %d\n", i);
592 i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
597 ("test4: unexpected return value "
598 "from backtrace_pcinfo %d\n"),
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);
611 printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
624 struct symdata symdata;
626 uintptr_t addr = (uintptr_t) &global;
628 if (sizeof (global) > 1)
636 i = backtrace_syminfo (state, addr, callback_three,
637 error_callback_three, &symdata);
641 "test5: unexpected return value from backtrace_syminfo %d\n",
648 if (symdata.name == NULL)
650 fprintf (stderr, "test5: NULL syminfo name\n");
653 else if (strcmp (symdata.name, "global") != 0)
656 "test5: unexpected syminfo name got %s expected %s\n",
657 symdata.name, "global");
660 else if (symdata.val != (uintptr_t) &global)
663 "test5: unexpected syminfo value got %lx expected %lx\n",
664 (unsigned long) symdata.val,
665 (unsigned long) (uintptr_t) &global);
668 else if (symdata.size != sizeof (global))
671 "test5: unexpected syminfo size got %lx expected %lx\n",
672 (unsigned long) symdata.size,
673 (unsigned long) sizeof (global));
678 printf ("%s: backtrace_syminfo variable\n",
679 symdata.failed ? "FAIL" : "PASS");
688 error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
691 fprintf (stderr, "%s", msg);
693 fprintf (stderr, ": %s", strerror (errnum));
694 fprintf (stderr, "\n");
698 /* Run all the tests. */
701 main (int argc ATTRIBUTE_UNUSED, char **argv)
703 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
704 error_callback_create, NULL);
706 #if BACKTRACE_SUPPORTED
714 exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);