1 /* mtest.c -- Minidebug test for libbacktrace library
2 Copyright (C) 2020-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 using libbacktrace with a program that uses the
34 minidebuginfo format in a .gnu_debugdata section. See
35 https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html
36 for a bit more information about minidebuginfo. What is relevant
37 for libbacktrace is that we have just a symbol table, with no debug
38 info, so we should be able to do a function backtrace, but we can't
39 do a file/line backtrace. */
45 #include "backtrace.h"
46 #include "backtrace-supported.h"
50 static int test1 (void) __attribute__ ((noinline
, noclone
, unused
));
51 static int f2 (int) __attribute__ ((noinline
, noclone
));
52 static int f3 (int, int) __attribute__ ((noinline
, noclone
));
54 /* Collected PC values. */
56 static uintptr_t addrs
[20];
58 /* The backtrace callback function. This is like callback_one in
59 testlib.c, but it saves the PC also. */
62 callback_mtest (void *vdata
, uintptr_t pc
, const char *filename
, int lineno
,
65 struct bdata
*data
= (struct bdata
*) vdata
;
67 if (data
->index
>= sizeof addrs
/ sizeof addrs
[0])
69 fprintf (stderr
, "callback_mtest: callback called too many times\n");
74 addrs
[data
->index
] = pc
;
76 return callback_one (vdata
, pc
, filename
, lineno
, function
);
79 /* Test the backtrace function with non-inlined functions. (We don't
80 test with inlined functions because they won't work with minidebug
86 /* Returning a value here and elsewhere avoids a tailcall which
87 would mess up the backtrace. */
88 return f2 (__LINE__
) + 1;
94 return f3 (f1line
, __LINE__
) + 2;
98 f3 (int f1line
__attribute__ ((unused
)), int f2line
__attribute__ ((unused
)))
110 i
= backtrace_full (state
, 0, callback_mtest
, error_callback_one
, &data
);
114 fprintf (stderr
, "test1: unexpected return value %d\n", i
);
121 "test1: not enough frames; got %zu, expected at least 3\n",
126 /* When using minidebug we don't expect the function name here. */
128 for (j
= 0; j
< 3 && j
< data
.index
; j
++)
130 if (all
[j
].function
== NULL
)
132 struct symdata symdata
;
139 i
= backtrace_syminfo (state
, addrs
[j
], callback_three
,
140 error_callback_three
, &symdata
);
144 ("test1: [%zu], unexpected return value from "
145 "backtrace_syminfo %d\n"),
149 else if (symdata
.name
== NULL
)
151 fprintf (stderr
, "test1: [%zu]: syminfo did not find name\n", j
);
155 all
[j
].function
= strdup (symdata
.name
);
161 if (all
[0].function
== NULL
)
163 fprintf (stderr
, "test1: [0]: missing function name\n");
166 else if (strcmp (all
[0].function
, "f3") != 0)
168 fprintf (stderr
, "test1: [0]: got %s expected %s\n",
169 all
[0].function
, "f3");
176 if (all
[1].function
== NULL
)
178 fprintf (stderr
, "test1: [1]: missing function name\n");
181 else if (strcmp (all
[1].function
, "f2") != 0)
183 fprintf (stderr
, "test1: [1]: got %s expected %s\n",
184 all
[0].function
, "f2");
191 if (all
[2].function
== NULL
)
193 fprintf (stderr
, "test1: [2]: missing function name\n");
196 else if (strcmp (all
[2].function
, "test1") != 0)
198 fprintf (stderr
, "test1: [2]: got %s expected %s\n",
199 all
[0].function
, "test1");
204 printf ("%s: backtrace_full noinline\n", data
.failed
? "FAIL" : "PASS");
212 /* Test the backtrace_simple function with non-inlined functions. */
214 static int test3 (void) __attribute__ ((noinline
, noclone
, unused
));
215 static int f22 (int) __attribute__ ((noinline
, noclone
));
216 static int f23 (int, int) __attribute__ ((noinline
, noclone
));
221 return f22 (__LINE__
) + 1;
227 return f23 (f1line
, __LINE__
) + 2;
231 f23 (int f1line
__attribute__ ((unused
)), int f2line
__attribute__ ((unused
)))
237 data
.addrs
= &addrs
[0];
242 i
= backtrace_simple (state
, 0, callback_two
, error_callback_two
, &data
);
246 fprintf (stderr
, "test3: unexpected return value %d\n", i
);
254 for (j
= 0; j
< 3; ++j
)
256 struct symdata symdata
;
263 i
= backtrace_syminfo (state
, addrs
[j
], callback_three
,
264 error_callback_three
, &symdata
);
268 ("test3: [%d]: unexpected return value "
269 "from backtrace_syminfo %d\n"),
276 const char *expected
;
293 if (symdata
.name
== NULL
)
295 fprintf (stderr
, "test3: [%d]: NULL syminfo name\n", j
);
298 /* Use strncmp, not strcmp, because GCC might create a
300 else if (strncmp (symdata
.name
, expected
, strlen (expected
))
304 ("test3: [%d]: unexpected syminfo name "
305 "got %s expected %s\n"),
306 j
, symdata
.name
, expected
);
316 printf ("%s: backtrace_simple noinline\n", data
.failed
? "FAIL" : "PASS");
324 int test5 (void) __attribute__ ((unused
));
331 struct symdata symdata
;
333 uintptr_t addr
= (uintptr_t) &global
;
335 if (sizeof (global
) > 1)
343 i
= backtrace_syminfo (state
, addr
, callback_three
,
344 error_callback_three
, &symdata
);
348 "test5: unexpected return value from backtrace_syminfo %d\n",
355 if (symdata
.name
== NULL
)
357 fprintf (stderr
, "test5: NULL syminfo name\n");
360 else if (!(strncmp (symdata
.name
, "global", 6) == 0
361 && (symdata
.name
[6] == '\0'|| symdata
.name
[6] == '.')))
364 "test5: unexpected syminfo name got %s expected %s\n",
365 symdata
.name
, "global");
368 else if (symdata
.val
!= (uintptr_t) &global
)
371 "test5: unexpected syminfo value got %lx expected %lx\n",
372 (unsigned long) symdata
.val
,
373 (unsigned long) (uintptr_t) &global
);
376 else if (symdata
.size
!= sizeof (global
))
379 "test5: unexpected syminfo size got %lx expected %lx\n",
380 (unsigned long) symdata
.size
,
381 (unsigned long) sizeof (global
));
386 printf ("%s: backtrace_syminfo variable\n",
387 symdata
.failed
? "FAIL" : "PASS");
396 main (int argc ATTRIBUTE_UNUSED
, char **argv
)
398 state
= backtrace_create_state (argv
[0], BACKTRACE_SUPPORTS_THREADS
,
399 error_callback_create
, NULL
);
401 #if BACKTRACE_SUPPORTED
404 #if BACKTRACE_SUPPORTS_DATA
409 exit (failures
? EXIT_FAILURE
: EXIT_SUCCESS
);