diff options
author | Denis Khalikov <d.khalikov@partner.samsung.com> | 2018-06-07 13:20:04 +0300 |
---|---|---|
committer | Dongkyun Son <dongkyun.s@samsung.com> | 2018-07-19 09:04:50 +0000 |
commit | 36676e9f8ff8a4e34dda6ea05eae81dd6357f46b (patch) | |
tree | 23f612d53de16cbab092938272f99842258ae50a | |
parent | be2ed3c61077a3d9b333f95c1af7c2f46a3e2ef5 (diff) | |
download | linaro-gcc-36676e9f8ff8a4e34dda6ea05eae81dd6357f46b.tar.gz linaro-gcc-36676e9f8ff8a4e34dda6ea05eae81dd6357f46b.tar.bz2 linaro-gcc-36676e9f8ff8a4e34dda6ea05eae81dd6357f46b.zip |
libbacktrace: backport from mainline.
* btest.c (test5): Replace #ifdef guard with 'unused' attribute
to fix compile warning when BACKTRACE_SUPPORTED isn't defined.
* dwarf.c (free_line_header): Don't free dirs if dirs_count == 0.
(read_line_header): Don't allocate dirs if dirs_count == 0.
* edtest.c: New file.
* edtest2.c: New file.
* Makefile.am (edtest_SOURCES, edtest_LDADD): Define.
(check_PROGRAMS): Add edtest.
(edtest2_build.c, gen_edtest2_build): New targets.
* Makefile.in: Rebuild.
* elf.c (backtrace_initialize): Always set *fileline_fn.
* ttest.c: New file.
* btest.c: Move support functions into testlib.c. Change calls to
check to pass file name.
* testlib.c: New file, copied from (part of) btest.c.
* testlib.h: New file, declarations for testlib.c.
* edtest.c: Use testlib.h and testlib.c.
* configure.ac: Test for -pthread, set HAVE_PTHREAD conditional.
* Makefile.am (btest_SOURCES): Add testlib.c.
(edtest_SOURCES): Likewise.
(CHECK_PROGRAMS): Add ttest if HAVE_PTHREAD.
(ttest_SOURCES, ttest_CFLAGS, ttest_LDADD): Define.
* configure, Makefile.in: Rebuild.
* configure.ac: Add AC_SYS_LARGEFILE.
* config.h.in: Regenerate.
* configure: Likewise.
* filetype.awk: Add AIX XCOFF type detection.
* configure.ac: Recognize xcoff format.
* Makefile.am (FORMAT_FILES): Add xcoff.c.
* fileline.c: Include <unistd.h>.
(fileline_initialize): Add case for AIX procfs.
* xcoff.c: New file.
* configure, Makefile.in: Rebuild.
* configure.ac: Check for XCOFF32/XCOFF64. Check for loadquery.
* filetype.awk: Separate AIX XCOFF32 and XCOFF64.
* xcoff.c: Add support for AIX XCOFF32 and XCOFF64 formats.
* configure, config.h.in: Regenerate.
* fileline.c (fileline_initialize): Print pid_t as long.
* xcoff.c: Don't leak a file descriptor if an archive is malformed.
* xcoff.c (xcoff_process_linenos): Initialize incl to NULL.
* libbacktrace/Makefile.in
(HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_CFLAGS): Add $(AM_CFLAGS)
* Makefile.am (ttest_CFLAGS): Add $(AM_CFLAGS)
* Makefile.in: Regenerate.
Change-Id: Ib61ad222b79b9c3a38d35705608f74041acc767a
-rw-r--r-- | libbacktrace/ChangeLog | 80 | ||||
-rw-r--r-- | libbacktrace/Makefile.am | 30 | ||||
-rw-r--r-- | libbacktrace/Makefile.in | 69 | ||||
-rw-r--r-- | libbacktrace/btest.c | 271 | ||||
-rw-r--r-- | libbacktrace/config.h.in | 15 | ||||
-rwxr-xr-x | libbacktrace/configure | 311 | ||||
-rw-r--r-- | libbacktrace/configure.ac | 49 | ||||
-rw-r--r-- | libbacktrace/dwarf.c | 25 | ||||
-rw-r--r-- | libbacktrace/edtest.c | 121 | ||||
-rw-r--r-- | libbacktrace/edtest2.c | 43 | ||||
-rw-r--r-- | libbacktrace/elf.c | 16 | ||||
-rw-r--r-- | libbacktrace/fileline.c | 9 | ||||
-rw-r--r-- | libbacktrace/filetype.awk | 3 | ||||
-rw-r--r-- | libbacktrace/testlib.c | 234 | ||||
-rw-r--r-- | libbacktrace/testlib.h | 110 | ||||
-rw-r--r-- | libbacktrace/ttest.c | 161 | ||||
-rw-r--r-- | libbacktrace/xcoff.c | 1485 |
17 files changed, 2740 insertions, 292 deletions
diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog index 4cb639bfdec..e2285fd586a 100644 --- a/libbacktrace/ChangeLog +++ b/libbacktrace/ChangeLog @@ -1,3 +1,83 @@ +2017-09-12 Steve Ellcey <sellcey@cavium.com> + + PR other/81096 + * Makefile.am (ttest_CFLAGS): Add $(AM_CFLAGS) + * Makefile.in: Regenerate. + +2017-09-12 Steve Ellcey <sellcey@cavium.com> + + PR other/81096 + * libbacktrace/Makefile.in + (HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_CFLAGS): Add $(AM_CFLAGS) + +2017-08-02 David Edelsohn <dje.gcc@gmail.com> + + PR bootstrap/81638 + * xcoff.c (xcoff_process_linenos): Initialize incl to NULL. + +2017-07-28 Tony Reix <tony.reix@atos.net> + + * xcoff.c: Don't leak a file descriptor if an archive is malformed. + +2017-07-28 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * fileline.c (fileline_initialize): Print pid_t as long. + +2017-07-26 Tony Reix <tony.reix@atos.net> + + * configure.ac: Check for XCOFF32/XCOFF64. Check for loadquery. + * filetype.awk: Separate AIX XCOFF32 and XCOFF64. + * xcoff.c: Add support for AIX XCOFF32 and XCOFF64 formats. + * configure, config.h.in: Regenerate. + +2017-07-21 Tony Reix <tony.reix@atos.net> + + * filetype.awk: Add AIX XCOFF type detection. + * configure.ac: Recognize xcoff format. + * Makefile.am (FORMAT_FILES): Add xcoff.c. + * fileline.c: Include <unistd.h>. + (fileline_initialize): Add case for AIX procfs. + * xcoff.c: New file. + * configure, Makefile.in: Rebuild. + +2017-06-21 Richard Biener <rguenther@suse.de> + + * configure.ac: Add AC_SYS_LARGEFILE. + * config.h.in: Regenerate. + * configure: Likewise. + +2017-06-11 Ian Lance Taylor <iant@golang.org> + + * elf.c (backtrace_initialize): Always set *fileline_fn. + * ttest.c: New file. + * btest.c: Move support functions into testlib.c. Change calls to + check to pass file name. + * testlib.c: New file, copied from (part of) btest.c. + * testlib.h: New file, declarations for testlib.c. + * edtest.c: Use testlib.h and testlib.c. + * configure.ac: Test for -pthread, set HAVE_PTHREAD conditional. + * Makefile.am (btest_SOURCES): Add testlib.c. + (edtest_SOURCES): Likewise. + (CHECK_PROGRAMS): Add ttest if HAVE_PTHREAD. + (ttest_SOURCES, ttest_CFLAGS, ttest_LDADD): Define. + * configure, Makefile.in: Rebuild. + +2017-05-19 Than McIntosh <thanm@google.com> + + * dwarf.c (free_line_header): Don't free dirs if dirs_count == 0. + (read_line_header): Don't allocate dirs if dirs_count == 0. + * edtest.c: New file. + * edtest2.c: New file. + * Makefile.am (edtest_SOURCES, edtest_LDADD): Define. + (check_PROGRAMS): Add edtest. + (edtest2_build.c, gen_edtest2_build): New targets. + * Makefile.in: Rebuild. + +2017-03-08 Sam Thursfield <sam.thursfield@codethink.co.uk> + + * btest.c (test5): Replace #ifdef guard with 'unused' attribute + to fix compile warning when BACKTRACE_SUPPORTED isn't defined. + 2016-12-21 Release Manager * GCC 6.3.0 released. diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index a7df0259098..ec7dde075a3 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -1,5 +1,5 @@ # Makefile.am -- Backtrace Makefile. -# Copyright (C) 2012-2016 Free Software Foundation, Inc. +# Copyright (C) 2012-2017 Free Software Foundation, Inc. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -57,7 +57,8 @@ BACKTRACE_FILES = \ FORMAT_FILES = \ elf.c \ pecoff.c \ - unknown.c + unknown.c \ + xcoff.c VIEW_FILES = \ read.c \ @@ -89,7 +90,7 @@ TESTS = $(check_PROGRAMS) if NATIVE -btest_SOURCES = btest.c +btest_SOURCES = btest.c testlib.c btest_CFLAGS = $(AM_CFLAGS) -g -O btest_LDADD = libbacktrace.la @@ -100,6 +101,27 @@ stest_LDADD = libbacktrace.la check_PROGRAMS += stest +edtest_SOURCES = edtest.c edtest2_build.c testlib.c +edtest_LDADD = libbacktrace.la + +check_PROGRAMS += edtest + +edtest2_build.c: gen_edtest2_build; @true +gen_edtest2_build: $(srcdir)/edtest2.c + cat $(srcdir)/edtest2.c > tmp-edtest2_build.c + $(SHELL) $(srcdir)/../move-if-change tmp-edtest2_build.c edtest2_build.c + echo timestamp > $@ + +if HAVE_PTHREAD + +check_PROGRAMS += ttest + +ttest_SOURCES = ttest.c testlib.c +ttest_CFLAGS = $(AM_CFLAGS) -pthread +ttest_LDADD = libbacktrace.la + +endif HAVE_PTHREAD + endif NATIVE # We can't use automake's automatic dependency tracking, because it @@ -134,3 +156,5 @@ sort.lo: config.h backtrace.h internal.h stest.lo: config.h backtrace.h internal.h state.lo: config.h backtrace.h backtrace-supported.h internal.h unknown.lo: config.h backtrace.h internal.h +xcoff.lo: config.h backtrace.h internal.h + diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in index 586b6a6eaa1..be5b4b6f10c 100644 --- a/libbacktrace/Makefile.in +++ b/libbacktrace/Makefile.in @@ -83,8 +83,9 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ -check_PROGRAMS = $(am__EXEEXT_1) -@NATIVE_TRUE@am__append_1 = btest stest +check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) +@NATIVE_TRUE@am__append_1 = btest stest edtest +@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_2 = ttest subdir = . DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/configure \ @@ -113,16 +114,31 @@ am__DEPENDENCIES_1 = am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \ print.lo sort.lo state.lo libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS) -@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) -@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) +@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) \ +@NATIVE_TRUE@ edtest$(EXEEXT) +@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT) +@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) \ +@NATIVE_TRUE@ btest-testlib.$(OBJEXT) btest_OBJECTS = $(am_btest_OBJECTS) @NATIVE_TRUE@btest_DEPENDENCIES = libbacktrace.la btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ +@NATIVE_TRUE@am_edtest_OBJECTS = edtest.$(OBJEXT) \ +@NATIVE_TRUE@ edtest2_build.$(OBJEXT) testlib.$(OBJEXT) +edtest_OBJECTS = $(am_edtest_OBJECTS) +@NATIVE_TRUE@edtest_DEPENDENCIES = libbacktrace.la @NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT) stest_OBJECTS = $(am_stest_OBJECTS) @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la +@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am_ttest_OBJECTS = \ +@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ ttest-ttest.$(OBJEXT) \ +@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ ttest-testlib.$(OBJEXT) +ttest_OBJECTS = $(am_ttest_OBJECTS) +@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_DEPENDENCIES = libbacktrace.la +ttest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(ttest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = am__depfiles_maybe = @@ -136,7 +152,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \ - $(btest_SOURCES) $(stest_SOURCES) + $(btest_SOURCES) $(edtest_SOURCES) $(stest_SOURCES) \ + $(ttest_SOURCES) MULTISRCTOP = MULTIBUILDTOP = MULTIDIRS = @@ -213,6 +230,7 @@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIC_FLAG = @PIC_FLAG@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ @@ -301,7 +319,8 @@ BACKTRACE_FILES = \ FORMAT_FILES = \ elf.c \ pecoff.c \ - unknown.c + unknown.c \ + xcoff.c VIEW_FILES = \ read.c \ @@ -325,11 +344,16 @@ libbacktrace_la_LIBADD = \ libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD) TESTS = $(check_PROGRAMS) -@NATIVE_TRUE@btest_SOURCES = btest.c +@NATIVE_TRUE@btest_SOURCES = btest.c testlib.c @NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O @NATIVE_TRUE@btest_LDADD = libbacktrace.la @NATIVE_TRUE@stest_SOURCES = stest.c @NATIVE_TRUE@stest_LDADD = libbacktrace.la +@NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c testlib.c +@NATIVE_TRUE@edtest_LDADD = libbacktrace.la +@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_SOURCES = ttest.c testlib.c +@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_CFLAGS = $(AM_CFLAGS) -pthread +@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_LDADD = libbacktrace.la # We can't use automake's automatic dependency tracking, because it # breaks when using bootstrap-lean. Automatic dependency tracking @@ -422,9 +446,15 @@ clean-checkPROGRAMS: btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) @rm -f btest$(EXEEXT) $(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS) +edtest$(EXEEXT): $(edtest_OBJECTS) $(edtest_DEPENDENCIES) $(EXTRA_edtest_DEPENDENCIES) + @rm -f edtest$(EXEEXT) + $(LINK) $(edtest_OBJECTS) $(edtest_LDADD) $(LIBS) stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) @rm -f stest$(EXEEXT) $(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS) +ttest$(EXEEXT): $(ttest_OBJECTS) $(ttest_DEPENDENCIES) $(EXTRA_ttest_DEPENDENCIES) + @rm -f ttest$(EXEEXT) + $(ttest_LINK) $(ttest_OBJECTS) $(ttest_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -447,6 +477,24 @@ btest-btest.o: btest.c btest-btest.obj: btest.c $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi` +btest-testlib.o: testlib.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c + +btest-testlib.obj: testlib.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi` + +ttest-ttest.o: ttest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-ttest.o `test -f 'ttest.c' || echo '$(srcdir)/'`ttest.c + +ttest-ttest.obj: ttest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-ttest.obj `if test -f 'ttest.c'; then $(CYGPATH_W) 'ttest.c'; else $(CYGPATH_W) '$(srcdir)/ttest.c'; fi` + +ttest-testlib.o: testlib.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c + +ttest-testlib.obj: testlib.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi` + mostlyclean-libtool: -rm -f *.lo @@ -745,6 +793,12 @@ uninstall-am: mostlyclean-multi pdf pdf-am ps ps-am tags uninstall \ uninstall-am + +@NATIVE_TRUE@edtest2_build.c: gen_edtest2_build; @true +@NATIVE_TRUE@gen_edtest2_build: $(srcdir)/edtest2.c +@NATIVE_TRUE@ cat $(srcdir)/edtest2.c > tmp-edtest2_build.c +@NATIVE_TRUE@ $(SHELL) $(srcdir)/../move-if-change tmp-edtest2_build.c edtest2_build.c +@NATIVE_TRUE@ echo timestamp > $@ alloc.lo: config.h backtrace.h internal.h backtrace.lo: config.h backtrace.h internal.h btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h @@ -764,6 +818,7 @@ sort.lo: config.h backtrace.h internal.h stest.lo: config.h backtrace.h internal.h state.lo: config.h backtrace.h backtrace-supported.h internal.h unknown.lo: config.h backtrace.h internal.h +xcoff.lo: config.h backtrace.h internal.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/libbacktrace/btest.c b/libbacktrace/btest.c index 0506d2b1121..ff29607ddb9 100644 --- a/libbacktrace/btest.c +++ b/libbacktrace/btest.c @@ -43,237 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #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; -} +#include "testlib.h" /* Test the backtrace function with non-inlined functions. */ @@ -325,9 +95,9 @@ f3 (int f1line, int f2line) 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); + check ("test1", 0, all, f3line, "f3", "btest.c", &data.failed); + check ("test1", 1, all, f2line, "f2", "btest.c", &data.failed); + check ("test1", 2, all, f1line, "test1", "btest.c", &data.failed); printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS"); @@ -377,9 +147,9 @@ f13 (int f1line, int f2line) 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); + check ("test2", 0, all, f3line, "f13", "btest.c", &data.failed); + check ("test2", 1, all, f2line, "f12", "btest.c", &data.failed); + check ("test2", 2, all, f1line, "test2", "btest.c", &data.failed); printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS"); @@ -462,9 +232,9 @@ f23 (int f1line, int f2line) } } - check ("test3", 0, all, f3line, "f23", &bdata.failed); - check ("test3", 1, all, f2line, "f22", &bdata.failed); - check ("test3", 2, all, f1line, "test3", &bdata.failed); + check ("test3", 0, all, f3line, "f23", "btest.c", &bdata.failed); + check ("test3", 1, all, f2line, "f22", "btest.c", &bdata.failed); + check ("test3", 2, all, f1line, "test3", "btest.c", &bdata.failed); if (bdata.failed) data.failed = 1; @@ -600,9 +370,9 @@ f33 (int f1line, int f2line) 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); + check ("test4", 0, all, f3line, "f33", "btest.c", &bdata.failed); + check ("test4", 1, all, f2line, "f32", "btest.c", &bdata.failed); + check ("test4", 2, all, f1line, "test4", "btest.c", &bdata.failed); if (bdata.failed) data.failed = 1; @@ -616,7 +386,7 @@ f33 (int f1line, int f2line) return failures; } -#if BACKTRACE_SUPPORTS_DATA +static int test5 (void) __attribute__ ((unused)); int global = 1; @@ -686,19 +456,6 @@ test5 (void) return failures; } -#endif /* BACKTRACE_SUPPORTS_DATA */ - -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 diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index 87cb805984d..9fc771564ba 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -3,6 +3,9 @@ /* ELF size: 32 or 64 */ #undef BACKTRACE_ELF_SIZE +/* XCOFF size: 32 or 64 */ +#undef BACKTRACE_XCOFF_SIZE + /* Define to 1 if you have the __atomic functions */ #undef HAVE_ATOMIC_FUNCTIONS @@ -31,6 +34,9 @@ /* Define to 1 if you have the <link.h> header file. */ #undef HAVE_LINK_H +/* Define if AIX loadquery is available. */ +#undef HAVE_LOADQUERY + /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H @@ -49,6 +55,9 @@ /* Define to 1 if you have the __sync functions */ #undef HAVE_SYNC_FUNCTIONS +/* Define to 1 if you have the <sys/ldr.h> header file. */ +#undef HAVE_SYS_LDR_H + /* Define to 1 if you have the <sys/mman.h> header file. */ #undef HAVE_SYS_MMAN_H @@ -123,6 +132,12 @@ #endif +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + /* Define to 1 if on MINIX. */ #undef _MINIX diff --git a/libbacktrace/configure b/libbacktrace/configure index 4e720e19f43..b7b88e2ebe5 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -604,6 +604,9 @@ LTLIBOBJS LIBOBJS NATIVE_FALSE NATIVE_TRUE +HAVE_PTHREAD_FALSE +HAVE_PTHREAD_TRUE +PTHREAD_CFLAGS BACKTRACE_USES_MALLOC ALLOC_FILE VIEW_FILE @@ -731,6 +734,7 @@ with_pic enable_fast_install with_gnu_ld enable_libtool_lock +enable_largefile with_system_libunwind enable_host_shared ' @@ -1371,6 +1375,7 @@ Optional Features: --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) + --disable-largefile omit support for large files --enable-host-shared build host code as shared libraries Optional Packages: @@ -11131,7 +11136,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11134 "configure" +#line 11139 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11237,7 +11242,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11240 "configure" +#line 11245 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11476,6 +11481,205 @@ CC="$lt_save_CC" +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if test "${ac_cv_sys_largefile_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if test "${ac_cv_sys_file_offset_bits+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include <sys/types.h> + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if test "${ac_cv_sys_large_files+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include <sys/types.h> + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi +fi + + backtrace_supported=yes if test -n "${with_target_subdir}"; then @@ -11844,6 +12048,9 @@ elf*) FORMAT_FILE="elf.lo" ;; pecoff) FORMAT_FILE="pecoff.lo" backtrace_supports_data=no ;; +xcoff*) FORMAT_FILE="xcoff.lo" + backtrace_supports_data=no + ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not determine output file type" >&5 $as_echo "$as_me: WARNING: could not determine output file type" >&2;} FORMAT_FILE="unknown.lo" @@ -11865,6 +12072,19 @@ cat >>confdefs.h <<_ACEOF _ACEOF +# XCOFF defines. +xcoffsize= +case "$libbacktrace_cv_sys_filetype" in +xcoff32) xcoffsize=32 ;; +xcoff64) xcoffsize=64 ;; +*) xcoffsize=unused +esac + +cat >>confdefs.h <<_ACEOF +#define BACKTRACE_XCOFF_SIZE $xcoffsize +_ACEOF + + BACKTRACE_SUPPORTED=0 if test "$backtrace_supported" = "yes"; then BACKTRACE_SUPPORTED=1 @@ -12403,6 +12623,53 @@ $as_echo "#define HAVE_DL_ITERATE_PHDR 1" >>confdefs.h fi +# Check for loadquery. +for ac_header in sys/ldr.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/ldr.h" "ac_cv_header_sys_ldr_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_ldr_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_LDR_H 1 +_ACEOF + +fi + +done + +if test "$ac_cv_header_sys_ldr_h" = "no"; then + have_loadquery=no +else + if test -n "${with_target_subdir}"; then + # When built as a GCC target library, we can't do a link test. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/ldr.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "loadquery" >/dev/null 2>&1; then : + have_loadquery=yes +else + have_loadquery=no +fi +rm -f conftest* + + else + ac_fn_c_check_func "$LINENO" "loadquery" "ac_cv_func_loadquery" +if test "x$ac_cv_func_loadquery" = x""yes; then : + have_loadquery=yes +else + have_loadquery=no +fi + + fi +fi +if test "$have_loadquery" = "yes"; then + +$as_echo "#define HAVE_LOADQUERY 1" >>confdefs.h + +fi + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in @@ -12458,6 +12725,42 @@ $as_echo "#define HAVE_GETEXECNAME 1" >>confdefs.h fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is supported" >&5 +$as_echo_n "checking whether -pthread is supported... " >&6; } +if test "${libgo_cv_lib_pthread+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + CFLAGS_hold=$CFLAGS +CFLAGS="$CFLAGS -pthread" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int i; +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + libgo_cv_lib_pthread=yes +else + libgo_cv_lib_pthread=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS=$CFLAGS_hold +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_lib_pthread" >&5 +$as_echo "$libgo_cv_lib_pthread" >&6; } +PTHREAD_CFLAGS= +if test "$libgo_cv_lib_pthread" = yes; then + PTHREAD_CFLAGS=-pthread +fi + + + if test "$libgo_cv_lib_pthread" = yes; then + HAVE_PTHREAD_TRUE= + HAVE_PTHREAD_FALSE='#' +else + HAVE_PTHREAD_TRUE='#' + HAVE_PTHREAD_FALSE= +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tests can run" >&5 $as_echo_n "checking whether tests can run... " >&6; } if test "${libbacktrace_cv_sys_native+set}" = set; then : @@ -12620,6 +12923,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${HAVE_PTHREAD_TRUE}" && test -z "${HAVE_PTHREAD_FALSE}"; then + as_fn_error "conditional \"HAVE_PTHREAD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${NATIVE_TRUE}" && test -z "${NATIVE_FALSE}"; then as_fn_error "conditional \"NATIVE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 71e85187ef5..03e33c5771a 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -82,6 +82,8 @@ esac LT_INIT AM_PROG_LIBTOOL +AC_SYS_LARGEFILE + backtrace_supported=yes if test -n "${with_target_subdir}"; then @@ -231,6 +233,9 @@ elf*) FORMAT_FILE="elf.lo" ;; pecoff) FORMAT_FILE="pecoff.lo" backtrace_supports_data=no ;; +xcoff*) FORMAT_FILE="xcoff.lo" + backtrace_supports_data=no + ;; *) AC_MSG_WARN([could not determine output file type]) FORMAT_FILE="unknown.lo" backtrace_supported=no @@ -247,6 +252,15 @@ elf64) elfsize=64 ;; esac AC_DEFINE_UNQUOTED([BACKTRACE_ELF_SIZE], [$elfsize], [ELF size: 32 or 64]) +# XCOFF defines. +xcoffsize= +case "$libbacktrace_cv_sys_filetype" in +xcoff32) xcoffsize=32 ;; +xcoff64) xcoffsize=64 ;; +*) xcoffsize=unused +esac +AC_DEFINE_UNQUOTED([BACKTRACE_XCOFF_SIZE], [$xcoffsize], [XCOFF size: 32 or 64]) + BACKTRACE_SUPPORTED=0 if test "$backtrace_supported" = "yes"; then BACKTRACE_SUPPORTED=1 @@ -325,6 +339,24 @@ if test "$have_dl_iterate_phdr" = "yes"; then AC_DEFINE(HAVE_DL_ITERATE_PHDR, 1, [Define if dl_iterate_phdr is available.]) fi +# Check for loadquery. +AC_CHECK_HEADERS(sys/ldr.h) +if test "$ac_cv_header_sys_ldr_h" = "no"; then + have_loadquery=no +else + if test -n "${with_target_subdir}"; then + # When built as a GCC target library, we can't do a link test. + AC_EGREP_HEADER([loadquery], [sys/ldr.h], [have_loadquery=yes], + [have_loadquery=no]) + else + AC_CHECK_FUNC([loadquery], [have_loadquery=yes], + [have_loadquery=no]) + fi +fi +if test "$have_loadquery" = "yes"; then + AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.]) +fi + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in @@ -355,6 +387,23 @@ if test "$have_getexecname" = "yes"; then AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.]) fi +dnl Test whether the compiler supports the -pthread option. +AC_CACHE_CHECK([whether -pthread is supported], +[libgo_cv_lib_pthread], +[CFLAGS_hold=$CFLAGS +CFLAGS="$CFLAGS -pthread" +AC_COMPILE_IFELSE([[int i;]], +[libgo_cv_lib_pthread=yes], +[libgo_cv_lib_pthread=no]) +CFLAGS=$CFLAGS_hold]) +PTHREAD_CFLAGS= +if test "$libgo_cv_lib_pthread" = yes; then + PTHREAD_CFLAGS=-pthread +fi +AC_SUBST(PTHREAD_CFLAGS) + +AM_CONDITIONAL(HAVE_PTHREAD, test "$libgo_cv_lib_pthread" = yes) + AC_CACHE_CHECK([whether tests can run], [libbacktrace_cv_sys_native], [AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])], diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 55b8d7dc2a5..e1cb47e11ec 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -1563,16 +1563,15 @@ add_line (struct backtrace_state *state, struct dwarf_data *ddata, return 1; } -/* Free the line header information. If FREE_FILENAMES is true we - free the file names themselves, otherwise we leave them, as there - may be line structures pointing to them. */ +/* Free the line header information. */ static void free_line_header (struct backtrace_state *state, struct line_header *hdr, backtrace_error_callback error_callback, void *data) { - backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *), - error_callback, data); + if (hdr->dirs_count != 0) + backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *), + error_callback, data); backtrace_free (state, hdr->filenames, hdr->filenames_count * sizeof (char *), error_callback, data); @@ -1633,12 +1632,16 @@ read_line_header (struct backtrace_state *state, struct unit *u, ++hdr->dirs_count; } - hdr->dirs = ((const char **) - backtrace_alloc (state, - hdr->dirs_count * sizeof (const char *), - line_buf->error_callback, line_buf->data)); - if (hdr->dirs == NULL) - return 0; + hdr->dirs = NULL; + if (hdr->dirs_count != 0) + { + hdr->dirs = ((const char **) + backtrace_alloc (state, + hdr->dirs_count * sizeof (const char *), + line_buf->error_callback, line_buf->data)); + if (hdr->dirs == NULL) + return 0; + } i = 0; while (*hdr_buf.buf != '\0') diff --git a/libbacktrace/edtest.c b/libbacktrace/edtest.c new file mode 100644 index 00000000000..54c705cb1ba --- /dev/null +++ b/libbacktrace/edtest.c @@ -0,0 +1,121 @@ +/* edtest.c -- Test for libbacktrace storage allocation stress handling + Copyright (C) 2017 Free Software Foundation, Inc. + +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. */ + +#include "config.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "backtrace.h" +#include "backtrace-supported.h" +#include "internal.h" + +#include "testlib.h" + +static int test1 (void) __attribute__ ((noinline, unused)); +static int test1 (void) __attribute__ ((noinline, unused)); +extern int f2 (int); +extern int f3 (int, int); + +static int +test1 (void) +{ + /* Returning a value here and elsewhere avoids a tailcall which + would mess up the backtrace. */ + return f2 (__LINE__) + 1; +} + +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", "edtest.c", &data.failed); + check ("test1", 1, all, f2line, "f2", "edtest2_build.c", &data.failed); + check ("test1", 2, all, f1line, "test1", "edtest.c", &data.failed); + + printf ("%s: backtrace_full alloc stress\n", data.failed ? "FAIL" : "PASS"); + + if (data.failed) + ++failures; + + return failures; +} + +int +main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS, + error_callback_create, NULL); + + // Grab the storage allocation lock prior to doing anything interesting. + // The intent here is to insure that the backtrace_alloc code is forced + // to always call mmap() for new memory as opposed to reusing previously + // allocated memory from the free list. Doing things this way helps + // simulate what you might see in a multithreaded program in which there + // are racing calls to the allocator. + struct backtrace_state *state_internal = + (struct backtrace_state *) state; + state_internal->lock_alloc = 1; + + // Kick off the test + test1(); + + exit (failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/libbacktrace/edtest2.c b/libbacktrace/edtest2.c new file mode 100644 index 00000000000..1ab78ee9612 --- /dev/null +++ b/libbacktrace/edtest2.c @@ -0,0 +1,43 @@ +/* edtest2.c -- Test for libbacktrace storage allocation stress handling (p2) + Copyright (C) 2017 Free Software Foundation, Inc. + +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 file intentionally written without any #include's + */ + +extern int f3(int, int); +extern int f2(int); + +int f2(int x) +{ + /* Returning a value here and elsewhere avoids a tailcall which + would mess up the backtrace. */ + return f3(x, __LINE__) + 3; +} diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 81ba3440ab7..ed6f4e19153 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -70,7 +70,7 @@ dl_iterate_phdr (int (*callback) (struct dl_phdr_info *, ELF. We could make this code test and support either possibility, but there is no point. This code only works for the currently running executable, which means that we know the ELF mode at - configure mode. */ + configure time. */ #if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64 #error "Unknown BACKTRACE_ELF_SIZE" @@ -962,18 +962,12 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, } if (!state->threaded) - { - if (state->fileline_fn == NULL || state->fileline_fn == elf_nodebug) - *fileline_fn = elf_fileline_fn; - } + *fileline_fn = state->fileline_fn; else - { - fileline current_fn; + *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - if (current_fn == NULL || current_fn == elf_nodebug) - *fileline_fn = elf_fileline_fn; - } + if (*fileline_fn == NULL || *fileline_fn == elf_nodebug) + *fileline_fn = elf_fileline_fn; return 1; } diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index 27ebbedc21c..674fbba4379 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include <errno.h> #include <fcntl.h> #include <stdlib.h> +#include <unistd.h> #include "backtrace.h" #include "internal.h" @@ -57,6 +58,7 @@ fileline_initialize (struct backtrace_state *state, int pass; int called_error_callback; int descriptor; + char buf[64]; if (!state->threaded) failed = state->fileline_initialization_failed; @@ -80,7 +82,7 @@ fileline_initialize (struct backtrace_state *state, descriptor = -1; called_error_callback = 0; - for (pass = 0; pass < 4; ++pass) + for (pass = 0; pass < 5; ++pass) { const char *filename; int does_not_exist; @@ -99,6 +101,11 @@ fileline_initialize (struct backtrace_state *state, case 3: filename = "/proc/curproc/file"; break; + case 4: + snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out", + (long) getpid ()); + filename = buf; + break; default: abort (); } diff --git a/libbacktrace/filetype.awk b/libbacktrace/filetype.awk index 57bab797a9a..cf6e1b695d2 100644 --- a/libbacktrace/filetype.awk +++ b/libbacktrace/filetype.awk @@ -3,3 +3,6 @@ /\177ELF\002/ { if (NR == 1) { print "elf64"; exit } } /\114\001/ { if (NR == 1) { print "pecoff"; exit } } /\144\206/ { if (NR == 1) { print "pecoff"; exit } } +/\001\337/ { if (NR == 1) { print "xcoff32"; exit } } +/\001\367/ { if (NR == 1) { print "xcoff64"; exit } } + diff --git a/libbacktrace/testlib.c b/libbacktrace/testlib.c new file mode 100644 index 00000000000..05420cad5f3 --- /dev/null +++ b/libbacktrace/testlib.c @@ -0,0 +1,234 @@ +/* testlib.c -- test functions for libbacktrace library + Copyright (C) 2012-2017 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. */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "filenames.h" + +#include "backtrace.h" + +#include "testlib.h" + +/* The backtrace state. */ + +void *state; + +/* The number of failures. */ + +int failures; + +/* Return the base name in a path. */ + +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. */ + +void +check (const char *name, int index, const struct info *all, int want_lineno, + const char *want_function, const char *want_file, 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), want_file) != 0) + { + fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index, + all[index].filename, want_file); + *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. */ + +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. */ + +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. */ + +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. */ + +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. */ + +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. */ + +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; +} + +/* The backtrace_create_state error callback function. */ + +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); +} diff --git a/libbacktrace/testlib.h b/libbacktrace/testlib.h new file mode 100644 index 00000000000..2bfe62f3daa --- /dev/null +++ b/libbacktrace/testlib.h @@ -0,0 +1,110 @@ +/* testlib.h -- Header for test functions for libbacktrace library + Copyright (C) 2012-2017 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. */ + +#ifndef LIBBACKTRACE_TESTLIB_H +#define LIBBACKTRACE_TESTLIB_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. */ + +extern void *state; + +/* The number of failures. */ + +extern int failures; + +extern const char *base (const char *p); +extern void check (const char *name, int index, const struct info *all, + int want_lineno, const char *want_function, + const char *want_file, int *failed); +extern int callback_one (void *, uintptr_t, const char *, int, const char *); +extern void error_callback_one (void *, const char *, int); +extern int callback_two (void *, uintptr_t); +extern void error_callback_two (void *, const char *, int); +extern void callback_three (void *, uintptr_t, const char *, uintptr_t, + uintptr_t); +extern void error_callback_three (void *, const char *, int); +extern void error_callback_create (void *, const char *, int); + +#endif /* !defined(LIBBACKTRACE_TESTLIB_H) */ diff --git a/libbacktrace/ttest.c b/libbacktrace/ttest.c new file mode 100644 index 00000000000..6c2d26cafeb --- /dev/null +++ b/libbacktrace/ttest.c @@ -0,0 +1,161 @@ +/* ttest.c -- Test for libbacktrace library + Copyright (C) 2017 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. */ + +/* Test using the libbacktrace library from multiple threads. */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <pthread.h> + +#include "filenames.h" + +#include "backtrace.h" +#include "backtrace-supported.h" + +#include "testlib.h" + +static int f2 (int) __attribute__ ((noinline)); +static int f3 (int, int) __attribute__ ((noinline)); + +/* Test that a simple backtrace works. This is called via + pthread_create. It returns the number of failures, as void *. */ + +static void * +test1_thread (void *arg ATTRIBUTE_UNUSED) +{ + /* Returning a value here and elsewhere avoids a tailcall which + would mess up the backtrace. */ + return (void *) (uintptr_t) (f2 (__LINE__) - 2); +} + +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", "ttest.c", &data.failed); + check ("test1", 1, all, f2line, "f2", "ttest.c", &data.failed); + check ("test1", 2, all, f1line, "test1_thread", "ttest.c", &data.failed); + + return data.failed; +} + +/* Run the test with 10 threads simultaneously. */ + +#define THREAD_COUNT 10 + +static void test1 (void) __attribute__ ((unused)); + +static void +test1 (void) +{ + pthread_t atid[THREAD_COUNT]; + int i; + int errnum; + int this_fail; + void *ret; + + for (i = 0; i < THREAD_COUNT; i++) + { + errnum = pthread_create (&atid[i], NULL, test1_thread, NULL); + if (errnum != 0) + { + fprintf (stderr, "pthread_create %d: %s\n", i, strerror (errnum)); + exit (EXIT_FAILURE); + } + } + + this_fail = 0; + for (i = 0; i < THREAD_COUNT; i++) + { + errnum = pthread_join (atid[i], &ret); + if (errnum != 0) + { + fprintf (stderr, "pthread_join %d: %s\n", i, strerror (errnum)); + exit (EXIT_FAILURE); + } + this_fail += (int) (uintptr_t) ret; + } + + printf ("%s: threaded backtrace_full noinline\n", this_fail > 0 ? "FAIL" : "PASS"); + + failures += this_fail; +} + +int +main (int argc ATTRIBUTE_UNUSED, char **argv) +{ + state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS, + error_callback_create, NULL); + +#if BACKTRACE_SUPPORTED +#if BACKTRACE_SUPPORTS_THREADS + test1 (); +#endif +#endif + + exit (failures ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/libbacktrace/xcoff.c b/libbacktrace/xcoff.c new file mode 100644 index 00000000000..b3d7e24256b --- /dev/null +++ b/libbacktrace/xcoff.c @@ -0,0 +1,1485 @@ +/* xcoff.c -- Get debug data from an XCOFF file for backtraces. + Copyright (C) 2012-2017 Free Software Foundation, Inc. + Adapted from elf.c. + +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. */ + +#include "config.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#ifdef HAVE_LOADQUERY +#include <sys/ldr.h> +#endif + +#include "backtrace.h" +#include "internal.h" + +/* The configure script must tell us whether we are 32-bit or 64-bit + XCOFF. We could make this code test and support either possibility, + but there is no point. This code only works for the currently + running executable, which means that we know the XCOFF mode at + configure time. */ + +#if BACKTRACE_XCOFF_SIZE != 32 && BACKTRACE_XCOFF_SIZE != 64 +#error "Unknown BACKTRACE_XCOFF_SIZE" +#endif + +/* XCOFF file header. */ + +#if BACKTRACE_XCOFF_SIZE == 32 + +typedef struct { + uint16_t f_magic; + uint16_t f_nscns; + uint32_t f_timdat; + uint32_t f_symptr; + uint32_t f_nsyms; + uint16_t f_opthdr; + uint16_t f_flags; +} b_xcoff_filhdr; + +#define XCOFF_MAGIC 0737 + +#else /* BACKTRACE_XCOFF_SIZE != 32 */ + +typedef struct { + uint16_t f_magic; + uint16_t f_nscns; + uint32_t f_timdat; + uint64_t f_symptr; + uint16_t f_opthdr; + uint16_t f_flags; + uint32_t f_nsyms; +} b_xcoff_filhdr; + +#define XCOFF_MAGIC 0767 + +#endif /* BACKTRACE_XCOFF_SIZE != 32 */ + +#define F_SHROBJ 0x2000 /* File is a shared object. */ + +/* XCOFF section header. */ + +#if BACKTRACE_XCOFF_SIZE == 32 + +typedef struct { + char s_name[8]; + uint32_t s_paddr; + uint32_t s_vaddr; + uint32_t s_size; + uint32_t s_scnptr; + uint32_t s_relptr; + uint32_t s_lnnoptr; + uint16_t s_nreloc; + uint16_t s_nlnno; + uint32_t s_flags; +} b_xcoff_scnhdr; + +#define _OVERFLOW_MARKER 65535 + +#else /* BACKTRACE_XCOFF_SIZE != 32 */ + +typedef struct { + char name[8]; + uint64_t s_paddr; + uint64_t s_vaddr; + uint64_t s_size; + uint64_t s_scnptr; + uint64_t s_relptr; + uint64_t s_lnnoptr; + uint32_t s_nreloc; + uint32_t s_nlnno; + uint32_t s_flags; +} b_xcoff_scnhdr; + +#endif /* BACKTRACE_XCOFF_SIZE != 32 */ + +#define STYP_TEXT 0x20 /* Executable text (code) section. */ +#define STYP_OVRFLO 0x8000 /* Line-number field overflow section. */ + +/* XCOFF symbol. */ + +#define SYMNMLEN 8 + +#if BACKTRACE_XCOFF_SIZE == 32 + +typedef struct { + union { + char _name[SYMNMLEN]; + struct { + uint32_t _zeroes; + uint32_t _offset; + } _s; + } _u; +#define n_name _u._name +#define n_zeroes _u._s._zeroes +#define n_offset_ _u._s._offset + + uint32_t n_value; + int16_t n_scnum; + uint16_t n_type; + uint8_t n_sclass; + uint8_t n_numaux; +} __attribute__ ((packed)) b_xcoff_syment; + +#else /* BACKTRACE_XCOFF_SIZE != 32 */ + +typedef struct { + uint64_t n_value; + uint32_t n_offset_; + int16_t n_scnum; + uint16_t n_type; + uint8_t n_sclass; + uint8_t n_numaux; +} __attribute__ ((packed)) b_xcoff_syment; + +#endif /* BACKTRACE_XCOFF_SIZE != 32 */ + +#define SYMESZ 18 + +#define C_EXT 2 /* External symbol. */ +#define C_FCN 101 /* Beginning or end of function. */ +#define C_FILE 103 /* Source file name. */ +#define C_HIDEXT 107 /* Unnamed external symbol. */ +#define C_BINCL 108 /* Beginning of include file. */ +#define C_EINCL 109 /* End of include file. */ +#define C_WEAKEXT 111 /* Weak external symbol. */ + +#define ISFCN(x) ((x) & 0x0020) + +/* XCOFF AUX entry. */ + +#define AUXESZ 18 +#define FILNMLEN 14 + +typedef union { +#if BACKTRACE_XCOFF_SIZE == 32 + struct { + uint16_t pad; + uint16_t x_lnnohi; + uint16_t x_lnno; + } x_block; +#else + struct { + uint32_t x_lnno; + } x_block; +#endif + union { + char x_fname[FILNMLEN]; + struct { + uint32_t x_zeroes; + uint32_t x_offset; + char pad[FILNMLEN-8]; + uint8_t x_ftype; + } _x; + } x_file; +#if BACKTRACE_XCOFF_SIZE == 32 + struct { + uint32_t x_exptr; + uint32_t x_fsize; + uint32_t x_lnnoptr; + uint32_t x_endndx; + } x_fcn; +#else + struct { + uint64_t x_lnnoptr; + uint32_t x_fsize; + uint32_t x_endndx; + } x_fcn; +#endif + struct { + uint8_t pad[AUXESZ-1]; + uint8_t x_auxtype; + } x_auxtype; +} __attribute__ ((packed)) b_xcoff_auxent; + +/* XCOFF line number entry. */ + +#if BACKTRACE_XCOFF_SIZE == 32 + +typedef struct { + union { + uint32_t l_symndx; + uint32_t l_paddr; + } l_addr; + uint16_t l_lnno; +} b_xcoff_lineno; + +#define LINESZ 6 + +#else /* BACKTRACE_XCOFF_SIZE != 32 */ + +typedef struct { + union { + uint32_t l_symndx; + uint64_t l_paddr; + } l_addr; + uint32_t l_lnno; +} b_xcoff_lineno; + +#define LINESZ 12 + +#endif /* BACKTRACE_XCOFF_SIZE != 32 */ + +#if BACKTRACE_XCOFF_SIZE == 32 +#define XCOFF_AIX_TEXTBASE 0x10000000u +#else +#define XCOFF_AIX_TEXTBASE 0x100000000ul +#endif + +/* AIX big archive fixed-length header. */ + +#define AIAMAGBIG "<bigaf>\n" + +typedef struct { + char fl_magic[8]; /* Archive magic string. */ + char fl_memoff[20]; /* Offset to member table. */ + char fl_gstoff[20]; /* Offset to global symbol table. */ + char fl_gst64off[20]; /* Offset to global symbol table for 64-bit objects. */ + char fl_fstmoff[20]; /* Offset to first archive member. */ + char fl_freeoff[20]; /* Offset to first member on free list. */ +} b_ar_fl_hdr; + +/* AIX big archive file member header. */ + +typedef struct { + char ar_size[20]; /* File member size - decimal. */ + char ar_nxtmem[20]; /* Next member offset - decimal. */ + char ar_prvmem[20]; /* Previous member offset - decimal. */ + char ar_date[12]; /* File member date - decimal. */ + char ar_uid[12]; /* File member userid - decimal. */ + char ar_gid[12]; /* File member group id - decimal. */ + char ar_mode[12]; /* File member mode - octal. */ + char ar_namlen[4]; /* File member name length - decimal. */ + char ar_name[2]; /* Start of member name. */ +} b_ar_hdr; + + +/* Information we keep for an XCOFF symbol. */ + +struct xcoff_symbol +{ + /* The name of the symbol. */ + const char *name; + /* The address of the symbol. */ + uintptr_t address; + /* The size of the symbol. */ + size_t size; +}; + +/* Information to pass to xcoff_syminfo. */ + +struct xcoff_syminfo_data +{ + /* Symbols for the next module. */ + struct xcoff_syminfo_data *next; + /* The XCOFF symbols, sorted by address. */ + struct xcoff_symbol *symbols; + /* The number of symbols. */ + size_t count; +}; + +/* Information about an include file. */ + +struct xcoff_incl +{ + /* File name. */ + const char *filename; + /* Offset to first line number from the include file. */ + uintptr_t begin; + /* Offset to last line number from the include file. */ + uintptr_t end; +}; + +/* A growable vector of include files information. */ + +struct xcoff_incl_vector +{ + /* Memory. This is an array of struct xcoff_incl. */ + struct backtrace_vector vec; + /* Number of include files. */ + size_t count; +}; + +/* Map a single PC value to a file/function/line. */ + +struct xcoff_line +{ + /* PC. */ + uintptr_t pc; + /* File name. Many entries in the array are expected to point to + the same file name. */ + const char *filename; + /* Function name. */ + const char *function; + /* Line number. */ + int lineno; +}; + +/* A growable vector of line number information. This is used while + reading the line numbers. */ + +struct xcoff_line_vector +{ + /* Memory. This is an array of struct xcoff_line. */ + struct backtrace_vector vec; + /* Number of valid mappings. */ + size_t count; +}; + +/* The information we need to map a PC to a file and line. */ + +struct xcoff_fileline_data +{ + /* The data for the next file we know about. */ + struct xcoff_fileline_data *next; + /* Line number information. */ + struct xcoff_line_vector vec; +}; + + +/* A dummy callback function used when we can't find any debug info. */ + +static int +xcoff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t pc ATTRIBUTE_UNUSED, + backtrace_full_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no debug info in XCOFF executable", -1); + return 0; +} + +/* A dummy callback function used when we can't find a symbol + table. */ + +static void +xcoff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t addr ATTRIBUTE_UNUSED, + backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no symbol table in XCOFF executable", -1); +} + +/* Compare struct xcoff_symbol for qsort. */ + +static int +xcoff_symbol_compare (const void *v1, const void *v2) +{ + const struct xcoff_symbol *e1 = (const struct xcoff_symbol *) v1; + const struct xcoff_symbol *e2 = (const struct xcoff_symbol *) v2; + + if (e1->address < e2->address) + return -1; + else if (e1->address > e2->address) + return 1; + else + return 0; +} + +/* Compare an ADDR against an xcoff_symbol for bsearch. */ + +static int +xcoff_symbol_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct xcoff_symbol *entry = (const struct xcoff_symbol *) ventry; + uintptr_t addr; + + addr = *key; + if (addr < entry->address) + return -1; + else if ((entry->size == 0 && addr > entry->address) + || (entry->size > 0 && addr >= entry->address + entry->size)) + return 1; + else + return 0; +} + +/* Add XDATA to the list in STATE. */ + +static void +xcoff_add_syminfo_data (struct backtrace_state *state, + struct xcoff_syminfo_data *xdata) +{ + if (!state->threaded) + { + struct xcoff_syminfo_data **pp; + + for (pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = xdata; + } + else + { + while (1) + { + struct xcoff_syminfo_data **pp; + + pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data; + + while (1) + { + struct xcoff_syminfo_data *p; + + p = backtrace_atomic_load_pointer (pp); + + if (p == NULL) + break; + + pp = &p->next; + } + + if (__sync_bool_compare_and_swap (pp, NULL, xdata)) + break; + } + } +} + +/* Return the symbol name and value for an ADDR. */ + +static void +xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data) +{ + struct xcoff_syminfo_data *edata; + struct xcoff_symbol *sym = NULL; + + if (!state->threaded) + { + for (edata = (struct xcoff_syminfo_data *) state->syminfo_data; + edata != NULL; + edata = edata->next) + { + sym = ((struct xcoff_symbol *) + bsearch (&addr, edata->symbols, edata->count, + sizeof (struct xcoff_symbol), xcoff_symbol_search)); + if (sym != NULL) + break; + } + } + else + { + struct xcoff_syminfo_data **pp; + + pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data; + while (1) + { + edata = backtrace_atomic_load_pointer (pp); + if (edata == NULL) + break; + + sym = ((struct xcoff_symbol *) + bsearch (&addr, edata->symbols, edata->count, + sizeof (struct xcoff_symbol), xcoff_symbol_search)); + if (sym != NULL) + break; + + pp = &edata->next; + } + } + + if (sym == NULL) + callback (data, addr, NULL, 0, 0); + else + callback (data, addr, sym->name, sym->address, sym->size); +} + +/* Return the name of an XCOFF symbol. */ + +static const char * +xcoff_symname (const b_xcoff_syment *asym, + const unsigned char *strtab, size_t strtab_size) +{ +#if BACKTRACE_XCOFF_SIZE == 32 + if (asym->n_zeroes != 0) + { + /* Make a copy as we will release the symtab view. */ + char name[SYMNMLEN+1]; + strncpy (name, asym->n_name, SYMNMLEN); + name[SYMNMLEN] = '\0'; + return strdup (name); + } +#endif + if (asym->n_sclass & 0x80) + return NULL; /* .debug */ + if (asym->n_offset_ >= strtab_size) + return NULL; + return (const char *) strtab + asym->n_offset_; +} + +/* Initialize the symbol table info for xcoff_syminfo. */ + +static int +xcoff_initialize_syminfo (struct backtrace_state *state, + uintptr_t base_address, + const b_xcoff_scnhdr *sects, + const b_xcoff_syment *syms, size_t nsyms, + const unsigned char *strtab, size_t strtab_size, + backtrace_error_callback error_callback, void *data, + struct xcoff_syminfo_data *sdata) +{ + size_t xcoff_symbol_count; + size_t xcoff_symbol_size; + struct xcoff_symbol *xcoff_symbols; + size_t i; + unsigned int j; + + /* We only care about function symbols. Count them. */ + xcoff_symbol_count = 0; + for (i = 0; i < nsyms; ++i) + { + const b_xcoff_syment *asym = &syms[i]; + if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT + || asym->n_sclass == C_WEAKEXT) + && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0) + ++xcoff_symbol_count; + + i += asym->n_numaux; + } + + xcoff_symbol_size = xcoff_symbol_count * sizeof (struct xcoff_symbol); + xcoff_symbols = ((struct xcoff_symbol *) + backtrace_alloc (state, xcoff_symbol_size, error_callback, + data)); + if (xcoff_symbols == NULL) + return 0; + + j = 0; + for (i = 0; i < nsyms; ++i) + { + const b_xcoff_syment *asym = &syms[i]; + if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT + || asym->n_sclass == C_WEAKEXT) + && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0) + { + const b_xcoff_auxent *aux = (const b_xcoff_auxent *) (asym + 1); + xcoff_symbols[j].name = xcoff_symname (asym, strtab, strtab_size); + xcoff_symbols[j].address = base_address + asym->n_value + - sects[asym->n_scnum - 1].s_paddr; + /* x_fsize will be 0 if there is no debug information. */ + xcoff_symbols[j].size = aux->x_fcn.x_fsize; + ++j; + } + + i += asym->n_numaux; + } + + backtrace_qsort (xcoff_symbols, xcoff_symbol_count, + sizeof (struct xcoff_symbol), xcoff_symbol_compare); + + sdata->next = NULL; + sdata->symbols = xcoff_symbols; + sdata->count = xcoff_symbol_count; + + return 1; +} + +/* Compare struct xcoff_line for qsort. */ + +static int +xcoff_line_compare (const void *v1, const void *v2) +{ + const struct xcoff_line *ln1 = (const struct xcoff_line *) v1; + const struct xcoff_line *ln2 = (const struct xcoff_line *) v2; + + if (ln1->pc < ln2->pc) + return -1; + else if (ln1->pc > ln2->pc) + return 1; + else + return 0; +} + +/* Find a PC in a line vector. We always allocate an extra entry at + the end of the lines vector, so that this routine can safely look + at the next entry. */ + +static int +xcoff_line_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct xcoff_line *entry = (const struct xcoff_line *) ventry; + uintptr_t pc; + + pc = *key; + if (pc < entry->pc) + return -1; + else if ((entry + 1)->pc == (uintptr_t) -1 || pc >= (entry + 1)->pc) + return 1; + else + return 0; +} + +/* Look for a PC in the line vector for one module. On success, + call CALLBACK and return whatever it returns. On error, call + ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found, + 0 if not. */ + +static int +xcoff_lookup_pc (struct backtrace_state *state ATTRIBUTE_UNUSED, + struct xcoff_fileline_data *fdata, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data, int *found) +{ + const struct xcoff_line *ln; + const char *function; + + *found = 1; + + ln = (struct xcoff_line *) bsearch (&pc, fdata->vec.vec.base, + fdata->vec.count, + sizeof (struct xcoff_line), + xcoff_line_search); + if (ln == NULL) + { + *found = 0; + return 0; + } + + function = ln->function; + /* AIX prepends a '.' to function entry points, remove it. */ + if (*function == '.') + ++function; + return callback (data, pc, ln->filename, ln->lineno, function); +} + +/* Return the file/line information for a PC using the XCOFF lineno + mapping we built earlier. */ + +static int +xcoff_fileline (struct backtrace_state *state, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data) + +{ + struct xcoff_fileline_data *fdata; + int found; + int ret; + + if (!state->threaded) + { + for (fdata = (struct xcoff_fileline_data *) state->fileline_data; + fdata != NULL; + fdata = fdata->next) + { + ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback, + data, &found); + if (ret != 0 || found) + return ret; + } + } + else + { + struct xcoff_fileline_data **pp; + + pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data; + while (1) + { + fdata = backtrace_atomic_load_pointer (pp); + if (fdata == NULL) + break; + + ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback, + data, &found); + if (ret != 0 || found) + return ret; + + pp = &fdata->next; + } + } + + /* FIXME: See if any libraries have been dlopen'ed. */ + + return callback (data, pc, NULL, 0, NULL); +} + +/* Add a new mapping to the vector of line mappings that we are + building. Returns 1 on success, 0 on failure. */ + +static int +xcoff_add_line (struct backtrace_state *state, uintptr_t pc, + const char *filename, const char *function, uint32_t lnno, + backtrace_error_callback error_callback, void *data, + struct xcoff_line_vector *vec) +{ + struct xcoff_line *ln; + + ln = ((struct xcoff_line *) + backtrace_vector_grow (state, sizeof (struct xcoff_line), + error_callback, data, &vec->vec)); + if (ln == NULL) + return 0; + + ln->pc = pc; + ln->filename = filename; + ln->function = function; + ln->lineno = lnno; + + ++vec->count; + + return 1; +} + +/* Add the line number entries for a function to the line vector. */ + +static int +xcoff_process_linenos (struct backtrace_state *state, uintptr_t base_address, + const b_xcoff_syment *fsym, const char *filename, + const b_xcoff_scnhdr *sects, + const unsigned char *strtab, size_t strtab_size, + uint32_t fcn_lnno, struct xcoff_incl_vector *vec, + struct xcoff_line_vector *lvec, + const unsigned char *linenos, size_t linenos_size, + uintptr_t lnnoptr0, + backtrace_error_callback error_callback, void *data) +{ + const b_xcoff_auxent *aux; + const b_xcoff_lineno *lineno; + const unsigned char *lineptr; + const char *function; + struct xcoff_incl *incl = NULL; + uintptr_t lnnoptr; + uintptr_t pc; + uint32_t lnno; + int begincl; + size_t i; + + aux = (const b_xcoff_auxent *) (fsym + 1); + lnnoptr = aux->x_fcn.x_lnnoptr; + + if (lnnoptr < lnnoptr0 || lnnoptr + LINESZ > lnnoptr0 + linenos_size) + return 0; + + function = xcoff_symname (fsym, strtab, strtab_size); + if (function == NULL) + return 0; + + /* Skip first entry that points to symtab. */ + + lnnoptr += LINESZ; + + lineptr = linenos + (lnnoptr - lnnoptr0); + + begincl = -1; + while (lineptr + LINESZ <= linenos + linenos_size) + { + lineno = (const b_xcoff_lineno *) lineptr; + + lnno = lineno->l_lnno; + if (lnno == 0) + break; + + /* If part of a function other than the beginning comes from an + include file, the line numbers are absolute, rather than + relative to the beginning of the function. */ + for (i = 0; i < vec->count; ++i) + { + incl = (struct xcoff_incl *) vec->vec.base + i; + if (incl->begin <= lnnoptr && lnnoptr <= incl->end) + break; + } + if (begincl == -1) + begincl = (i < vec->count); + if (i < vec->count) + { + filename = incl->filename; + if (begincl == 1) + lnno += fcn_lnno - 1; + } + else + lnno += fcn_lnno - 1; + + pc = base_address + lineno->l_addr.l_paddr + - sects[fsym->n_scnum - 1].s_paddr; + xcoff_add_line (state, pc, filename, function, lnno, error_callback, + data, lvec); + + lnnoptr += LINESZ; + lineptr += LINESZ; + } + + return 1; +} + +/* Initialize the line vector info for xcoff_fileline. */ + +static int +xcoff_initialize_fileline (struct backtrace_state *state, + uintptr_t base_address, + const b_xcoff_scnhdr *sects, + const b_xcoff_syment *syms, size_t nsyms, + const unsigned char *strtab, size_t strtab_size, + const unsigned char *linenos, size_t linenos_size, + uint64_t lnnoptr0, + backtrace_error_callback error_callback, void *data) +{ + struct xcoff_fileline_data *fdata; + struct xcoff_incl_vector vec; + struct xcoff_line *ln; + const b_xcoff_syment *fsym; + const b_xcoff_auxent *aux; + const char *filename; + const char *name; + struct xcoff_incl *incl; + uintptr_t begin, end; + uintptr_t lnno; + size_t i; + + fdata = ((struct xcoff_fileline_data *) + backtrace_alloc (state, sizeof (struct xcoff_fileline_data), + error_callback, data)); + if (fdata == NULL) + return 0; + + memset (fdata, 0, sizeof *fdata); + memset (&vec, 0, sizeof vec); + + /* Process include files first. */ + + begin = 0; + for (i = 0; i < nsyms; ++i) + { + const b_xcoff_syment *asym = &syms[i]; + + switch (asym->n_sclass) + { + case C_BINCL: + begin = asym->n_value; + break; + + case C_EINCL: + if (begin == 0) + break; + end = asym->n_value; + incl = ((struct xcoff_incl *) + backtrace_vector_grow (state, sizeof (struct xcoff_incl), + error_callback, data, &vec.vec)); + if (incl != NULL) + { + incl->filename = xcoff_symname (asym, strtab, strtab_size); + incl->begin = begin; + incl->end = end; + ++vec.count; + } + begin = 0; + break; + } + + i += asym->n_numaux; + } + + filename = NULL; + fsym = NULL; + for (i = 0; i < nsyms; ++i) + { + const b_xcoff_syment *asym = &syms[i]; + + switch (asym->n_sclass) + { + case C_FILE: + filename = xcoff_symname (asym, strtab, strtab_size); + if (filename == NULL) + break; + + /* If the file auxiliary entry is not used, the symbol name is + the name of the source file. If the file auxiliary entry is + used, then the symbol name should be .file, and the first + file auxiliary entry (by convention) contains the source + file name. */ + + if (asym->n_numaux > 0 && !strcmp (filename, ".file")) + { + aux = (const b_xcoff_auxent *) (asym + 1); + if (aux->x_file._x.x_zeroes != 0) + { + /* Make a copy as we will release the symtab view. */ + char name[FILNMLEN+1]; + strncpy (name, aux->x_file.x_fname, FILNMLEN); + name[FILNMLEN] = '\0'; + filename = strdup (name); + } + else if (aux->x_file._x.x_offset < strtab_size) + filename = (const char *) strtab + aux->x_file._x.x_offset; + else + filename = NULL; + } + break; + + case C_EXT: + case C_HIDEXT: + case C_WEAKEXT: + fsym = NULL; + if (!ISFCN (asym->n_type) || asym->n_numaux == 0) + break; + if (filename == NULL) + break; + fsym = asym; + break; + + case C_FCN: + if (asym->n_numaux == 0) + break; + if (fsym == NULL) + break; + name = xcoff_symname (asym, strtab, strtab_size); + if (name == NULL) + break; + aux = (const b_xcoff_auxent *) (asym + 1); +#if BACKTRACE_XCOFF_SIZE == 32 + lnno = (uint32_t) aux->x_block.x_lnnohi << 16 + | aux->x_block.x_lnno; +#else + lnno = aux->x_block.x_lnno; +#endif + if (!strcmp (name, ".bf")) + { + xcoff_process_linenos (state, base_address, fsym, filename, + sects, strtab, strtab_size, lnno, &vec, + &fdata->vec, linenos, linenos_size, + lnnoptr0, error_callback, data); + } + else if (!strcmp (name, ".ef")) + { + fsym = NULL; + } + break; + } + + i += asym->n_numaux; + } + + /* Allocate one extra entry at the end. */ + ln = ((struct xcoff_line *) + backtrace_vector_grow (state, sizeof (struct xcoff_line), + error_callback, data, &fdata->vec.vec)); + if (ln == NULL) + goto fail; + ln->pc = (uintptr_t) -1; + ln->filename = NULL; + ln->function = NULL; + ln->lineno = 0; + + if (!backtrace_vector_release (state, &fdata->vec.vec, error_callback, data)) + goto fail; + + backtrace_qsort (fdata->vec.vec.base, fdata->vec.count, + sizeof (struct xcoff_line), xcoff_line_compare); + + if (!state->threaded) + { + struct xcoff_fileline_data **pp; + + for (pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = fdata; + } + else + { + while (1) + { + struct xcoff_fileline_data **pp; + + pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data; + + while (1) + { + struct xcoff_fileline_data *p; + + p = backtrace_atomic_load_pointer (pp); + + if (p == NULL) + break; + + pp = &p->next; + } + + if (__sync_bool_compare_and_swap (pp, NULL, fdata)) + break; + } + } + + return 1; + +fail: + return 0; +} + +/* Add the backtrace data for one XCOFF file. Returns 1 on success, + 0 on failure (in both cases descriptor is closed). */ + +static int +xcoff_add (struct backtrace_state *state, int descriptor, off_t offset, + uintptr_t base_address, backtrace_error_callback error_callback, + void *data, fileline *fileline_fn, int *found_sym, int exe) +{ + struct backtrace_view fhdr_view; + struct backtrace_view sects_view; + struct backtrace_view linenos_view; + struct backtrace_view syms_view; + struct backtrace_view str_view; + b_xcoff_filhdr fhdr; + const b_xcoff_scnhdr *sects; + const b_xcoff_scnhdr *stext; + uint64_t lnnoptr; + uint32_t nlnno; + off_t str_off; + size_t sects_size; + size_t syms_size; + int32_t str_size; + int sects_view_valid; + int linenos_view_valid; + int syms_view_valid; + int str_view_valid; + int magic_ok; + int i; + + *found_sym = 0; + + sects_view_valid = 0; + linenos_view_valid = 0; + syms_view_valid = 0; + str_view_valid = 0; + + /* Map the XCOFF file header. */ + if (!backtrace_get_view (state, descriptor, offset, sizeof (b_xcoff_filhdr), + error_callback, data, &fhdr_view)) + goto fail; + + memcpy (&fhdr, fhdr_view.data, sizeof fhdr); + magic_ok = (fhdr.f_magic == XCOFF_MAGIC); + + backtrace_release_view (state, &fhdr_view, error_callback, data); + + if (!magic_ok) + { + if (exe) + error_callback (data, "executable file is not XCOFF", 0); + goto fail; + } + + /* Verify object is of expected type. */ + if ((exe && (fhdr.f_flags & F_SHROBJ)) + || (!exe && !(fhdr.f_flags & F_SHROBJ))) + goto fail; + + /* Read the section headers. */ + + sects_size = fhdr.f_nscns * sizeof (b_xcoff_scnhdr); + + if (!backtrace_get_view (state, descriptor, + offset + sizeof (fhdr) + fhdr.f_opthdr, + sects_size, error_callback, data, §s_view)) + goto fail; + sects_view_valid = 1; + sects = (const b_xcoff_scnhdr *) sects_view.data; + + /* FIXME: assumes only one .text section. */ + for (i = 0; i < fhdr.f_nscns; ++i) + if ((sects[i].s_flags & 0xffff) == STYP_TEXT) + break; + if (i == fhdr.f_nscns) + goto fail; + + stext = §s[i]; + + /* AIX ldinfo_textorg includes the XCOFF headers. */ + base_address = (exe ? XCOFF_AIX_TEXTBASE : base_address) + stext->s_scnptr; + + lnnoptr = stext->s_lnnoptr; + nlnno = stext->s_nlnno; + +#if BACKTRACE_XCOFF_SIZE == 32 + if (nlnno == _OVERFLOW_MARKER) + { + int sntext = i + 1; + /* Find the matching .ovrflo section. */ + for (i = 0; i < fhdr.f_nscns; ++i) + { + if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO) + && sects[i].s_nlnno == sntext) + { + nlnno = sects[i].s_vaddr; + break; + } + } + } +#endif + + /* Read the symbol table and the string table. */ + + if (fhdr.f_symptr != 0) + { + struct xcoff_syminfo_data *sdata; + + /* Symbol table is followed by the string table. The string table + starts with its length (on 4 bytes). + Map the symbol table and the length of the string table. */ + syms_size = fhdr.f_nsyms * sizeof (b_xcoff_syment); + + if (!backtrace_get_view (state, descriptor, offset + fhdr.f_symptr, + syms_size + 4, error_callback, data, + &syms_view)) + goto fail; + syms_view_valid = 1; + + memcpy (&str_size, syms_view.data + syms_size, 4); + + str_off = fhdr.f_symptr + syms_size; + + if (str_size > 4) + { + /* Map string table (including the length word). */ + + if (!backtrace_get_view (state, descriptor, offset + str_off, + str_size, error_callback, data, &str_view)) + goto fail; + str_view_valid = 1; + } + + sdata = ((struct xcoff_syminfo_data *) + backtrace_alloc (state, sizeof *sdata, error_callback, data)); + if (sdata == NULL) + goto fail; + + if (!xcoff_initialize_syminfo (state, base_address, sects, + syms_view.data, fhdr.f_nsyms, + str_view.data, str_size, + error_callback, data, sdata)) + { + backtrace_free (state, sdata, sizeof *sdata, error_callback, data); + goto fail; + } + + *found_sym = 1; + + xcoff_add_syminfo_data (state, sdata); + } + + /* Read the line number entries. */ + + if (fhdr.f_symptr != 0 && lnnoptr != 0) + { + size_t linenos_size = (size_t) nlnno * LINESZ; + + if (!backtrace_get_view (state, descriptor, offset + lnnoptr, + linenos_size, + error_callback, data, &linenos_view)) + goto fail; + linenos_view_valid = 1; + + if (xcoff_initialize_fileline (state, base_address, sects, + syms_view.data, fhdr.f_nsyms, + str_view.data, str_size, + linenos_view.data, linenos_size, + lnnoptr, error_callback, data)) + *fileline_fn = xcoff_fileline; + + backtrace_release_view (state, &linenos_view, error_callback, data); + linenos_view_valid = 0; + } + + backtrace_release_view (state, §s_view, error_callback, data); + sects_view_valid = 0; + if (syms_view_valid) + backtrace_release_view (state, &syms_view, error_callback, data); + syms_view_valid = 0; + + /* We've read all we need from the executable. */ + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + descriptor = -1; + + return 1; + + fail: + if (sects_view_valid) + backtrace_release_view (state, §s_view, error_callback, data); + if (str_view_valid) + backtrace_release_view (state, &str_view, error_callback, data); + if (syms_view_valid) + backtrace_release_view (state, &syms_view, error_callback, data); + if (linenos_view_valid) + backtrace_release_view (state, &linenos_view, error_callback, data); + if (descriptor != -1 && offset == 0) + backtrace_close (descriptor, error_callback, data); + return 0; +} + +#ifdef HAVE_LOADQUERY + +/* Read an integer value in human-readable format from an AIX + big archive fixed-length or member header. */ + +static int +xcoff_parse_decimal (const char *buf, size_t size, off_t *off) +{ + char str[32]; + char *end; + + if (size >= sizeof str) + return 0; + memcpy (str, buf, size); + str[size] = '\0'; + *off = strtol (str, &end, 10); + if (*end != '\0' && *end != ' ') + return 0; + + return 1; +} + +/* Add the backtrace data for a member of an AIX big archive. + Returns 1 on success, 0 on failure. */ + +static int +xcoff_armem_add (struct backtrace_state *state, int descriptor, + uintptr_t base_address, const char *member, + backtrace_error_callback error_callback, void *data, + fileline *fileline_fn, int *found_sym) +{ + struct backtrace_view view; + b_ar_fl_hdr fl_hdr; + const b_ar_hdr *ar_hdr; + off_t off; + off_t len; + int memlen; + + *found_sym = 0; + + /* Map archive fixed-length header. */ + + if (!backtrace_get_view (state, descriptor, 0, sizeof (b_ar_fl_hdr), + error_callback, data, &view)) + goto fail; + + memcpy (&fl_hdr, view.data, sizeof (b_ar_fl_hdr)); + + backtrace_release_view (state, &view, error_callback, data); + + if (memcmp (fl_hdr.fl_magic, AIAMAGBIG, 8) != 0) + goto fail; + + memlen = strlen (member); + + /* Read offset of first archive member. */ + if (!xcoff_parse_decimal (fl_hdr.fl_fstmoff, sizeof fl_hdr.fl_fstmoff, &off)) + goto fail; + while (off != 0) + { + /* Map archive member header and member name. */ + + if (!backtrace_get_view (state, descriptor, off, + sizeof (b_ar_hdr) + memlen, + error_callback, data, &view)) + break; + + ar_hdr = (const b_ar_hdr *) view.data; + + /* Read archive member name length. */ + if (!xcoff_parse_decimal (ar_hdr->ar_namlen, sizeof ar_hdr->ar_namlen, + &len)) + { + backtrace_release_view (state, &view, error_callback, data); + break; + } + if (len == memlen && !memcmp (ar_hdr->ar_name, member, memlen)) + { + off = (off + sizeof (b_ar_hdr) + memlen + 1) & ~1; + + /* The archive can contain several members with the same name + (e.g. 32-bit and 64-bit), so continue if not ok. */ + + if (xcoff_add (state, descriptor, off, base_address, error_callback, + data, fileline_fn, found_sym, 0)) + { + backtrace_release_view (state, &view, error_callback, data); + return 1; + } + } + + /* Read offset of next archive member. */ + if (!xcoff_parse_decimal (ar_hdr->ar_nxtmem, sizeof ar_hdr->ar_nxtmem, + &off)) + { + backtrace_release_view (state, &view, error_callback, data); + break; + } + backtrace_release_view (state, &view, error_callback, data); + } + + fail: + /* No matching member found. */ + backtrace_close (descriptor, error_callback, data); + return 0; +} + +/* Add the backtrace data for dynamically loaded libraries. */ + +static void +xcoff_add_shared_libs (struct backtrace_state *state, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn, int *found_sym) +{ + const struct ld_info *ldinfo; + void *buf; + unsigned int buflen; + const char *member; + int descriptor; + int does_not_exist; + int lib_found_sym; + int ret; + + /* Retrieve the list of loaded libraries. */ + + buf = NULL; + buflen = 512; + do + { + buf = realloc (buf, buflen); + if (buf == NULL) + { + ret = -1; + break; + } + ret = loadquery (L_GETINFO, buf, buflen); + if (ret == 0) + break; + buflen *= 2; + } + while (ret == -1 && errno == ENOMEM); + if (ret != 0) + { + free (buf); + return; + } + + ldinfo = (const struct ld_info *) buf; + while ((const char *) ldinfo < (const char *) buf + buflen) + { + if (*ldinfo->ldinfo_filename != '/') + goto next; + + descriptor = backtrace_open (ldinfo->ldinfo_filename, error_callback, + data, &does_not_exist); + if (descriptor < 0) + goto next; + + /* Check if it is an archive (member name not empty). */ + + member = ldinfo->ldinfo_filename + strlen (ldinfo->ldinfo_filename) + 1; + if (*member) + { + xcoff_armem_add (state, descriptor, + (uintptr_t) ldinfo->ldinfo_textorg, member, + error_callback, data, fileline_fn, &lib_found_sym); + } + else + { + xcoff_add (state, descriptor, 0, (uintptr_t) ldinfo->ldinfo_textorg, + error_callback, data, fileline_fn, &lib_found_sym, 0); + } + if (lib_found_sym) + *found_sym = 1; + + next: + if (ldinfo->ldinfo_next == 0) + break; + ldinfo = (const struct ld_info *) ((const char *) ldinfo + + ldinfo->ldinfo_next); + } + + free (buf); +} +#endif /* HAVE_LOADQUERY */ + +/* Initialize the backtrace data we need from an XCOFF executable. + Returns 1 on success, 0 on failure. */ + +int +backtrace_initialize (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn) +{ + int ret; + int found_sym; + fileline xcoff_fileline_fn = xcoff_nodebug; + + ret = xcoff_add (state, descriptor, 0, 0, error_callback, data, + &xcoff_fileline_fn, &found_sym, 1); + if (!ret) + return 0; + +#ifdef HAVE_LOADQUERY + xcoff_add_shared_libs (state, error_callback, data, &xcoff_fileline_fn, + &found_sym); +#endif + + if (!state->threaded) + { + if (found_sym) + state->syminfo_fn = xcoff_syminfo; + else if (state->syminfo_fn == NULL) + state->syminfo_fn = xcoff_nosyms; + } + else + { + if (found_sym) + backtrace_atomic_store_pointer (&state->syminfo_fn, xcoff_syminfo); + else + __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, xcoff_nosyms); + } + + if (!state->threaded) + { + if (state->fileline_fn == NULL || state->fileline_fn == xcoff_nodebug) + *fileline_fn = xcoff_fileline_fn; + } + else + { + fileline current_fn; + + current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); + if (current_fn == NULL || current_fn == xcoff_nodebug) + *fileline_fn = xcoff_fileline_fn; + } + + return 1; +} |