1 /* btest.c -- Test for libbacktrace library
2 Copyright (C) 2012-2024 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. */
43 #include "filenames.h"
45 #include "backtrace.h"
46 #include "backtrace-supported.h"
50 /* Test the backtrace function with non-inlined functions. */
52 static int test1 (void) __attribute__ ((noinline
, noclone
, unused
));
53 static int f2 (int) __attribute__ ((noinline
, noclone
));
54 static int f3 (int, int) __attribute__ ((noinline
, noclone
));
59 /* Returning a value here and elsewhere avoids a tailcall which
60 would mess up the backtrace. */
61 return f2 (__LINE__
) + 1;
67 return f3 (f1line
, __LINE__
) + 2;
71 f3 (int f1line
, int f2line
)
83 f3line
= __LINE__
+ 1;
84 i
= backtrace_full (state
, 0, callback_one
, error_callback_one
, &data
);
88 fprintf (stderr
, "test1: unexpected return value %d\n", i
);
95 "test1: not enough frames; got %zu, expected at least 3\n",
100 check ("test1", 0, all
, f3line
, "f3", "btest.c", &data
.failed
);
101 check ("test1", 1, all
, f2line
, "f2", "btest.c", &data
.failed
);
102 check ("test1", 2, all
, f1line
, "test1", "btest.c", &data
.failed
);
104 printf ("%s: backtrace_full noinline\n", data
.failed
? "FAIL" : "PASS");
112 /* Test the backtrace function with inlined functions. */
114 static inline int test2 (void) __attribute__ ((always_inline
, unused
));
115 static inline int f12 (int) __attribute__ ((always_inline
));
116 static inline int f13 (int, int) __attribute__ ((always_inline
));
121 return f12 (__LINE__
) + 1;
127 return f13 (f1line
, __LINE__
) + 2;
131 f13 (int f1line
, int f2line
)
143 f3line
= __LINE__
+ 1;
144 i
= backtrace_full (state
, 0, callback_one
, error_callback_one
, &data
);
148 fprintf (stderr
, "test2: unexpected return value %d\n", i
);
152 check ("test2", 0, all
, f3line
, "f13", "btest.c", &data
.failed
);
153 check ("test2", 1, all
, f2line
, "f12", "btest.c", &data
.failed
);
154 check ("test2", 2, all
, f1line
, "test2", "btest.c", &data
.failed
);
156 printf ("%s: backtrace_full inline\n", data
.failed
? "FAIL" : "PASS");
164 /* Test the backtrace_simple function with non-inlined functions. */
166 static int test3 (void) __attribute__ ((noinline
, noclone
, unused
));
167 static int f22 (int) __attribute__ ((noinline
, noclone
));
168 static int f23 (int, int) __attribute__ ((noinline
, noclone
));
173 return f22 (__LINE__
) + 1;
179 return f23 (f1line
, __LINE__
) + 2;
183 f23 (int f1line
, int f2line
)
190 data
.addrs
= &addrs
[0];
195 f3line
= __LINE__
+ 1;
196 i
= backtrace_simple (state
, 0, callback_two
, error_callback_two
, &data
);
200 fprintf (stderr
, "test3: unexpected return value %d\n", i
);
215 for (j
= 0; j
< 3; ++j
)
217 i
= backtrace_pcinfo (state
, addrs
[j
], callback_one
,
218 error_callback_one
, &bdata
);
222 ("test3: unexpected return value "
223 "from backtrace_pcinfo %d\n"),
227 if (!bdata
.failed
&& bdata
.index
!= (size_t) (j
+ 1))
230 ("wrong number of calls from backtrace_pcinfo "
231 "got %u expected %d\n"),
232 (unsigned int) bdata
.index
, j
+ 1);
237 check ("test3", 0, all
, f3line
, "f23", "btest.c", &bdata
.failed
);
238 check ("test3", 1, all
, f2line
, "f22", "btest.c", &bdata
.failed
);
239 check ("test3", 2, all
, f1line
, "test3", "btest.c", &bdata
.failed
);
244 for (j
= 0; j
< 3; ++j
)
246 struct symdata symdata
;
253 i
= backtrace_syminfo (state
, addrs
[j
], callback_three
,
254 error_callback_three
, &symdata
);
258 ("test3: [%d]: unexpected return value "
259 "from backtrace_syminfo %d\n"),
266 const char *expected
;
283 if (symdata
.name
== NULL
)
285 fprintf (stderr
, "test3: [%d]: NULL syminfo name\n", j
);
288 /* Use strncmp, not strcmp, because GCC might create a
290 else if (strncmp (symdata
.name
, expected
, strlen (expected
))
294 ("test3: [%d]: unexpected syminfo name "
295 "got %s expected %s\n"),
296 j
, symdata
.name
, expected
);
306 printf ("%s: backtrace_simple noinline\n", data
.failed
? "FAIL" : "PASS");
314 /* Test the backtrace_simple function with inlined functions. */
316 static inline int test4 (void) __attribute__ ((always_inline
, unused
));
317 static inline int f32 (int) __attribute__ ((always_inline
));
318 static inline int f33 (int, int) __attribute__ ((always_inline
));
323 return f32 (__LINE__
) + 1;
329 return f33 (f1line
, __LINE__
) + 2;
333 f33 (int f1line
, int f2line
)
340 data
.addrs
= &addrs
[0];
345 f3line
= __LINE__
+ 1;
346 i
= backtrace_simple (state
, 0, callback_two
, error_callback_two
, &data
);
350 fprintf (stderr
, "test3: unexpected return value %d\n", i
);
364 i
= backtrace_pcinfo (state
, addrs
[0], callback_one
, error_callback_one
,
369 ("test4: unexpected return value "
370 "from backtrace_pcinfo %d\n"),
375 check ("test4", 0, all
, f3line
, "f33", "btest.c", &bdata
.failed
);
376 check ("test4", 1, all
, f2line
, "f32", "btest.c", &bdata
.failed
);
377 check ("test4", 2, all
, f1line
, "test4", "btest.c", &bdata
.failed
);
383 printf ("%s: backtrace_simple inline\n", data
.failed
? "FAIL" : "PASS");
391 static int test5 (void) __attribute__ ((unused
));
398 struct symdata symdata
;
400 uintptr_t addr
= (uintptr_t) &global
;
402 if (sizeof (global
) > 1)
410 i
= backtrace_syminfo (state
, addr
, callback_three
,
411 error_callback_three
, &symdata
);
415 "test5: unexpected return value from backtrace_syminfo %d\n",
422 if (symdata
.name
== NULL
)
424 fprintf (stderr
, "test5: NULL syminfo name\n");
427 else if (!(strncmp (symdata
.name
, "global", 6) == 0
428 && (symdata
.name
[6] == '\0'|| symdata
.name
[6] == '.')))
431 "test5: unexpected syminfo name got %s expected %s\n",
432 symdata
.name
, "global");
435 else if (symdata
.val
!= (uintptr_t) &global
)
438 "test5: unexpected syminfo value got %lx expected %lx\n",
439 (unsigned long) symdata
.val
,
440 (unsigned long) (uintptr_t) &global
);
443 else if (symdata
.size
!= sizeof (global
))
446 "test5: unexpected syminfo size got %lx expected %lx\n",
447 (unsigned long) symdata
.size
,
448 (unsigned long) sizeof (global
));
453 printf ("%s: backtrace_syminfo variable\n",
454 symdata
.failed
? "FAIL" : "PASS");
462 #define MIN_DESCRIPTOR 3
463 #define MAX_DESCRIPTOR 10
465 static int fstat_status
[MAX_DESCRIPTOR
];
467 /* Check files that are available. */
470 check_available_files (void)
473 for (unsigned i
= MIN_DESCRIPTOR
; i
< MAX_DESCRIPTOR
; i
++)
474 fstat_status
[i
] = fstat (i
, &s
);
477 /* Check that are no files left open. */
480 check_open_files (void)
482 for (unsigned i
= MIN_DESCRIPTOR
; i
< MAX_DESCRIPTOR
; i
++)
484 if (fstat_status
[i
] != 0 && close (i
) == 0)
487 "ERROR: descriptor %d still open after tests complete\n",
494 /* Run all the tests. */
497 main (int argc ATTRIBUTE_UNUSED
, char **argv
)
499 check_available_files ();
501 state
= backtrace_create_state (argv
[0], BACKTRACE_SUPPORTS_THREADS
,
502 error_callback_create
, NULL
);
504 #if BACKTRACE_SUPPORTED
509 #if BACKTRACE_SUPPORTS_DATA
516 exit (failures
? EXIT_FAILURE
: EXIT_SUCCESS
);