1 /* btest.c -- Test for libbacktrace library
2 Copyright (C) 2012-2013 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 (strcmp (base (all
[index
].filename
), "btest.c") != 0)
134 fprintf (stderr
, "%s: [%d]: got %s expected test.c\n", name
, index
,
135 all
[index
].filename
);
138 if (all
[index
].lineno
!= want_lineno
)
140 fprintf (stderr
, "%s: [%d]: got %d expected %d\n", name
, index
,
141 all
[index
].lineno
, want_lineno
);
144 if (strcmp (all
[index
].function
, want_function
) != 0)
146 fprintf (stderr
, "%s: [%d]: got %s expected %s\n", name
, index
,
147 all
[index
].function
, want_function
);
152 /* The backtrace callback function. */
155 callback_one (void *vdata
, uintptr_t pc ATTRIBUTE_UNUSED
,
156 const char *filename
, int lineno
, const char *function
)
158 struct bdata
*data
= (struct bdata
*) vdata
;
161 if (data
->index
>= data
->max
)
163 fprintf (stderr
, "callback_one: callback called too many times\n");
168 p
= &data
->all
[data
->index
];
169 if (filename
== NULL
)
173 p
->filename
= strdup (filename
);
174 assert (p
->filename
!= NULL
);
177 if (function
== NULL
)
181 p
->function
= strdup (function
);
182 assert (p
->function
!= NULL
);
189 /* An error callback passed to backtrace. */
192 error_callback_one (void *vdata
, const char *msg
, int errnum
)
194 struct bdata
*data
= (struct bdata
*) vdata
;
196 fprintf (stderr
, "%s", msg
);
198 fprintf (stderr
, ": %s", strerror (errnum
));
199 fprintf (stderr
, "\n");
203 /* The backtrace_simple callback function. */
206 callback_two (void *vdata
, uintptr_t pc
)
208 struct sdata
*data
= (struct sdata
*) vdata
;
210 if (data
->index
>= data
->max
)
212 fprintf (stderr
, "callback_two: callback called too many times\n");
217 data
->addrs
[data
->index
] = pc
;
223 /* An error callback passed to backtrace_simple. */
226 error_callback_two (void *vdata
, const char *msg
, int errnum
)
228 struct sdata
*data
= (struct sdata
*) vdata
;
230 fprintf (stderr
, "%s", msg
);
232 fprintf (stderr
, ": %s", strerror (errnum
));
233 fprintf (stderr
, "\n");
237 /* The backtrace_syminfo callback function. */
240 callback_three (void *vdata
, uintptr_t pc ATTRIBUTE_UNUSED
,
241 const char *symname
, uintptr_t symval
,
244 struct symdata
*data
= (struct symdata
*) vdata
;
250 data
->name
= strdup (symname
);
251 assert (data
->name
!= NULL
);
254 data
->size
= symsize
;
257 /* The backtrace_syminfo error callback function. */
260 error_callback_three (void *vdata
, const char *msg
, int errnum
)
262 struct symdata
*data
= (struct symdata
*) vdata
;
264 fprintf (stderr
, "%s", msg
);
266 fprintf (stderr
, ": %s", strerror (errnum
));
267 fprintf (stderr
, "\n");
271 /* Test the backtrace function with non-inlined functions. */
273 static int test1 (void) __attribute__ ((noinline
, unused
));
274 static int f2 (int) __attribute__ ((noinline
));
275 static int f3 (int, int) __attribute__ ((noinline
));
280 /* Returning a value here and elsewhere avoids a tailcall which
281 would mess up the backtrace. */
282 return f2 (__LINE__
) + 1;
288 return f3 (f1line
, __LINE__
) + 2;
292 f3 (int f1line
, int f2line
)
304 f3line
= __LINE__
+ 1;
305 i
= backtrace_full (state
, 0, callback_one
, error_callback_one
, &data
);
309 fprintf (stderr
, "test1: unexpected return value %d\n", i
);
313 check ("test1", 0, all
, f3line
, "f3", &data
.failed
);
314 check ("test1", 1, all
, f2line
, "f2", &data
.failed
);
315 check ("test1", 2, all
, f1line
, "test1", &data
.failed
);
317 printf ("%s: backtrace_full noinline\n", data
.failed
? "FAIL" : "PASS");
325 /* Test the backtrace function with inlined functions. */
327 static inline int test2 (void) __attribute__ ((always_inline
, unused
));
328 static inline int f12 (int) __attribute__ ((always_inline
));
329 static inline int f13 (int, int) __attribute__ ((always_inline
));
334 return f12 (__LINE__
) + 1;
340 return f13 (f1line
, __LINE__
) + 2;
344 f13 (int f1line
, int f2line
)
356 f3line
= __LINE__
+ 1;
357 i
= backtrace_full (state
, 0, callback_one
, error_callback_one
, &data
);
361 fprintf (stderr
, "test2: unexpected return value %d\n", i
);
365 check ("test2", 0, all
, f3line
, "f13", &data
.failed
);
366 check ("test2", 1, all
, f2line
, "f12", &data
.failed
);
367 check ("test2", 2, all
, f1line
, "test2", &data
.failed
);
369 printf ("%s: backtrace_full inline\n", data
.failed
? "FAIL" : "PASS");
377 /* Test the backtrace_simple function with non-inlined functions. */
379 static int test3 (void) __attribute__ ((noinline
, unused
));
380 static int f22 (int) __attribute__ ((noinline
));
381 static int f23 (int, int) __attribute__ ((noinline
));
386 return f22 (__LINE__
) + 1;
392 return f23 (f1line
, __LINE__
) + 2;
396 f23 (int f1line
, int f2line
)
403 data
.addrs
= &addrs
[0];
408 f3line
= __LINE__
+ 1;
409 i
= backtrace_simple (state
, 0, callback_two
, error_callback_two
, &data
);
413 fprintf (stderr
, "test3: unexpected return value %d\n", i
);
428 for (j
= 0; j
< 3; ++j
)
430 i
= backtrace_pcinfo (state
, addrs
[j
], callback_one
,
431 error_callback_one
, &bdata
);
435 ("test3: unexpected return value "
436 "from backtrace_pcinfo %d\n"),
440 if (!bdata
.failed
&& bdata
.index
!= (size_t) (j
+ 1))
443 ("wrong number of calls from backtrace_pcinfo "
444 "got %u expected %d\n"),
445 (unsigned int) bdata
.index
, j
+ 1);
450 check ("test3", 0, all
, f3line
, "f23", &bdata
.failed
);
451 check ("test3", 1, all
, f2line
, "f22", &bdata
.failed
);
452 check ("test3", 2, all
, f1line
, "test3", &bdata
.failed
);
457 for (j
= 0; j
< 3; ++j
)
459 struct symdata symdata
;
466 i
= backtrace_syminfo (state
, addrs
[j
], callback_three
,
467 error_callback_three
, &symdata
);
471 ("test3: [%d]: unexpected return value "
472 "from backtrace_syminfo %d\n"),
479 const char *expected
;
496 if (symdata
.name
== NULL
)
498 fprintf (stderr
, "test3: [%d]: NULL syminfo name\n", j
);
501 /* Use strncmp, not strcmp, because GCC might create a
503 else if (strncmp (symdata
.name
, expected
, strlen (expected
))
507 ("test3: [%d]: unexpected syminfo name "
508 "got %s expected %s\n"),
509 j
, symdata
.name
, expected
);
519 printf ("%s: backtrace_simple noinline\n", data
.failed
? "FAIL" : "PASS");
527 /* Test the backtrace_simple function with inlined functions. */
529 static inline int test4 (void) __attribute__ ((always_inline
, unused
));
530 static inline int f32 (int) __attribute__ ((always_inline
));
531 static inline int f33 (int, int) __attribute__ ((always_inline
));
536 return f32 (__LINE__
) + 1;
542 return f33 (f1line
, __LINE__
) + 2;
546 f33 (int f1line
, int f2line
)
553 data
.addrs
= &addrs
[0];
558 f3line
= __LINE__
+ 1;
559 i
= backtrace_simple (state
, 0, callback_two
, error_callback_two
, &data
);
563 fprintf (stderr
, "test3: unexpected return value %d\n", i
);
577 i
= backtrace_pcinfo (state
, addrs
[0], callback_one
, error_callback_one
,
582 ("test4: unexpected return value "
583 "from backtrace_pcinfo %d\n"),
588 check ("test4", 0, all
, f3line
, "f33", &bdata
.failed
);
589 check ("test4", 1, all
, f2line
, "f32", &bdata
.failed
);
590 check ("test4", 2, all
, f1line
, "test4", &bdata
.failed
);
596 printf ("%s: backtrace_simple inline\n", data
.failed
? "FAIL" : "PASS");
609 struct symdata symdata
;
611 uintptr_t addr
= (uintptr_t) &global
;
613 if (sizeof (global
) > 1)
621 i
= backtrace_syminfo (state
, addr
, callback_three
,
622 error_callback_three
, &symdata
);
626 "test5: unexpected return value from backtrace_syminfo %d\n",
633 if (symdata
.name
== NULL
)
635 fprintf (stderr
, "test5: NULL syminfo name\n");
638 else if (strcmp (symdata
.name
, "global") != 0)
641 "test5: unexpected syminfo name got %s expected %s\n",
642 symdata
.name
, "global");
645 else if (symdata
.val
!= (uintptr_t) &global
)
648 "test5: unexpected syminfo value got %lx expected %lx\n",
649 (unsigned long) symdata
.val
,
650 (unsigned long) (uintptr_t) &global
);
653 else if (symdata
.size
!= sizeof (global
))
656 "test5: unexpected syminfo size got %lx expected %lx\n",
657 (unsigned long) symdata
.size
,
658 (unsigned long) sizeof (global
));
663 printf ("%s: backtrace_syminfo variable\n",
664 symdata
.failed
? "FAIL" : "PASS");
673 error_callback_create (void *data ATTRIBUTE_UNUSED
, const char *msg
,
676 fprintf (stderr
, "%s", msg
);
678 fprintf (stderr
, ": %s", strerror (errnum
));
679 fprintf (stderr
, "\n");
683 /* Run all the tests. */
686 main (int argc ATTRIBUTE_UNUSED
, char **argv
)
688 state
= backtrace_create_state (argv
[0], BACKTRACE_SUPPORTS_THREADS
,
689 error_callback_create
, NULL
);
691 #if BACKTRACE_SUPPORTED
699 exit (failures
? EXIT_FAILURE
: EXIT_SUCCESS
);