diff options
author | Jose Fonseca <jfonseca@vmware.com> | 2016-01-27 12:33:53 +0000 |
---|---|---|
committer | Jose Fonseca <jfonseca@vmware.com> | 2016-01-27 12:33:53 +0000 |
commit | 8f654894d52a70291d6da17c4394e16507b77a79 (patch) | |
tree | b6f012861dbcc35fe4455ee33419ab4356c39388 /thirdparty/libbacktrace | |
parent | e11395e9a4afddfc68b40facb1007dd303ee24f6 (diff) |
libbacktrace: Update.
To git commit f1717362de1e56fe1ffab540289d7d0c6ed48b20,
svn+ssh://gcc.gnu.org/svn/gcc/trunk@232055.
Fixes #419.
Diffstat (limited to 'thirdparty/libbacktrace')
25 files changed, 2222 insertions, 351 deletions
diff --git a/thirdparty/libbacktrace/CMakeLists.txt b/thirdparty/libbacktrace/CMakeLists.txt index 2a4a685e..3fc54306 100644 --- a/thirdparty/libbacktrace/CMakeLists.txt +++ b/thirdparty/libbacktrace/CMakeLists.txt @@ -66,6 +66,13 @@ check_c_source_compiles ( __sync_lock_release (&i);}" HAVE_SYNC_FUNCTIONS) +check_c_source_compiles ( + "int i; + int main() { + __atomic_load_n (&i, __ATOMIC_ACQUIRE); + __atomic_store_n (&i, i, __ATOMIC_RELEASE);}" + HAVE_ATOMIC_FUNCTIONS) + if (HAVE_SYNC_FUNCTIONS) set (BACKTRACE_SUPPORTS_THREADS 1) else () @@ -75,10 +82,12 @@ endif () if (CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF") set (FORMAT_FILE elf.c dwarf.c) math (EXPR BACKTRACE_ELF_SIZE 8*${CMAKE_C_SIZEOF_DATA_PTR}) + set (BACKTRACE_SUPPORTS_DATA 1) else () set (FORMAT_FILE unknown.c) set (BACKTRACE_SUPPORTED 0) message (STATUS "Executable format is not ELF. Disabling Backtrace support.") + set (BACKTRACE_SUPPORTS_DATA 0) endif () check_symbol_exists (mmap sys/mman.h HAVE_MMAP) @@ -88,9 +97,9 @@ if (HAVE_MMAP) check_symbol_exists (MAP_ANONYMOUS sys/mman.h HAVE_MMAP_ANONYMOUS) check_symbol_exists (MAP_ANON sys/mman.h HAVE_MMAP_ANON) if (HAVE_MMAP_ANONYMOUS AND HAVE_MMAP_ANON) - set (ALLOC_FILE mmap.c) + set (ALLOC_FILE mmap.c) else () - set (ALLOC_FILE alloc.c) + set (ALLOC_FILE alloc.c) endif () else () set (VIEW_FILE read.c) @@ -137,10 +146,12 @@ add_convenience_library (backtrace EXCLUDE_FROM_ALL ${FORMAT_FILE} ${VIEW_FILE} ${ALLOC_FILE} + atomic.c fileline.c posix.c print.c state.c + sort.c ) add_executable (btest btest.c) @@ -148,3 +159,9 @@ set_target_properties (btest PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS_DEBUG}") target_link_libraries (btest backtrace) add_dependencies (check btest) add_test (libbacktrace_btest btest) + +add_executable (stest stest.c) +set_target_properties (stest PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS_DEBUG}") +target_link_libraries (stest backtrace) +add_dependencies (check stest) +add_test (libbacktrace_stest stest) diff --git a/thirdparty/libbacktrace/ChangeLog b/thirdparty/libbacktrace/ChangeLog index d6f7205f..2afa4705 100644 --- a/thirdparty/libbacktrace/ChangeLog +++ b/thirdparty/libbacktrace/ChangeLog @@ -1,3 +1,275 @@ +2016-01-04 Jakub Jelinek <jakub@redhat.com> + + Update copyright years. + +2015-12-18 Andris Pavenis <andris.pavenis@iki.fi> + + * configure.ac: Specify that DJGPP do not have mmap even when sys/mman.h exists + * configure: Regenerate + +2015-12-09 John David Anglin <danglin@gcc.gnu.org> + + PR 68115/libfortran + * configure.ac: Set libbacktrace_cv_sys_sync to no on hppa*-*-hpux*. + * configure: Regenerate. + * elf.c (backtrace_initialize): Cast __sync_bool_compare_and_swap call + to void. + +2015-09-17 Ian Lance Taylor <iant@google.com> + + * posix.c (backtrace_open): Cast second argument of open() to int. + +2015-09-11 Ian Lance Taylor <iant@google.com> + + * Makefile.am (backtrace.lo): Depend on internal.h. + (sort.lo, stest.lo): Add explicit dependencies. + * Makefile.in: Rebuild. + +2015-09-09 Hans-Peter Nilsson <hp@axis.com> + + * backtrace.c: #include <sys/types.h>. + +2015-09-08 Ian Lance Taylor <iant@google.com> + + PR other/67457 + * backtrace.c: #include "internal.h". + (struct backtrace_data): Add can_alloc field. + (unwind): If can_alloc is false, don't try to get file/line + information. + (backtrace_full): Set can_alloc field in bdata. + * alloc.c (backtrace_alloc): Don't call error_callback if it is + NULL. + * mmap.c (backtrace_alloc): Likewise. + * internal.h: Update comments for backtrace_alloc and + backtrace_free. + +2015-09-08 Ian Lance Taylor <iant@google.com> + + PR other/67457 + * mmap.c (backtrace_alloc): Correct test for mmap failure. + +2015-08-31 Ulrich Weigand <Ulrich.Weigand@de.ibm.com> + + * configure.ac: For spu-*-* targets, set have_fcntl to no. + * configure: Regenerate. + +2015-08-27 Ulrich Weigand <Ulrich.Weigand@de.ibm.com> + + * configure.ac: Remove [disable-shared] argument to LT_INIT. + Remove setting PIC_FLAG when building as target library. + * configure: Regenerate. + +2015-08-26 Hans-Peter Nilsson <hp@axis.com> + + * configure.ac: Only compile with -fPIC if the target + supports it. + * configure: Regenerate. + +2015-08-24 Ulrich Weigand <Ulrich.Weigand@de.ibm.com> + + * configure.ac: Set have_mmap to no on spu-*-* targets. + * configure: Regenerate. + +2015-08-13 Ian Lance Taylor <iant@google.com> + + * dwarf.c (read_function_entry): Add vec_inlined parameter. + Change all callers. + +2015-06-11 Martin Sebor <msebor@redhat.com> + + PR sanitizer/65479 + * dwarf.c (struct line): Add new field idx. + (line_compare): Use it. + (add_line): Set it. + (read_line_info): Reset it. + +2015-05-29 Tristan Gingold <gingold@adacore.com> + + * pecoff.c: New file. + * Makefile.am (FORMAT_FILES): Add pecoff.c and dependencies. + * Makefile.in: Regenerate. + * filetype.awk: Detect pecoff. + * configure.ac: Define BACKTRACE_SUPPORTS_DATA on elf platforms. + Add pecoff. + * btest.c (test5): Test enabled only if BACKTRACE_SUPPORTS_DATA is + true. + * backtrace-supported.h.in (BACKTRACE_SUPPORTS_DATA): Define. + * configure: Regenerate. + * pecoff.c: New file. + +2015-05-13 Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com> + + * Makefile.in: Regenerated with automake-1.11.6. + * aclocal.m4: Likewise. + * configure: Likewise. + +2015-01-24 Matthias Klose <doko@ubuntu.com> + + * configure.ac: Move AM_ENABLE_MULTILIB before AC_PROG_CC. + * configure: Regenerate. + +2015-01-05 Jakub Jelinek <jakub@redhat.com> + + Update copyright years. + +2014-11-21 H.J. Lu <hongjiu.lu@intel.com> + + PR bootstrap/63784 + * configure: Regenerated. + +2014-11-11 David Malcolm <dmalcolm@redhat.com> + + * ChangeLog.jit: New. + +2014-11-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org> + + PR target/63610 + * configure: Regenerate. + +2014-10-23 Ian Lance Taylor <iant@google.com> + + * internal.h (backtrace_atomic_load_pointer) [no atomic or sync]: + Fix to return void *. + +2014-05-08 Ian Lance Taylor <iant@google.com> + + * mmap.c (backtrace_free): If freeing a large aligned block of + memory, call munmap rather than holding onto it. + (backtrace_vector_grow): When growing a vector, double the number + of pages requested. When releasing the old version of a grown + vector, pass the correct size to backtrace_free. + +2014-03-07 Ian Lance Taylor <iant@google.com> + + * sort.c (backtrace_qsort): Use middle element as pivot. + +2014-03-06 Ian Lance Taylor <iant@google.com> + + * sort.c: New file. + * stest.c: New file. + * internal.h (backtrace_qsort): Declare. + * dwarf.c (read_abbrevs): Call backtrace_qsort instead of qsort. + (read_line_info, read_function_entry): Likewise. + (read_function_info, build_dwarf_data): Likewise. + * elf.c (elf_initialize_syminfo): Likewise. + * Makefile.am (libbacktrace_la_SOURCES): Add sort.c. + (stest_SOURCES, stest_LDADD): Define. + (check_PROGRAMS): Add stest. + +2014-02-07 Misty De Meo <misty@brew.sh> + + PR target/58710 + * configure.ac: Use AC_LINK_IFELSE in check for + _Unwind_GetIPInfo. + * configure: Regenerate. + +2014-01-02 Richard Sandiford <rdsandiford@googlemail.com> + + Update copyright years + +2013-12-06 Jakub Jelinek <jakub@redhat.com> + + * elf.c (ET_DYN): Undefine and define again. + (elf_add): Add exe argument, if true and ehdr.e_type is ET_DYN, + return early -1 without closing the descriptor. + (struct phdr_data): Add exe_descriptor. + (phdr_callback): If pd->exe_descriptor is not -1, for very first + call if dlpi_name is NULL just call elf_add with the exe_descriptor, + otherwise backtrace_close the exe_descriptor if not -1. Adjust + call to elf_add. + (backtrace_initialize): Adjust call to elf_add. If it returns + -1, set pd.exe_descriptor to descriptor, otherwise set it to -1. + +2013-12-05 Ian Lance Taylor <iant@google.com> + + * alloc.c (backtrace_vector_finish): Add error_callback and data + parameters. Call backtrace_vector_release. Return address base. + * mmap.c (backtrace_vector_finish): Add error_callback and data + parameters. Return address base. + * dwarf.c (read_function_info): Get new address base from + backtrace_vector_finish. + * internal.h (backtrace_vector_finish): Update declaration. + +2013-11-27 Ian Lance Taylor <iant@google.com> + + * dwarf.c (find_address_ranges): New static function, broken out + of build_address_map. + (build_address_map): Call it. + * btest.c (check): Check for missing filename or function, rather + than crashing. + (f3): Check that enough frames were returned. + +2013-11-19 Jakub Jelinek <jakub@redhat.com> + + * backtrace.h (backtrace_syminfo_callback): Add symsize argument. + * elf.c (elf_syminfo): Pass 0 or sym->size to the callback as + last argument. + * btest.c (struct symdata): Add size field. + (callback_three): Add symsize argument. Copy it to the data->size + field. + (f23): Set symdata.size to 0. + (test5): Likewise. If sizeof (int) > 1, lookup address of + ((uintptr_t) &global) + 1. Verify symdata.val and symdata.size + values. + + * atomic.c: Include sys/types.h. + +2013-11-18 Ian Lance Taylor <iant@google.com> + + * configure.ac: Check for support of __atomic extensions. + * internal.h: Declare or #define atomic functions for use in + backtrace code. + * atomic.c: New file. + * dwarf.c (dwarf_lookup_pc): Use atomic functions. + (dwarf_fileline, backtrace_dwarf_add): Likewise. + * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise. + (backtrace_initialize): Likewise. + * fileline.c (fileline_initialize): Likewise. + * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c. + * configure, config.h.in, Makefile.in: Rebuild. + +2013-11-18 Jakub Jelinek <jakub@redhat.com> + + * elf.c (SHN_UNDEF): Define. + (elf_initialize_syminfo): Add base_address argument. Ignore symbols + with st_shndx == SHN_UNDEF. Add base_address to address fields. + (elf_add): Adjust caller. + + * elf.c (phdr_callback): Process info->dlpi_addr == 0 normally. + +2013-11-16 Ian Lance Taylor <iant@google.com> + + * backtrace.h (backtrace_create_state): Correct comment about + threading. + +2013-11-15 Ian Lance Taylor <iant@google.com> + + * backtrace.h (backtrace_syminfo): Update comment and parameter + name to take any address, not just a PC value. + * elf.c (STT_OBJECT): Define. + (elf_nosyms): Rename parameter pc to addr. + (elf_symbol_search): Rename local variable pc to addr. + (elf_initialize_syminfo): Add STT_OBJECT symbols to elf_symbols. + (elf_syminfo): Rename parameter pc to addr. + * btest.c (global): New global variable. + (test5): New test. + (main): Call test5. + +2013-10-17 Ian Lance Taylor <iant@google.com> + + * elf.c (elf_add): Don't get the wrong offsets if a debug section + is missing. + +2013-10-15 David Malcolm <dmalcolm@redhat.com> + + * configure.ac: Add --enable-host-shared, setting up + pre-existing PIC_FLAG variable within Makefile.am et al. + * configure: Regenerate. + +2013-09-20 Alan Modra <amodra@gmail.com> + + * configure: Regenerate. + 2013-07-23 Alexander Monakov <amonakov@ispras.ru> * elf.c (elf_syminfo): Loop over the elf_syminfo_data chain. @@ -292,3 +564,9 @@ 2012-09-17 Ian Lance Taylor <iant@google.com> * Initial implementation. + +Copyright (C) 2012-2016 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/thirdparty/libbacktrace/alloc.c b/thirdparty/libbacktrace/alloc.c index d0796737..a9f07a01 100644 --- a/thirdparty/libbacktrace/alloc.c +++ b/thirdparty/libbacktrace/alloc.c @@ -1,5 +1,5 @@ /* alloc.c -- Memory allocation without mmap. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -44,7 +44,8 @@ POSSIBILITY OF SUCH DAMAGE. */ backtrace functions may not be safely invoked from a signal handler. */ -/* Allocate memory like malloc. */ +/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't + report an error. */ void * backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED, @@ -55,7 +56,10 @@ backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED, ret = malloc (size); if (ret == NULL) - error_callback (data, "malloc", errno); + { + if (error_callback) + error_callback (data, "malloc", errno); + } return ret; } @@ -113,12 +117,24 @@ backtrace_vector_grow (struct backtrace_state *state ATTRIBUTE_UNUSED, /* Finish the current allocation on VEC. */ -void -backtrace_vector_finish (struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_vector *vec) +void * +backtrace_vector_finish (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data) { - vec->base = (char *) vec->base + vec->size; + void *ret; + + /* With this allocator we call realloc in backtrace_vector_grow, + which means we can't easily reuse the memory here. So just + release it. */ + if (!backtrace_vector_release (state, vec, error_callback, data)) + return NULL; + ret = vec->base; + vec->base = NULL; vec->size = 0; + vec->alc = 0; + return ret; } /* Release any extra space allocated for VEC. */ diff --git a/thirdparty/libbacktrace/atomic.c b/thirdparty/libbacktrace/atomic.c new file mode 100644 index 00000000..cb0ad029 --- /dev/null +++ b/thirdparty/libbacktrace/atomic.c @@ -0,0 +1,113 @@ +/* atomic.c -- Support for atomic functions if not present. + Copyright (C) 2013-2016 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 "config.h" + +#include <sys/types.h> + +#include "backtrace.h" +#include "backtrace-supported.h" +#include "internal.h" + +/* This file holds implementations of the atomic functions that are + used if the host compiler has the sync functions but not the atomic + functions, as is true of versions of GCC before 4.7. */ + +#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS) + +/* Do an atomic load of a pointer. */ + +void * +backtrace_atomic_load_pointer (void *arg) +{ + void **pp; + void *p; + + pp = (void **) arg; + p = *pp; + while (!__sync_bool_compare_and_swap (pp, p, p)) + p = *pp; + return p; +} + +/* Do an atomic load of an int. */ + +int +backtrace_atomic_load_int (int *p) +{ + int i; + + i = *p; + while (!__sync_bool_compare_and_swap (p, i, i)) + i = *p; + return i; +} + +/* Do an atomic store of a pointer. */ + +void +backtrace_atomic_store_pointer (void *arg, void *p) +{ + void **pp; + void *old; + + pp = (void **) arg; + old = *pp; + while (!__sync_bool_compare_and_swap (pp, old, p)) + old = *pp; +} + +/* Do an atomic store of a size_t value. */ + +void +backtrace_atomic_store_size_t (size_t *p, size_t v) +{ + size_t old; + + old = *p; + while (!__sync_bool_compare_and_swap (p, old, v)) + old = *p; +} + +/* Do an atomic store of a int value. */ + +void +backtrace_atomic_store_int (int *p, int v) +{ + size_t old; + + old = *p; + while (!__sync_bool_compare_and_swap (p, old, v)) + old = *p; +} + +#endif diff --git a/thirdparty/libbacktrace/backtrace-supported.h.in b/thirdparty/libbacktrace/backtrace-supported.h.in index c615f640..ab34199f 100644 --- a/thirdparty/libbacktrace/backtrace-supported.h.in +++ b/thirdparty/libbacktrace/backtrace-supported.h.in @@ -1,5 +1,5 @@ /* backtrace-supported.h.in -- Whether stack backtrace is supported. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -59,3 +59,8 @@ POSSIBILITY OF SUCH DAMAGE. */ as 0. */ #define BACKTRACE_SUPPORTS_THREADS @BACKTRACE_SUPPORTS_THREADS@ + +/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo + will work for variables. It will always work for functions. */ + +#define BACKTRACE_SUPPORTS_DATA @BACKTRACE_SUPPORTS_DATA@ diff --git a/thirdparty/libbacktrace/backtrace.c b/thirdparty/libbacktrace/backtrace.c index 428f53a2..b89bf554 100644 --- a/thirdparty/libbacktrace/backtrace.c +++ b/thirdparty/libbacktrace/backtrace.c @@ -1,5 +1,5 @@ /* backtrace.c -- Entry point for stack backtrace library. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -32,8 +32,11 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" +#include <sys/types.h> + #include "unwind.h" #include "backtrace.h" +#include "internal.h" /* The main backtrace_full routine. */ @@ -53,6 +56,8 @@ struct backtrace_data void *data; /* Value to return from backtrace_full. */ int ret; + /* Whether there is any memory available. */ + int can_alloc; }; /* Unwind library callback routine. This is passed to @@ -80,8 +85,11 @@ unwind (struct _Unwind_Context *context, void *vdata) if (!ip_before_insn) --pc; - bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, - bdata->error_callback, bdata->data); + if (!bdata->can_alloc) + bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL); + else + bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, + bdata->error_callback, bdata->data); if (bdata->ret != 0) return _URC_END_OF_STACK; @@ -96,6 +104,7 @@ backtrace_full (struct backtrace_state *state, int skip, backtrace_error_callback error_callback, void *data) { struct backtrace_data bdata; + void *p; bdata.skip = skip + 1; bdata.state = state; @@ -103,6 +112,18 @@ backtrace_full (struct backtrace_state *state, int skip, bdata.error_callback = error_callback; bdata.data = data; bdata.ret = 0; + + /* If we can't allocate any memory at all, don't try to produce + file/line information. */ + p = backtrace_alloc (state, 4096, NULL, NULL); + if (p == NULL) + bdata.can_alloc = 0; + else + { + backtrace_free (state, p, 4096, NULL, NULL); + bdata.can_alloc = 1; + } + _Unwind_Backtrace (unwind, &bdata); return bdata.ret; } diff --git a/thirdparty/libbacktrace/backtrace.h b/thirdparty/libbacktrace/backtrace.h index da16e3d7..d209219d 100644 --- a/thirdparty/libbacktrace/backtrace.h +++ b/thirdparty/libbacktrace/backtrace.h @@ -1,5 +1,5 @@ /* backtrace.h -- Public header file for stack backtrace library. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -89,8 +89,7 @@ typedef void (*backtrace_error_callback) (void *data, const char *msg, system-specific path names. If not NULL, FILENAME must point to a permanent buffer. If THREADED is non-zero the state may be accessed by multiple threads simultaneously, and the library will - use appropriate locks (this requires that the library be configured - with --enable-backtrace-threads). If THREADED is zero the state + use appropriate atomic operations. If THREADED is zero the state may only be accessed by one thread at a time. This returns a state pointer on success, NULL on error. If an error occurs, this will call the ERROR_CALLBACK routine. */ @@ -170,24 +169,25 @@ extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, /* The type of the callback argument to backtrace_syminfo. DATA and PC are the arguments passed to backtrace_syminfo. SYMNAME is the name of the symbol for the corresponding code. SYMVAL is the - value. SYMNAME will be NULL if no error occurred but the symbol - could not be found. */ + value and SYMSIZE is the size of the symbol. SYMNAME will be NULL + if no error occurred but the symbol could not be found. */ typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc, const char *symname, - uintptr_t symval); - -/* Given PC, a program counter in the current program, call the - callback information with the symbol name and value describing the - function in which PC may be found. This will call either CALLBACK - or ERROR_CALLBACK exactly once. This returns 1 on success, 0 on - failure. This function requires the symbol table but does not - require the debug info. Note that if the symbol table is present - but PC could not be found in the table, CALLBACK will be called - with a NULL SYMNAME argument. Returns 1 on success, 0 on - error. */ - -extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t pc, + uintptr_t symval, + uintptr_t symsize); + +/* Given ADDR, an address or program counter in the current program, + call the callback information with the symbol name and value + describing the function or variable in which ADDR may be found. + This will call either CALLBACK or ERROR_CALLBACK exactly once. + This returns 1 on success, 0 on failure. This function requires + the symbol table but does not require the debug info. Note that if + the symbol table is present but ADDR could not be found in the + table, CALLBACK will be called with a NULL SYMNAME argument. + Returns 1 on success, 0 on error. */ + +extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr, backtrace_syminfo_callback callback, backtrace_error_callback error_callback, void *data); diff --git a/thirdparty/libbacktrace/btest.c b/thirdparty/libbacktrace/btest.c index cc647b8d..0506d2b1 100644 --- a/thirdparty/libbacktrace/btest.c +++ b/thirdparty/libbacktrace/btest.c @@ -1,5 +1,5 @@ /* btest.c -- Test for libbacktrace library - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -92,7 +92,7 @@ struct sdata struct symdata { const char *name; - uintptr_t val; + uintptr_t val, size; int failed; }; @@ -129,6 +129,13 @@ check (const char *name, int index, const struct info *all, int want_lineno, { 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, @@ -238,7 +245,8 @@ error_callback_two (void *vdata, const char *msg, int errnum) static void callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, - const char *symname, uintptr_t symval) + const char *symname, uintptr_t symval, + uintptr_t symsize) { struct symdata *data = (struct symdata *) vdata; @@ -250,6 +258,7 @@ callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, assert (data->name != NULL); } data->val = symval; + data->size = symsize; } /* The backtrace_syminfo error callback function. */ @@ -308,6 +317,14 @@ f3 (int f1line, int f2line) data.failed = 1; } + if (data.index < 3) + { + fprintf (stderr, + "test1: not enough frames; got %zu, expected at least 3\n", + data.index); + data.failed = 1; + } + check ("test1", 0, all, f3line, "f3", &data.failed); check ("test1", 1, all, f2line, "f2", &data.failed); check ("test1", 2, all, f1line, "test1", &data.failed); @@ -458,6 +475,7 @@ f23 (int f1line, int f2line) symdata.name = NULL; symdata.val = 0; + symdata.size = 0; symdata.failed = 0; i = backtrace_syminfo (state, addrs[j], callback_three, @@ -598,6 +616,78 @@ f33 (int f1line, int f2line) return failures; } +#if BACKTRACE_SUPPORTS_DATA + +int global = 1; + +static int +test5 (void) +{ + struct symdata symdata; + int i; + uintptr_t addr = (uintptr_t) &global; + + if (sizeof (global) > 1) + addr += 1; + + symdata.name = NULL; + symdata.val = 0; + symdata.size = 0; + symdata.failed = 0; + + i = backtrace_syminfo (state, addr, callback_three, + error_callback_three, &symdata); + if (i == 0) + { + fprintf (stderr, + "test5: unexpected return value from backtrace_syminfo %d\n", + i); + symdata.failed = 1; + } + + if (!symdata.failed) + { + if (symdata.name == NULL) + { + fprintf (stderr, "test5: NULL syminfo name\n"); + symdata.failed = 1; + } + else if (strcmp (symdata.name, "global") != 0) + { + fprintf (stderr, + "test5: unexpected syminfo name got %s expected %s\n", + symdata.name, "global"); + symdata.failed = 1; + } + else if (symdata.val != (uintptr_t) &global) + { + fprintf (stderr, + "test5: unexpected syminfo value got %lx expected %lx\n", + (unsigned long) symdata.val, + (unsigned long) (uintptr_t) &global); + symdata.failed = 1; + } + else if (symdata.size != sizeof (global)) + { + fprintf (stderr, + "test5: unexpected syminfo size got %lx expected %lx\n", + (unsigned long) symdata.size, + (unsigned long) sizeof (global)); + symdata.failed = 1; + } + } + + printf ("%s: backtrace_syminfo variable\n", + symdata.failed ? "FAIL" : "PASS"); + + if (symdata.failed) + ++failures; + + return failures; +} + +#endif /* BACKTRACE_SUPPORTS_DATA */ + static void error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg, int errnum) @@ -622,6 +712,9 @@ main (int argc ATTRIBUTE_UNUSED, char **argv) test2 (); test3 (); test4 (); +#if BACKTRACE_SUPPORTS_DATA + test5 (); +#endif #endif exit (failures ? EXIT_FAILURE : EXIT_SUCCESS); diff --git a/thirdparty/libbacktrace/config.h.in.cmake b/thirdparty/libbacktrace/config.h.in.cmake index 4ac13266..876ea359 100644 --- a/thirdparty/libbacktrace/config.h.in.cmake +++ b/thirdparty/libbacktrace/config.h.in.cmake @@ -1,6 +1,9 @@ /* ELF size: 32 or 64 */ #define BACKTRACE_ELF_SIZE @BACKTRACE_ELF_SIZE@ +/* Define to 1 if you have the __atomic functions */ +#cmakedefine HAVE_ATOMIC_FUNCTIONS 1 + /* Define to 1 if you have the declaration of `strnlen', and to 0 if you don't. */ #cmakedefine HAVE_DECL_STRNLEN 1 diff --git a/thirdparty/libbacktrace/dwarf.c b/thirdparty/libbacktrace/dwarf.c index 501afe55..55b8d7dc 100644 --- a/thirdparty/libbacktrace/dwarf.c +++ b/thirdparty/libbacktrace/dwarf.c @@ -1,5 +1,5 @@ /* dwarf.c -- Get file/line information from DWARF for backtraces. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -211,6 +211,10 @@ struct line const char *filename; /* Line number. */ int lineno; + /* Index of the object in the original array read from the DWARF + section, before it has been sorted. The index makes it possible + to use Quicksort and maintain stability. */ + int idx; }; /* A growable vector of line number information. This is used while @@ -940,9 +944,10 @@ unit_addrs_search (const void *vkey, const void *ventry) return 0; } -/* Sort the line vector by PC. We want a stable sort here. We know - that the pointers are into the same array, so it is safe to compare - them directly. */ +/* Sort the line vector by PC. We want a stable sort here to maintain + the order of lines for the same PC values. Since the sequence is + being sorted in place, their addresses cannot be relied on to + maintain stability. That is the purpose of the index member. */ static int line_compare (const void *v1, const void *v2) @@ -954,9 +959,9 @@ line_compare (const void *v1, const void *v2) return -1; else if (ln1->pc > ln2->pc) return 1; - else if (ln1 < ln2) + else if (ln1->idx < ln2->idx) return -1; - else if (ln1 > ln2) + else if (ln1->idx > ln2->idx) return 1; else return 0; @@ -1134,8 +1139,8 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, ++num_abbrevs; } - qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, sizeof (struct abbrev), - abbrev_compare); + backtrace_qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, + sizeof (struct abbrev), abbrev_compare); return 1; @@ -1235,54 +1240,24 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address, return 1; } -/* Build a mapping from address ranges to the compilation units where - the line number information for that range can be found. Returns 1 - on success, 0 on failure. */ +/* Find the address range covered by a compilation unit, reading from + UNIT_BUF and adding values to U. Returns 1 if all data could be + read, 0 if there is some error. */ static int -build_address_map (struct backtrace_state *state, uintptr_t base_address, - const unsigned char *dwarf_info, size_t dwarf_info_size, - const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, size_t dwarf_ranges_size, - const unsigned char *dwarf_str, size_t dwarf_str_size, - int is_bigendian, backtrace_error_callback error_callback, - void *data, struct unit_addrs_vector *addrs) +find_address_ranges (struct backtrace_state *state, uintptr_t base_address, + struct dwarf_buf *unit_buf, + const unsigned char *dwarf_str, size_t dwarf_str_size, + const unsigned char *dwarf_ranges, + size_t dwarf_ranges_size, + int is_bigendian, backtrace_error_callback error_callback, + void *data, struct unit *u, + struct unit_addrs_vector *addrs) { - struct dwarf_buf info; - struct abbrevs abbrevs; - - memset (&addrs->vec, 0, sizeof addrs->vec); - addrs->count = 0; - - /* Read through the .debug_info section. FIXME: Should we use the - .debug_aranges section? gdb and addr2line don't use it, but I'm - not sure why. */ - - info.name = ".debug_info"; - info.start = dwarf_info; - info.buf = dwarf_info; - info.left = dwarf_info_size; - info.is_bigendian = is_bigendian; - info.error_callback = error_callback; - info.data = data; - info.reported_underflow = 0; - - memset (&abbrevs, 0, sizeof abbrevs); - while (info.left > 0) + while (unit_buf->left > 0) { - const unsigned char *unit_data_start; - uint64_t len; - int is_dwarf64; - struct dwarf_buf unit_buf; - int version; - uint64_t abbrev_offset; - const struct abbrev *abbrev; - int addrsize; - const unsigned char *unit_data; - size_t unit_data_len; - size_t unit_data_offset; uint64_t code; - size_t i; + const struct abbrev *abbrev; uint64_t lowpc; int have_lowpc; uint64_t highpc; @@ -1290,57 +1265,15 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, int highpc_is_relative; uint64_t ranges; int have_ranges; - uint64_t lineoff; - int have_lineoff; - const char *filename; - const char *comp_dir; - - if (info.reported_underflow) - goto fail; - - unit_data_start = info.buf; - - is_dwarf64 = 0; - len = read_uint32 (&info); - if (len == 0xffffffff) - { - len = read_uint64 (&info); - is_dwarf64 = 1; - } - - unit_buf = info; - unit_buf.left = len; - - if (!advance (&info, len)) - goto fail; - - version = read_uint16 (&unit_buf); - if (version < 2 || version > 4) - { - dwarf_buf_error (&unit_buf, "unrecognized DWARF version"); - goto fail; - } - - abbrev_offset = read_offset (&unit_buf, is_dwarf64); - if (!read_abbrevs (state, abbrev_offset, dwarf_abbrev, dwarf_abbrev_size, - is_bigendian, error_callback, data, &abbrevs)) - goto fail; - - addrsize = read_byte (&unit_buf); - - unit_data = unit_buf.buf; - unit_data_len = unit_buf.left; - unit_data_offset = unit_buf.buf - unit_data_start; + size_t i; - /* We only look at the first attribute in the compilation unit. - In practice this will be a DW_TAG_compile_unit which will - tell us the PC range and where to find the line number - information. */ + code = read_uleb128 (unit_buf); + if (code == 0) + return 1; - code = read_uleb128 (&unit_buf); - abbrev = lookup_abbrev (&abbrevs, code, error_callback, data); + abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); if (abbrev == NULL) - goto fail; + return 0; lowpc = 0; have_lowpc = 0; @@ -1349,18 +1282,14 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, highpc_is_relative = 0; ranges = 0; have_ranges = 0; - lineoff = 0; - have_lineoff = 0; - filename = NULL; - comp_dir = NULL; for (i = 0; i < abbrev->num_attrs; ++i) { struct attr_val val; - if (!read_attribute (abbrev->attrs[i].form, &unit_buf, is_dwarf64, - version, addrsize, dwarf_str, dwarf_str_size, - &val)) - goto fail; + if (!read_attribute (abbrev->attrs[i].form, unit_buf, + u->is_dwarf64, u->version, u->addrsize, + dwarf_str, dwarf_str_size, &val)) + return 0; switch (abbrev->attrs[i].name) { @@ -1371,6 +1300,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, have_lowpc = 1; } break; + case DW_AT_high_pc: if (val.encoding == ATTR_VAL_ADDRESS) { @@ -1384,6 +1314,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, highpc_is_relative = 1; } break; + case DW_AT_ranges: if (val.encoding == ATTR_VAL_UINT || val.encoding == ATTR_VAL_REF_SECTION) @@ -1392,73 +1323,46 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, have_ranges = 1; } break; + case DW_AT_stmt_list: - if (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_SECTION) - { - lineoff = val.u.uint; - have_lineoff = 1; - } + if (abbrev->tag == DW_TAG_compile_unit + && (val.encoding == ATTR_VAL_UINT + || val.encoding == ATTR_VAL_REF_SECTION)) + u->lineoff = val.u.uint; break; + case DW_AT_name: - if (val.encoding == ATTR_VAL_STRING) - filename = val.u.string; + if (abbrev->tag == DW_TAG_compile_unit + && val.encoding == ATTR_VAL_STRING) + u->filename = val.u.string; break; + case DW_AT_comp_dir: - if (val.encoding == ATTR_VAL_STRING) - comp_dir = val.u.string; + if (abbrev->tag == DW_TAG_compile_unit + && val.encoding == ATTR_VAL_STRING) + u->comp_dir = val.u.string; break; + default: break; } } - if (unit_buf.reported_underflow) - goto fail; - - if (((have_lowpc && have_highpc) || have_ranges) && have_lineoff) + if (abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_subprogram) { - struct unit *u; - struct unit_addrs a; - - u = ((struct unit *) - backtrace_alloc (state, sizeof *u, error_callback, data)); - if (u == NULL) - goto fail; - u->unit_data = unit_data; - u->unit_data_len = unit_data_len; - u->unit_data_offset = unit_data_offset; - u->version = version; - u->is_dwarf64 = is_dwarf64; - u->addrsize = addrsize; - u->filename = filename; - u->comp_dir = comp_dir; - u->abs_filename = NULL; - u->lineoff = lineoff; - u->abbrevs = abbrevs; - memset (&abbrevs, 0, sizeof abbrevs); - - /* The actual line number mappings will be read as - needed. */ - u->lines = NULL; - u->lines_count = 0; - u->function_addrs = NULL; - u->function_addrs_count = 0; - if (have_ranges) { if (!add_unit_ranges (state, base_address, u, ranges, lowpc, is_bigendian, dwarf_ranges, - dwarf_ranges_size, error_callback, data, - addrs)) - { - free_abbrevs (state, &u->abbrevs, error_callback, data); - backtrace_free (state, u, sizeof *u, error_callback, data); - goto fail; - } + dwarf_ranges_size, error_callback, + data, addrs)) + return 0; } - else + else if (have_lowpc && have_highpc) { + struct unit_addrs a; + if (highpc_is_relative) highpc += lowpc; a.low = lowpc; @@ -1467,17 +1371,146 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, if (!add_unit_addr (state, base_address, a, error_callback, data, addrs)) - { - free_abbrevs (state, &u->abbrevs, error_callback, data); - backtrace_free (state, u, sizeof *u, error_callback, data); - goto fail; - } + return 0; } + + /* If we found the PC range in the DW_TAG_compile_unit, we + can stop now. */ + if (abbrev->tag == DW_TAG_compile_unit + && (have_ranges || (have_lowpc && have_highpc))) + return 1; } - else + + if (abbrev->has_children) + { + if (!find_address_ranges (state, base_address, unit_buf, + dwarf_str, dwarf_str_size, + dwarf_ranges, dwarf_ranges_size, + is_bigendian, error_callback, data, + u, addrs)) + return 0; + } + } + + return 1; +} + +/* Build a mapping from address ranges to the compilation units where + the line number information for that range can be found. Returns 1 + on success, 0 on failure. */ + +static int +build_address_map (struct backtrace_state *state, uintptr_t base_address, + const unsigned char *dwarf_info, size_t dwarf_info_size, + const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, + const unsigned char *dwarf_ranges, size_t dwarf_ranges_size, + const unsigned char *dwarf_str, size_t dwarf_str_size, + int is_bigendian, backtrace_error_callback error_callback, + void *data, struct unit_addrs_vector *addrs) +{ + struct dwarf_buf info; + struct abbrevs abbrevs; + + memset (&addrs->vec, 0, sizeof addrs->vec); + addrs->count = 0; + + /* Read through the .debug_info section. FIXME: Should we use the + .debug_aranges section? gdb and addr2line don't use it, but I'm + not sure why. */ + + info.name = ".debug_info"; + info.start = dwarf_info; + info.buf = dwarf_info; + info.left = dwarf_info_size; + info.is_bigendian = is_bigendian; + info.error_callback = error_callback; + info.data = data; + info.reported_underflow = 0; + + memset (&abbrevs, 0, sizeof abbrevs); + while (info.left > 0) + { + const unsigned char *unit_data_start; + uint64_t len; + int is_dwarf64; + struct dwarf_buf unit_buf; + int version; + uint64_t abbrev_offset; + int addrsize; + struct unit *u; + + if (info.reported_underflow) + goto fail; + + unit_data_start = info.buf; + + is_dwarf64 = 0; + len = read_uint32 (&info); + if (len == 0xffffffff) + { + len = read_uint64 (&info); + is_dwarf64 = 1; + } + + unit_buf = info; + unit_buf.left = len; + + if (!advance (&info, len)) + goto fail; + + version = read_uint16 (&unit_buf); + if (version < 2 || version > 4) { - free_abbrevs (state, &abbrevs, error_callback, data); - memset (&abbrevs, 0, sizeof abbrevs); + dwarf_buf_error (&unit_buf, "unrecognized DWARF version"); + goto fail; + } + + abbrev_offset = read_offset (&unit_buf, is_dwarf64); + if (!read_abbrevs (state, abbrev_offset, dwarf_abbrev, dwarf_abbrev_size, + is_bigendian, error_callback, data, &abbrevs)) + goto fail; + + addrsize = read_byte (&unit_buf); + + u = ((struct unit *) + backtrace_alloc (state, sizeof *u, error_callback, data)); + if (u == NULL) + goto fail; + u->unit_data = unit_buf.buf; + u->unit_data_len = unit_buf.left; + u->unit_data_offset = unit_buf.buf - unit_data_start; + u->version = version; + u->is_dwarf64 = is_dwarf64; + u->addrsize = addrsize; + u->filename = NULL; + u->comp_dir = NULL; + u->abs_filename = NULL; + u->lineoff = 0; + u->abbrevs = abbrevs; + memset (&abbrevs, 0, sizeof abbrevs); + + /* The actual line number mappings will be read as needed. */ + u->lines = NULL; + u->lines_count = 0; + u->function_addrs = NULL; + u->function_addrs_count = 0; + + if (!find_address_ranges (state, base_address, &unit_buf, + dwarf_str, dwarf_str_size, + dwarf_ranges, dwarf_ranges_size, + is_bigendian, error_callback, data, + u, addrs)) + { + free_abbrevs (state, &u->abbrevs, error_callback, data); + backtrace_free (state, u, sizeof *u, error_callback, data); + goto fail; + } + + if (unit_buf.reported_underflow) + { + free_abbrevs (state, &u->abbrevs, error_callback, data); + backtrace_free (state, u, sizeof *u, error_callback, data); + goto fail; } } if (info.reported_underflow) @@ -1523,6 +1556,7 @@ add_line (struct backtrace_state *state, struct dwarf_data *ddata, ln->filename = filename; ln->lineno = lineno; + ln->idx = vec->count; ++vec->count; @@ -1983,12 +2017,13 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata, ln->pc = (uintptr_t) -1; ln->filename = NULL; ln->lineno = 0; + ln->idx = 0; if (!backtrace_vector_release (state, &vec.vec, error_callback, data)) goto fail; ln = (struct line *) vec.vec.base; - qsort (ln, vec.count, sizeof (struct line), line_compare); + backtrace_qsort (ln, vec.count, sizeof (struct line), line_compare); *lines = ln; *lines_count = vec.count; @@ -2215,7 +2250,8 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, struct unit *u, uint64_t base, struct dwarf_buf *unit_buf, const struct line_header *lhdr, backtrace_error_callback error_callback, void *data, - struct function_vector *vec) + struct function_vector *vec_function, + struct function_vector *vec_inlined) { while (unit_buf->left > 0) { @@ -2223,6 +2259,7 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, const struct abbrev *abbrev; int is_function; struct function *function; + struct function_vector *vec; size_t i; uint64_t lowpc; int have_lowpc; @@ -2244,6 +2281,11 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, || abbrev->tag == DW_TAG_entry_point || abbrev->tag == DW_TAG_inlined_subroutine); + if (abbrev->tag == DW_TAG_inlined_subroutine) + vec = vec_inlined; + else + vec = vec_function; + function = NULL; if (is_function) { @@ -2423,7 +2465,8 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, if (!is_function) { if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, - error_callback, data, vec)) + error_callback, data, vec_function, + vec_inlined)) return 0; } else @@ -2436,7 +2479,8 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, memset (&fvec, 0, sizeof fvec); if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, - error_callback, data, &fvec)) + error_callback, data, vec_function, + &fvec)) return 0; if (fvec.count > 0) @@ -2448,9 +2492,9 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, return 0; faddrs = (struct function_addrs *) fvec.vec.base; - qsort (faddrs, fvec.count, - sizeof (struct function_addrs), - function_addrs_compare); + backtrace_qsort (faddrs, fvec.count, + sizeof (struct function_addrs), + function_addrs_compare); function->function_addrs = faddrs; function->function_addrs_count = fvec.count; @@ -2500,31 +2544,35 @@ read_function_info (struct backtrace_state *state, struct dwarf_data *ddata, while (unit_buf.left > 0) { if (!read_function_entry (state, ddata, u, 0, &unit_buf, lhdr, - error_callback, data, pfvec)) + error_callback, data, pfvec, pfvec)) return; } if (pfvec->count == 0) return; - addrs = (struct function_addrs *) pfvec->vec.base; addrs_count = pfvec->count; if (fvec == NULL) { if (!backtrace_vector_release (state, &lvec.vec, error_callback, data)) return; + addrs = (struct function_addrs *) pfvec->vec.base; } else { /* Finish this list of addresses, but leave the remaining space in the vector available for the next function unit. */ - backtrace_vector_finish (state, &fvec->vec); + addrs = ((struct function_addrs *) + backtrace_vector_finish (state, &fvec->vec, + error_callback, data)); + if (addrs == NULL) + return; fvec->count = 0; } - qsort (addrs, addrs_count, sizeof (struct function_addrs), - function_addrs_compare); + backtrace_qsort (addrs, addrs_count, sizeof (struct function_addrs), + function_addrs_compare); *ret_addrs = addrs; *ret_addrs_count = addrs_count; @@ -2643,12 +2691,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, && pc < (entry - 1)->high) { if (state->threaded) - { - /* Use __sync_bool_compare_and_swap to do a - load-acquire. */ - while (!__sync_bool_compare_and_swap (&u->lines, lines, lines)) - lines = u->lines; - } + lines = (struct line *) backtrace_atomic_load_pointer (&u->lines); if (lines != (struct line *) (uintptr_t) -1) break; @@ -2659,13 +2702,8 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, lines = u->lines; } - /* Do a load-acquire of u->lines. */ if (state->threaded) - { - /* Use __sync_bool_compare_and_swap to do an atomic load. */ - while (!__sync_bool_compare_and_swap (&u->lines, lines, lines)) - lines = u->lines; - } + lines = backtrace_atomic_load_pointer (&u->lines); new_data = 0; if (lines == NULL) @@ -2713,12 +2751,11 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, } else { - __sync_bool_compare_and_swap (&u->lines_count, 0, count); - __sync_bool_compare_and_swap (&u->function_addrs, NULL, - function_addrs); - __sync_bool_compare_and_swap (&u->function_addrs_count, 0, - function_addrs_count); - __sync_bool_compare_and_swap (&u->lines, NULL, lines); + backtrace_atomic_store_size_t (&u->lines_count, count); + backtrace_atomic_store_pointer (&u->function_addrs, function_addrs); + backtrace_atomic_store_size_t (&u->function_addrs_count, + function_addrs_count); + backtrace_atomic_store_pointer (&u->lines, lines); } } @@ -2849,11 +2886,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc, pp = (struct dwarf_data **) (void *) &state->fileline_data; while (1) { - ddata = *pp; - /* Atomic load. */ - while (!__sync_bool_compare_and_swap (pp, ddata, ddata)) - ddata = *pp; - + ddata = backtrace_atomic_load_pointer (pp); if (ddata == NULL) break; @@ -2906,7 +2939,8 @@ build_dwarf_data (struct backtrace_state *state, return NULL; addrs = (struct unit_addrs *) addrs_vec.vec.base; addrs_count = addrs_vec.count; - qsort (addrs, addrs_count, sizeof (struct unit_addrs), unit_addrs_compare); + backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs), + unit_addrs_compare); fdata = ((struct dwarf_data *) backtrace_alloc (state, sizeof (struct dwarf_data), @@ -2985,10 +3019,7 @@ backtrace_dwarf_add (struct backtrace_state *state, { struct dwarf_data *p; - /* Atomic load. */ - p = *pp; - while (!__sync_bool_compare_and_swap (pp, p, p)) - p = *pp; + p = backtrace_atomic_load_pointer (pp); if (p == NULL) break; diff --git a/thirdparty/libbacktrace/elf.c b/thirdparty/libbacktrace/elf.c index c1dbc549..05cc5c04 100644 --- a/thirdparty/libbacktrace/elf.c +++ b/thirdparty/libbacktrace/elf.c @@ -1,5 +1,5 @@ /* elf.c -- Get debug data from an ELF file for backtraces. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -96,11 +96,14 @@ dl_iterate_phdr (int (*callback) (struct dl_phdr_info *, #undef ELFDATA2LSB #undef ELFDATA2MSB #undef EV_CURRENT +#undef ET_DYN #undef SHN_LORESERVE #undef SHN_XINDEX +#undef SHN_UNDEF #undef SHT_SYMTAB #undef SHT_STRTAB #undef SHT_DYNSYM +#undef STT_OBJECT #undef STT_FUNC /* Basic types. */ @@ -169,6 +172,8 @@ typedef struct { #define EV_CURRENT 1 +#define ET_DYN 3 + typedef struct { b_elf_word sh_name; /* Section name, index in string tbl */ b_elf_word sh_type; /* Type of section */ @@ -182,6 +187,7 @@ typedef struct { b_elf_wxword sh_entsize; /* Entry size if section holds table */ } b_elf_shdr; /* Elf_Shdr. */ +#define SHN_UNDEF 0x0000 /* Undefined section */ #define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ #define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ @@ -215,6 +221,7 @@ typedef struct #endif /* BACKTRACE_ELF_SIZE != 32 */ +#define STT_OBJECT 1 #define STT_FUNC 2 /* An index of ELF sections we care about. */ @@ -293,7 +300,7 @@ elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, static void elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t pc ATTRIBUTE_UNUSED, + uintptr_t addr ATTRIBUTE_UNUSED, backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, backtrace_error_callback error_callback, void *data) { @@ -316,7 +323,7 @@ elf_symbol_compare (const void *v1, const void *v2) return 0; } -/* Compare a PC against an elf_symbol for bsearch. We allocate one +/* Compare an ADDR against an elf_symbol for bsearch. We allocate one extra entry in the array so that this can look safely at the next entry. */ @@ -325,12 +332,12 @@ elf_symbol_search (const void *vkey, const void *ventry) { const uintptr_t *key = (const uintptr_t *) vkey; const struct elf_symbol *entry = (const struct elf_symbol *) ventry; - uintptr_t pc; + uintptr_t addr; - pc = *key; - if (pc < entry->address) + addr = *key; + if (addr < entry->address) return -1; - else if (pc >= entry->address + entry->size) + else if (addr >= entry->address + entry->size) return 1; else return 0; @@ -340,6 +347,7 @@ elf_symbol_search (const void *vkey, const void *ventry) static int elf_initialize_syminfo (struct backtrace_state *state, + uintptr_t base_address, const unsigned char *symtab_data, size_t symtab_size, const unsigned char *strtab, size_t strtab_size, backtrace_error_callback error_callback, @@ -360,7 +368,11 @@ elf_initialize_syminfo (struct backtrace_state *state, elf_symbol_count = 0; for (i = 0; i < sym_count; ++i, ++sym) { - if ((sym->st_info & 0xf) == STT_FUNC) + int info; + + info = sym->st_info & 0xf; + if ((info == STT_FUNC || info == STT_OBJECT) + && sym->st_shndx != SHN_UNDEF) ++elf_symbol_count; } @@ -375,7 +387,12 @@ elf_initialize_syminfo (struct backtrace_state *state, j = 0; for (i = 0; i < sym_count; ++i, ++sym) { - if ((sym->st_info & 0xf) != STT_FUNC) + int info; + + info = sym->st_info & 0xf; + if (info != STT_FUNC && info != STT_OBJECT) + continue; + if (sym->st_shndx == SHN_UNDEF) continue; if (sym->st_name >= strtab_size) { @@ -385,13 +402,13 @@ elf_initialize_syminfo (struct backtrace_state *state, return 0; } elf_symbols[j].name = (const char *) strtab + sym->st_name; - elf_symbols[j].address = sym->st_value; + elf_symbols[j].address = sym->st_value + base_address; elf_symbols[j].size = sym->st_size; ++j; } - qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), - elf_symbol_compare); + backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), + elf_symbol_compare); sdata->next = NULL; sdata->symbols = elf_symbols; @@ -428,10 +445,7 @@ elf_add_syminfo_data (struct backtrace_state *state, { struct elf_syminfo_data *p; - /* Atomic load. */ - p = *pp; - while (!__sync_bool_compare_and_swap (pp, p, p)) - p = *pp; + p = backtrace_atomic_load_pointer (pp); if (p == NULL) break; @@ -445,10 +459,10 @@ elf_add_syminfo_data (struct backtrace_state *state, } } -/* Return the symbol name and value for a PC. */ +/* Return the symbol name and value for an ADDR. */ static void -elf_syminfo (struct backtrace_state *state, uintptr_t pc, +elf_syminfo (struct backtrace_state *state, uintptr_t addr, backtrace_syminfo_callback callback, backtrace_error_callback error_callback ATTRIBUTE_UNUSED, void *data) @@ -463,7 +477,7 @@ elf_syminfo (struct backtrace_state *state, uintptr_t pc, edata = edata->next) { sym = ((struct elf_symbol *) - bsearch (&pc, edata->symbols, edata->count, + bsearch (&addr, edata->symbols, edata->count, sizeof (struct elf_symbol), elf_symbol_search)); if (sym != NULL) break; @@ -476,16 +490,12 @@ elf_syminfo (struct backtrace_state *state, uintptr_t pc, pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; while (1) { - edata = *pp; - /* Atomic load. */ - while (!__sync_bool_compare_and_swap (pp, edata, edata)) - edata = *pp; - + edata = backtrace_atomic_load_pointer (pp); if (edata == NULL) break; sym = ((struct elf_symbol *) - bsearch (&pc, edata->symbols, edata->count, + bsearch (&addr, edata->symbols, edata->count, sizeof (struct elf_symbol), elf_symbol_search)); if (sym != NULL) break; @@ -495,17 +505,21 @@ elf_syminfo (struct backtrace_state *state, uintptr_t pc, } if (sym == NULL) - callback (data, pc, NULL, 0); + callback (data, addr, NULL, 0, 0); else - callback (data, pc, sym->name, sym->address); + callback (data, addr, sym->name, sym->address, sym->size); } -/* Add the backtrace data for one ELF file. */ +/* Add the backtrace data for one ELF file. Returns 1 on success, + 0 on failure (in both cases descriptor is closed) or -1 if exe + is non-zero and the ELF file is ET_DYN, which tells the caller that + elf_add will need to be called on the descriptor again after + base_address is determined. */ static int elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, backtrace_error_callback error_callback, void *data, - fileline *fileline_fn, int *found_sym, int *found_dwarf) + fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe) { struct backtrace_view ehdr_view; b_elf_ehdr ehdr; @@ -584,6 +598,12 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, goto fail; } + /* If the executable is ET_DYN, it is either a PIE, or we are running + directly a shared library with .interp. We need to wait for + dl_iterate_phdr in that case to determine the actual base_address. */ + if (exe && ehdr.e_type == ET_DYN) + return -1; + shoff = ehdr.e_shoff; shnum = ehdr.e_shnum; shstrndx = ehdr.e_shstrndx; @@ -725,7 +745,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, if (sdata == NULL) goto fail; - if (!elf_initialize_syminfo (state, + if (!elf_initialize_syminfo (state, base_address, symtab_view.data, symtab_shdr->sh_size, strtab_view.data, strtab_shdr->sh_size, error_callback, data, sdata)) @@ -759,6 +779,8 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, { off_t end; + if (sections[i].size == 0) + continue; if (min_offset == 0 || sections[i].offset < min_offset) min_offset = sections[i].offset; end = sections[i].offset + sections[i].size; @@ -785,8 +807,13 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, descriptor = -1; for (i = 0; i < (int) DEBUG_MAX; ++i) - sections[i].data = ((const unsigned char *) debug_view.data - + (sections[i].offset - min_offset)); + { + if (sections[i].size == 0) + sections[i].data = NULL; + else + sections[i].data = ((const unsigned char *) debug_view.data + + (sections[i].offset - min_offset)); + } if (!backtrace_dwarf_add (state, base_address, sections[DEBUG_INFO].data, @@ -833,6 +860,7 @@ struct phdr_data fileline *fileline_fn; int *found_sym; int *found_dwarf; + int exe_descriptor; }; /* Callback passed to dl_iterate_phdr. Load debug info from shared @@ -848,21 +876,32 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, fileline elf_fileline_fn; int found_dwarf; - /* There is not much we can do if we don't have the module name. If - the base address is 0, this is probably the executable, which we - already loaded. */ - if (info->dlpi_name == NULL - || info->dlpi_name[0] == '\0' - || info->dlpi_addr == 0) - return 0; + /* There is not much we can do if we don't have the module name, + unless executable is ET_DYN, where we expect the very first + phdr_callback to be for the PIE. */ + if (info->dlpi_name == NULL || info->dlpi_name[0] == '\0') + { + if (pd->exe_descriptor == -1) + return 0; + descriptor = pd->exe_descriptor; + pd->exe_descriptor = -1; + } + else + { + if (pd->exe_descriptor != -1) + { + backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data); + pd->exe_descriptor = -1; + } - descriptor = backtrace_open (info->dlpi_name, pd->error_callback, pd->data, - &does_not_exist); - if (descriptor < 0) - return 0; + descriptor = backtrace_open (info->dlpi_name, pd->error_callback, + pd->data, &does_not_exist); + if (descriptor < 0) + return 0; + } if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback, - pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf)) + pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, 0)) { if (found_dwarf) { @@ -883,14 +922,15 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, backtrace_error_callback error_callback, void *data, fileline *fileline_fn) { + int ret; int found_sym; int found_dwarf; - syminfo elf_syminfo_fn; fileline elf_fileline_fn; struct phdr_data pd; - if (!elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn, - &found_sym, &found_dwarf)) + ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn, + &found_sym, &found_dwarf, 1); + if (!ret) return 0; pd.state = state; @@ -899,21 +939,24 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, pd.fileline_fn = &elf_fileline_fn; pd.found_sym = &found_sym; pd.found_dwarf = &found_dwarf; + pd.exe_descriptor = ret < 0 ? descriptor : -1; dl_iterate_phdr (phdr_callback, (void *) &pd); - elf_syminfo_fn = found_sym ? elf_syminfo : elf_nosyms; if (!state->threaded) { - if (state->syminfo_fn == NULL || found_sym) - state->syminfo_fn = elf_syminfo_fn; + if (found_sym) + state->syminfo_fn = elf_syminfo; + else if (state->syminfo_fn == NULL) + state->syminfo_fn = elf_nosyms; } else { - __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, elf_syminfo_fn); if (found_sym) - __sync_bool_compare_and_swap (&state->syminfo_fn, elf_nosyms, - elf_syminfo_fn); + backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo); + else + (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, + elf_nosyms); } if (!state->threaded) @@ -925,11 +968,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, { fileline current_fn; - /* Atomic load. */ - current_fn = state->fileline_fn; - while (!__sync_bool_compare_and_swap (&state->fileline_fn, current_fn, - current_fn)) - current_fn = 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; } diff --git a/thirdparty/libbacktrace/fileline.c b/thirdparty/libbacktrace/fileline.c index e5c39be8..27ebbedc 100644 --- a/thirdparty/libbacktrace/fileline.c +++ b/thirdparty/libbacktrace/fileline.c @@ -1,5 +1,5 @@ /* fileline.c -- Get file and line number information in a backtrace. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -58,15 +58,10 @@ fileline_initialize (struct backtrace_state *state, int called_error_callback; int descriptor; - failed = state->fileline_initialization_failed; - - if (state->threaded) - { - /* Use __sync_bool_compare_and_swap to do an atomic load. */ - while (!__sync_bool_compare_and_swap - (&state->fileline_initialization_failed, failed, failed)) - failed = state->fileline_initialization_failed; - } + if (!state->threaded) + failed = state->fileline_initialization_failed; + else + failed = backtrace_atomic_load_int (&state->fileline_initialization_failed); if (failed) { @@ -74,13 +69,10 @@ fileline_initialize (struct backtrace_state *state, return 0; } - fileline_fn = state->fileline_fn; - if (state->threaded) - { - while (!__sync_bool_compare_and_swap (&state->fileline_fn, fileline_fn, - fileline_fn)) - fileline_fn = state->fileline_fn; - } + if (!state->threaded) + fileline_fn = state->fileline_fn; + else + fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); if (fileline_fn != NULL) return 1; @@ -151,8 +143,7 @@ fileline_initialize (struct backtrace_state *state, if (!state->threaded) state->fileline_initialization_failed = 1; else - __sync_bool_compare_and_swap (&state->fileline_initialization_failed, - 0, failed); + backtrace_atomic_store_int (&state->fileline_initialization_failed, 1); return 0; } @@ -160,15 +151,10 @@ fileline_initialize (struct backtrace_state *state, state->fileline_fn = fileline_fn; else { - __sync_bool_compare_and_swap (&state->fileline_fn, NULL, fileline_fn); - - /* At this point we know that state->fileline_fn is not NULL. - Either we stored our value, or some other thread stored its - value. If some other thread stored its value, we leak the - one we just initialized. Either way, state->fileline_fn is - initialized. The compare_and_swap is a full memory barrier, - so we should have full access to that value even if it was - created by another thread. */ + backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn); + + /* Note that if two threads initialize at once, one of the data + sets may be leaked. */ } return 1; diff --git a/thirdparty/libbacktrace/internal.h b/thirdparty/libbacktrace/internal.h index 1ea664a0..73728da3 100644 --- a/thirdparty/libbacktrace/internal.h +++ b/thirdparty/libbacktrace/internal.h @@ -1,5 +1,5 @@ /* internal.h -- Internal header file for stack backtrace library. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -65,7 +65,48 @@ POSSIBILITY OF SUCH DAMAGE. */ #define __sync_lock_test_and_set(A, B) (abort(), 0) #define __sync_lock_release(A) abort() -#endif /* !defined(HAVE_SYNC_FUNCTIONS) */ +#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ + +#ifdef HAVE_ATOMIC_FUNCTIONS + +/* We have the atomic builtin functions. */ + +#define backtrace_atomic_load_pointer(p) \ + __atomic_load_n ((p), __ATOMIC_ACQUIRE) +#define backtrace_atomic_load_int(p) \ + __atomic_load_n ((p), __ATOMIC_ACQUIRE) +#define backtrace_atomic_store_pointer(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) +#define backtrace_atomic_store_size_t(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) +#define backtrace_atomic_store_int(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) + +#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */ +#ifdef HAVE_SYNC_FUNCTIONS + +/* We have the sync functions but not the atomic functions. Define + the atomic ones in terms of the sync ones. */ + +extern void *backtrace_atomic_load_pointer (void *); +extern int backtrace_atomic_load_int (int *); +extern void backtrace_atomic_store_pointer (void *, void *); +extern void backtrace_atomic_store_size_t (size_t *, size_t); +extern void backtrace_atomic_store_int (int *, int); + +#else /* !defined (HAVE_SYNC_FUNCTIONS) */ + +/* We have neither the sync nor the atomic functions. These will + never be called. */ + +#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL) +#define backtrace_atomic_load_int(p) (abort(), 0) +#define backtrace_atomic_store_pointer(p, v) abort() +#define backtrace_atomic_store_size_t(p, v) abort() +#define backtrace_atomic_store_int(p, v) abort() + +#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ +#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */ /* The type of the function that collects file/line information. This is like backtrace_pcinfo. */ @@ -155,13 +196,20 @@ extern int backtrace_close (int descriptor, backtrace_error_callback error_callback, void *data); -/* Allocate memory. This is like malloc. */ +/* Sort without using memory. */ + +extern void backtrace_qsort (void *base, size_t count, size_t size, + int (*compar) (const void *, const void *)); + +/* Allocate memory. This is like malloc. If ERROR_CALLBACK is NULL, + this does not report an error, it just returns NULL. */ extern void *backtrace_alloc (struct backtrace_state *state, size_t size, backtrace_error_callback error_callback, void *data) ATTRIBUTE_MALLOC; -/* Free memory allocated by backtrace_alloc. */ +/* Free memory allocated by backtrace_alloc. If ERROR_CALLBACK is + NULL, this does not report an error. */ extern void backtrace_free (struct backtrace_state *state, void *mem, size_t size, @@ -192,13 +240,17 @@ extern void *backtrace_vector_grow (struct backtrace_state *state, size_t size, struct backtrace_vector *vec); /* Finish the current allocation on VEC. Prepare to start a new - allocation. The finished allocation will never be freed. */ + allocation. The finished allocation will never be freed. Returns + a pointer to the base of the finished entries, or NULL on + failure. */ -extern void backtrace_vector_finish (struct backtrace_state *state, - struct backtrace_vector *vec); +extern void* backtrace_vector_finish (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data); -/* Release any extra space allocated for VEC. Returns 1 on success, 0 - on failure. */ +/* Release any extra space allocated for VEC. This may change + VEC->base. Returns 1 on success, 0 on failure. */ extern int backtrace_vector_release (struct backtrace_state *state, struct backtrace_vector *vec, diff --git a/thirdparty/libbacktrace/mmap.c b/thirdparty/libbacktrace/mmap.c index 04aae85e..0ed4802d 100644 --- a/thirdparty/libbacktrace/mmap.c +++ b/thirdparty/libbacktrace/mmap.c @@ -1,5 +1,5 @@ /* mmap.c -- Memory allocation with mmap. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -77,7 +77,8 @@ backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size) } } -/* Allocate memory like malloc. */ +/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't + report an error. */ void * backtrace_alloc (struct backtrace_state *state, @@ -139,8 +140,11 @@ backtrace_alloc (struct backtrace_state *state, asksize = (size + pagesize - 1) & ~ (pagesize - 1); page = mmap (NULL, asksize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (page == NULL) - error_callback (data, "mmap", errno); + if (page == MAP_FAILED) + { + if (error_callback) + error_callback (data, "mmap", errno); + } else { size = (size + 7) & ~ (size_t) 7; @@ -164,6 +168,26 @@ backtrace_free (struct backtrace_state *state, void *addr, size_t size, { int locked; + /* If we are freeing a large aligned block, just release it back to + the system. This case arises when growing a vector for a large + binary with lots of debug info. Calling munmap here may cause us + to call mmap again if there is also a large shared library; we + just live with that. */ + if (size >= 16 * 4096) + { + size_t pagesize; + + pagesize = getpagesize (); + if (((uintptr_t) addr & (pagesize - 1)) == 0 + && (size & (pagesize - 1)) == 0) + { + /* If munmap fails for some reason, just add the block to + the freelist. */ + if (munmap (addr, size) == 0) + return; + } + } + /* If we can acquire the lock, add the new space to the free list. If we can't acquire the lock, just leak the memory. __sync_lock_test_and_set returns the old state of the lock, so we @@ -209,14 +233,18 @@ backtrace_vector_grow (struct backtrace_state *state,size_t size, alc = pagesize; } else - alc = (alc + pagesize - 1) & ~ (pagesize - 1); + { + alc *= 2; + alc = (alc + pagesize - 1) & ~ (pagesize - 1); + } base = backtrace_alloc (state, alc, error_callback, data); if (base == NULL) return NULL; if (vec->base != NULL) { memcpy (base, vec->base, vec->size); - backtrace_free (state, vec->base, vec->alc, error_callback, data); + backtrace_free (state, vec->base, vec->size + vec->alc, + error_callback, data); } vec->base = base; vec->alc = alc - vec->size; @@ -230,12 +258,19 @@ backtrace_vector_grow (struct backtrace_state *state,size_t size, /* Finish the current allocation on VEC. */ -void -backtrace_vector_finish (struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_vector *vec) +void * +backtrace_vector_finish ( + struct backtrace_state *state ATTRIBUTE_UNUSED, + struct backtrace_vector *vec, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) { + void *ret; + + ret = vec->base; vec->base = (char *) vec->base + vec->size; vec->size = 0; + return ret; } /* Release any extra space allocated for VEC. */ diff --git a/thirdparty/libbacktrace/mmapio.c b/thirdparty/libbacktrace/mmapio.c index 60c68c66..dfdaf6fa 100644 --- a/thirdparty/libbacktrace/mmapio.c +++ b/thirdparty/libbacktrace/mmapio.c @@ -1,5 +1,5 @@ /* mmapio.c -- File views using mmap. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without diff --git a/thirdparty/libbacktrace/nounwind.c b/thirdparty/libbacktrace/nounwind.c index 5c8e23c9..448a2049 100644 --- a/thirdparty/libbacktrace/nounwind.c +++ b/thirdparty/libbacktrace/nounwind.c @@ -1,5 +1,5 @@ /* backtrace.c -- Entry point for stack backtrace library. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without diff --git a/thirdparty/libbacktrace/pecoff.c b/thirdparty/libbacktrace/pecoff.c new file mode 100644 index 00000000..c7d32aa6 --- /dev/null +++ b/thirdparty/libbacktrace/pecoff.c @@ -0,0 +1,937 @@ +/* pecoff.c -- Get debug data from a PE/COFFF file for backtraces. + Copyright (C) 2015-2016 Free Software Foundation, Inc. + Adapted from elf.c by Tristan Gingold, AdaCore. + +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 <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "backtrace.h" +#include "internal.h" + +/* Coff file header. */ + +typedef struct { + uint16_t machine; + uint16_t number_of_sections; + uint32_t time_date_stamp; + uint32_t pointer_to_symbol_table; + uint32_t number_of_symbols; + uint16_t size_of_optional_header; + uint16_t characteristics; +} b_coff_file_header; + +/* Coff optional header. */ + +typedef struct { + uint16_t magic; + uint8_t major_linker_version; + uint8_t minor_linker_version; + uint32_t size_of_code; + uint32_t size_of_initialized_data; + uint32_t size_of_uninitialized_data; + uint32_t address_of_entry_point; + uint32_t base_of_code; + union { + struct { + uint32_t base_of_data; + uint32_t image_base; + } pe; + struct { + uint64_t image_base; + } pep; + } u; +} b_coff_optional_header; + +/* Values of magic in optional header. */ + +#define PE_MAGIC 0x10b /* PE32 executable. */ +#define PEP_MAGIC 0x20b /* PE32+ executable (for 64bit targets). */ + +/* Coff section header. */ + +typedef struct { + char name[8]; + uint32_t virtual_size; + uint32_t virtual_address; + uint32_t size_of_raw_data; + uint32_t pointer_to_raw_data; + uint32_t pointer_to_relocations; + uint32_t pointer_to_line_numbers; + uint16_t number_of_relocations; + uint16_t number_of_line_numbers; + uint32_t characteristics; +} b_coff_section_header; + +/* Coff symbol name. */ + +typedef union { + char short_name[8]; + struct { + unsigned char zeroes[4]; + unsigned char off[4]; + } long_name; +} b_coff_name; + +/* Coff symbol (external representation which is unaligned). */ + +typedef struct { + b_coff_name name; + unsigned char value[4]; + unsigned char section_number[2]; + unsigned char type[2]; + unsigned char storage_class; + unsigned char number_of_aux_symbols; +} b_coff_external_symbol; + +/* Symbol types. */ + +#define N_TBSHFT 4 /* Shift for the derived type. */ +#define IMAGE_SYM_DTYPE_FUNCTION 2 /* Function derived type. */ + +/* Size of a coff symbol. */ + +#define SYM_SZ 18 + +/* Coff symbol, internal representation (aligned). */ + +typedef struct { + const char *name; + uint32_t value; + int16_t sec; + uint16_t type; + uint16_t sc; +} b_coff_internal_symbol; + +/* An index of sections we care about. */ + +enum debug_section +{ + DEBUG_INFO, + DEBUG_LINE, + DEBUG_ABBREV, + DEBUG_RANGES, + DEBUG_STR, + DEBUG_MAX +}; + +/* Names of sections, indexed by enum debug_section. */ + +static const char * const debug_section_names[DEBUG_MAX] = +{ + ".debug_info", + ".debug_line", + ".debug_abbrev", + ".debug_ranges", + ".debug_str" +}; + +/* Information we gather for the sections we care about. */ + +struct debug_section_info +{ + /* Section file offset. */ + off_t offset; + /* Section size. */ + size_t size; + /* Section contents, after read from file. */ + const unsigned char *data; +}; + +/* Information we keep for an coff symbol. */ + +struct coff_symbol +{ + /* The name of the symbol. */ + const char *name; + /* The address of the symbol. */ + uintptr_t address; +}; + +/* Information to pass to coff_syminfo. */ + +struct coff_syminfo_data +{ + /* Symbols for the next module. */ + struct coff_syminfo_data *next; + /* The COFF symbols, sorted by address. */ + struct coff_symbol *symbols; + /* The number of symbols. */ + size_t count; +}; + +/* A dummy callback function used when we can't find any debug info. */ + +static int +coff_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 PE/COFF executable", -1); + return 0; +} + +/* A dummy callback function used when we can't find a symbol + table. */ + +static void +coff_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 PE/COFF executable", -1); +} + +/* Read a potentially unaligned 4 byte word at P, using native endianness. */ + +static uint32_t +coff_read4 (const unsigned char *p) +{ + uint32_t res; + + memcpy (&res, p, 4); + return res; +} + +/* Read a potentially unaligned 2 byte word at P, using native endianness. + All 2 byte word in symbols are always aligned, but for coherency all + fields are declared as char arrays. */ + +static uint16_t +coff_read2 (const unsigned char *p) +{ + uint16_t res; + + memcpy (&res, p, sizeof (res)); + return res; +} + +/* Return the length (without the trailing 0) of a COFF short name. */ + +static size_t +coff_short_name_len (const char *name) +{ + int i; + + for (i = 0; i < 8; i++) + if (name[i] == 0) + return i; + return 8; +} + +/* Return true iff COFF short name CNAME is the same as NAME (a NUL-terminated + string). */ + +static int +coff_short_name_eq (const char *name, const char *cname) +{ + int i; + + for (i = 0; i < 8; i++) + { + if (name[i] != cname[i]) + return 0; + if (name[i] == 0) + return 1; + } + return name[8] == 0; +} + +/* Return true iff NAME is the same as string at offset OFF. */ + +static int +coff_long_name_eq (const char *name, unsigned int off, + struct backtrace_view *str_view) +{ + if (off >= str_view->len) + return 0; + return strcmp (name, (const char *)str_view->data + off) == 0; +} + +/* Compare struct coff_symbol for qsort. */ + +static int +coff_symbol_compare (const void *v1, const void *v2) +{ + const struct coff_symbol *e1 = (const struct coff_symbol *) v1; + const struct coff_symbol *e2 = (const struct coff_symbol *) v2; + + if (e1->address < e2->address) + return -1; + else if (e1->address > e2->address) + return 1; + else + return 0; +} + +/* Convert SYM to internal (and aligned) format ISYM, using string table + from STRTAB and STRTAB_SIZE, and number of sections SECTS_NUM. + Return -1 in case of error (invalid section number or string index). */ + +static int +coff_expand_symbol (b_coff_internal_symbol *isym, + const b_coff_external_symbol *sym, + uint16_t sects_num, + const unsigned char *strtab, size_t strtab_size) +{ + isym->type = coff_read2 (sym->type); + isym->sec = coff_read2 (sym->section_number); + isym->sc = sym->storage_class; + + if (isym->sec > 0 && (uint16_t) isym->sec > sects_num) + return -1; + if (sym->name.short_name[0] != 0) + isym->name = sym->name.short_name; + else + { + uint32_t off = coff_read4 (sym->name.long_name.off); + + if (off >= strtab_size) + return -1; + isym->name = (const char *) strtab + off; + } + return 0; +} + +/* Return true iff SYM is a defined symbol for a function. Data symbols + aren't considered because they aren't easily identified (same type as + section names, presence of symbols defined by the linker script). */ + +static int +coff_is_function_symbol (const b_coff_internal_symbol *isym) +{ + return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION + && isym->sec > 0; +} + +/* Initialize the symbol table info for coff_syminfo. */ + +static int +coff_initialize_syminfo (struct backtrace_state *state, + uintptr_t base_address, + const b_coff_section_header *sects, size_t sects_num, + const b_coff_external_symbol *syms, size_t syms_size, + const unsigned char *strtab, size_t strtab_size, + backtrace_error_callback error_callback, + void *data, struct coff_syminfo_data *sdata) +{ + size_t syms_count; + char *coff_symstr; + size_t coff_symstr_len; + size_t coff_symbol_count; + size_t coff_symbol_size; + struct coff_symbol *coff_symbols; + struct coff_symbol *coff_sym; + char *coff_str; + size_t i; + + syms_count = syms_size / SYM_SZ; + + /* We only care about function symbols. Count them. Also count size of + strings for in-symbol names. */ + coff_symbol_count = 0; + coff_symstr_len = 0; + for (i = 0; i < syms_count; ++i) + { + const b_coff_external_symbol *asym = &syms[i]; + b_coff_internal_symbol isym; + + if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size) < 0) + { + error_callback (data, "invalid section or offset in coff symbol", 0); + return 0; + } + if (coff_is_function_symbol (&isym)) + { + ++coff_symbol_count; + if (asym->name.short_name[0] != 0) + coff_symstr_len += coff_short_name_len (asym->name.short_name) + 1; + } + + i += asym->number_of_aux_symbols; + } + + coff_symbol_size = (coff_symbol_count + 1) * sizeof (struct coff_symbol); + coff_symbols = ((struct coff_symbol *) + backtrace_alloc (state, coff_symbol_size, error_callback, + data)); + if (coff_symbols == NULL) + return 0; + + /* Allocate memory for symbols strings. */ + if (coff_symstr_len > 0) + { + coff_symstr = ((char *) + backtrace_alloc (state, coff_symstr_len, error_callback, + data)); + if (coff_symstr == NULL) + { + backtrace_free (state, coff_symbols, coff_symbol_size, + error_callback, data); + return 0; + } + } + else + coff_symstr = NULL; + + /* Copy symbols. */ + coff_sym = coff_symbols; + coff_str = coff_symstr; + for (i = 0; i < syms_count; ++i) + { + const b_coff_external_symbol *asym = &syms[i]; + b_coff_internal_symbol isym; + + if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size)) + { + /* Should not fail, as it was already tested in the previous + loop. */ + abort (); + } + if (coff_is_function_symbol (&isym)) + { + const char *name; + int16_t secnum; + + if (asym->name.short_name[0] != 0) + { + size_t len = coff_short_name_len (isym.name); + name = coff_str; + memcpy (coff_str, isym.name, len); + coff_str[len] = 0; + coff_str += len + 1; + } + else + name = isym.name; + + /* Strip leading '_'. */ + if (name[0] == '_') + name++; + + /* Symbol value is section relative, so we need to read the address + of its section. */ + secnum = coff_read2 (asym->section_number); + + coff_sym->name = name; + coff_sym->address = (coff_read4 (asym->value) + + sects[secnum - 1].virtual_address + + base_address); + coff_sym++; + } + + i += asym->number_of_aux_symbols; + } + + /* End of symbols marker. */ + coff_sym->name = NULL; + coff_sym->address = -1; + + backtrace_qsort (coff_symbols, coff_symbol_count, + sizeof (struct coff_symbol), coff_symbol_compare); + + sdata->next = NULL; + sdata->symbols = coff_symbols; + sdata->count = coff_symbol_count; + + return 1; +} + +/* Add EDATA to the list in STATE. */ + +static void +coff_add_syminfo_data (struct backtrace_state *state, + struct coff_syminfo_data *sdata) +{ + if (!state->threaded) + { + struct coff_syminfo_data **pp; + + for (pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = sdata; + } + else + { + while (1) + { + struct coff_syminfo_data **pp; + + pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data; + + while (1) + { + struct coff_syminfo_data *p; + + p = backtrace_atomic_load_pointer (pp); + + if (p == NULL) + break; + + pp = &p->next; + } + + if (__sync_bool_compare_and_swap (pp, NULL, sdata)) + break; + } + } +} + +/* Compare an ADDR against an elf_symbol for bsearch. We allocate one + extra entry in the array so that this can look safely at the next + entry. */ + +static int +coff_symbol_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct coff_symbol *entry = (const struct coff_symbol *) ventry; + uintptr_t addr; + + addr = *key; + if (addr < entry->address) + return -1; + else if (addr >= entry[1].address) + return 1; + else + return 0; +} + +/* Return the symbol name and value for an ADDR. */ + +static void +coff_syminfo (struct backtrace_state *state, uintptr_t addr, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data) +{ + struct coff_syminfo_data *sdata; + struct coff_symbol *sym = NULL; + + if (!state->threaded) + { + for (sdata = (struct coff_syminfo_data *) state->syminfo_data; + sdata != NULL; + sdata = sdata->next) + { + sym = ((struct coff_symbol *) + bsearch (&addr, sdata->symbols, sdata->count, + sizeof (struct coff_symbol), coff_symbol_search)); + if (sym != NULL) + break; + } + } + else + { + struct coff_syminfo_data **pp; + + pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data; + while (1) + { + sdata = backtrace_atomic_load_pointer (pp); + if (sdata == NULL) + break; + + sym = ((struct coff_symbol *) + bsearch (&addr, sdata->symbols, sdata->count, + sizeof (struct coff_symbol), coff_symbol_search)); + if (sym != NULL) + break; + + pp = &sdata->next; + } + } + + if (sym == NULL) + callback (data, addr, NULL, 0, 0); + else + callback (data, addr, sym->name, sym->address, 0); +} + +/* Add the backtrace data for one PE/COFF file. Returns 1 on success, + 0 on failure (in both cases descriptor is closed). */ + +static int +coff_add (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, void *data, + fileline *fileline_fn, int *found_sym, int *found_dwarf) +{ + struct backtrace_view fhdr_view; + off_t fhdr_off; + int magic_ok; + b_coff_file_header fhdr; + off_t opt_sects_off; + size_t opt_sects_size; + unsigned int sects_num; + struct backtrace_view sects_view; + int sects_view_valid; + const b_coff_optional_header *opt_hdr; + const b_coff_section_header *sects; + struct backtrace_view str_view; + int str_view_valid; + size_t str_size; + off_t str_off; + struct backtrace_view syms_view; + off_t syms_off; + size_t syms_size; + int syms_view_valid; + unsigned int syms_num; + unsigned int i; + struct debug_section_info sections[DEBUG_MAX]; + off_t min_offset; + off_t max_offset; + struct backtrace_view debug_view; + int debug_view_valid; + uintptr_t image_base; + + *found_sym = 0; + *found_dwarf = 0; + + sects_view_valid = 0; + syms_view_valid = 0; + str_view_valid = 0; + debug_view_valid = 0; + + /* Map the MS-DOS stub (if any) and extract file header offset. */ + if (!backtrace_get_view (state, descriptor, 0, 0x40, error_callback, + data, &fhdr_view)) + goto fail; + + { + const char *vptr = (const char *)fhdr_view.data; + + if (vptr[0] == 'M' && vptr[1] == 'Z') + memcpy (&fhdr_off, vptr + 0x3c, 4); + else + fhdr_off = 0; + } + + backtrace_release_view (state, &fhdr_view, error_callback, data); + + /* Map the coff file header. */ + if (!backtrace_get_view (state, descriptor, fhdr_off, + sizeof (b_coff_file_header) + 4, + error_callback, data, &fhdr_view)) + goto fail; + + if (fhdr_off != 0) + { + const char *magic = (const char *) fhdr_view.data; + magic_ok = memcmp (magic, "PE\0", 4) == 0; + fhdr_off += 4; + + memcpy (&fhdr, fhdr_view.data + 4, sizeof fhdr); + } + else + { + memcpy (&fhdr, fhdr_view.data, sizeof fhdr); + /* TODO: test fhdr.machine for coff but non-PE platforms. */ + magic_ok = 0; + } + backtrace_release_view (state, &fhdr_view, error_callback, data); + + if (!magic_ok) + { + error_callback (data, "executable file is not COFF", 0); + goto fail; + } + + sects_num = fhdr.number_of_sections; + syms_num = fhdr.number_of_symbols; + + opt_sects_off = fhdr_off + sizeof (fhdr); + opt_sects_size = (fhdr.size_of_optional_header + + sects_num * sizeof (b_coff_section_header)); + + /* To translate PC to file/line when using DWARF, we need to find + the .debug_info and .debug_line sections. */ + + /* Read the optional header and the section headers. */ + + if (!backtrace_get_view (state, descriptor, opt_sects_off, opt_sects_size, + error_callback, data, §s_view)) + goto fail; + sects_view_valid = 1; + opt_hdr = (const b_coff_optional_header *) sects_view.data; + sects = (const b_coff_section_header *) + (sects_view.data + fhdr.size_of_optional_header); + + if (fhdr.size_of_optional_header > sizeof (*opt_hdr)) + { + if (opt_hdr->magic == PE_MAGIC) + image_base = opt_hdr->u.pe.image_base; + else if (opt_hdr->magic == PEP_MAGIC) + image_base = opt_hdr->u.pep.image_base; + else + { + error_callback (data, "bad magic in PE optional header", 0); + goto fail; + } + } + else + image_base = 0; + + /* Read the symbol table and the string table. */ + + if (fhdr.pointer_to_symbol_table == 0) + { + /* No symbol table, no string table. */ + str_off = 0; + str_size = 0; + syms_num = 0; + syms_size = 0; + } + else + { + /* 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_off = fhdr.pointer_to_symbol_table; + syms_size = syms_num * SYM_SZ; + + if (!backtrace_get_view (state, descriptor, syms_off, 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 = syms_off + syms_size; + + if (str_size > 4) + { + /* Map string table (including the length word). */ + + if (!backtrace_get_view (state, descriptor, str_off, str_size, + error_callback, data, &str_view)) + goto fail; + str_view_valid = 1; + } + } + + memset (sections, 0, sizeof sections); + + /* Look for the symbol table. */ + for (i = 0; i < sects_num; ++i) + { + const b_coff_section_header *s = sects + i; + unsigned int str_off; + int j; + + if (s->name[0] == '/') + { + /* Extended section name. */ + str_off = atoi (s->name + 1); + } + else + str_off = 0; + + for (j = 0; j < (int) DEBUG_MAX; ++j) + { + const char *dbg_name = debug_section_names[j]; + int match; + + if (str_off != 0) + match = coff_long_name_eq (dbg_name, str_off, &str_view); + else + match = coff_short_name_eq (dbg_name, s->name); + if (match) + { + sections[j].offset = s->pointer_to_raw_data; + sections[j].size = s->virtual_size <= s->size_of_raw_data ? + s->virtual_size : s->size_of_raw_data; + break; + } + } + } + + if (syms_num != 0) + { + struct coff_syminfo_data *sdata; + + sdata = ((struct coff_syminfo_data *) + backtrace_alloc (state, sizeof *sdata, error_callback, data)); + if (sdata == NULL) + goto fail; + + if (!coff_initialize_syminfo (state, image_base, + sects, sects_num, + syms_view.data, syms_size, + str_view.data, str_size, + error_callback, data, sdata)) + { + backtrace_free (state, sdata, sizeof *sdata, error_callback, data); + goto fail; + } + + *found_sym = 1; + + coff_add_syminfo_data (state, sdata); + } + + backtrace_release_view (state, §s_view, error_callback, data); + sects_view_valid = 0; + backtrace_release_view (state, &syms_view, error_callback, data); + syms_view_valid = 0; + + /* Read all the debug sections in a single view, since they are + probably adjacent in the file. We never release this view. */ + + min_offset = 0; + max_offset = 0; + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + off_t end; + + if (sections[i].size == 0) + continue; + if (min_offset == 0 || sections[i].offset < min_offset) + min_offset = sections[i].offset; + end = sections[i].offset + sections[i].size; + if (end > max_offset) + max_offset = end; + } + if (min_offset == 0 || max_offset == 0) + { + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + *fileline_fn = coff_nodebug; + return 1; + } + + if (!backtrace_get_view (state, descriptor, min_offset, + max_offset - min_offset, + error_callback, data, &debug_view)) + goto fail; + debug_view_valid = 1; + + /* We've read all we need from the executable. */ + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + descriptor = -1; + + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + if (sections[i].size == 0) + sections[i].data = NULL; + else + sections[i].data = ((const unsigned char *) debug_view.data + + (sections[i].offset - min_offset)); + } + + if (!backtrace_dwarf_add (state, /* base_address */ 0, + sections[DEBUG_INFO].data, + sections[DEBUG_INFO].size, + sections[DEBUG_LINE].data, + sections[DEBUG_LINE].size, + sections[DEBUG_ABBREV].data, + sections[DEBUG_ABBREV].size, + sections[DEBUG_RANGES].data, + sections[DEBUG_RANGES].size, + sections[DEBUG_STR].data, + sections[DEBUG_STR].size, + 0, /* FIXME */ + error_callback, data, fileline_fn)) + goto fail; + + *found_dwarf = 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 (debug_view_valid) + backtrace_release_view (state, &debug_view, error_callback, data); + if (descriptor != -1) + backtrace_close (descriptor, error_callback, data); + return 0; +} + +/* Initialize the backtrace data we need from an ELF executable. At + the ELF level, all we need to do is find the debug info + sections. */ + +int +backtrace_initialize (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn) +{ + int ret; + int found_sym; + int found_dwarf; + fileline coff_fileline_fn; + + ret = coff_add (state, descriptor, error_callback, data, + &coff_fileline_fn, &found_sym, &found_dwarf); + if (!ret) + return 0; + + if (!state->threaded) + { + if (found_sym) + state->syminfo_fn = coff_syminfo; + else if (state->syminfo_fn == NULL) + state->syminfo_fn = coff_nosyms; + } + else + { + if (found_sym) + backtrace_atomic_store_pointer (&state->syminfo_fn, coff_syminfo); + else + __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, coff_nosyms); + } + + if (!state->threaded) + { + if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug) + *fileline_fn = coff_fileline_fn; + } + else + { + fileline current_fn; + + current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); + if (current_fn == NULL || current_fn == coff_nodebug) + *fileline_fn = coff_fileline_fn; + } + + return 1; +} diff --git a/thirdparty/libbacktrace/posix.c b/thirdparty/libbacktrace/posix.c index be0a1a55..09f5e95a 100644 --- a/thirdparty/libbacktrace/posix.c +++ b/thirdparty/libbacktrace/posix.c @@ -1,5 +1,5 @@ /* posix.c -- POSIX file I/O routines for the backtrace library. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -64,7 +64,7 @@ backtrace_open (const char *filename, backtrace_error_callback error_callback, if (does_not_exist != NULL) *does_not_exist = 0; - descriptor = open (filename, O_RDONLY | O_BINARY | O_CLOEXEC); + descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC)); if (descriptor < 0) { if (does_not_exist != NULL && errno == ENOENT) diff --git a/thirdparty/libbacktrace/print.c b/thirdparty/libbacktrace/print.c index c8cc2989..74c8fcbe 100644 --- a/thirdparty/libbacktrace/print.c +++ b/thirdparty/libbacktrace/print.c @@ -1,5 +1,5 @@ /* print.c -- Print the current backtrace. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without diff --git a/thirdparty/libbacktrace/read.c b/thirdparty/libbacktrace/read.c index d6e648e5..7f0317c3 100644 --- a/thirdparty/libbacktrace/read.c +++ b/thirdparty/libbacktrace/read.c @@ -1,5 +1,5 @@ /* read.c -- File views without mmap. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without diff --git a/thirdparty/libbacktrace/simple.c b/thirdparty/libbacktrace/simple.c index b03f039f..018773a7 100644 --- a/thirdparty/libbacktrace/simple.c +++ b/thirdparty/libbacktrace/simple.c @@ -1,5 +1,5 @@ /* simple.c -- The backtrace_simple function. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without diff --git a/thirdparty/libbacktrace/sort.c b/thirdparty/libbacktrace/sort.c new file mode 100644 index 00000000..68a7df65 --- /dev/null +++ b/thirdparty/libbacktrace/sort.c @@ -0,0 +1,108 @@ +/* sort.c -- Sort without allocating memory + Copyright (C) 2012-2016 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 "config.h" + +#include <stddef.h> +#include <sys/types.h> + +#include "backtrace.h" +#include "internal.h" + +/* The GNU glibc version of qsort allocates memory, which we must not + do if we are invoked by a signal handler. So provide our own + sort. */ + +static void +swap (char *a, char *b, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++, a++, b++) + { + char t; + + t = *a; + *a = *b; + *b = t; + } +} + +void +backtrace_qsort (void *basearg, size_t count, size_t size, + int (*compar) (const void *, const void *)) +{ + char *base = (char *) basearg; + size_t i; + size_t mid; + + tail_recurse: + if (count < 2) + return; + + /* The symbol table and DWARF tables, which is all we use this + routine for, tend to be roughly sorted. Pick the middle element + in the array as our pivot point, so that we are more likely to + cut the array in half for each recursion step. */ + swap (base, base + (count / 2) * size, size); + + mid = 0; + for (i = 1; i < count; i++) + { + if ((*compar) (base, base + i * size) > 0) + { + ++mid; + if (i != mid) + swap (base + mid * size, base + i * size, size); + } + } + + if (mid > 0) + swap (base, base + mid * size, size); + + /* Recurse with the smaller array, loop with the larger one. That + ensures that our maximum stack depth is log count. */ + if (2 * mid < count) + { + backtrace_qsort (base, mid, size, compar); + base += (mid + 1) * size; + count -= mid + 1; + goto tail_recurse; + } + else + { + backtrace_qsort (base + (mid + 1) * size, count - (mid + 1), + size, compar); + count = mid; + goto tail_recurse; + } +} diff --git a/thirdparty/libbacktrace/state.c b/thirdparty/libbacktrace/state.c index 03bba481..93420d9c 100644 --- a/thirdparty/libbacktrace/state.c +++ b/thirdparty/libbacktrace/state.c @@ -1,5 +1,5 @@ /* state.c -- Create the backtrace state. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without diff --git a/thirdparty/libbacktrace/stest.c b/thirdparty/libbacktrace/stest.c new file mode 100644 index 00000000..55ec31d1 --- /dev/null +++ b/thirdparty/libbacktrace/stest.c @@ -0,0 +1,137 @@ +/* stest.c -- Test for libbacktrace internal sort function + Copyright (C) 2012-2016 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 "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "backtrace.h" +#include "internal.h" + +/* Test the local qsort implementation. */ + +#define MAX 10 + +struct test +{ + size_t count; + int input[MAX]; + int output[MAX]; +}; + +static struct test tests[] = + { + { + 10, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } + }, + { + 9, + { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9 } + }, + { + 10, + { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + }, + { + 9, + { 9, 8, 7, 6, 5, 4, 3, 2, 1 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + }, + { + 10, + { 2, 4, 6, 8, 10, 1, 3, 5, 7, 9 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + }, + { + 5, + { 4, 5, 3, 1, 2 }, + { 1, 2, 3, 4, 5 }, + }, + { + 5, + { 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1 }, + }, + { + 5, + { 1, 1, 2, 1, 1 }, + { 1, 1, 1, 1, 2 }, + }, + { + 5, + { 2, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 2 }, + }, + }; + +static int +compare (const void *a, const void *b) +{ + const int *ai = (const int *) a; + const int *bi = (const int *) b; + + return *ai - *bi; +} + +int +main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + int failures; + size_t i; + int a[MAX]; + + failures = 0; + for (i = 0; i < sizeof tests / sizeof tests[0]; i++) + { + memcpy (a, tests[i].input, tests[i].count * sizeof (int)); + backtrace_qsort (a, tests[i].count, sizeof (int), compare); + if (memcmp (a, tests[i].output, tests[i].count * sizeof (int)) != 0) + { + size_t j; + + fprintf (stderr, "test %d failed:", (int) i); + for (j = 0; j < tests[i].count; j++) + fprintf (stderr, " %d", a[j]); + fprintf (stderr, "\n"); + ++failures; + } + } + + exit (failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/thirdparty/libbacktrace/unknown.c b/thirdparty/libbacktrace/unknown.c index d9a3ac75..8d06c315 100644 --- a/thirdparty/libbacktrace/unknown.c +++ b/thirdparty/libbacktrace/unknown.c @@ -1,5 +1,5 @@ /* unknown.c -- used when backtrace configury does not know file format. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without |