123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- /* mtest.c -- Minidebug test for libbacktrace library
- Copyright (C) 2020-2021 Free Software Foundation, Inc.
- Written by Ian Lance Taylor, Google.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- (1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- (2) Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- (3) The name of the author may not be used to
- endorse or promote products derived from this software without
- specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE. */
- /* This program tests using libbacktrace with a program that uses the
- minidebuginfo format in a .gnu_debugdata section. See
- https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html
- for a bit more information about minidebuginfo. What is relevant
- for libbacktrace is that we have just a symbol table, with no debug
- info, so we should be able to do a function backtrace, but we can't
- do a file/line backtrace. */
- #include <assert.h>
- #include <stdlib.h>
- #include <string.h>
- #include "backtrace.h"
- #include "backtrace-supported.h"
- #include "testlib.h"
- static int test1 (void) __attribute__ ((noinline, noclone, unused));
- static int f2 (int) __attribute__ ((noinline, noclone));
- static int f3 (int, int) __attribute__ ((noinline, noclone));
- /* Collected PC values. */
- static uintptr_t addrs[20];
- /* The backtrace callback function. This is like callback_one in
- testlib.c, but it saves the PC also. */
- static int
- callback_mtest (void *vdata, uintptr_t pc, const char *filename, int lineno,
- const char *function)
- {
- struct bdata *data = (struct bdata *) vdata;
- if (data->index >= sizeof addrs / sizeof addrs[0])
- {
- fprintf (stderr, "callback_mtest: callback called too many times\n");
- data->failed = 1;
- return 1;
- }
- addrs[data->index] = pc;
- return callback_one (vdata, pc, filename, lineno, function);
- }
- /* Test the backtrace function with non-inlined functions. (We don't
- test with inlined functions because they won't work with minidebug
- anyhow.) */
- static int
- test1 (void)
- {
- /* Returning a value here and elsewhere avoids a tailcall which
- would mess up the backtrace. */
- return f2 (__LINE__) + 1;
- }
- static int
- f2 (int f1line)
- {
- return f3 (f1line, __LINE__) + 2;
- }
- static int
- f3 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
- {
- struct info all[20];
- struct bdata data;
- int i;
- size_t j;
- data.all = &all[0];
- data.index = 0;
- data.max = 20;
- data.failed = 0;
- i = backtrace_full (state, 0, callback_mtest, error_callback_one, &data);
- if (i != 0)
- {
- fprintf (stderr, "test1: unexpected return value %d\n", i);
- data.failed = 1;
- }
- if (data.index < 3)
- {
- fprintf (stderr,
- "test1: not enough frames; got %zu, expected at least 3\n",
- data.index);
- data.failed = 1;
- }
- /* When using minidebug we don't expect the function name here. */
- for (j = 0; j < 3 && j < data.index; j++)
- {
- if (all[j].function == NULL)
- {
- struct symdata symdata;
- symdata.name = NULL;
- symdata.val = 0;
- symdata.size = 0;
- symdata.failed = 0;
- i = backtrace_syminfo (state, addrs[j], callback_three,
- error_callback_three, &symdata);
- if (i == 0)
- {
- fprintf (stderr,
- ("test1: [%zu], unexpected return value from "
- "backtrace_syminfo %d\n"),
- j, i);
- data.failed = 1;
- }
- else if (symdata.name == NULL)
- {
- fprintf (stderr, "test1: [%zu]: syminfo did not find name\n", j);
- data.failed = 1;
- }
- else
- all[j].function = strdup (symdata.name);
- }
- }
- if (data.index > 0)
- {
- if (all[0].function == NULL)
- {
- fprintf (stderr, "test1: [0]: missing function name\n");
- data.failed = 1;
- }
- else if (strcmp (all[0].function, "f3") != 0)
- {
- fprintf (stderr, "test1: [0]: got %s expected %s\n",
- all[0].function, "f3");
- data.failed = 1;
- }
- }
- if (data.index > 1)
- {
- if (all[1].function == NULL)
- {
- fprintf (stderr, "test1: [1]: missing function name\n");
- data.failed = 1;
- }
- else if (strcmp (all[1].function, "f2") != 0)
- {
- fprintf (stderr, "test1: [1]: got %s expected %s\n",
- all[0].function, "f2");
- data.failed = 1;
- }
- }
- if (data.index > 2)
- {
- if (all[2].function == NULL)
- {
- fprintf (stderr, "test1: [2]: missing function name\n");
- data.failed = 1;
- }
- else if (strcmp (all[2].function, "test1") != 0)
- {
- fprintf (stderr, "test1: [2]: got %s expected %s\n",
- all[0].function, "test1");
- data.failed = 1;
- }
- }
- printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
- if (data.failed)
- ++failures;
- return failures;
- }
- /* Test the backtrace_simple function with non-inlined functions. */
- static int test3 (void) __attribute__ ((noinline, noclone, unused));
- static int f22 (int) __attribute__ ((noinline, noclone));
- static int f23 (int, int) __attribute__ ((noinline, noclone));
- static int
- test3 (void)
- {
- return f22 (__LINE__) + 1;
- }
- static int
- f22 (int f1line)
- {
- return f23 (f1line, __LINE__) + 2;
- }
- static int
- f23 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
- {
- uintptr_t addrs[20];
- struct sdata data;
- int i;
- data.addrs = &addrs[0];
- data.index = 0;
- data.max = 20;
- data.failed = 0;
- i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
- if (i != 0)
- {
- fprintf (stderr, "test3: unexpected return value %d\n", i);
- data.failed = 1;
- }
- if (!data.failed)
- {
- int j;
- for (j = 0; j < 3; ++j)
- {
- struct symdata symdata;
- symdata.name = NULL;
- symdata.val = 0;
- symdata.size = 0;
- symdata.failed = 0;
- i = backtrace_syminfo (state, addrs[j], callback_three,
- error_callback_three, &symdata);
- if (i == 0)
- {
- fprintf (stderr,
- ("test3: [%d]: unexpected return value "
- "from backtrace_syminfo %d\n"),
- j, i);
- symdata.failed = 1;
- }
- if (!symdata.failed)
- {
- const char *expected;
- switch (j)
- {
- case 0:
- expected = "f23";
- break;
- case 1:
- expected = "f22";
- break;
- case 2:
- expected = "test3";
- break;
- default:
- assert (0);
- }
- if (symdata.name == NULL)
- {
- fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
- symdata.failed = 1;
- }
- /* Use strncmp, not strcmp, because GCC might create a
- clone. */
- else if (strncmp (symdata.name, expected, strlen (expected))
- != 0)
- {
- fprintf (stderr,
- ("test3: [%d]: unexpected syminfo name "
- "got %s expected %s\n"),
- j, symdata.name, expected);
- symdata.failed = 1;
- }
- }
- if (symdata.failed)
- data.failed = 1;
- }
- }
- printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
- if (data.failed)
- ++failures;
- return failures;
- }
- int test5 (void) __attribute__ ((unused));
- int global = 1;
- int
- test5 (void)
- {
- struct symdata symdata;
- int i;
- uintptr_t addr = (uintptr_t) &global;
- if (sizeof (global) > 1)
- addr += 1;
- symdata.name = NULL;
- symdata.val = 0;
- symdata.size = 0;
- symdata.failed = 0;
- i = backtrace_syminfo (state, addr, callback_three,
- error_callback_three, &symdata);
- if (i == 0)
- {
- fprintf (stderr,
- "test5: unexpected return value from backtrace_syminfo %d\n",
- i);
- symdata.failed = 1;
- }
- if (!symdata.failed)
- {
- if (symdata.name == NULL)
- {
- fprintf (stderr, "test5: NULL syminfo name\n");
- symdata.failed = 1;
- }
- else if (!(strncmp (symdata.name, "global", 6) == 0
- && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
- {
- fprintf (stderr,
- "test5: unexpected syminfo name got %s expected %s\n",
- symdata.name, "global");
- symdata.failed = 1;
- }
- else if (symdata.val != (uintptr_t) &global)
- {
- fprintf (stderr,
- "test5: unexpected syminfo value got %lx expected %lx\n",
- (unsigned long) symdata.val,
- (unsigned long) (uintptr_t) &global);
- symdata.failed = 1;
- }
- else if (symdata.size != sizeof (global))
- {
- fprintf (stderr,
- "test5: unexpected syminfo size got %lx expected %lx\n",
- (unsigned long) symdata.size,
- (unsigned long) sizeof (global));
- symdata.failed = 1;
- }
- }
- printf ("%s: backtrace_syminfo variable\n",
- symdata.failed ? "FAIL" : "PASS");
- if (symdata.failed)
- ++failures;
- return failures;
- }
- int
- main (int argc ATTRIBUTE_UNUSED, char **argv)
- {
- state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
- error_callback_create, NULL);
- #if BACKTRACE_SUPPORTED
- test1 ();
- test3 ();
- #if BACKTRACE_SUPPORTS_DATA
- test5 ();
- #endif
- #endif
- exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
- }
|