123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716 |
- /* btest.c -- Test for libbacktrace library
- Copyright (C) 2012-2015 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 the externally visible interfaces of the
- libbacktrace library. */
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "filenames.h"
- #include "backtrace.h"
- #include "backtrace-supported.h"
- /* Portable attribute syntax. Actually some of these tests probably
- won't work if the attributes are not recognized. */
- #ifndef GCC_VERSION
- # define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
- #endif
- #if (GCC_VERSION < 2007)
- # define __attribute__(x)
- #endif
- #ifndef ATTRIBUTE_UNUSED
- # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
- #endif
- /* Used to collect backtrace info. */
- struct info
- {
- char *filename;
- int lineno;
- char *function;
- };
- /* Passed to backtrace callback function. */
- struct bdata
- {
- struct info *all;
- size_t index;
- size_t max;
- int failed;
- };
- /* Passed to backtrace_simple callback function. */
- struct sdata
- {
- uintptr_t *addrs;
- size_t index;
- size_t max;
- int failed;
- };
- /* Passed to backtrace_syminfo callback function. */
- struct symdata
- {
- const char *name;
- uintptr_t val, size;
- int failed;
- };
- /* The backtrace state. */
- static void *state;
- /* The number of failures. */
- static int failures;
- /* Return the base name in a path. */
- static const char *
- base (const char *p)
- {
- const char *last;
- const char *s;
- last = NULL;
- for (s = p; *s != '\0'; ++s)
- {
- if (IS_DIR_SEPARATOR (*s))
- last = s + 1;
- }
- return last != NULL ? last : p;
- }
- /* Check an entry in a struct info array. */
- static void
- check (const char *name, int index, const struct info *all, int want_lineno,
- const char *want_function, int *failed)
- {
- if (*failed)
- return;
- if (all[index].filename == NULL || all[index].function == NULL)
- {
- fprintf (stderr, "%s: [%d]: missing file name or function name\n",
- name, index);
- *failed = 1;
- return;
- }
- if (strcmp (base (all[index].filename), "btest.c") != 0)
- {
- fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
- all[index].filename);
- *failed = 1;
- }
- if (all[index].lineno != want_lineno)
- {
- fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
- all[index].lineno, want_lineno);
- *failed = 1;
- }
- if (strcmp (all[index].function, want_function) != 0)
- {
- fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
- all[index].function, want_function);
- *failed = 1;
- }
- }
- /* The backtrace callback function. */
- static int
- callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
- const char *filename, int lineno, const char *function)
- {
- struct bdata *data = (struct bdata *) vdata;
- struct info *p;
- if (data->index >= data->max)
- {
- fprintf (stderr, "callback_one: callback called too many times\n");
- data->failed = 1;
- return 1;
- }
- p = &data->all[data->index];
- if (filename == NULL)
- p->filename = NULL;
- else
- {
- p->filename = strdup (filename);
- assert (p->filename != NULL);
- }
- p->lineno = lineno;
- if (function == NULL)
- p->function = NULL;
- else
- {
- p->function = strdup (function);
- assert (p->function != NULL);
- }
- ++data->index;
- return 0;
- }
- /* An error callback passed to backtrace. */
- static void
- error_callback_one (void *vdata, const char *msg, int errnum)
- {
- struct bdata *data = (struct bdata *) vdata;
- fprintf (stderr, "%s", msg);
- if (errnum > 0)
- fprintf (stderr, ": %s", strerror (errnum));
- fprintf (stderr, "\n");
- data->failed = 1;
- }
- /* The backtrace_simple callback function. */
- static int
- callback_two (void *vdata, uintptr_t pc)
- {
- struct sdata *data = (struct sdata *) vdata;
- if (data->index >= data->max)
- {
- fprintf (stderr, "callback_two: callback called too many times\n");
- data->failed = 1;
- return 1;
- }
- data->addrs[data->index] = pc;
- ++data->index;
- return 0;
- }
- /* An error callback passed to backtrace_simple. */
- static void
- error_callback_two (void *vdata, const char *msg, int errnum)
- {
- struct sdata *data = (struct sdata *) vdata;
- fprintf (stderr, "%s", msg);
- if (errnum > 0)
- fprintf (stderr, ": %s", strerror (errnum));
- fprintf (stderr, "\n");
- data->failed = 1;
- }
- /* The backtrace_syminfo callback function. */
- static void
- callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
- const char *symname, uintptr_t symval,
- uintptr_t symsize)
- {
- struct symdata *data = (struct symdata *) vdata;
- if (symname == NULL)
- data->name = NULL;
- else
- {
- data->name = strdup (symname);
- assert (data->name != NULL);
- }
- data->val = symval;
- data->size = symsize;
- }
- /* The backtrace_syminfo error callback function. */
- static void
- error_callback_three (void *vdata, const char *msg, int errnum)
- {
- struct symdata *data = (struct symdata *) vdata;
- fprintf (stderr, "%s", msg);
- if (errnum > 0)
- fprintf (stderr, ": %s", strerror (errnum));
- fprintf (stderr, "\n");
- data->failed = 1;
- }
- /* Test the backtrace function with non-inlined functions. */
- static int test1 (void) __attribute__ ((noinline, unused));
- static int f2 (int) __attribute__ ((noinline));
- static int f3 (int, int) __attribute__ ((noinline));
- 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, int f2line)
- {
- struct info all[20];
- struct bdata data;
- int f3line;
- int i;
- data.all = &all[0];
- data.index = 0;
- data.max = 20;
- data.failed = 0;
- f3line = __LINE__ + 1;
- i = backtrace_full (state, 0, callback_one, 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;
- }
- check ("test1", 0, all, f3line, "f3", &data.failed);
- check ("test1", 1, all, f2line, "f2", &data.failed);
- check ("test1", 2, all, f1line, "test1", &data.failed);
- printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
- if (data.failed)
- ++failures;
- return failures;
- }
- /* Test the backtrace function with inlined functions. */
- static inline int test2 (void) __attribute__ ((always_inline, unused));
- static inline int f12 (int) __attribute__ ((always_inline));
- static inline int f13 (int, int) __attribute__ ((always_inline));
- static inline int
- test2 (void)
- {
- return f12 (__LINE__) + 1;
- }
- static inline int
- f12 (int f1line)
- {
- return f13 (f1line, __LINE__) + 2;
- }
- static inline int
- f13 (int f1line, int f2line)
- {
- struct info all[20];
- struct bdata data;
- int f3line;
- int i;
- data.all = &all[0];
- data.index = 0;
- data.max = 20;
- data.failed = 0;
- f3line = __LINE__ + 1;
- i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
- if (i != 0)
- {
- fprintf (stderr, "test2: unexpected return value %d\n", i);
- data.failed = 1;
- }
- check ("test2", 0, all, f3line, "f13", &data.failed);
- check ("test2", 1, all, f2line, "f12", &data.failed);
- check ("test2", 2, all, f1line, "test2", &data.failed);
- printf ("%s: backtrace_full inline\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, unused));
- static int f22 (int) __attribute__ ((noinline));
- static int f23 (int, int) __attribute__ ((noinline));
- static int
- test3 (void)
- {
- return f22 (__LINE__) + 1;
- }
- static int
- f22 (int f1line)
- {
- return f23 (f1line, __LINE__) + 2;
- }
- static int
- f23 (int f1line, int f2line)
- {
- uintptr_t addrs[20];
- struct sdata data;
- int f3line;
- int i;
- data.addrs = &addrs[0];
- data.index = 0;
- data.max = 20;
- data.failed = 0;
- f3line = __LINE__ + 1;
- 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)
- {
- struct info all[20];
- struct bdata bdata;
- int j;
- bdata.all = &all[0];
- bdata.index = 0;
- bdata.max = 20;
- bdata.failed = 0;
- for (j = 0; j < 3; ++j)
- {
- i = backtrace_pcinfo (state, addrs[j], callback_one,
- error_callback_one, &bdata);
- if (i != 0)
- {
- fprintf (stderr,
- ("test3: unexpected return value "
- "from backtrace_pcinfo %d\n"),
- i);
- bdata.failed = 1;
- }
- if (!bdata.failed && bdata.index != (size_t) (j + 1))
- {
- fprintf (stderr,
- ("wrong number of calls from backtrace_pcinfo "
- "got %u expected %d\n"),
- (unsigned int) bdata.index, j + 1);
- bdata.failed = 1;
- }
- }
- check ("test3", 0, all, f3line, "f23", &bdata.failed);
- check ("test3", 1, all, f2line, "f22", &bdata.failed);
- check ("test3", 2, all, f1line, "test3", &bdata.failed);
- if (bdata.failed)
- data.failed = 1;
- 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;
- }
- /* Test the backtrace_simple function with inlined functions. */
- static inline int test4 (void) __attribute__ ((always_inline, unused));
- static inline int f32 (int) __attribute__ ((always_inline));
- static inline int f33 (int, int) __attribute__ ((always_inline));
- static inline int
- test4 (void)
- {
- return f32 (__LINE__) + 1;
- }
- static inline int
- f32 (int f1line)
- {
- return f33 (f1line, __LINE__) + 2;
- }
- static inline int
- f33 (int f1line, int f2line)
- {
- uintptr_t addrs[20];
- struct sdata data;
- int f3line;
- int i;
- data.addrs = &addrs[0];
- data.index = 0;
- data.max = 20;
- data.failed = 0;
- f3line = __LINE__ + 1;
- 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)
- {
- struct info all[20];
- struct bdata bdata;
- bdata.all = &all[0];
- bdata.index = 0;
- bdata.max = 20;
- bdata.failed = 0;
- i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
- &bdata);
- if (i != 0)
- {
- fprintf (stderr,
- ("test4: unexpected return value "
- "from backtrace_pcinfo %d\n"),
- i);
- bdata.failed = 1;
- }
- check ("test4", 0, all, f3line, "f33", &bdata.failed);
- check ("test4", 1, all, f2line, "f32", &bdata.failed);
- check ("test4", 2, all, f1line, "test4", &bdata.failed);
- if (bdata.failed)
- data.failed = 1;
- }
- printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
- if (data.failed)
- ++failures;
- return failures;
- }
- int global = 1;
- static 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 (strcmp (symdata.name, "global") != 0)
- {
- 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;
- }
- static void
- error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
- int errnum)
- {
- fprintf (stderr, "%s", msg);
- if (errnum > 0)
- fprintf (stderr, ": %s", strerror (errnum));
- fprintf (stderr, "\n");
- exit (EXIT_FAILURE);
- }
- /* Run all the tests. */
- 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 ();
- test2 ();
- test3 ();
- test4 ();
- test5 ();
- #endif
- exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
- }
|