1 /* btest.c -- Test for libbacktrace library
2 Copyright (C) 2012 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. */
42 #include "filenames.h"
44 #include "backtrace.h"
45 #include "backtrace-supported.h"
47 /* Portable attribute syntax. Actually some of these tests probably
48 won't work if the attributes are not recognized. */
51 # define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
54 #if (GCC_VERSION < 2007)
55 # define __attribute__(x)
58 #ifndef ATTRIBUTE_UNUSED
59 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
62 /* Used to collect backtrace info. */
71 /* Passed to backtrace callback function. */
81 /* Passed to backtrace_simple callback function. */
91 /* Passed to backtrace_syminfo callback function. */
100 /* The backtrace state. */
104 /* The number of failures. */
108 /* Return the base name in a path. */
117 for (s
= p
; *s
!= '\0'; ++s
)
119 if (IS_DIR_SEPARATOR (*s
))
122 return last
!= NULL
? last
: p
;
125 /* Check an entry in a struct info array. */
128 check (const char *name
, int index
, const struct info
*all
, int want_lineno
,
129 const char *want_function
, int *failed
)
133 if (strcmp (base (all
[index
].filename
), "btest.c") != 0)
135 fprintf (stderr
, "%s: [%d]: got %s expected test.c\n", name
, index
,
136 all
[index
].filename
);
139 if (all
[index
].lineno
!= want_lineno
)
141 fprintf (stderr
, "%s: [%d]: got %d expected %d\n", name
, index
,
142 all
[index
].lineno
, want_lineno
);
145 if (strcmp (all
[index
].function
, want_function
) != 0)
147 fprintf (stderr
, "%s: [%d]: got %s expected %s\n", name
, index
,
148 all
[index
].function
, want_function
);
153 /* The backtrace callback function. */
156 callback_one (void *vdata
, uintptr_t pc ATTRIBUTE_UNUSED
,
157 const char *filename
, int lineno
, const char *function
)
159 struct bdata
*data
= (struct bdata
*) vdata
;
162 if (data
->index
>= data
->max
)
164 fprintf (stderr
, "callback_one: callback called too many times\n");
169 p
= &data
->all
[data
->index
];
170 if (filename
== NULL
)
174 p
->filename
= strdup (filename
);
175 assert (p
->filename
!= NULL
);
178 if (function
== NULL
)
182 p
->function
= strdup (function
);
183 assert (p
->function
!= NULL
);
190 /* An error callback passed to backtrace. */
193 error_callback_one (void *vdata
, const char *msg
, int errnum
)
195 struct bdata
*data
= (struct bdata
*) vdata
;
197 fprintf (stderr
, "%s", msg
);
199 fprintf (stderr
, ": %s", strerror (errnum
));
200 fprintf (stderr
, "\n");
204 /* The backtrace_simple callback function. */
207 callback_two (void *vdata
, uintptr_t pc
)
209 struct sdata
*data
= (struct sdata
*) vdata
;
211 if (data
->index
>= data
->max
)
213 fprintf (stderr
, "callback_two: callback called too many times\n");
218 data
->addrs
[data
->index
] = pc
;
224 /* An error callback passed to backtrace_simple. */
227 error_callback_two (void *vdata
, const char *msg
, int errnum
)
229 struct sdata
*data
= (struct sdata
*) vdata
;
231 fprintf (stderr
, "%s", msg
);
233 fprintf (stderr
, ": %s", strerror (errnum
));
234 fprintf (stderr
, "\n");
238 /* The backtrace_syminfo callback function. */
241 callback_three (void *vdata
, uintptr_t pc ATTRIBUTE_UNUSED
,
242 const char *symname
, uintptr_t symval
)
244 struct symdata
*data
= (struct symdata
*) vdata
;
250 data
->name
= strdup (symname
);
251 assert (data
->name
!= NULL
);
256 /* The backtrace_syminfo error callback function. */
259 error_callback_three (void *vdata
, const char *msg
, int errnum
)
261 struct symdata
*data
= (struct symdata
*) vdata
;
263 fprintf (stderr
, "%s", msg
);
265 fprintf (stderr
, ": %s", strerror (errnum
));
266 fprintf (stderr
, "\n");
270 /* Test the backtrace function with non-inlined functions. */
272 static int test1 (void) __attribute__ ((noinline
, unused
));
273 static int f2 (int) __attribute__ ((noinline
));
274 static int f3 (int, int) __attribute__ ((noinline
));
279 /* Returning a value here and elsewhere avoids a tailcall which
280 would mess up the backtrace. */
281 return f2 (__LINE__
) + 1;
287 return f3 (f1line
, __LINE__
) + 2;
291 f3 (int f1line
, int f2line
)
303 f3line
= __LINE__
+ 1;
304 i
= backtrace_full (state
, 0, callback_one
, error_callback_one
, &data
);
308 fprintf (stderr
, "test1: unexpected return value %d\n", i
);
312 check ("test1", 0, all
, f3line
, "f3", &data
.failed
);
313 check ("test1", 1, all
, f2line
, "f2", &data
.failed
);
314 check ("test1", 2, all
, f1line
, "test1", &data
.failed
);
316 printf ("%s: backtrace_full noinline\n", data
.failed
? "FAIL" : "PASS");
324 /* Test the backtrace function with inlined functions. */
326 static inline int test2 (void) __attribute__ ((always_inline
, unused
));
327 static inline int f12 (int) __attribute__ ((always_inline
));
328 static inline int f13 (int, int) __attribute__ ((always_inline
));
333 return f12 (__LINE__
) + 1;
339 return f13 (f1line
, __LINE__
) + 2;
343 f13 (int f1line
, int f2line
)
355 f3line
= __LINE__
+ 1;
356 i
= backtrace_full (state
, 0, callback_one
, error_callback_one
, &data
);
360 fprintf (stderr
, "test2: unexpected return value %d\n", i
);
364 check ("test2", 0, all
, f3line
, "f13", &data
.failed
);
365 check ("test2", 1, all
, f2line
, "f12", &data
.failed
);
366 check ("test2", 2, all
, f1line
, "test2", &data
.failed
);
368 printf ("%s: backtrace_full inline\n", data
.failed
? "FAIL" : "PASS");
376 /* Test the backtrace_simple function with non-inlined functions. */
378 static int test3 (void) __attribute__ ((noinline
, unused
));
379 static int f22 (int) __attribute__ ((noinline
));
380 static int f23 (int, int) __attribute__ ((noinline
));
385 return f22 (__LINE__
) + 1;
391 return f23 (f1line
, __LINE__
) + 2;
395 f23 (int f1line
, int f2line
)
402 data
.addrs
= &addrs
[0];
407 f3line
= __LINE__
+ 1;
408 i
= backtrace_simple (state
, 0, callback_two
, error_callback_two
, &data
);
412 fprintf (stderr
, "test3: unexpected return value %d\n", i
);
427 for (j
= 0; j
< 3; ++j
)
429 i
= backtrace_pcinfo (state
, addrs
[j
], callback_one
,
430 error_callback_one
, &bdata
);
434 ("test3: unexpected return value "
435 "from backtrace_pcinfo %d\n"),
439 if (!bdata
.failed
&& bdata
.index
!= (size_t) (j
+ 1))
442 ("wrong number of calls from backtrace_pcinfo "
443 "got %u expected %d\n"),
444 (unsigned int) bdata
.index
, j
+ 1);
449 check ("test3", 0, all
, f3line
, "f23", &bdata
.failed
);
450 check ("test3", 1, all
, f2line
, "f22", &bdata
.failed
);
451 check ("test3", 2, all
, f1line
, "test3", &bdata
.failed
);
456 for (j
= 0; j
< 3; ++j
)
458 struct symdata symdata
;
464 i
= backtrace_syminfo (state
, addrs
[j
], callback_three
,
465 error_callback_three
, &symdata
);
469 ("test3: [%d]: unexpected return value "
470 "from backtrace_syminfo %d\n"),
477 const char *expected
;
494 if (symdata
.name
== NULL
)
496 fprintf (stderr
, "test3: [%d]: NULL syminfo name\n", j
);
499 /* Use strncmp, not strcmp, because GCC might create a
501 else if (strncmp (symdata
.name
, expected
, strlen (expected
))
505 ("test3: [%d]: unexpected syminfo name "
506 "got %s expected %s\n"),
507 j
, symdata
.name
, expected
);
517 printf ("%s: backtrace_simple noinline\n", data
.failed
? "FAIL" : "PASS");
525 /* Test the backtrace_simple function with inlined functions. */
527 static inline int test4 (void) __attribute__ ((always_inline
, unused
));
528 static inline int f32 (int) __attribute__ ((always_inline
));
529 static inline int f33 (int, int) __attribute__ ((always_inline
));
534 return f32 (__LINE__
) + 1;
540 return f33 (f1line
, __LINE__
) + 2;
544 f33 (int f1line
, int f2line
)
551 data
.addrs
= &addrs
[0];
556 f3line
= __LINE__
+ 1;
557 i
= backtrace_simple (state
, 0, callback_two
, error_callback_two
, &data
);
561 fprintf (stderr
, "test3: unexpected return value %d\n", i
);
575 i
= backtrace_pcinfo (state
, addrs
[0], callback_one
, error_callback_one
,
580 ("test4: unexpected return value "
581 "from backtrace_pcinfo %d\n"),
586 check ("test4", 0, all
, f3line
, "f33", &bdata
.failed
);
587 check ("test4", 1, all
, f2line
, "f32", &bdata
.failed
);
588 check ("test4", 2, all
, f1line
, "test4", &bdata
.failed
);
594 printf ("%s: backtrace_simple inline\n", data
.failed
? "FAIL" : "PASS");
603 error_callback_create (void *data ATTRIBUTE_UNUSED
, const char *msg
,
606 fprintf (stderr
, "%s", msg
);
608 fprintf (stderr
, ": %s", strerror (errnum
));
609 fprintf (stderr
, "\n");
613 /* Run all the tests. */
616 main (int argc ATTRIBUTE_UNUSED
, char **argv
)
618 state
= backtrace_create_state (argv
[0], BACKTRACE_SUPPORTS_THREADS
,
619 error_callback_create
, NULL
);
621 #if BACKTRACE_SUPPORTED
628 exit (failures
? EXIT_FAILURE
: EXIT_SUCCESS
);