mirror of
https://github.com/ianlancetaylor/libbacktrace.git
synced 2026-03-13 22:09:07 +08:00
libbacktrace: initial commit
This is a standalone version of the libbacktrace library that I originally wrote for GCC. This is a copy of libbacktrace from GCC trunk, with all dependencies incorporated here.
This commit is contained in:
29
LICENSE
Normal file
29
LICENSE
Normal file
@@ -0,0 +1,29 @@
|
||||
# Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# (1) Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
|
||||
# (2) Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
|
||||
# (3) The name of the author may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
130
Makefile.am
Normal file
130
Makefile.am
Normal file
@@ -0,0 +1,130 @@
|
||||
# Makefile.am -- Backtrace Makefile.
|
||||
# Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# (1) Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
|
||||
# (2) Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
|
||||
# (3) The name of the author may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG)
|
||||
|
||||
lib_LTLIBRARIES = libbacktrace.la
|
||||
include_HEADERS = backtrace.h backtrace-supported.h
|
||||
|
||||
libbacktrace_la_SOURCES = \
|
||||
backtrace.h \
|
||||
atomic.c \
|
||||
dwarf.c \
|
||||
fileline.c \
|
||||
internal.h \
|
||||
posix.c \
|
||||
print.c \
|
||||
sort.c \
|
||||
state.c
|
||||
|
||||
BACKTRACE_FILES = \
|
||||
backtrace.c \
|
||||
simple.c \
|
||||
nounwind.c
|
||||
|
||||
FORMAT_FILES = \
|
||||
elf.c \
|
||||
pecoff.c \
|
||||
unknown.c
|
||||
|
||||
VIEW_FILES = \
|
||||
read.c \
|
||||
mmapio.c
|
||||
|
||||
ALLOC_FILES = \
|
||||
alloc.c \
|
||||
mmap.c
|
||||
|
||||
EXTRA_libbacktrace_la_SOURCES = \
|
||||
$(BACKTRACE_FILES) \
|
||||
$(FORMAT_FILES) \
|
||||
$(VIEW_FILES) \
|
||||
$(ALLOC_FILES)
|
||||
|
||||
libbacktrace_la_LIBADD = \
|
||||
$(BACKTRACE_FILE) \
|
||||
$(FORMAT_FILE) \
|
||||
$(VIEW_FILE) \
|
||||
$(ALLOC_FILE)
|
||||
|
||||
libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
|
||||
|
||||
# Testsuite.
|
||||
|
||||
check_PROGRAMS =
|
||||
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
if NATIVE
|
||||
|
||||
btest_SOURCES = btest.c
|
||||
btest_CFLAGS = $(AM_CFLAGS) -g -O
|
||||
btest_LDADD = libbacktrace.la
|
||||
|
||||
check_PROGRAMS += btest
|
||||
|
||||
stest_SOURCES = stest.c
|
||||
stest_LDADD = libbacktrace.la
|
||||
|
||||
check_PROGRAMS += stest
|
||||
|
||||
endif NATIVE
|
||||
|
||||
# We can't use automake's automatic dependency tracking, because it
|
||||
# breaks when using bootstrap-lean. Automatic dependency tracking
|
||||
# with GCC bootstrap will cause some of the objects to depend on
|
||||
# header files in prev-gcc/include, e.g., stddef.h and stdarg.h. When
|
||||
# using bootstrap-lean, prev-gcc is removed after each stage. When
|
||||
# running "make install", those header files will be gone, causing the
|
||||
# library to be rebuilt at install time. That may not succeed.
|
||||
|
||||
# These manual dependencies do not include dependencies on unwind.h,
|
||||
# even though that is part of GCC, because where to find it depends on
|
||||
# whether we are being built as a host library or a target library.
|
||||
|
||||
alloc.lo: config.h backtrace.h internal.h
|
||||
backtrace.lo: config.h backtrace.h internal.h
|
||||
btest.lo: backtrace.h backtrace-supported.h
|
||||
dwarf.lo: config.h backtrace.h internal.h
|
||||
elf.lo: config.h backtrace.h internal.h
|
||||
fileline.lo: config.h backtrace.h internal.h
|
||||
mmap.lo: config.h backtrace.h internal.h
|
||||
mmapio.lo: config.h backtrace.h internal.h
|
||||
nounwind.lo: config.h internal.h
|
||||
pecoff.lo: config.h backtrace.h internal.h
|
||||
posix.lo: config.h backtrace.h internal.h
|
||||
print.lo: config.h backtrace.h internal.h
|
||||
read.lo: config.h backtrace.h internal.h
|
||||
simple.lo: config.h backtrace.h internal.h
|
||||
sort.lo: config.h backtrace.h internal.h
|
||||
stest.lo: config.h backtrace.h internal.h
|
||||
state.lo: config.h backtrace.h backtrace-supported.h internal.h
|
||||
unknown.lo: config.h backtrace.h internal.h
|
||||
837
Makefile.in
Normal file
837
Makefile.in
Normal file
@@ -0,0 +1,837 @@
|
||||
# Makefile.in generated by automake 1.11.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Makefile.am -- Backtrace Makefile.
|
||||
# Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# (1) Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
|
||||
# (2) Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
|
||||
# (3) The name of the author may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__make_dryrun = \
|
||||
{ \
|
||||
am__dry=no; \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
|
||||
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
|
||||
*) \
|
||||
for am__flg in $$MAKEFLAGS; do \
|
||||
case $$am__flg in \
|
||||
*=*|--*) ;; \
|
||||
*n*) am__dry=yes; break;; \
|
||||
esac; \
|
||||
done;; \
|
||||
esac; \
|
||||
test $$am__dry = yes; \
|
||||
}
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
check_PROGRAMS = $(am__EXEEXT_1)
|
||||
@NATIVE_TRUE@am__append_1 = btest stest
|
||||
subdir = .
|
||||
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
|
||||
$(top_srcdir)/configure $(am__configure_deps) \
|
||||
$(srcdir)/config.h.in $(srcdir)/backtrace-supported.h.in \
|
||||
$(include_HEADERS)
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno config.status.lineno
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES = backtrace-supported.h
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
am__DEPENDENCIES_1 =
|
||||
am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \
|
||||
print.lo sort.lo state.lo
|
||||
libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS)
|
||||
@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT)
|
||||
@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT)
|
||||
btest_OBJECTS = $(am_btest_OBJECTS)
|
||||
@NATIVE_TRUE@btest_DEPENDENCIES = libbacktrace.la
|
||||
btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
@NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
|
||||
stest_OBJECTS = $(am_stest_OBJECTS)
|
||||
@NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||
depcomp =
|
||||
am__depfiles_maybe =
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
|
||||
$(btest_SOURCES) $(stest_SOURCES)
|
||||
MULTISRCTOP =
|
||||
MULTIBUILDTOP =
|
||||
MULTIDIRS =
|
||||
MULTISUBDIR =
|
||||
MULTIDO = true
|
||||
MULTICLEAN = true
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
HEADERS = $(include_HEADERS)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__tty_colors = \
|
||||
red=; grn=; lgn=; blu=; std=
|
||||
ACLOCAL = @ACLOCAL@
|
||||
ALLOC_FILE = @ALLOC_FILE@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BACKTRACE_FILE = @BACKTRACE_FILE@
|
||||
BACKTRACE_SUPPORTED = @BACKTRACE_SUPPORTED@
|
||||
BACKTRACE_SUPPORTS_DATA = @BACKTRACE_SUPPORTS_DATA@
|
||||
BACKTRACE_SUPPORTS_THREADS = @BACKTRACE_SUPPORTS_THREADS@
|
||||
BACKTRACE_USES_MALLOC = @BACKTRACE_USES_MALLOC@
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
EXTRA_FLAGS = @EXTRA_FLAGS@
|
||||
FGREP = @FGREP@
|
||||
FORMAT_FILE = @FORMAT_FILE@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PIC_FLAG = @PIC_FLAG@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
VIEW_FILE = @VIEW_FILE@
|
||||
WARN_FLAGS = @WARN_FLAGS@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
libtool_VERSION = @libtool_VERSION@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
lt_ECHO = @lt_ECHO@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
multi_basedir = @multi_basedir@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG)
|
||||
lib_LTLIBRARIES = libbacktrace.la
|
||||
include_HEADERS = backtrace.h backtrace-supported.h
|
||||
libbacktrace_la_SOURCES = \
|
||||
backtrace.h \
|
||||
atomic.c \
|
||||
dwarf.c \
|
||||
fileline.c \
|
||||
internal.h \
|
||||
posix.c \
|
||||
print.c \
|
||||
sort.c \
|
||||
state.c
|
||||
|
||||
BACKTRACE_FILES = \
|
||||
backtrace.c \
|
||||
simple.c \
|
||||
nounwind.c
|
||||
|
||||
FORMAT_FILES = \
|
||||
elf.c \
|
||||
pecoff.c \
|
||||
unknown.c
|
||||
|
||||
VIEW_FILES = \
|
||||
read.c \
|
||||
mmapio.c
|
||||
|
||||
ALLOC_FILES = \
|
||||
alloc.c \
|
||||
mmap.c
|
||||
|
||||
EXTRA_libbacktrace_la_SOURCES = \
|
||||
$(BACKTRACE_FILES) \
|
||||
$(FORMAT_FILES) \
|
||||
$(VIEW_FILES) \
|
||||
$(ALLOC_FILES)
|
||||
|
||||
libbacktrace_la_LIBADD = \
|
||||
$(BACKTRACE_FILE) \
|
||||
$(FORMAT_FILE) \
|
||||
$(VIEW_FILE) \
|
||||
$(ALLOC_FILE)
|
||||
|
||||
libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
|
||||
TESTS = $(check_PROGRAMS)
|
||||
@NATIVE_TRUE@btest_SOURCES = btest.c
|
||||
@NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
|
||||
@NATIVE_TRUE@btest_LDADD = libbacktrace.la
|
||||
@NATIVE_TRUE@stest_SOURCES = stest.c
|
||||
@NATIVE_TRUE@stest_LDADD = libbacktrace.la
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
am--refresh: Makefile
|
||||
@:
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps'; \
|
||||
$(am__cd) $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign --ignore-deps Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
$(am__cd) $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
config.h: stamp-h1
|
||||
@if test ! -f $@; then rm -f stamp-h1; else :; fi
|
||||
@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi
|
||||
|
||||
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h1
|
||||
cd $(top_builddir) && $(SHELL) ./config.status config.h
|
||||
$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
|
||||
rm -f stamp-h1
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config.h stamp-h1
|
||||
backtrace-supported.h: $(top_builddir)/config.status $(srcdir)/backtrace-supported.h.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@
|
||||
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
list2=; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
list2="$$list2 $$p"; \
|
||||
else :; fi; \
|
||||
done; \
|
||||
test -z "$$list2" || { \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
|
||||
}
|
||||
|
||||
uninstall-libLTLIBRARIES:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
|
||||
done
|
||||
|
||||
clean-libLTLIBRARIES:
|
||||
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
|
||||
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES)
|
||||
$(LINK) -rpath $(libdir) $(libbacktrace_la_OBJECTS) $(libbacktrace_la_LIBADD) $(LIBS)
|
||||
|
||||
clean-checkPROGRAMS:
|
||||
@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list || exit $$?; \
|
||||
test -n "$(EXEEXT)" || exit 0; \
|
||||
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list
|
||||
btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES)
|
||||
@rm -f btest$(EXEEXT)
|
||||
$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
|
||||
stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES)
|
||||
@rm -f stest$(EXEEXT)
|
||||
$(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
$(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
btest-btest.o: btest.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
|
||||
|
||||
btest-btest.obj: btest.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
distclean-libtool:
|
||||
-rm -f libtool config.lt
|
||||
|
||||
# GNU Make needs to see an explicit $(MAKE) variable in the command it
|
||||
# runs to enable its job server during parallel builds. Hence the
|
||||
# comments below.
|
||||
all-multi:
|
||||
$(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do # $(MAKE)
|
||||
install-multi:
|
||||
$(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do # $(MAKE)
|
||||
|
||||
mostlyclean-multi:
|
||||
$(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean # $(MAKE)
|
||||
clean-multi:
|
||||
$(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean # $(MAKE)
|
||||
distclean-multi:
|
||||
$(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean # $(MAKE)
|
||||
maintainer-clean-multi:
|
||||
$(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean # $(MAKE)
|
||||
install-includeHEADERS: $(include_HEADERS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
|
||||
$(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-includeHEADERS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
check-TESTS: $(TESTS)
|
||||
@failed=0; all=0; xfail=0; xpass=0; skip=0; \
|
||||
srcdir=$(srcdir); export srcdir; \
|
||||
list=' $(TESTS) '; \
|
||||
$(am__tty_colors); \
|
||||
if test -n "$$list"; then \
|
||||
for tst in $$list; do \
|
||||
if test -f ./$$tst; then dir=./; \
|
||||
elif test -f $$tst; then dir=; \
|
||||
else dir="$(srcdir)/"; fi; \
|
||||
if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
|
||||
all=`expr $$all + 1`; \
|
||||
case " $(XFAIL_TESTS) " in \
|
||||
*[\ \ ]$$tst[\ \ ]*) \
|
||||
xpass=`expr $$xpass + 1`; \
|
||||
failed=`expr $$failed + 1`; \
|
||||
col=$$red; res=XPASS; \
|
||||
;; \
|
||||
*) \
|
||||
col=$$grn; res=PASS; \
|
||||
;; \
|
||||
esac; \
|
||||
elif test $$? -ne 77; then \
|
||||
all=`expr $$all + 1`; \
|
||||
case " $(XFAIL_TESTS) " in \
|
||||
*[\ \ ]$$tst[\ \ ]*) \
|
||||
xfail=`expr $$xfail + 1`; \
|
||||
col=$$lgn; res=XFAIL; \
|
||||
;; \
|
||||
*) \
|
||||
failed=`expr $$failed + 1`; \
|
||||
col=$$red; res=FAIL; \
|
||||
;; \
|
||||
esac; \
|
||||
else \
|
||||
skip=`expr $$skip + 1`; \
|
||||
col=$$blu; res=SKIP; \
|
||||
fi; \
|
||||
echo "$${col}$$res$${std}: $$tst"; \
|
||||
done; \
|
||||
if test "$$all" -eq 1; then \
|
||||
tests="test"; \
|
||||
All=""; \
|
||||
else \
|
||||
tests="tests"; \
|
||||
All="All "; \
|
||||
fi; \
|
||||
if test "$$failed" -eq 0; then \
|
||||
if test "$$xfail" -eq 0; then \
|
||||
banner="$$All$$all $$tests passed"; \
|
||||
else \
|
||||
if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
|
||||
banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
|
||||
fi; \
|
||||
else \
|
||||
if test "$$xpass" -eq 0; then \
|
||||
banner="$$failed of $$all $$tests failed"; \
|
||||
else \
|
||||
if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
|
||||
banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
|
||||
fi; \
|
||||
fi; \
|
||||
dashes="$$banner"; \
|
||||
skipped=""; \
|
||||
if test "$$skip" -ne 0; then \
|
||||
if test "$$skip" -eq 1; then \
|
||||
skipped="($$skip test was not run)"; \
|
||||
else \
|
||||
skipped="($$skip tests were not run)"; \
|
||||
fi; \
|
||||
test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
|
||||
dashes="$$skipped"; \
|
||||
fi; \
|
||||
report=""; \
|
||||
if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
|
||||
report="Please report to $(PACKAGE_BUGREPORT)"; \
|
||||
test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
|
||||
dashes="$$report"; \
|
||||
fi; \
|
||||
dashes=`echo "$$dashes" | sed s/./=/g`; \
|
||||
if test "$$failed" -eq 0; then \
|
||||
col="$$grn"; \
|
||||
else \
|
||||
col="$$red"; \
|
||||
fi; \
|
||||
echo "$${col}$$dashes$${std}"; \
|
||||
echo "$${col}$$banner$${std}"; \
|
||||
test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
|
||||
test -z "$$report" || echo "$${col}$$report$${std}"; \
|
||||
echo "$${col}$$dashes$${std}"; \
|
||||
test "$$failed" -eq 0; \
|
||||
else :; fi
|
||||
check-am: all-am
|
||||
$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
|
||||
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES) all-multi $(HEADERS) config.h
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am clean-multi
|
||||
|
||||
clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \
|
||||
clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-am distclean-multi
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-hdr distclean-libtool distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-includeHEADERS
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am: install-libLTLIBRARIES install-multi
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am maintainer-clean-multi
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am mostlyclean-multi
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
|
||||
|
||||
.MAKE: all all-multi check-am clean-multi distclean-multi install-am \
|
||||
install-multi install-strip maintainer-clean-multi \
|
||||
mostlyclean-multi
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am all-multi am--refresh check check-TESTS \
|
||||
check-am clean clean-checkPROGRAMS clean-generic \
|
||||
clean-libLTLIBRARIES clean-libtool clean-multi ctags distclean \
|
||||
distclean-compile distclean-generic distclean-hdr \
|
||||
distclean-libtool distclean-multi distclean-tags dvi dvi-am \
|
||||
html html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am \
|
||||
install-includeHEADERS install-info install-info-am \
|
||||
install-libLTLIBRARIES install-man install-multi install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic maintainer-clean-multi mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
|
||||
mostlyclean-multi pdf pdf-am ps ps-am tags uninstall \
|
||||
uninstall-am uninstall-includeHEADERS uninstall-libLTLIBRARIES
|
||||
|
||||
|
||||
# We can't use automake's automatic dependency tracking, because it
|
||||
# breaks when using bootstrap-lean. Automatic dependency tracking
|
||||
# with GCC bootstrap will cause some of the objects to depend on
|
||||
# header files in prev-gcc/include, e.g., stddef.h and stdarg.h. When
|
||||
# using bootstrap-lean, prev-gcc is removed after each stage. When
|
||||
# running "make install", those header files will be gone, causing the
|
||||
# library to be rebuilt at install time. That may not succeed.
|
||||
|
||||
# These manual dependencies do not include dependencies on unwind.h,
|
||||
# even though that is part of GCC, because where to find it depends on
|
||||
# whether we are being built as a host library or a target library.
|
||||
|
||||
alloc.lo: config.h backtrace.h internal.h
|
||||
backtrace.lo: config.h backtrace.h internal.h
|
||||
btest.lo: backtrace.h backtrace-supported.h
|
||||
dwarf.lo: config.h backtrace.h internal.h
|
||||
elf.lo: config.h backtrace.h internal.h
|
||||
fileline.lo: config.h backtrace.h internal.h
|
||||
mmap.lo: config.h backtrace.h internal.h
|
||||
mmapio.lo: config.h backtrace.h internal.h
|
||||
nounwind.lo: config.h internal.h
|
||||
pecoff.lo: config.h backtrace.h internal.h
|
||||
posix.lo: config.h backtrace.h internal.h
|
||||
print.lo: config.h backtrace.h internal.h
|
||||
read.lo: config.h backtrace.h internal.h
|
||||
simple.lo: config.h backtrace.h internal.h
|
||||
sort.lo: config.h backtrace.h internal.h
|
||||
stest.lo: config.h backtrace.h internal.h
|
||||
state.lo: config.h backtrace.h backtrace-supported.h internal.h
|
||||
unknown.lo: config.h backtrace.h internal.h
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
28
README.md
28
README.md
@@ -1,2 +1,30 @@
|
||||
# libbacktrace
|
||||
A C library that may be linked into a C/C++ program to produce symbolic backtraces
|
||||
|
||||
Initially written by Ian Lance Taylor <iant@golang.org>
|
||||
|
||||
The libbacktrace library may be linked into a program or library and
|
||||
used to produce symbolic backtraces.
|
||||
Sample uses would be to print a detailed backtrace when an error
|
||||
occurs or to gather detailed profiling information.
|
||||
|
||||
The libbacktrace library is provided under a BSD license.
|
||||
See the source files for the exact license text.
|
||||
|
||||
The public functions are declared and documented in the header file
|
||||
backtrace.h, which should be #include'd by a user of the library.
|
||||
|
||||
Building libbacktrace will generate a file backtrace-supported.h,
|
||||
which a user of the library may use to determine whether backtraces
|
||||
will work.
|
||||
See the source file backtrace-supported.h.in for the macros that it
|
||||
defines.
|
||||
|
||||
As of September 2016, libbacktrace only supports ELF and PE/COFF
|
||||
executables with DWARF debugging information.
|
||||
The library is written to make it straightforward to add support for
|
||||
other object file and debugging formats.
|
||||
|
||||
The library relies on the C++ unwind API defined at
|
||||
http://mentorembedded.github.io/cxx-abi/abi-eh.html.
|
||||
This API is provided by GCC.
|
||||
|
||||
71
acinclude.m4
Normal file
71
acinclude.m4
Normal file
@@ -0,0 +1,71 @@
|
||||
dnl
|
||||
dnl Check whether _Unwind_GetIPInfo is available without doing a link
|
||||
dnl test so we can use this with libstdc++-v3 and libjava. Need to
|
||||
dnl use $target to set defaults because automatic checking is not possible
|
||||
dnl without a link test (and maybe even with a link test).
|
||||
dnl
|
||||
|
||||
AC_DEFUN([GCC_CHECK_UNWIND_GETIPINFO], [
|
||||
AC_ARG_WITH(system-libunwind,
|
||||
[ --with-system-libunwind use installed libunwind])
|
||||
# If system-libunwind was not specifically set, pick a default setting.
|
||||
if test x$with_system_libunwind = x; then
|
||||
case ${target} in
|
||||
ia64-*-hpux*) with_system_libunwind=yes ;;
|
||||
*) with_system_libunwind=no ;;
|
||||
esac
|
||||
fi
|
||||
# Based on system-libunwind and target, do we have ipinfo?
|
||||
if test x$with_system_libunwind = xyes; then
|
||||
case ${target} in
|
||||
ia64-*-*) have_unwind_getipinfo=no ;;
|
||||
*) have_unwind_getipinfo=yes ;;
|
||||
esac
|
||||
else
|
||||
# Darwin before version 9 does not have _Unwind_GetIPInfo.
|
||||
changequote(,)
|
||||
case ${target} in
|
||||
*-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;;
|
||||
*) have_unwind_getipinfo=yes ;;
|
||||
esac
|
||||
changequote([,])
|
||||
fi
|
||||
|
||||
if test x$have_unwind_getipinfo = xyes; then
|
||||
AC_DEFINE(HAVE_GETIPINFO, 1, [Define if _Unwind_GetIPInfo is available.])
|
||||
fi
|
||||
])
|
||||
|
||||
# ACX_PROG_CC_WARNING_OPTS(WARNINGS, [VARIABLE = WARN_CFLAGS])
|
||||
# Sets @VARIABLE@ to the subset of the given options which the
|
||||
# compiler accepts.
|
||||
AC_DEFUN([ACX_PROG_CC_WARNING_OPTS],
|
||||
[AC_REQUIRE([AC_PROG_CC])dnl
|
||||
AC_LANG_PUSH(C)
|
||||
m4_pushdef([acx_Var], [m4_default([$2], [WARN_CFLAGS])])dnl
|
||||
AC_SUBST(acx_Var)dnl
|
||||
m4_expand_once([acx_Var=
|
||||
],m4_quote(acx_Var=))dnl
|
||||
save_CFLAGS="$CFLAGS"
|
||||
for real_option in $1; do
|
||||
# Do the check with the no- prefix removed since gcc silently
|
||||
# accepts any -Wno-* option on purpose
|
||||
case $real_option in
|
||||
-Wno-*) option=-W`expr x$real_option : 'x-Wno-\(.*\)'` ;;
|
||||
*) option=$real_option ;;
|
||||
esac
|
||||
AS_VAR_PUSHDEF([acx_Woption], [acx_cv_prog_cc_warning_$option])
|
||||
AC_CACHE_CHECK([whether $CC supports $option], acx_Woption,
|
||||
[CFLAGS="$option"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],
|
||||
[AS_VAR_SET(acx_Woption, yes)],
|
||||
[AS_VAR_SET(acx_Woption, no)])
|
||||
])
|
||||
AS_IF([test AS_VAR_GET(acx_Woption) = yes],
|
||||
[acx_Var="$acx_Var${acx_Var:+ }$real_option"])
|
||||
AS_VAR_POPDEF([acx_Woption])dnl
|
||||
done
|
||||
CFLAGS="$save_CFLAGS"
|
||||
m4_popdef([acx_Var])dnl
|
||||
AC_LANG_POP(C)
|
||||
])# ACX_PROG_CC_WARNING_OPTS
|
||||
8660
aclocal.m4
vendored
Normal file
8660
aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
156
alloc.c
Normal file
156
alloc.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/* alloc.c -- Memory allocation without mmap.
|
||||
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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Allocation routines to use on systems that do not support anonymous
|
||||
mmap. This implementation just uses malloc, which means that the
|
||||
backtrace functions may not be safely invoked from a signal
|
||||
handler. */
|
||||
|
||||
/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't
|
||||
report an error. */
|
||||
|
||||
void *
|
||||
backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
size_t size, backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
ret = malloc (size);
|
||||
if (ret == NULL)
|
||||
{
|
||||
if (error_callback)
|
||||
error_callback (data, "malloc", errno);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Free memory. */
|
||||
|
||||
void
|
||||
backtrace_free (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
void *p, size_t size ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
free (p);
|
||||
}
|
||||
|
||||
/* Grow VEC by SIZE bytes. */
|
||||
|
||||
void *
|
||||
backtrace_vector_grow (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
size_t size, backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_vector *vec)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (size > vec->alc)
|
||||
{
|
||||
size_t alc;
|
||||
void *base;
|
||||
|
||||
if (vec->size == 0)
|
||||
alc = 32 * size;
|
||||
else if (vec->size >= 4096)
|
||||
alc = vec->size + 4096;
|
||||
else
|
||||
alc = 2 * vec->size;
|
||||
|
||||
if (alc < vec->size + size)
|
||||
alc = vec->size + size;
|
||||
|
||||
base = realloc (vec->base, alc);
|
||||
if (base == NULL)
|
||||
{
|
||||
error_callback (data, "realloc", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec->base = base;
|
||||
vec->alc = alc - vec->size;
|
||||
}
|
||||
|
||||
ret = (char *) vec->base + vec->size;
|
||||
vec->size += size;
|
||||
vec->alc -= size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Finish the current allocation on VEC. */
|
||||
|
||||
void *
|
||||
backtrace_vector_finish (struct backtrace_state *state,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
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. */
|
||||
|
||||
int
|
||||
backtrace_vector_release (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
vec->base = realloc (vec->base, vec->size);
|
||||
if (vec->base == NULL)
|
||||
{
|
||||
error_callback (data, "realloc", errno);
|
||||
return 0;
|
||||
}
|
||||
vec->alc = 0;
|
||||
return 1;
|
||||
}
|
||||
113
atomic.c
Normal file
113
atomic.c
Normal file
@@ -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
|
||||
66
backtrace-supported.h.in
Normal file
66
backtrace-supported.h.in
Normal file
@@ -0,0 +1,66 @@
|
||||
/* backtrace-supported.h.in -- Whether stack backtrace is supported.
|
||||
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. */
|
||||
|
||||
/* The file backtrace-supported.h.in is used by configure to generate
|
||||
the file backtrace-supported.h. The file backtrace-supported.h may
|
||||
be #include'd to see whether the backtrace library will be able to
|
||||
get a backtrace and produce symbolic information. */
|
||||
|
||||
|
||||
/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library
|
||||
should work, 0 if it will not. Libraries may #include this to make
|
||||
other arrangements. */
|
||||
|
||||
#define BACKTRACE_SUPPORTED @BACKTRACE_SUPPORTED@
|
||||
|
||||
/* BACKTRACE_USES_MALLOC will be #define'd as 1 if the backtrace
|
||||
library will call malloc as it works, 0 if it will call mmap
|
||||
instead. This may be used to determine whether it is safe to call
|
||||
the backtrace functions from a signal handler. In general this
|
||||
only applies to calls like backtrace and backtrace_pcinfo. It does
|
||||
not apply to backtrace_simple, which never calls malloc. It does
|
||||
not apply to backtrace_print, which always calls fprintf and
|
||||
therefore malloc. */
|
||||
|
||||
#define BACKTRACE_USES_MALLOC @BACKTRACE_USES_MALLOC@
|
||||
|
||||
/* BACKTRACE_SUPPORTS_THREADS will be #define'd as 1 if the backtrace
|
||||
library is configured with threading support, 0 if not. If this is
|
||||
0, the threaded parameter to backtrace_create_state must be passed
|
||||
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@
|
||||
129
backtrace.c
Normal file
129
backtrace.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/* backtrace.c -- Entry point for stack backtrace library.
|
||||
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 <sys/types.h>
|
||||
|
||||
#include "unwind.h"
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* The main backtrace_full routine. */
|
||||
|
||||
/* Data passed through _Unwind_Backtrace. */
|
||||
|
||||
struct backtrace_data
|
||||
{
|
||||
/* Number of frames to skip. */
|
||||
int skip;
|
||||
/* Library state. */
|
||||
struct backtrace_state *state;
|
||||
/* Callback routine. */
|
||||
backtrace_full_callback callback;
|
||||
/* Error callback routine. */
|
||||
backtrace_error_callback error_callback;
|
||||
/* Data to pass to callback routines. */
|
||||
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
|
||||
_Unwind_Backtrace. */
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
unwind (struct _Unwind_Context *context, void *vdata)
|
||||
{
|
||||
struct backtrace_data *bdata = (struct backtrace_data *) vdata;
|
||||
uintptr_t pc;
|
||||
int ip_before_insn = 0;
|
||||
|
||||
#ifdef HAVE_GETIPINFO
|
||||
pc = _Unwind_GetIPInfo (context, &ip_before_insn);
|
||||
#else
|
||||
pc = _Unwind_GetIP (context);
|
||||
#endif
|
||||
|
||||
if (bdata->skip > 0)
|
||||
{
|
||||
--bdata->skip;
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
if (!ip_before_insn)
|
||||
--pc;
|
||||
|
||||
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;
|
||||
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
/* Get a stack backtrace. */
|
||||
|
||||
int
|
||||
backtrace_full (struct backtrace_state *state, int skip,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
struct backtrace_data bdata;
|
||||
void *p;
|
||||
|
||||
bdata.skip = skip + 1;
|
||||
bdata.state = state;
|
||||
bdata.callback = callback;
|
||||
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;
|
||||
}
|
||||
182
backtrace.h
Normal file
182
backtrace.h
Normal file
@@ -0,0 +1,182 @@
|
||||
/* backtrace.h -- Public header file for stack backtrace library.
|
||||
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. */
|
||||
|
||||
#ifndef BACKTRACE_H
|
||||
#define BACKTRACE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The backtrace state. This struct is intentionally not defined in
|
||||
the public interface. */
|
||||
|
||||
struct backtrace_state;
|
||||
|
||||
/* The type of the error callback argument to backtrace functions.
|
||||
This function, if not NULL, will be called for certain error cases.
|
||||
The DATA argument is passed to the function that calls this one.
|
||||
The MSG argument is an error message. The ERRNUM argument, if
|
||||
greater than 0, holds an errno value. The MSG buffer may become
|
||||
invalid after this function returns.
|
||||
|
||||
As a special case, the ERRNUM argument will be passed as -1 if no
|
||||
debug info can be found for the executable, but the function
|
||||
requires debug info (e.g., backtrace_full, backtrace_pcinfo). The
|
||||
MSG in this case will be something along the lines of "no debug
|
||||
info". Similarly, ERRNUM will be passed as -1 if there is no
|
||||
symbol table, but the function requires a symbol table (e.g.,
|
||||
backtrace_syminfo). This may be used as a signal that some other
|
||||
approach should be tried. */
|
||||
|
||||
typedef void (*backtrace_error_callback) (void *data, const char *msg,
|
||||
int errnum);
|
||||
|
||||
/* Create state information for the backtrace routines. This must be
|
||||
called before any of the other routines, and its return value must
|
||||
be passed to all of the other routines. FILENAME is the path name
|
||||
of the executable file; if it is NULL the library will try
|
||||
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 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. */
|
||||
|
||||
extern struct backtrace_state *backtrace_create_state (
|
||||
const char *filename, int threaded,
|
||||
backtrace_error_callback error_callback, void *data);
|
||||
|
||||
/* The type of the callback argument to the backtrace_full function.
|
||||
DATA is the argument passed to backtrace_full. PC is the program
|
||||
counter. FILENAME is the name of the file containing PC, or NULL
|
||||
if not available. LINENO is the line number in FILENAME containing
|
||||
PC, or 0 if not available. FUNCTION is the name of the function
|
||||
containing PC, or NULL if not available. This should return 0 to
|
||||
continuing tracing. The FILENAME and FUNCTION buffers may become
|
||||
invalid after this function returns. */
|
||||
|
||||
typedef int (*backtrace_full_callback) (void *data, uintptr_t pc,
|
||||
const char *filename, int lineno,
|
||||
const char *function);
|
||||
|
||||
/* Get a full stack backtrace. SKIP is the number of frames to skip;
|
||||
passing 0 will start the trace with the function calling
|
||||
backtrace_full. DATA is passed to the callback routine. If any
|
||||
call to CALLBACK returns a non-zero value, the stack backtrace
|
||||
stops, and backtrace returns that value; this may be used to limit
|
||||
the number of stack frames desired. If all calls to CALLBACK
|
||||
return 0, backtrace returns 0. The backtrace_full function will
|
||||
make at least one call to either CALLBACK or ERROR_CALLBACK. This
|
||||
function requires debug info for the executable. */
|
||||
|
||||
extern int backtrace_full (struct backtrace_state *state, int skip,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* The type of the callback argument to the backtrace_simple function.
|
||||
DATA is the argument passed to simple_backtrace. PC is the program
|
||||
counter. This should return 0 to continue tracing. */
|
||||
|
||||
typedef int (*backtrace_simple_callback) (void *data, uintptr_t pc);
|
||||
|
||||
/* Get a simple backtrace. SKIP is the number of frames to skip, as
|
||||
in backtrace. DATA is passed to the callback routine. If any call
|
||||
to CALLBACK returns a non-zero value, the stack backtrace stops,
|
||||
and backtrace_simple returns that value. Otherwise
|
||||
backtrace_simple returns 0. The backtrace_simple function will
|
||||
make at least one call to either CALLBACK or ERROR_CALLBACK. This
|
||||
function does not require any debug info for the executable. */
|
||||
|
||||
extern int backtrace_simple (struct backtrace_state *state, int skip,
|
||||
backtrace_simple_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* Print the current backtrace in a user readable format to a FILE.
|
||||
SKIP is the number of frames to skip, as in backtrace_full. Any
|
||||
error messages are printed to stderr. This function requires debug
|
||||
info for the executable. */
|
||||
|
||||
extern void backtrace_print (struct backtrace_state *state, int skip, FILE *);
|
||||
|
||||
/* Given PC, a program counter in the current program, call the
|
||||
callback function with filename, line number, and function name
|
||||
information. This will normally call the callback function exactly
|
||||
once. However, if the PC happens to describe an inlined call, and
|
||||
the debugging information contains the necessary information, then
|
||||
this may call the callback function multiple times. This will make
|
||||
at least one call to either CALLBACK or ERROR_CALLBACK. This
|
||||
returns the first non-zero value returned by CALLBACK, or 0. */
|
||||
|
||||
extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* 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 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,
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End extern "C". */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
725
btest.c
Normal file
725
btest.c
Normal file
@@ -0,0 +1,725 @@
|
||||
/* btest.c -- Test for libbacktrace library
|
||||
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. */
|
||||
|
||||
/* This program tests the externally visible interfaces of the
|
||||
libbacktrace library. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "backtrace-supported.h"
|
||||
|
||||
/* Portable attribute syntax. Actually some of these tests probably
|
||||
won't work if the attributes are not recognized. */
|
||||
|
||||
#ifndef GCC_VERSION
|
||||
# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
|
||||
#endif
|
||||
|
||||
#if (GCC_VERSION < 2007)
|
||||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__)
|
||||
# define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\')
|
||||
#else
|
||||
# define IS_DIR_SEPARATOR(c) ((c) == '/')
|
||||
#endif
|
||||
|
||||
/* Used to collect backtrace info. */
|
||||
|
||||
struct info
|
||||
{
|
||||
char *filename;
|
||||
int lineno;
|
||||
char *function;
|
||||
};
|
||||
|
||||
/* Passed to backtrace callback function. */
|
||||
|
||||
struct bdata
|
||||
{
|
||||
struct info *all;
|
||||
size_t index;
|
||||
size_t max;
|
||||
int failed;
|
||||
};
|
||||
|
||||
/* Passed to backtrace_simple callback function. */
|
||||
|
||||
struct sdata
|
||||
{
|
||||
uintptr_t *addrs;
|
||||
size_t index;
|
||||
size_t max;
|
||||
int failed;
|
||||
};
|
||||
|
||||
/* Passed to backtrace_syminfo callback function. */
|
||||
|
||||
struct symdata
|
||||
{
|
||||
const char *name;
|
||||
uintptr_t val, size;
|
||||
int failed;
|
||||
};
|
||||
|
||||
/* The backtrace state. */
|
||||
|
||||
static void *state;
|
||||
|
||||
/* The number of failures. */
|
||||
|
||||
static int failures;
|
||||
|
||||
/* Return the base name in a path. */
|
||||
|
||||
static const char *
|
||||
base (const char *p)
|
||||
{
|
||||
const char *last;
|
||||
const char *s;
|
||||
|
||||
last = NULL;
|
||||
for (s = p; *s != '\0'; ++s)
|
||||
{
|
||||
if (IS_DIR_SEPARATOR (*s))
|
||||
last = s + 1;
|
||||
}
|
||||
return last != NULL ? last : p;
|
||||
}
|
||||
|
||||
/* Check an entry in a struct info array. */
|
||||
|
||||
static void
|
||||
check (const char *name, int index, const struct info *all, int want_lineno,
|
||||
const char *want_function, int *failed)
|
||||
{
|
||||
if (*failed)
|
||||
return;
|
||||
if (all[index].filename == NULL || all[index].function == NULL)
|
||||
{
|
||||
fprintf (stderr, "%s: [%d]: missing file name or function name\n",
|
||||
name, index);
|
||||
*failed = 1;
|
||||
return;
|
||||
}
|
||||
if (strcmp (base (all[index].filename), "btest.c") != 0)
|
||||
{
|
||||
fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
|
||||
all[index].filename);
|
||||
*failed = 1;
|
||||
}
|
||||
if (all[index].lineno != want_lineno)
|
||||
{
|
||||
fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
|
||||
all[index].lineno, want_lineno);
|
||||
*failed = 1;
|
||||
}
|
||||
if (strcmp (all[index].function, want_function) != 0)
|
||||
{
|
||||
fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
|
||||
all[index].function, want_function);
|
||||
*failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The backtrace callback function. */
|
||||
|
||||
static int
|
||||
callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
|
||||
const char *filename, int lineno, const char *function)
|
||||
{
|
||||
struct bdata *data = (struct bdata *) vdata;
|
||||
struct info *p;
|
||||
|
||||
if (data->index >= data->max)
|
||||
{
|
||||
fprintf (stderr, "callback_one: callback called too many times\n");
|
||||
data->failed = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
p = &data->all[data->index];
|
||||
if (filename == NULL)
|
||||
p->filename = NULL;
|
||||
else
|
||||
{
|
||||
p->filename = strdup (filename);
|
||||
assert (p->filename != NULL);
|
||||
}
|
||||
p->lineno = lineno;
|
||||
if (function == NULL)
|
||||
p->function = NULL;
|
||||
else
|
||||
{
|
||||
p->function = strdup (function);
|
||||
assert (p->function != NULL);
|
||||
}
|
||||
++data->index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* An error callback passed to backtrace. */
|
||||
|
||||
static void
|
||||
error_callback_one (void *vdata, const char *msg, int errnum)
|
||||
{
|
||||
struct bdata *data = (struct bdata *) vdata;
|
||||
|
||||
fprintf (stderr, "%s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fprintf (stderr, "\n");
|
||||
data->failed = 1;
|
||||
}
|
||||
|
||||
/* The backtrace_simple callback function. */
|
||||
|
||||
static int
|
||||
callback_two (void *vdata, uintptr_t pc)
|
||||
{
|
||||
struct sdata *data = (struct sdata *) vdata;
|
||||
|
||||
if (data->index >= data->max)
|
||||
{
|
||||
fprintf (stderr, "callback_two: callback called too many times\n");
|
||||
data->failed = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
data->addrs[data->index] = pc;
|
||||
++data->index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* An error callback passed to backtrace_simple. */
|
||||
|
||||
static void
|
||||
error_callback_two (void *vdata, const char *msg, int errnum)
|
||||
{
|
||||
struct sdata *data = (struct sdata *) vdata;
|
||||
|
||||
fprintf (stderr, "%s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fprintf (stderr, "\n");
|
||||
data->failed = 1;
|
||||
}
|
||||
|
||||
/* The backtrace_syminfo callback function. */
|
||||
|
||||
static void
|
||||
callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
|
||||
const char *symname, uintptr_t symval,
|
||||
uintptr_t symsize)
|
||||
{
|
||||
struct symdata *data = (struct symdata *) vdata;
|
||||
|
||||
if (symname == NULL)
|
||||
data->name = NULL;
|
||||
else
|
||||
{
|
||||
data->name = strdup (symname);
|
||||
assert (data->name != NULL);
|
||||
}
|
||||
data->val = symval;
|
||||
data->size = symsize;
|
||||
}
|
||||
|
||||
/* The backtrace_syminfo error callback function. */
|
||||
|
||||
static void
|
||||
error_callback_three (void *vdata, const char *msg, int errnum)
|
||||
{
|
||||
struct symdata *data = (struct symdata *) vdata;
|
||||
|
||||
fprintf (stderr, "%s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fprintf (stderr, "\n");
|
||||
data->failed = 1;
|
||||
}
|
||||
|
||||
/* Test the backtrace function with non-inlined functions. */
|
||||
|
||||
static int test1 (void) __attribute__ ((noinline, unused));
|
||||
static int f2 (int) __attribute__ ((noinline));
|
||||
static int f3 (int, int) __attribute__ ((noinline));
|
||||
|
||||
static int
|
||||
test1 (void)
|
||||
{
|
||||
/* Returning a value here and elsewhere avoids a tailcall which
|
||||
would mess up the backtrace. */
|
||||
return f2 (__LINE__) + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
f2 (int f1line)
|
||||
{
|
||||
return f3 (f1line, __LINE__) + 2;
|
||||
}
|
||||
|
||||
static int
|
||||
f3 (int f1line, int f2line)
|
||||
{
|
||||
struct info all[20];
|
||||
struct bdata data;
|
||||
int f3line;
|
||||
int i;
|
||||
|
||||
data.all = &all[0];
|
||||
data.index = 0;
|
||||
data.max = 20;
|
||||
data.failed = 0;
|
||||
|
||||
f3line = __LINE__ + 1;
|
||||
i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr, "test1: unexpected return value %d\n", i);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
if (data.index < 3)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"test1: not enough frames; got %zu, expected at least 3\n",
|
||||
data.index);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
check ("test1", 0, all, f3line, "f3", &data.failed);
|
||||
check ("test1", 1, all, f2line, "f2", &data.failed);
|
||||
check ("test1", 2, all, f1line, "test1", &data.failed);
|
||||
|
||||
printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
|
||||
|
||||
if (data.failed)
|
||||
++failures;
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
/* Test the backtrace function with inlined functions. */
|
||||
|
||||
static inline int test2 (void) __attribute__ ((always_inline, unused));
|
||||
static inline int f12 (int) __attribute__ ((always_inline));
|
||||
static inline int f13 (int, int) __attribute__ ((always_inline));
|
||||
|
||||
static inline int
|
||||
test2 (void)
|
||||
{
|
||||
return f12 (__LINE__) + 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
f12 (int f1line)
|
||||
{
|
||||
return f13 (f1line, __LINE__) + 2;
|
||||
}
|
||||
|
||||
static inline int
|
||||
f13 (int f1line, int f2line)
|
||||
{
|
||||
struct info all[20];
|
||||
struct bdata data;
|
||||
int f3line;
|
||||
int i;
|
||||
|
||||
data.all = &all[0];
|
||||
data.index = 0;
|
||||
data.max = 20;
|
||||
data.failed = 0;
|
||||
|
||||
f3line = __LINE__ + 1;
|
||||
i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr, "test2: unexpected return value %d\n", i);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
check ("test2", 0, all, f3line, "f13", &data.failed);
|
||||
check ("test2", 1, all, f2line, "f12", &data.failed);
|
||||
check ("test2", 2, all, f1line, "test2", &data.failed);
|
||||
|
||||
printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
|
||||
|
||||
if (data.failed)
|
||||
++failures;
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
/* Test the backtrace_simple function with non-inlined functions. */
|
||||
|
||||
static int test3 (void) __attribute__ ((noinline, unused));
|
||||
static int f22 (int) __attribute__ ((noinline));
|
||||
static int f23 (int, int) __attribute__ ((noinline));
|
||||
|
||||
static int
|
||||
test3 (void)
|
||||
{
|
||||
return f22 (__LINE__) + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
f22 (int f1line)
|
||||
{
|
||||
return f23 (f1line, __LINE__) + 2;
|
||||
}
|
||||
|
||||
static int
|
||||
f23 (int f1line, int f2line)
|
||||
{
|
||||
uintptr_t addrs[20];
|
||||
struct sdata data;
|
||||
int f3line;
|
||||
int i;
|
||||
|
||||
data.addrs = &addrs[0];
|
||||
data.index = 0;
|
||||
data.max = 20;
|
||||
data.failed = 0;
|
||||
|
||||
f3line = __LINE__ + 1;
|
||||
i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr, "test3: unexpected return value %d\n", i);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
if (!data.failed)
|
||||
{
|
||||
struct info all[20];
|
||||
struct bdata bdata;
|
||||
int j;
|
||||
|
||||
bdata.all = &all[0];
|
||||
bdata.index = 0;
|
||||
bdata.max = 20;
|
||||
bdata.failed = 0;
|
||||
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
i = backtrace_pcinfo (state, addrs[j], callback_one,
|
||||
error_callback_one, &bdata);
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
("test3: unexpected return value "
|
||||
"from backtrace_pcinfo %d\n"),
|
||||
i);
|
||||
bdata.failed = 1;
|
||||
}
|
||||
if (!bdata.failed && bdata.index != (size_t) (j + 1))
|
||||
{
|
||||
fprintf (stderr,
|
||||
("wrong number of calls from backtrace_pcinfo "
|
||||
"got %u expected %d\n"),
|
||||
(unsigned int) bdata.index, j + 1);
|
||||
bdata.failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
check ("test3", 0, all, f3line, "f23", &bdata.failed);
|
||||
check ("test3", 1, all, f2line, "f22", &bdata.failed);
|
||||
check ("test3", 2, all, f1line, "test3", &bdata.failed);
|
||||
|
||||
if (bdata.failed)
|
||||
data.failed = 1;
|
||||
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
struct symdata symdata;
|
||||
|
||||
symdata.name = NULL;
|
||||
symdata.val = 0;
|
||||
symdata.size = 0;
|
||||
symdata.failed = 0;
|
||||
|
||||
i = backtrace_syminfo (state, addrs[j], callback_three,
|
||||
error_callback_three, &symdata);
|
||||
if (i == 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
("test3: [%d]: unexpected return value "
|
||||
"from backtrace_syminfo %d\n"),
|
||||
j, i);
|
||||
symdata.failed = 1;
|
||||
}
|
||||
|
||||
if (!symdata.failed)
|
||||
{
|
||||
const char *expected;
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0:
|
||||
expected = "f23";
|
||||
break;
|
||||
case 1:
|
||||
expected = "f22";
|
||||
break;
|
||||
case 2:
|
||||
expected = "test3";
|
||||
break;
|
||||
default:
|
||||
assert (0);
|
||||
}
|
||||
|
||||
if (symdata.name == NULL)
|
||||
{
|
||||
fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
|
||||
symdata.failed = 1;
|
||||
}
|
||||
/* Use strncmp, not strcmp, because GCC might create a
|
||||
clone. */
|
||||
else if (strncmp (symdata.name, expected, strlen (expected))
|
||||
!= 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
("test3: [%d]: unexpected syminfo name "
|
||||
"got %s expected %s\n"),
|
||||
j, symdata.name, expected);
|
||||
symdata.failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (symdata.failed)
|
||||
data.failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
|
||||
|
||||
if (data.failed)
|
||||
++failures;
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
/* Test the backtrace_simple function with inlined functions. */
|
||||
|
||||
static inline int test4 (void) __attribute__ ((always_inline, unused));
|
||||
static inline int f32 (int) __attribute__ ((always_inline));
|
||||
static inline int f33 (int, int) __attribute__ ((always_inline));
|
||||
|
||||
static inline int
|
||||
test4 (void)
|
||||
{
|
||||
return f32 (__LINE__) + 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
f32 (int f1line)
|
||||
{
|
||||
return f33 (f1line, __LINE__) + 2;
|
||||
}
|
||||
|
||||
static inline int
|
||||
f33 (int f1line, int f2line)
|
||||
{
|
||||
uintptr_t addrs[20];
|
||||
struct sdata data;
|
||||
int f3line;
|
||||
int i;
|
||||
|
||||
data.addrs = &addrs[0];
|
||||
data.index = 0;
|
||||
data.max = 20;
|
||||
data.failed = 0;
|
||||
|
||||
f3line = __LINE__ + 1;
|
||||
i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr, "test3: unexpected return value %d\n", i);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
if (!data.failed)
|
||||
{
|
||||
struct info all[20];
|
||||
struct bdata bdata;
|
||||
|
||||
bdata.all = &all[0];
|
||||
bdata.index = 0;
|
||||
bdata.max = 20;
|
||||
bdata.failed = 0;
|
||||
|
||||
i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
|
||||
&bdata);
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
("test4: unexpected return value "
|
||||
"from backtrace_pcinfo %d\n"),
|
||||
i);
|
||||
bdata.failed = 1;
|
||||
}
|
||||
|
||||
check ("test4", 0, all, f3line, "f33", &bdata.failed);
|
||||
check ("test4", 1, all, f2line, "f32", &bdata.failed);
|
||||
check ("test4", 2, all, f1line, "test4", &bdata.failed);
|
||||
|
||||
if (bdata.failed)
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
|
||||
|
||||
if (data.failed)
|
||||
++failures;
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
fprintf (stderr, "%s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fprintf (stderr, "\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Run all the tests. */
|
||||
|
||||
int
|
||||
main (int argc ATTRIBUTE_UNUSED, char **argv)
|
||||
{
|
||||
state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
|
||||
error_callback_create, NULL);
|
||||
|
||||
#if BACKTRACE_SUPPORTED
|
||||
test1 ();
|
||||
test2 ();
|
||||
test3 ();
|
||||
test4 ();
|
||||
#if BACKTRACE_SUPPORTS_DATA
|
||||
test5 ();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
1530
config.guess
vendored
Executable file
1530
config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
119
config.h.in
Normal file
119
config.h.in
Normal file
@@ -0,0 +1,119 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* ELF size: 32 or 64 */
|
||||
#undef BACKTRACE_ELF_SIZE
|
||||
|
||||
/* Define to 1 if you have the __atomic functions */
|
||||
#undef HAVE_ATOMIC_FUNCTIONS
|
||||
|
||||
/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_STRNLEN
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define if dl_iterate_phdr is available. */
|
||||
#undef HAVE_DL_ITERATE_PHDR
|
||||
|
||||
/* Define to 1 if you have the fcntl function */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
/* Define if getexecname is available. */
|
||||
#undef HAVE_GETEXECNAME
|
||||
|
||||
/* Define if _Unwind_GetIPInfo is available. */
|
||||
#undef HAVE_GETIPINFO
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <link.h> header file. */
|
||||
#undef HAVE_LINK_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the __sync functions */
|
||||
#undef HAVE_SYNC_FUNCTIONS
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#undef HAVE_SYS_MMAN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
#undef _POSIX_1_SOURCE
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
1773
config.sub
vendored
Executable file
1773
config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
408
configure.ac
Normal file
408
configure.ac
Normal file
@@ -0,0 +1,408 @@
|
||||
# configure.ac -- Backtrace configure script.
|
||||
# Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# (1) Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
|
||||
# (2) Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
|
||||
# (3) The name of the author may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
AC_PREREQ(2.64)
|
||||
AC_INIT(package-unused, version-unused,, libbacktrace)
|
||||
AC_CONFIG_SRCDIR(backtrace.h)
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
# with_target_subdir is used when configured as part of a GCC tree.
|
||||
if test -n "${with_target_subdir}"; then
|
||||
AM_ENABLE_MULTILIB(, ..)
|
||||
fi
|
||||
|
||||
AC_CANONICAL_SYSTEM
|
||||
target_alias=${target_alias-$host_alias}
|
||||
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
libtool_VERSION=1:0:0
|
||||
AC_SUBST(libtool_VERSION)
|
||||
|
||||
# 1.11.1: Require that version of automake.
|
||||
# foreign: Don't require README, INSTALL, NEWS, etc.
|
||||
# no-define: Don't define PACKAGE and VERSION.
|
||||
# no-dependencies: Don't generate automatic dependencies.
|
||||
# (because it breaks when using bootstrap-lean, since some of the
|
||||
# headers are gone at "make install" time).
|
||||
# -Wall: Issue all automake warnings.
|
||||
# -Wno-portability: Don't warn about constructs supported by GNU make.
|
||||
# (because GCC requires GNU make anyhow).
|
||||
AM_INIT_AUTOMAKE([1.11.1 foreign no-dist no-define no-dependencies -Wall -Wno-portability])
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AC_ARG_WITH(target-subdir,
|
||||
[ --with-target-subdir=SUBDIR Configuring in a subdirectory for target])
|
||||
|
||||
# We must force CC to /not/ be precious variables; otherwise
|
||||
# the wrong, non-multilib-adjusted value will be used in multilibs.
|
||||
# As a side effect, we have to subst CFLAGS ourselves.
|
||||
m4_rename([_AC_ARG_VAR_PRECIOUS],[backtrace_PRECIOUS])
|
||||
m4_define([_AC_ARG_VAR_PRECIOUS],[])
|
||||
AC_PROG_CC
|
||||
m4_rename_force([backtrace_PRECIOUS],[_AC_ARG_VAR_PRECIOUS])
|
||||
|
||||
AC_SUBST(CFLAGS)
|
||||
|
||||
AC_PROG_RANLIB
|
||||
|
||||
AC_PROG_AWK
|
||||
case "$AWK" in
|
||||
"") AC_MSG_ERROR([can't build without awk]) ;;
|
||||
esac
|
||||
|
||||
LT_INIT
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
backtrace_supported=yes
|
||||
|
||||
if test -n "${with_target_subdir}"; then
|
||||
# We are compiling a GCC library. We can assume that the unwind
|
||||
# library exists.
|
||||
BACKTRACE_FILE="backtrace.lo simple.lo"
|
||||
else
|
||||
AC_CHECK_HEADER([unwind.h],
|
||||
[AC_CHECK_FUNC([_Unwind_Backtrace],
|
||||
[BACKTRACE_FILE="backtrace.lo simple.lo"],
|
||||
[BACKTRACE_FILE="nounwind.lo"
|
||||
backtrace_supported=no])],
|
||||
[BACKTRACE_FILE="nounwind.lo"
|
||||
backtrace_supported=no])
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_FILE)
|
||||
|
||||
EXTRA_FLAGS=
|
||||
if test -n "${with_target_subdir}"; then
|
||||
EXTRA_FLAGS="-funwind-tables -frandom-seed=\$@"
|
||||
else
|
||||
AC_CACHE_CHECK([for -funwind-tables option],
|
||||
[libbacktrace_cv_c_unwind_tables],
|
||||
[CFLAGS_hold="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -funwind-tables"
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([static int f() { return 0; }], [return f();])],
|
||||
[libbacktrace_cv_c_unwind_tables=yes],
|
||||
[libbacktrace_cv_c_unwind_tables=no])
|
||||
CFLAGS="$CFLAGS_hold"])
|
||||
if test "$libbacktrace_cv_c_unwind_tables" = "yes"; then
|
||||
EXTRA_FLAGS=-funwind-tables
|
||||
fi
|
||||
AC_CACHE_CHECK([for -frandom-seed=string option],
|
||||
[libbacktrace_cv_c_random_seed_string],
|
||||
[CFLAGS_hold="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -frandom-seed=conftest.lo"
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([], [return 0;])],
|
||||
[libbacktrace_cv_c_random_seed_string=yes],
|
||||
[libbacktrace_cv_c_random_seed_string=no])
|
||||
CFLAGS="$CFLAGS_hold"])
|
||||
if test "$libbacktrace_cv_c_random_seed_string" = "yes"; then
|
||||
EXTRA_FLAGS="$EXTRA_FLAGS -frandom-seed=\$@"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(EXTRA_FLAGS)
|
||||
|
||||
ACX_PROG_CC_WARNING_OPTS([-W -Wall -Wwrite-strings -Wstrict-prototypes \
|
||||
-Wmissing-prototypes -Wold-style-definition \
|
||||
-Wmissing-format-attribute -Wcast-qual],
|
||||
[WARN_FLAGS])
|
||||
|
||||
if test -n "${with_target_subdir}"; then
|
||||
WARN_FLAGS="$WARN_FLAGS -Werror"
|
||||
fi
|
||||
|
||||
AC_SUBST(WARN_FLAGS)
|
||||
|
||||
if test -n "${with_target_subdir}"; then
|
||||
GCC_CHECK_UNWIND_GETIPINFO
|
||||
else
|
||||
ac_save_CFFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Werror-implicit-function-declaration"
|
||||
AC_MSG_CHECKING([for _Unwind_GetIPInfo])
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[#include "unwind.h"
|
||||
struct _Unwind_Context *context;
|
||||
int ip_before_insn = 0;],
|
||||
[return _Unwind_GetIPInfo (context, &ip_before_insn);])],
|
||||
[have_unwind_getipinfo=yes], [have_unwind_getipinfo=no])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
AC_MSG_RESULT([$have_unwind_getipinfo])
|
||||
if test "$have_unwind_getipinfo" = "yes"; then
|
||||
AC_DEFINE(HAVE_GETIPINFO, 1, [Define if _Unwind_GetIPInfo is available.])
|
||||
fi
|
||||
fi
|
||||
|
||||
# Enable --enable-host-shared.
|
||||
AC_ARG_ENABLE(host-shared,
|
||||
[AS_HELP_STRING([--enable-host-shared],
|
||||
[build host code as shared libraries])],
|
||||
[PIC_FLAG=-fPIC], [PIC_FLAG=])
|
||||
AC_SUBST(PIC_FLAG)
|
||||
|
||||
# Test for __sync support.
|
||||
AC_CACHE_CHECK([__sync extensions],
|
||||
[libbacktrace_cv_sys_sync],
|
||||
[if test -n "${with_target_subdir}"; then
|
||||
case "${host}" in
|
||||
hppa*-*-hpux*) libbacktrace_cv_sys_sync=no ;;
|
||||
*) libbacktrace_cv_sys_sync=yes ;;
|
||||
esac
|
||||
else
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([int i;],
|
||||
[__sync_bool_compare_and_swap (&i, i, i);
|
||||
__sync_lock_test_and_set (&i, 1);
|
||||
__sync_lock_release (&i);])],
|
||||
[libbacktrace_cv_sys_sync=yes],
|
||||
[libbacktrace_cv_sys_sync=no])
|
||||
fi])
|
||||
BACKTRACE_SUPPORTS_THREADS=0
|
||||
if test "$libbacktrace_cv_sys_sync" = "yes"; then
|
||||
BACKTRACE_SUPPORTS_THREADS=1
|
||||
AC_DEFINE([HAVE_SYNC_FUNCTIONS], 1,
|
||||
[Define to 1 if you have the __sync functions])
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_SUPPORTS_THREADS)
|
||||
|
||||
# Test for __atomic support.
|
||||
AC_CACHE_CHECK([__atomic extensions],
|
||||
[libbacktrace_cv_sys_atomic],
|
||||
[if test -n "${with_target_subdir}"; then
|
||||
libbacktrace_cv_sys_atomic=yes
|
||||
else
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([int i;],
|
||||
[__atomic_load_n (&i, __ATOMIC_ACQUIRE);
|
||||
__atomic_store_n (&i, 1, __ATOMIC_RELEASE);])],
|
||||
[libbacktrace_cv_sys_atomic=yes],
|
||||
[libbacktrace_cv_sys_atomic=no])
|
||||
fi])
|
||||
if test "$libbacktrace_cv_sys_atomic" = "yes"; then
|
||||
AC_DEFINE([HAVE_ATOMIC_FUNCTIONS], 1,
|
||||
[Define to 1 if you have the __atomic functions])
|
||||
fi
|
||||
|
||||
# The library needs to be able to read the executable itself. Compile
|
||||
# a file to determine the executable format. The awk script
|
||||
# filetype.awk prints out the file type.
|
||||
AC_CACHE_CHECK([output filetype],
|
||||
[libbacktrace_cv_sys_filetype],
|
||||
[filetype=
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([int i;], [int j;])],
|
||||
[filetype=`${AWK} -f $srcdir/filetype.awk conftest.$ac_objext`],
|
||||
[AC_MSG_FAILURE([compiler failed])])
|
||||
libbacktrace_cv_sys_filetype=$filetype])
|
||||
|
||||
# Match the file type to decide what files to compile.
|
||||
FORMAT_FILE=
|
||||
backtrace_supports_data=yes
|
||||
case "$libbacktrace_cv_sys_filetype" in
|
||||
elf*) FORMAT_FILE="elf.lo" ;;
|
||||
pecoff) FORMAT_FILE="pecoff.lo"
|
||||
backtrace_supports_data=no
|
||||
;;
|
||||
*) AC_MSG_WARN([could not determine output file type])
|
||||
FORMAT_FILE="unknown.lo"
|
||||
backtrace_supported=no
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(FORMAT_FILE)
|
||||
|
||||
# ELF defines.
|
||||
elfsize=
|
||||
case "$libbacktrace_cv_sys_filetype" in
|
||||
elf32) elfsize=32 ;;
|
||||
elf64) elfsize=64 ;;
|
||||
*) elfsize=unused
|
||||
esac
|
||||
AC_DEFINE_UNQUOTED([BACKTRACE_ELF_SIZE], [$elfsize], [ELF size: 32 or 64])
|
||||
|
||||
BACKTRACE_SUPPORTED=0
|
||||
if test "$backtrace_supported" = "yes"; then
|
||||
BACKTRACE_SUPPORTED=1
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_SUPPORTED)
|
||||
|
||||
BACKTRACE_SUPPORTS_DATA=0
|
||||
if test "$backtrace_supports_data" = "yes"; then
|
||||
BACKTRACE_SUPPORTS_DATA=1
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_SUPPORTS_DATA)
|
||||
|
||||
AC_CHECK_HEADERS(sys/mman.h)
|
||||
if test "$ac_cv_header_sys_mman_h" = "no"; then
|
||||
have_mmap=no
|
||||
else
|
||||
if test -n "${with_target_subdir}"; then
|
||||
# When built as a GCC target library, we can't do a link test. We
|
||||
# simply assume that if we have mman.h, we have mmap.
|
||||
have_mmap=yes
|
||||
case "${host}" in
|
||||
spu-*-*|*-*-msdosdjgpp)
|
||||
# The SPU does not have mmap, but it has a sys/mman.h header file
|
||||
# containing "mmap_eaddr" and the mmap flags, confusing the test.
|
||||
# DJGPP also has sys/man.h, but no mmap
|
||||
have_mmap=no ;;
|
||||
esac
|
||||
else
|
||||
AC_CHECK_FUNC(mmap, [have_mmap=yes], [have_mmap=no])
|
||||
fi
|
||||
fi
|
||||
if test "$have_mmap" = "no"; then
|
||||
VIEW_FILE=read.lo
|
||||
ALLOC_FILE=alloc.lo
|
||||
else
|
||||
VIEW_FILE=mmapio.lo
|
||||
AC_PREPROC_IFELSE([
|
||||
#include <sys/mman.h>
|
||||
#if !defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
|
||||
#error no MAP_ANONYMOUS
|
||||
#endif
|
||||
], [ALLOC_FILE=mmap.lo], [ALLOC_FILE=alloc.lo])
|
||||
fi
|
||||
AC_SUBST(VIEW_FILE)
|
||||
AC_SUBST(ALLOC_FILE)
|
||||
|
||||
BACKTRACE_USES_MALLOC=0
|
||||
if test "$ALLOC_FILE" = "alloc.lo"; then
|
||||
BACKTRACE_USES_MALLOC=1
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_USES_MALLOC)
|
||||
|
||||
# Check for dl_iterate_phdr.
|
||||
AC_CHECK_HEADERS(link.h)
|
||||
if test "$ac_cv_header_link_h" = "no"; then
|
||||
have_dl_iterate_phdr=no
|
||||
else
|
||||
if test -n "${with_target_subdir}"; then
|
||||
# When built as a GCC target library, we can't do a link test.
|
||||
AC_EGREP_HEADER([dl_iterate_phdr], [link.h], [have_dl_iterate_phdr=yes],
|
||||
[have_dl_iterate_phdr=no])
|
||||
case "${host}" in
|
||||
*-*-solaris2.10*)
|
||||
# Avoid dl_iterate_phdr on Solaris 10, where it is in the
|
||||
# header file but is only in -ldl.
|
||||
have_dl_iterate_phdr=no ;;
|
||||
esac
|
||||
else
|
||||
AC_CHECK_FUNC([dl_iterate_phdr], [have_dl_iterate_phdr=yes],
|
||||
[have_dl_iterate_phdr=no])
|
||||
fi
|
||||
fi
|
||||
if test "$have_dl_iterate_phdr" = "yes"; then
|
||||
AC_DEFINE(HAVE_DL_ITERATE_PHDR, 1, [Define if dl_iterate_phdr is available.])
|
||||
fi
|
||||
|
||||
# Check for the fcntl function.
|
||||
if test -n "${with_target_subdir}"; then
|
||||
case "${host}" in
|
||||
*-*-mingw*) have_fcntl=no ;;
|
||||
spu-*-*) have_fcntl=no ;;
|
||||
*) have_fcntl=yes ;;
|
||||
esac
|
||||
else
|
||||
AC_CHECK_FUNC(fcntl, [have_fcntl=yes], [have_fcntl=no])
|
||||
fi
|
||||
if test "$have_fcntl" = "yes"; then
|
||||
AC_DEFINE([HAVE_FCNTL], 1,
|
||||
[Define to 1 if you have the fcntl function])
|
||||
fi
|
||||
|
||||
AC_CHECK_DECLS(strnlen)
|
||||
|
||||
# Check for getexecname function.
|
||||
if test -n "${with_target_subdir}"; then
|
||||
case "${host}" in
|
||||
*-*-solaris2*) have_getexecname=yes ;;
|
||||
*) have_getexecname=no ;;
|
||||
esac
|
||||
else
|
||||
AC_CHECK_FUNC(getexecname, [have_getexecname=yes], [have_getexecname=no])
|
||||
fi
|
||||
if test "$have_getexecname" = "yes"; then
|
||||
AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether tests can run],
|
||||
[libbacktrace_cv_sys_native],
|
||||
[AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
|
||||
[libbacktrace_cv_sys_native=yes],
|
||||
[libbacktrace_cv_sys_native=no],
|
||||
[libbacktrace_cv_sys_native=no])])
|
||||
AM_CONDITIONAL(NATIVE, test "$libbacktrace_cv_sys_native" = "yes")
|
||||
|
||||
if test "${multilib}" = "yes"; then
|
||||
multilib_arg="--enable-multilib"
|
||||
else
|
||||
multilib_arg=
|
||||
fi
|
||||
|
||||
AC_CONFIG_FILES(Makefile backtrace-supported.h)
|
||||
|
||||
# We need multilib support, but only if configuring for the target.
|
||||
AC_CONFIG_COMMANDS([default],
|
||||
[if test -n "$CONFIG_FILES"; then
|
||||
if test -n "${with_target_subdir}"; then
|
||||
# Multilibs need MULTISUBDIR defined correctly in certain makefiles so
|
||||
# that multilib installs will end up installed in the correct place.
|
||||
# The testsuite needs it for multilib-aware ABI baseline files.
|
||||
# To work around this not being passed down from config-ml.in ->
|
||||
# srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually
|
||||
# append it here. Only modify Makefiles that have just been created.
|
||||
#
|
||||
# Also, get rid of this simulated-VPATH thing that automake does.
|
||||
cat > vpsed << \_EOF
|
||||
s!`test -f '$<' || echo '$(srcdir)/'`!!
|
||||
_EOF
|
||||
for i in $SUBDIRS; do
|
||||
case $CONFIG_FILES in
|
||||
*${i}/Makefile*)
|
||||
#echo "Adding MULTISUBDIR to $i/Makefile"
|
||||
sed -f vpsed $i/Makefile > tmp
|
||||
grep '^MULTISUBDIR =' Makefile >> tmp
|
||||
mv tmp $i/Makefile
|
||||
;;
|
||||
esac
|
||||
done
|
||||
rm vpsed
|
||||
fi
|
||||
fi
|
||||
],
|
||||
[
|
||||
# Variables needed in config.status (file generation) which aren't already
|
||||
# passed by autoconf.
|
||||
SUBDIRS="$SUBDIRS"
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
979
elf.c
Normal file
979
elf.c
Normal file
@@ -0,0 +1,979 @@
|
||||
/* elf.c -- Get debug data from an ELF file for backtraces.
|
||||
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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_DL_ITERATE_PHDR
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef HAVE_DL_ITERATE_PHDR
|
||||
|
||||
/* Dummy version of dl_iterate_phdr for systems that don't have it. */
|
||||
|
||||
#define dl_phdr_info x_dl_phdr_info
|
||||
#define dl_iterate_phdr x_dl_iterate_phdr
|
||||
|
||||
struct dl_phdr_info
|
||||
{
|
||||
uintptr_t dlpi_addr;
|
||||
const char *dlpi_name;
|
||||
};
|
||||
|
||||
static int
|
||||
dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
|
||||
size_t, void *) ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */
|
||||
|
||||
/* The configure script must tell us whether we are 32-bit or 64-bit
|
||||
ELF. We could make this code test and support either possibility,
|
||||
but there is no point. This code only works for the currently
|
||||
running executable, which means that we know the ELF mode at
|
||||
configure mode. */
|
||||
|
||||
#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64
|
||||
#error "Unknown BACKTRACE_ELF_SIZE"
|
||||
#endif
|
||||
|
||||
/* <link.h> might #include <elf.h> which might define our constants
|
||||
with slightly different values. Undefine them to be safe. */
|
||||
|
||||
#undef EI_NIDENT
|
||||
#undef EI_MAG0
|
||||
#undef EI_MAG1
|
||||
#undef EI_MAG2
|
||||
#undef EI_MAG3
|
||||
#undef EI_CLASS
|
||||
#undef EI_DATA
|
||||
#undef EI_VERSION
|
||||
#undef ELF_MAG0
|
||||
#undef ELF_MAG1
|
||||
#undef ELF_MAG2
|
||||
#undef ELF_MAG3
|
||||
#undef ELFCLASS32
|
||||
#undef ELFCLASS64
|
||||
#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. */
|
||||
|
||||
typedef uint16_t b_elf_half; /* Elf_Half. */
|
||||
typedef uint32_t b_elf_word; /* Elf_Word. */
|
||||
typedef int32_t b_elf_sword; /* Elf_Sword. */
|
||||
|
||||
#if BACKTRACE_ELF_SIZE == 32
|
||||
|
||||
typedef uint32_t b_elf_addr; /* Elf_Addr. */
|
||||
typedef uint32_t b_elf_off; /* Elf_Off. */
|
||||
|
||||
typedef uint32_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */
|
||||
|
||||
#else
|
||||
|
||||
typedef uint64_t b_elf_addr; /* Elf_Addr. */
|
||||
typedef uint64_t b_elf_off; /* Elf_Off. */
|
||||
typedef uint64_t b_elf_xword; /* Elf_Xword. */
|
||||
typedef int64_t b_elf_sxword; /* Elf_Sxword. */
|
||||
|
||||
typedef uint64_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */
|
||||
|
||||
#endif
|
||||
|
||||
/* Data structures and associated constants. */
|
||||
|
||||
#define EI_NIDENT 16
|
||||
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
|
||||
b_elf_half e_type; /* Identifies object file type */
|
||||
b_elf_half e_machine; /* Specifies required architecture */
|
||||
b_elf_word e_version; /* Identifies object file version */
|
||||
b_elf_addr e_entry; /* Entry point virtual address */
|
||||
b_elf_off e_phoff; /* Program header table file offset */
|
||||
b_elf_off e_shoff; /* Section header table file offset */
|
||||
b_elf_word e_flags; /* Processor-specific flags */
|
||||
b_elf_half e_ehsize; /* ELF header size in bytes */
|
||||
b_elf_half e_phentsize; /* Program header table entry size */
|
||||
b_elf_half e_phnum; /* Program header table entry count */
|
||||
b_elf_half e_shentsize; /* Section header table entry size */
|
||||
b_elf_half e_shnum; /* Section header table entry count */
|
||||
b_elf_half e_shstrndx; /* Section header string table index */
|
||||
} b_elf_ehdr; /* Elf_Ehdr. */
|
||||
|
||||
#define EI_MAG0 0
|
||||
#define EI_MAG1 1
|
||||
#define EI_MAG2 2
|
||||
#define EI_MAG3 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define EI_VERSION 6
|
||||
|
||||
#define ELFMAG0 0x7f
|
||||
#define ELFMAG1 'E'
|
||||
#define ELFMAG2 'L'
|
||||
#define ELFMAG3 'F'
|
||||
|
||||
#define ELFCLASS32 1
|
||||
#define ELFCLASS64 2
|
||||
|
||||
#define ELFDATA2LSB 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
#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 */
|
||||
b_elf_wxword sh_flags; /* Miscellaneous section attributes */
|
||||
b_elf_addr sh_addr; /* Section virtual addr at execution */
|
||||
b_elf_off sh_offset; /* Section file offset */
|
||||
b_elf_wxword sh_size; /* Size of section in bytes */
|
||||
b_elf_word sh_link; /* Index of another section */
|
||||
b_elf_word sh_info; /* Additional section information */
|
||||
b_elf_wxword sh_addralign; /* Section alignment */
|
||||
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 */
|
||||
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_DYNSYM 11
|
||||
|
||||
#if BACKTRACE_ELF_SIZE == 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
b_elf_word st_name; /* Symbol name, index in string tbl */
|
||||
b_elf_addr st_value; /* Symbol value */
|
||||
b_elf_word st_size; /* Symbol size */
|
||||
unsigned char st_info; /* Symbol binding and type */
|
||||
unsigned char st_other; /* Visibility and other data */
|
||||
b_elf_half st_shndx; /* Symbol section index */
|
||||
} b_elf_sym; /* Elf_Sym. */
|
||||
|
||||
#else /* BACKTRACE_ELF_SIZE != 32 */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
b_elf_word st_name; /* Symbol name, index in string tbl */
|
||||
unsigned char st_info; /* Symbol binding and type */
|
||||
unsigned char st_other; /* Visibility and other data */
|
||||
b_elf_half st_shndx; /* Symbol section index */
|
||||
b_elf_addr st_value; /* Symbol value */
|
||||
b_elf_xword st_size; /* Symbol size */
|
||||
} b_elf_sym; /* Elf_Sym. */
|
||||
|
||||
#endif /* BACKTRACE_ELF_SIZE != 32 */
|
||||
|
||||
#define STT_OBJECT 1
|
||||
#define STT_FUNC 2
|
||||
|
||||
/* An index of ELF 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 elf_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 ELF symbol. */
|
||||
|
||||
struct elf_symbol
|
||||
{
|
||||
/* The name of the symbol. */
|
||||
const char *name;
|
||||
/* The address of the symbol. */
|
||||
uintptr_t address;
|
||||
/* The size of the symbol. */
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* Information to pass to elf_syminfo. */
|
||||
|
||||
struct elf_syminfo_data
|
||||
{
|
||||
/* Symbols for the next module. */
|
||||
struct elf_syminfo_data *next;
|
||||
/* The ELF symbols, sorted by address. */
|
||||
struct elf_symbol *symbols;
|
||||
/* The number of symbols. */
|
||||
size_t count;
|
||||
};
|
||||
|
||||
/* A dummy callback function used when we can't find any debug info. */
|
||||
|
||||
static int
|
||||
elf_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 ELF executable", -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A dummy callback function used when we can't find a symbol
|
||||
table. */
|
||||
|
||||
static void
|
||||
elf_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 ELF executable", -1);
|
||||
}
|
||||
|
||||
/* Compare struct elf_symbol for qsort. */
|
||||
|
||||
static int
|
||||
elf_symbol_compare (const void *v1, const void *v2)
|
||||
{
|
||||
const struct elf_symbol *e1 = (const struct elf_symbol *) v1;
|
||||
const struct elf_symbol *e2 = (const struct elf_symbol *) v2;
|
||||
|
||||
if (e1->address < e2->address)
|
||||
return -1;
|
||||
else if (e1->address > e2->address)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare an ADDR against an elf_symbol for bsearch. We allocate one
|
||||
extra entry in the array so that this can look safely at the next
|
||||
entry. */
|
||||
|
||||
static int
|
||||
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 addr;
|
||||
|
||||
addr = *key;
|
||||
if (addr < entry->address)
|
||||
return -1;
|
||||
else if (addr >= entry->address + entry->size)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize the symbol table info for elf_syminfo. */
|
||||
|
||||
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,
|
||||
void *data, struct elf_syminfo_data *sdata)
|
||||
{
|
||||
size_t sym_count;
|
||||
const b_elf_sym *sym;
|
||||
size_t elf_symbol_count;
|
||||
size_t elf_symbol_size;
|
||||
struct elf_symbol *elf_symbols;
|
||||
size_t i;
|
||||
unsigned int j;
|
||||
|
||||
sym_count = symtab_size / sizeof (b_elf_sym);
|
||||
|
||||
/* We only care about function symbols. Count them. */
|
||||
sym = (const b_elf_sym *) symtab_data;
|
||||
elf_symbol_count = 0;
|
||||
for (i = 0; i < sym_count; ++i, ++sym)
|
||||
{
|
||||
int info;
|
||||
|
||||
info = sym->st_info & 0xf;
|
||||
if ((info == STT_FUNC || info == STT_OBJECT)
|
||||
&& sym->st_shndx != SHN_UNDEF)
|
||||
++elf_symbol_count;
|
||||
}
|
||||
|
||||
elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol);
|
||||
elf_symbols = ((struct elf_symbol *)
|
||||
backtrace_alloc (state, elf_symbol_size, error_callback,
|
||||
data));
|
||||
if (elf_symbols == NULL)
|
||||
return 0;
|
||||
|
||||
sym = (const b_elf_sym *) symtab_data;
|
||||
j = 0;
|
||||
for (i = 0; i < sym_count; ++i, ++sym)
|
||||
{
|
||||
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)
|
||||
{
|
||||
error_callback (data, "symbol string index out of range", 0);
|
||||
backtrace_free (state, elf_symbols, elf_symbol_size, error_callback,
|
||||
data);
|
||||
return 0;
|
||||
}
|
||||
elf_symbols[j].name = (const char *) strtab + sym->st_name;
|
||||
elf_symbols[j].address = sym->st_value + base_address;
|
||||
elf_symbols[j].size = sym->st_size;
|
||||
++j;
|
||||
}
|
||||
|
||||
backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),
|
||||
elf_symbol_compare);
|
||||
|
||||
sdata->next = NULL;
|
||||
sdata->symbols = elf_symbols;
|
||||
sdata->count = elf_symbol_count;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Add EDATA to the list in STATE. */
|
||||
|
||||
static void
|
||||
elf_add_syminfo_data (struct backtrace_state *state,
|
||||
struct elf_syminfo_data *edata)
|
||||
{
|
||||
if (!state->threaded)
|
||||
{
|
||||
struct elf_syminfo_data **pp;
|
||||
|
||||
for (pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
|
||||
*pp != NULL;
|
||||
pp = &(*pp)->next)
|
||||
;
|
||||
*pp = edata;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
struct elf_syminfo_data **pp;
|
||||
|
||||
pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct elf_syminfo_data *p;
|
||||
|
||||
p = backtrace_atomic_load_pointer (pp);
|
||||
|
||||
if (p == NULL)
|
||||
break;
|
||||
|
||||
pp = &p->next;
|
||||
}
|
||||
|
||||
if (__sync_bool_compare_and_swap (pp, NULL, edata))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the symbol name and value for an ADDR. */
|
||||
|
||||
static void
|
||||
elf_syminfo (struct backtrace_state *state, uintptr_t addr,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data)
|
||||
{
|
||||
struct elf_syminfo_data *edata;
|
||||
struct elf_symbol *sym = NULL;
|
||||
|
||||
if (!state->threaded)
|
||||
{
|
||||
for (edata = (struct elf_syminfo_data *) state->syminfo_data;
|
||||
edata != NULL;
|
||||
edata = edata->next)
|
||||
{
|
||||
sym = ((struct elf_symbol *)
|
||||
bsearch (&addr, edata->symbols, edata->count,
|
||||
sizeof (struct elf_symbol), elf_symbol_search));
|
||||
if (sym != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct elf_syminfo_data **pp;
|
||||
|
||||
pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
|
||||
while (1)
|
||||
{
|
||||
edata = backtrace_atomic_load_pointer (pp);
|
||||
if (edata == NULL)
|
||||
break;
|
||||
|
||||
sym = ((struct elf_symbol *)
|
||||
bsearch (&addr, edata->symbols, edata->count,
|
||||
sizeof (struct elf_symbol), elf_symbol_search));
|
||||
if (sym != NULL)
|
||||
break;
|
||||
|
||||
pp = &edata->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (sym == NULL)
|
||||
callback (data, addr, NULL, 0, 0);
|
||||
else
|
||||
callback (data, addr, sym->name, sym->address, sym->size);
|
||||
}
|
||||
|
||||
/* 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, int exe)
|
||||
{
|
||||
struct backtrace_view ehdr_view;
|
||||
b_elf_ehdr ehdr;
|
||||
off_t shoff;
|
||||
unsigned int shnum;
|
||||
unsigned int shstrndx;
|
||||
struct backtrace_view shdrs_view;
|
||||
int shdrs_view_valid;
|
||||
const b_elf_shdr *shdrs;
|
||||
const b_elf_shdr *shstrhdr;
|
||||
size_t shstr_size;
|
||||
off_t shstr_off;
|
||||
struct backtrace_view names_view;
|
||||
int names_view_valid;
|
||||
const char *names;
|
||||
unsigned int symtab_shndx;
|
||||
unsigned int dynsym_shndx;
|
||||
unsigned int i;
|
||||
struct debug_section_info sections[DEBUG_MAX];
|
||||
struct backtrace_view symtab_view;
|
||||
int symtab_view_valid;
|
||||
struct backtrace_view strtab_view;
|
||||
int strtab_view_valid;
|
||||
off_t min_offset;
|
||||
off_t max_offset;
|
||||
struct backtrace_view debug_view;
|
||||
int debug_view_valid;
|
||||
|
||||
*found_sym = 0;
|
||||
*found_dwarf = 0;
|
||||
|
||||
shdrs_view_valid = 0;
|
||||
names_view_valid = 0;
|
||||
symtab_view_valid = 0;
|
||||
strtab_view_valid = 0;
|
||||
debug_view_valid = 0;
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
|
||||
data, &ehdr_view))
|
||||
goto fail;
|
||||
|
||||
memcpy (&ehdr, ehdr_view.data, sizeof ehdr);
|
||||
|
||||
backtrace_release_view (state, &ehdr_view, error_callback, data);
|
||||
|
||||
if (ehdr.e_ident[EI_MAG0] != ELFMAG0
|
||||
|| ehdr.e_ident[EI_MAG1] != ELFMAG1
|
||||
|| ehdr.e_ident[EI_MAG2] != ELFMAG2
|
||||
|| ehdr.e_ident[EI_MAG3] != ELFMAG3)
|
||||
{
|
||||
error_callback (data, "executable file is not ELF", 0);
|
||||
goto fail;
|
||||
}
|
||||
if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
|
||||
{
|
||||
error_callback (data, "executable file is unrecognized ELF version", 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#if BACKTRACE_ELF_SIZE == 32
|
||||
#define BACKTRACE_ELFCLASS ELFCLASS32
|
||||
#else
|
||||
#define BACKTRACE_ELFCLASS ELFCLASS64
|
||||
#endif
|
||||
|
||||
if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS)
|
||||
{
|
||||
error_callback (data, "executable file is unexpected ELF class", 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB
|
||||
&& ehdr.e_ident[EI_DATA] != ELFDATA2MSB)
|
||||
{
|
||||
error_callback (data, "executable file has unknown endianness", 0);
|
||||
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;
|
||||
|
||||
if ((shnum == 0 || shstrndx == SHN_XINDEX)
|
||||
&& shoff != 0)
|
||||
{
|
||||
struct backtrace_view shdr_view;
|
||||
const b_elf_shdr *shdr;
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr,
|
||||
error_callback, data, &shdr_view))
|
||||
goto fail;
|
||||
|
||||
shdr = (const b_elf_shdr *) shdr_view.data;
|
||||
|
||||
if (shnum == 0)
|
||||
shnum = shdr->sh_size;
|
||||
|
||||
if (shstrndx == SHN_XINDEX)
|
||||
{
|
||||
shstrndx = shdr->sh_link;
|
||||
|
||||
/* Versions of the GNU binutils between 2.12 and 2.18 did
|
||||
not handle objects with more than SHN_LORESERVE sections
|
||||
correctly. All large section indexes were offset by
|
||||
0x100. There is more information at
|
||||
http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
|
||||
Fortunately these object files are easy to detect, as the
|
||||
GNU binutils always put the section header string table
|
||||
near the end of the list of sections. Thus if the
|
||||
section header string table index is larger than the
|
||||
number of sections, then we know we have to subtract
|
||||
0x100 to get the real section index. */
|
||||
if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100)
|
||||
shstrndx -= 0x100;
|
||||
}
|
||||
|
||||
backtrace_release_view (state, &shdr_view, error_callback, data);
|
||||
}
|
||||
|
||||
/* To translate PC to file/line when using DWARF, we need to find
|
||||
the .debug_info and .debug_line sections. */
|
||||
|
||||
/* Read the section headers, skipping the first one. */
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr),
|
||||
(shnum - 1) * sizeof (b_elf_shdr),
|
||||
error_callback, data, &shdrs_view))
|
||||
goto fail;
|
||||
shdrs_view_valid = 1;
|
||||
shdrs = (const b_elf_shdr *) shdrs_view.data;
|
||||
|
||||
/* Read the section names. */
|
||||
|
||||
shstrhdr = &shdrs[shstrndx - 1];
|
||||
shstr_size = shstrhdr->sh_size;
|
||||
shstr_off = shstrhdr->sh_offset;
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, shstr_off, shstr_size,
|
||||
error_callback, data, &names_view))
|
||||
goto fail;
|
||||
names_view_valid = 1;
|
||||
names = (const char *) names_view.data;
|
||||
|
||||
symtab_shndx = 0;
|
||||
dynsym_shndx = 0;
|
||||
|
||||
memset (sections, 0, sizeof sections);
|
||||
|
||||
/* Look for the symbol table. */
|
||||
for (i = 1; i < shnum; ++i)
|
||||
{
|
||||
const b_elf_shdr *shdr;
|
||||
unsigned int sh_name;
|
||||
const char *name;
|
||||
int j;
|
||||
|
||||
shdr = &shdrs[i - 1];
|
||||
|
||||
if (shdr->sh_type == SHT_SYMTAB)
|
||||
symtab_shndx = i;
|
||||
else if (shdr->sh_type == SHT_DYNSYM)
|
||||
dynsym_shndx = i;
|
||||
|
||||
sh_name = shdr->sh_name;
|
||||
if (sh_name >= shstr_size)
|
||||
{
|
||||
error_callback (data, "ELF section name out of range", 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
name = names + sh_name;
|
||||
|
||||
for (j = 0; j < (int) DEBUG_MAX; ++j)
|
||||
{
|
||||
if (strcmp (name, debug_section_names[j]) == 0)
|
||||
{
|
||||
sections[j].offset = shdr->sh_offset;
|
||||
sections[j].size = shdr->sh_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (symtab_shndx == 0)
|
||||
symtab_shndx = dynsym_shndx;
|
||||
if (symtab_shndx != 0)
|
||||
{
|
||||
const b_elf_shdr *symtab_shdr;
|
||||
unsigned int strtab_shndx;
|
||||
const b_elf_shdr *strtab_shdr;
|
||||
struct elf_syminfo_data *sdata;
|
||||
|
||||
symtab_shdr = &shdrs[symtab_shndx - 1];
|
||||
strtab_shndx = symtab_shdr->sh_link;
|
||||
if (strtab_shndx >= shnum)
|
||||
{
|
||||
error_callback (data,
|
||||
"ELF symbol table strtab link out of range", 0);
|
||||
goto fail;
|
||||
}
|
||||
strtab_shdr = &shdrs[strtab_shndx - 1];
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset,
|
||||
symtab_shdr->sh_size, error_callback, data,
|
||||
&symtab_view))
|
||||
goto fail;
|
||||
symtab_view_valid = 1;
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset,
|
||||
strtab_shdr->sh_size, error_callback, data,
|
||||
&strtab_view))
|
||||
goto fail;
|
||||
strtab_view_valid = 1;
|
||||
|
||||
sdata = ((struct elf_syminfo_data *)
|
||||
backtrace_alloc (state, sizeof *sdata, error_callback, data));
|
||||
if (sdata == NULL)
|
||||
goto fail;
|
||||
|
||||
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))
|
||||
{
|
||||
backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We no longer need the symbol table, but we hold on to the
|
||||
string table permanently. */
|
||||
backtrace_release_view (state, &symtab_view, error_callback, data);
|
||||
|
||||
*found_sym = 1;
|
||||
|
||||
elf_add_syminfo_data (state, sdata);
|
||||
}
|
||||
|
||||
/* FIXME: Need to handle compressed debug sections. */
|
||||
|
||||
backtrace_release_view (state, &shdrs_view, error_callback, data);
|
||||
shdrs_view_valid = 0;
|
||||
backtrace_release_view (state, &names_view, error_callback, data);
|
||||
names_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;
|
||||
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,
|
||||
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,
|
||||
ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
|
||||
error_callback, data, fileline_fn))
|
||||
goto fail;
|
||||
|
||||
*found_dwarf = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (shdrs_view_valid)
|
||||
backtrace_release_view (state, &shdrs_view, error_callback, data);
|
||||
if (names_view_valid)
|
||||
backtrace_release_view (state, &names_view, error_callback, data);
|
||||
if (symtab_view_valid)
|
||||
backtrace_release_view (state, &symtab_view, error_callback, data);
|
||||
if (strtab_view_valid)
|
||||
backtrace_release_view (state, &strtab_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;
|
||||
}
|
||||
|
||||
/* Data passed to phdr_callback. */
|
||||
|
||||
struct phdr_data
|
||||
{
|
||||
struct backtrace_state *state;
|
||||
backtrace_error_callback error_callback;
|
||||
void *data;
|
||||
fileline *fileline_fn;
|
||||
int *found_sym;
|
||||
int *found_dwarf;
|
||||
int exe_descriptor;
|
||||
};
|
||||
|
||||
/* Callback passed to dl_iterate_phdr. Load debug info from shared
|
||||
libraries. */
|
||||
|
||||
static int
|
||||
#ifdef __i386__
|
||||
__attribute__ ((__force_align_arg_pointer__))
|
||||
#endif
|
||||
phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
|
||||
void *pdata)
|
||||
{
|
||||
struct phdr_data *pd = (struct phdr_data *) pdata;
|
||||
int descriptor;
|
||||
int does_not_exist;
|
||||
fileline elf_fileline_fn;
|
||||
int found_dwarf;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback,
|
||||
pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, 0))
|
||||
{
|
||||
if (found_dwarf)
|
||||
{
|
||||
*pd->found_dwarf = 1;
|
||||
*pd->fileline_fn = elf_fileline_fn;
|
||||
}
|
||||
}
|
||||
|
||||
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 elf_fileline_fn = elf_nodebug;
|
||||
struct phdr_data pd;
|
||||
|
||||
ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
|
||||
&found_sym, &found_dwarf, 1);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
pd.state = state;
|
||||
pd.error_callback = error_callback;
|
||||
pd.data = data;
|
||||
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);
|
||||
|
||||
if (!state->threaded)
|
||||
{
|
||||
if (found_sym)
|
||||
state->syminfo_fn = elf_syminfo;
|
||||
else if (state->syminfo_fn == NULL)
|
||||
state->syminfo_fn = elf_nosyms;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found_sym)
|
||||
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)
|
||||
{
|
||||
if (state->fileline_fn == NULL || state->fileline_fn == elf_nodebug)
|
||||
*fileline_fn = elf_fileline_fn;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileline current_fn;
|
||||
|
||||
current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
|
||||
if (current_fn == NULL || current_fn == elf_nodebug)
|
||||
*fileline_fn = elf_fileline_fn;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
194
fileline.c
Normal file
194
fileline.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/* fileline.c -- Get file and line number information in a backtrace.
|
||||
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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef HAVE_GETEXECNAME
|
||||
#define getexecname() NULL
|
||||
#endif
|
||||
|
||||
/* Initialize the fileline information from the executable. Returns 1
|
||||
on success, 0 on failure. */
|
||||
|
||||
static int
|
||||
fileline_initialize (struct backtrace_state *state,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
int failed;
|
||||
fileline fileline_fn;
|
||||
int pass;
|
||||
int called_error_callback;
|
||||
int descriptor;
|
||||
|
||||
if (!state->threaded)
|
||||
failed = state->fileline_initialization_failed;
|
||||
else
|
||||
failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
|
||||
|
||||
if (failed)
|
||||
{
|
||||
error_callback (data, "failed to read executable information", -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!state->threaded)
|
||||
fileline_fn = state->fileline_fn;
|
||||
else
|
||||
fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
|
||||
if (fileline_fn != NULL)
|
||||
return 1;
|
||||
|
||||
/* We have not initialized the information. Do it now. */
|
||||
|
||||
descriptor = -1;
|
||||
called_error_callback = 0;
|
||||
for (pass = 0; pass < 4; ++pass)
|
||||
{
|
||||
const char *filename;
|
||||
int does_not_exist;
|
||||
|
||||
switch (pass)
|
||||
{
|
||||
case 0:
|
||||
filename = state->filename;
|
||||
break;
|
||||
case 1:
|
||||
filename = getexecname ();
|
||||
break;
|
||||
case 2:
|
||||
filename = "/proc/self/exe";
|
||||
break;
|
||||
case 3:
|
||||
filename = "/proc/curproc/file";
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (filename == NULL)
|
||||
continue;
|
||||
|
||||
descriptor = backtrace_open (filename, error_callback, data,
|
||||
&does_not_exist);
|
||||
if (descriptor < 0 && !does_not_exist)
|
||||
{
|
||||
called_error_callback = 1;
|
||||
break;
|
||||
}
|
||||
if (descriptor >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (descriptor < 0)
|
||||
{
|
||||
if (!called_error_callback)
|
||||
{
|
||||
if (state->filename != NULL)
|
||||
error_callback (data, state->filename, ENOENT);
|
||||
else
|
||||
error_callback (data,
|
||||
"libbacktrace could not find executable to open",
|
||||
0);
|
||||
}
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
if (!failed)
|
||||
{
|
||||
if (!backtrace_initialize (state, descriptor, error_callback, data,
|
||||
&fileline_fn))
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
{
|
||||
if (!state->threaded)
|
||||
state->fileline_initialization_failed = 1;
|
||||
else
|
||||
backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!state->threaded)
|
||||
state->fileline_fn = fileline_fn;
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* Given a PC, find the file name, line number, and function name. */
|
||||
|
||||
int
|
||||
backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
if (!fileline_initialize (state, error_callback, data))
|
||||
return 0;
|
||||
|
||||
if (state->fileline_initialization_failed)
|
||||
return 0;
|
||||
|
||||
return state->fileline_fn (state, pc, callback, error_callback, data);
|
||||
}
|
||||
|
||||
/* Given a PC, find the symbol for it, and its value. */
|
||||
|
||||
int
|
||||
backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
if (!fileline_initialize (state, error_callback, data))
|
||||
return 0;
|
||||
|
||||
if (state->fileline_initialization_failed)
|
||||
return 0;
|
||||
|
||||
state->syminfo_fn (state, pc, callback, error_callback, data);
|
||||
return 1;
|
||||
}
|
||||
5
filetype.awk
Normal file
5
filetype.awk
Normal file
@@ -0,0 +1,5 @@
|
||||
# An awk script to determine the type of a file.
|
||||
/\177ELF\001/ { if (NR == 1) { print "elf32"; exit } }
|
||||
/\177ELF\002/ { if (NR == 1) { print "elf64"; exit } }
|
||||
/\114\001/ { if (NR == 1) { print "pecoff"; exit } }
|
||||
/\144\206/ { if (NR == 1) { print "pecoff"; exit } }
|
||||
527
install-sh
Executable file
527
install-sh
Executable file
@@ -0,0 +1,527 @@
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2011-01-19.21; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
nl='
|
||||
'
|
||||
IFS=" "" $nl"
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit=${DOITPROG-}
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_glob='?'
|
||||
initialize_posix_glob='
|
||||
test "$posix_glob" != "?" || {
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=
|
||||
else
|
||||
posix_glob=:
|
||||
fi
|
||||
}
|
||||
'
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
no_target_directory=
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call `install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writeable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
eval "$initialize_posix_glob"
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
$posix_glob set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
$posix_glob set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
|
||||
eval "$initialize_posix_glob" &&
|
||||
$posix_glob set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
$posix_glob set +f &&
|
||||
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
294
internal.h
Normal file
294
internal.h
Normal file
@@ -0,0 +1,294 @@
|
||||
/* internal.h -- Internal header file for stack backtrace library.
|
||||
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. */
|
||||
|
||||
#ifndef BACKTRACE_INTERNAL_H
|
||||
#define BACKTRACE_INTERNAL_H
|
||||
|
||||
/* We assume that <sys/types.h> and "backtrace.h" have already been
|
||||
included. */
|
||||
|
||||
#ifndef GCC_VERSION
|
||||
# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
|
||||
#endif
|
||||
|
||||
#if (GCC_VERSION < 2007)
|
||||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_MALLOC
|
||||
# if (GCC_VERSION >= 2096)
|
||||
# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
|
||||
# else
|
||||
# define ATTRIBUTE_MALLOC
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SYNC_FUNCTIONS
|
||||
|
||||
/* Define out the sync functions. These should never be called if
|
||||
they are not available. */
|
||||
|
||||
#define __sync_bool_compare_and_swap(A, B, C) (abort(), 1)
|
||||
#define __sync_lock_test_and_set(A, B) (abort(), 0)
|
||||
#define __sync_lock_release(A) abort()
|
||||
|
||||
#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. */
|
||||
|
||||
typedef int (*fileline) (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback, void *data);
|
||||
|
||||
/* The type of the function that collects symbol information. This is
|
||||
like backtrace_syminfo. */
|
||||
|
||||
typedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback, void *data);
|
||||
|
||||
/* What the backtrace state pointer points to. */
|
||||
|
||||
struct backtrace_state
|
||||
{
|
||||
/* The name of the executable. */
|
||||
const char *filename;
|
||||
/* Non-zero if threaded. */
|
||||
int threaded;
|
||||
/* The master lock for fileline_fn, fileline_data, syminfo_fn,
|
||||
syminfo_data, fileline_initialization_failed and everything the
|
||||
data pointers point to. */
|
||||
void *lock;
|
||||
/* The function that returns file/line information. */
|
||||
fileline fileline_fn;
|
||||
/* The data to pass to FILELINE_FN. */
|
||||
void *fileline_data;
|
||||
/* The function that returns symbol information. */
|
||||
syminfo syminfo_fn;
|
||||
/* The data to pass to SYMINFO_FN. */
|
||||
void *syminfo_data;
|
||||
/* Whether initializing the file/line information failed. */
|
||||
int fileline_initialization_failed;
|
||||
/* The lock for the freelist. */
|
||||
int lock_alloc;
|
||||
/* The freelist when using mmap. */
|
||||
struct backtrace_freelist_struct *freelist;
|
||||
};
|
||||
|
||||
/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST
|
||||
is not NULL, *DOES_NOT_EXIST will be set to 0 normally and set to 1
|
||||
if the file does not exist. If the file does not exist and
|
||||
DOES_NOT_EXIST is not NULL, the function will return -1 and will
|
||||
not call ERROR_CALLBACK. On other errors, or if DOES_NOT_EXIST is
|
||||
NULL, the function will call ERROR_CALLBACK before returning. */
|
||||
extern int backtrace_open (const char *filename,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data,
|
||||
int *does_not_exist);
|
||||
|
||||
/* A view of the contents of a file. This supports mmap when
|
||||
available. A view will remain in memory even after backtrace_close
|
||||
is called on the file descriptor from which the view was
|
||||
obtained. */
|
||||
|
||||
struct backtrace_view
|
||||
{
|
||||
/* The data that the caller requested. */
|
||||
const void *data;
|
||||
/* The base of the view. */
|
||||
void *base;
|
||||
/* The total length of the view. */
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. Store the
|
||||
result in *VIEW. Returns 1 on success, 0 on error. */
|
||||
extern int backtrace_get_view (struct backtrace_state *state, int descriptor,
|
||||
off_t offset, size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_view *view);
|
||||
|
||||
/* Release a view created by backtrace_get_view. */
|
||||
extern void backtrace_release_view (struct backtrace_state *state,
|
||||
struct backtrace_view *view,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* Close a file opened by backtrace_open. Returns 1 on success, 0 on
|
||||
error. */
|
||||
|
||||
extern int backtrace_close (int descriptor,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* 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. If ERROR_CALLBACK is
|
||||
NULL, this does not report an error. */
|
||||
|
||||
extern void backtrace_free (struct backtrace_state *state, void *mem,
|
||||
size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* A growable vector of some struct. This is used for more efficient
|
||||
allocation when we don't know the final size of some group of data
|
||||
that we want to represent as an array. */
|
||||
|
||||
struct backtrace_vector
|
||||
{
|
||||
/* The base of the vector. */
|
||||
void *base;
|
||||
/* The number of bytes in the vector. */
|
||||
size_t size;
|
||||
/* The number of bytes available at the current allocation. */
|
||||
size_t alc;
|
||||
};
|
||||
|
||||
/* Grow VEC by SIZE bytes. Return a pointer to the newly allocated
|
||||
bytes. Note that this may move the entire vector to a new memory
|
||||
location. Returns NULL on failure. */
|
||||
|
||||
extern void *backtrace_vector_grow (struct backtrace_state *state, size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data,
|
||||
struct backtrace_vector *vec);
|
||||
|
||||
/* Finish the current allocation on VEC. Prepare to start a new
|
||||
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,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* 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,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* Read initial debug data from a descriptor, and set the
|
||||
fileline_data, syminfo_fn, and syminfo_data fields of STATE.
|
||||
Return the fileln_fn field in *FILELN_FN--this is done this way so
|
||||
that the synchronization code is only implemented once. This is
|
||||
called after the descriptor has first been opened. It will close
|
||||
the descriptor if it is no longer needed. Returns 1 on success, 0
|
||||
on error. There will be multiple implementations of this function,
|
||||
for different file formats. Each system will compile the
|
||||
appropriate one. */
|
||||
|
||||
extern int backtrace_initialize (struct backtrace_state *state,
|
||||
int descriptor,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data,
|
||||
fileline *fileline_fn);
|
||||
|
||||
/* Add file/line information for a DWARF module. */
|
||||
|
||||
extern int backtrace_dwarf_add (struct backtrace_state *state,
|
||||
uintptr_t base_address,
|
||||
const unsigned char* dwarf_info,
|
||||
size_t dwarf_info_size,
|
||||
const unsigned char *dwarf_line,
|
||||
size_t dwarf_line_size,
|
||||
const unsigned char *dwarf_abbrev,
|
||||
size_t dwarf_abbrev_size,
|
||||
const unsigned char *dwarf_ranges,
|
||||
size_t dwarf_range_size,
|
||||
const unsigned char *dwarf_str,
|
||||
size_t dwarf_str_size,
|
||||
int is_bigendian,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, fileline *fileline_fn);
|
||||
|
||||
#endif
|
||||
331
missing
Executable file
331
missing
Executable file
@@ -0,0 +1,331 @@
|
||||
#! /bin/sh
|
||||
# Common stub for a few missing GNU programs while installing.
|
||||
|
||||
scriptversion=2012-01-06.13; # UTC
|
||||
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
|
||||
# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
|
||||
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try \`$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run=:
|
||||
sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
|
||||
sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
|
||||
|
||||
# In the cases where this matters, `missing' is being run in the
|
||||
# srcdir already.
|
||||
if test -f configure.ac; then
|
||||
configure_ac=configure.ac
|
||||
else
|
||||
configure_ac=configure.in
|
||||
fi
|
||||
|
||||
msg="missing on your system"
|
||||
|
||||
case $1 in
|
||||
--run)
|
||||
# Try to run requested program, and just exit if it succeeds.
|
||||
run=
|
||||
shift
|
||||
"$@" && exit 0
|
||||
# Exit code 63 means version mismatch. This often happens
|
||||
# when the user try to use an ancient version of a tool on
|
||||
# a file that requires a minimum version. In this case we
|
||||
# we should proceed has if the program had been absent, or
|
||||
# if --run hadn't been passed.
|
||||
if test $? = 63; then
|
||||
run=:
|
||||
msg="probably too old"
|
||||
fi
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
|
||||
error status if there is no known handling for PROGRAM.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
--run try to run the given command, and emulate it if it fails
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal touch file \`aclocal.m4'
|
||||
autoconf touch file \`configure'
|
||||
autoheader touch file \`config.h.in'
|
||||
autom4te touch the output file, or create a stub one
|
||||
automake touch all \`Makefile.in' files
|
||||
bison create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||
flex create \`lex.yy.c', if possible, from existing .c
|
||||
help2man touch the output file
|
||||
lex create \`lex.yy.c', if possible, from existing .c
|
||||
makeinfo touch the output file
|
||||
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
|
||||
\`g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: Unknown \`$1' option"
|
||||
echo 1>&2 "Try \`$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# normalize program name to check for.
|
||||
program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
# Now exit if we have it, but it failed. Also exit now if we
|
||||
# don't have it and --version was passed (most likely to detect
|
||||
# the program). This is about non-GNU programs, so use $1 not
|
||||
# $program.
|
||||
case $1 in
|
||||
lex*|yacc*)
|
||||
# Not GNU programs, they don't have --version.
|
||||
;;
|
||||
|
||||
*)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
exit 1
|
||||
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
|
||||
# Could not run --version or --help. This is probably someone
|
||||
# running `$TOOL --version' or `$TOOL --help' to check whether
|
||||
# $TOOL exists and not knowing $TOOL uses missing.
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# If it does not exist, or fails to run (possibly an outdated version),
|
||||
# try to emulate it.
|
||||
case $program in
|
||||
aclocal*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
|
||||
to install the \`Automake' and \`Perl' packages. Grab them from
|
||||
any GNU archive site."
|
||||
touch aclocal.m4
|
||||
;;
|
||||
|
||||
autoconf*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`${configure_ac}'. You might want to install the
|
||||
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
|
||||
archive site."
|
||||
touch configure
|
||||
;;
|
||||
|
||||
autoheader*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`acconfig.h' or \`${configure_ac}'. You might want
|
||||
to install the \`Autoconf' and \`GNU m4' packages. Grab them
|
||||
from any GNU archive site."
|
||||
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
|
||||
test -z "$files" && files="config.h"
|
||||
touch_files=
|
||||
for f in $files; do
|
||||
case $f in
|
||||
*:*) touch_files="$touch_files "`echo "$f" |
|
||||
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
|
||||
*) touch_files="$touch_files $f.in";;
|
||||
esac
|
||||
done
|
||||
touch $touch_files
|
||||
;;
|
||||
|
||||
automake*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
|
||||
You might want to install the \`Automake' and \`Perl' packages.
|
||||
Grab them from any GNU archive site."
|
||||
find . -type f -name Makefile.am -print |
|
||||
sed 's/\.am$/.in/' |
|
||||
while read f; do touch "$f"; done
|
||||
;;
|
||||
|
||||
autom4te*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, but is $msg.
|
||||
You might have modified some files without having the
|
||||
proper tools for further handling them.
|
||||
You can get \`$1' as part of \`Autoconf' from any GNU
|
||||
archive site."
|
||||
|
||||
file=`echo "$*" | sed -n "$sed_output"`
|
||||
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
|
||||
if test -f "$file"; then
|
||||
touch $file
|
||||
else
|
||||
test -z "$file" || exec >$file
|
||||
echo "#! /bin/sh"
|
||||
echo "# Created by GNU Automake missing as a replacement of"
|
||||
echo "# $ $@"
|
||||
echo "exit 0"
|
||||
chmod +x $file
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
bison*|yacc*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' $msg. You should only need it if
|
||||
you modified a \`.y' file. You may need the \`Bison' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Bison' from any GNU archive site."
|
||||
rm -f y.tab.c y.tab.h
|
||||
if test $# -ne 1; then
|
||||
eval LASTARG=\${$#}
|
||||
case $LASTARG in
|
||||
*.y)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
|
||||
if test -f "$SRCFILE"; then
|
||||
cp "$SRCFILE" y.tab.c
|
||||
fi
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
|
||||
if test -f "$SRCFILE"; then
|
||||
cp "$SRCFILE" y.tab.h
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test ! -f y.tab.h; then
|
||||
echo >y.tab.h
|
||||
fi
|
||||
if test ! -f y.tab.c; then
|
||||
echo 'main() { return 0; }' >y.tab.c
|
||||
fi
|
||||
;;
|
||||
|
||||
lex*|flex*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified a \`.l' file. You may need the \`Flex' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Flex' from any GNU archive site."
|
||||
rm -f lex.yy.c
|
||||
if test $# -ne 1; then
|
||||
eval LASTARG=\${$#}
|
||||
case $LASTARG in
|
||||
*.l)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
|
||||
if test -f "$SRCFILE"; then
|
||||
cp "$SRCFILE" lex.yy.c
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test ! -f lex.yy.c; then
|
||||
echo 'main() { return 0; }' >lex.yy.c
|
||||
fi
|
||||
;;
|
||||
|
||||
help2man*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified a dependency of a manual page. You may need the
|
||||
\`Help2man' package in order for those modifications to take
|
||||
effect. You can get \`Help2man' from any GNU archive site."
|
||||
|
||||
file=`echo "$*" | sed -n "$sed_output"`
|
||||
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
|
||||
if test -f "$file"; then
|
||||
touch $file
|
||||
else
|
||||
test -z "$file" || exec >$file
|
||||
echo ".ab help2man is required to generate this page"
|
||||
exit $?
|
||||
fi
|
||||
;;
|
||||
|
||||
makeinfo*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified a \`.texi' or \`.texinfo' file, or any other file
|
||||
indirectly affecting the aspect of the manual. The spurious
|
||||
call might also be the consequence of using a buggy \`make' (AIX,
|
||||
DU, IRIX). You might want to install the \`Texinfo' package or
|
||||
the \`GNU make' package. Grab either from any GNU archive site."
|
||||
# The file to touch is that specified with -o ...
|
||||
file=`echo "$*" | sed -n "$sed_output"`
|
||||
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
|
||||
if test -z "$file"; then
|
||||
# ... or it is the one specified with @setfilename ...
|
||||
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
|
||||
file=`sed -n '
|
||||
/^@setfilename/{
|
||||
s/.* \([^ ]*\) *$/\1/
|
||||
p
|
||||
q
|
||||
}' $infile`
|
||||
# ... or it is derived from the source name (dir/f.texi becomes f.info)
|
||||
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
|
||||
fi
|
||||
# If the file does not exist, the user really needs makeinfo;
|
||||
# let's fail without touching anything.
|
||||
test -f $file || exit 1
|
||||
touch $file
|
||||
;;
|
||||
|
||||
*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, and is $msg.
|
||||
You might have modified some files without having the
|
||||
proper tools for further handling them. Check the \`README' file,
|
||||
it often tells you about the needed prerequisites for installing
|
||||
this package. You may also peek at any GNU archive site, in case
|
||||
some other package would contain this missing \`$1' program."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
303
mmap.c
Normal file
303
mmap.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/* mmap.c -- Memory allocation with mmap.
|
||||
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 <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Memory allocation on systems that provide anonymous mmap. This
|
||||
permits the backtrace functions to be invoked from a signal
|
||||
handler, assuming that mmap is async-signal safe. */
|
||||
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
#endif
|
||||
|
||||
/* A list of free memory blocks. */
|
||||
|
||||
struct backtrace_freelist_struct
|
||||
{
|
||||
/* Next on list. */
|
||||
struct backtrace_freelist_struct *next;
|
||||
/* Size of this block, including this structure. */
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* Free memory allocated by backtrace_alloc. */
|
||||
|
||||
static void
|
||||
backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size)
|
||||
{
|
||||
/* Just leak small blocks. We don't have to be perfect. */
|
||||
if (size >= sizeof (struct backtrace_freelist_struct))
|
||||
{
|
||||
struct backtrace_freelist_struct *p;
|
||||
|
||||
p = (struct backtrace_freelist_struct *) addr;
|
||||
p->next = state->freelist;
|
||||
p->size = size;
|
||||
state->freelist = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't
|
||||
report an error. */
|
||||
|
||||
void *
|
||||
backtrace_alloc (struct backtrace_state *state,
|
||||
size_t size, backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
void *ret;
|
||||
int locked;
|
||||
struct backtrace_freelist_struct **pp;
|
||||
size_t pagesize;
|
||||
size_t asksize;
|
||||
void *page;
|
||||
|
||||
ret = NULL;
|
||||
|
||||
/* If we can acquire the lock, then see if there is space on the
|
||||
free list. If we can't acquire the lock, drop straight into
|
||||
using mmap. __sync_lock_test_and_set returns the old state of
|
||||
the lock, so we have acquired it if it returns 0. */
|
||||
|
||||
if (!state->threaded)
|
||||
locked = 1;
|
||||
else
|
||||
locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0;
|
||||
|
||||
if (locked)
|
||||
{
|
||||
for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next)
|
||||
{
|
||||
if ((*pp)->size >= size)
|
||||
{
|
||||
struct backtrace_freelist_struct *p;
|
||||
|
||||
p = *pp;
|
||||
*pp = p->next;
|
||||
|
||||
/* Round for alignment; we assume that no type we care about
|
||||
is more than 8 bytes. */
|
||||
size = (size + 7) & ~ (size_t) 7;
|
||||
if (size < p->size)
|
||||
backtrace_free_locked (state, (char *) p + size,
|
||||
p->size - size);
|
||||
|
||||
ret = (void *) p;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->threaded)
|
||||
__sync_lock_release (&state->lock_alloc);
|
||||
}
|
||||
|
||||
if (ret == NULL)
|
||||
{
|
||||
/* Allocate a new page. */
|
||||
|
||||
pagesize = getpagesize ();
|
||||
asksize = (size + pagesize - 1) & ~ (pagesize - 1);
|
||||
page = mmap (NULL, asksize, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (page == MAP_FAILED)
|
||||
{
|
||||
if (error_callback)
|
||||
error_callback (data, "mmap", errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = (size + 7) & ~ (size_t) 7;
|
||||
if (size < asksize)
|
||||
backtrace_free (state, (char *) page + size, asksize - size,
|
||||
error_callback, data);
|
||||
|
||||
ret = page;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Free memory allocated by backtrace_alloc. */
|
||||
|
||||
void
|
||||
backtrace_free (struct backtrace_state *state, void *addr, size_t size,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
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
|
||||
have acquired it if it returns 0. */
|
||||
|
||||
if (!state->threaded)
|
||||
locked = 1;
|
||||
else
|
||||
locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0;
|
||||
|
||||
if (locked)
|
||||
{
|
||||
backtrace_free_locked (state, addr, size);
|
||||
|
||||
if (state->threaded)
|
||||
__sync_lock_release (&state->lock_alloc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Grow VEC by SIZE bytes. */
|
||||
|
||||
void *
|
||||
backtrace_vector_grow (struct backtrace_state *state,size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_vector *vec)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (size > vec->alc)
|
||||
{
|
||||
size_t pagesize;
|
||||
size_t alc;
|
||||
void *base;
|
||||
|
||||
pagesize = getpagesize ();
|
||||
alc = vec->size + size;
|
||||
if (vec->size == 0)
|
||||
alc = 16 * size;
|
||||
else if (alc < pagesize)
|
||||
{
|
||||
alc *= 2;
|
||||
if (alc > pagesize)
|
||||
alc = pagesize;
|
||||
}
|
||||
else
|
||||
{
|
||||
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->size + vec->alc,
|
||||
error_callback, data);
|
||||
}
|
||||
vec->base = base;
|
||||
vec->alc = alc - vec->size;
|
||||
}
|
||||
|
||||
ret = (char *) vec->base + vec->size;
|
||||
vec->size += size;
|
||||
vec->alc -= size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Finish the current allocation on 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. */
|
||||
|
||||
int
|
||||
backtrace_vector_release (struct backtrace_state *state,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
size_t size;
|
||||
size_t alc;
|
||||
size_t aligned;
|
||||
|
||||
/* Make sure that the block that we free is aligned on an 8-byte
|
||||
boundary. */
|
||||
size = vec->size;
|
||||
alc = vec->alc;
|
||||
aligned = (size + 7) & ~ (size_t) 7;
|
||||
alc -= aligned - size;
|
||||
|
||||
backtrace_free (state, (char *) vec->base + aligned, alc,
|
||||
error_callback, data);
|
||||
vec->alc = 0;
|
||||
return 1;
|
||||
}
|
||||
100
mmapio.c
Normal file
100
mmapio.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/* mmapio.c -- File views using mmap.
|
||||
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 <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
#endif
|
||||
|
||||
/* This file implements file views and memory allocation when mmap is
|
||||
available. */
|
||||
|
||||
/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */
|
||||
|
||||
int
|
||||
backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
int descriptor, off_t offset, size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_view *view)
|
||||
{
|
||||
size_t pagesize;
|
||||
unsigned int inpage;
|
||||
off_t pageoff;
|
||||
void *map;
|
||||
|
||||
pagesize = getpagesize ();
|
||||
inpage = offset % pagesize;
|
||||
pageoff = offset - inpage;
|
||||
|
||||
size += inpage;
|
||||
size = (size + (pagesize - 1)) & ~ (pagesize - 1);
|
||||
|
||||
map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff);
|
||||
if (map == MAP_FAILED)
|
||||
{
|
||||
error_callback (data, "mmap", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
view->data = (char *) map + inpage;
|
||||
view->base = map;
|
||||
view->len = size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Release a view read by backtrace_get_view. */
|
||||
|
||||
void
|
||||
backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
struct backtrace_view *view,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
union {
|
||||
const void *cv;
|
||||
void *v;
|
||||
} const_cast;
|
||||
|
||||
const_cast.cv = view->base;
|
||||
if (munmap (const_cast.v, view->len) < 0)
|
||||
error_callback (data, "munmap", errno);
|
||||
}
|
||||
66
nounwind.c
Normal file
66
nounwind.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/* backtrace.c -- Entry point for stack backtrace library.
|
||||
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 <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/* This source file is compiled if the unwind library is not
|
||||
available. */
|
||||
|
||||
int
|
||||
backtrace_full (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
int skip ATTRIBUTE_UNUSED,
|
||||
backtrace_full_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
error_callback (data,
|
||||
"no stack trace because unwind library not available",
|
||||
0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
backtrace_simple (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
int skip ATTRIBUTE_UNUSED,
|
||||
backtrace_simple_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
error_callback (data,
|
||||
"no stack trace because unwind library not available",
|
||||
0);
|
||||
return 0;
|
||||
}
|
||||
937
pecoff.c
Normal file
937
pecoff.c
Normal file
@@ -0,0 +1,937 @@
|
||||
/* pecoff.c -- Get debug data from a PE/COFF 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;
|
||||
}
|
||||
100
posix.c
Normal file
100
posix.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/* posix.c -- POSIX file I/O routines for the backtrace library.
|
||||
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 <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
#ifndef FD_CLOEXEC
|
||||
#define FD_CLOEXEC 1
|
||||
#endif
|
||||
|
||||
/* Open a file for reading. */
|
||||
|
||||
int
|
||||
backtrace_open (const char *filename, backtrace_error_callback error_callback,
|
||||
void *data, int *does_not_exist)
|
||||
{
|
||||
int descriptor;
|
||||
|
||||
if (does_not_exist != NULL)
|
||||
*does_not_exist = 0;
|
||||
|
||||
descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC));
|
||||
if (descriptor < 0)
|
||||
{
|
||||
if (does_not_exist != NULL && errno == ENOENT)
|
||||
*does_not_exist = 1;
|
||||
else
|
||||
error_callback (data, filename, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FCNTL
|
||||
/* Set FD_CLOEXEC just in case the kernel does not support
|
||||
O_CLOEXEC. It doesn't matter if this fails for some reason.
|
||||
FIXME: At some point it should be safe to only do this if
|
||||
O_CLOEXEC == 0. */
|
||||
fcntl (descriptor, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/* Close DESCRIPTOR. */
|
||||
|
||||
int
|
||||
backtrace_close (int descriptor, backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
if (close (descriptor) < 0)
|
||||
{
|
||||
error_callback (data, "close", errno);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
92
print.c
Normal file
92
print.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/* print.c -- Print the current backtrace.
|
||||
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 <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Passed to callbacks. */
|
||||
|
||||
struct print_data
|
||||
{
|
||||
struct backtrace_state *state;
|
||||
FILE *f;
|
||||
};
|
||||
|
||||
/* Print one level of a backtrace. */
|
||||
|
||||
static int
|
||||
print_callback (void *data, uintptr_t pc, const char *filename, int lineno,
|
||||
const char *function)
|
||||
{
|
||||
struct print_data *pdata = (struct print_data *) data;
|
||||
|
||||
fprintf (pdata->f, "0x%lx %s\n\t%s:%d\n",
|
||||
(unsigned long) pc,
|
||||
function == NULL ? "???" : function,
|
||||
filename == NULL ? "???" : filename,
|
||||
lineno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print errors to stderr. */
|
||||
|
||||
static void
|
||||
error_callback (void *data, const char *msg, int errnum)
|
||||
{
|
||||
struct print_data *pdata = (struct print_data *) data;
|
||||
|
||||
if (pdata->state->filename != NULL)
|
||||
fprintf (stderr, "%s: ", pdata->state->filename);
|
||||
fprintf (stderr, "libbacktrace: %s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
|
||||
/* Print a backtrace. */
|
||||
|
||||
void
|
||||
backtrace_print (struct backtrace_state *state, int skip, FILE *f)
|
||||
{
|
||||
struct print_data data;
|
||||
|
||||
data.state = state;
|
||||
data.f = f;
|
||||
backtrace_full (state, skip + 1, print_callback, error_callback,
|
||||
(void *) &data);
|
||||
}
|
||||
96
read.c
Normal file
96
read.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/* read.c -- File views without mmap.
|
||||
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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* This file implements file views when mmap is not available. */
|
||||
|
||||
/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */
|
||||
|
||||
int
|
||||
backtrace_get_view (struct backtrace_state *state, int descriptor,
|
||||
off_t offset, size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_view *view)
|
||||
{
|
||||
ssize_t got;
|
||||
|
||||
if (lseek (descriptor, offset, SEEK_SET) < 0)
|
||||
{
|
||||
error_callback (data, "lseek", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
view->base = backtrace_alloc (state, size, error_callback, data);
|
||||
if (view->base == NULL)
|
||||
return 0;
|
||||
view->data = view->base;
|
||||
view->len = size;
|
||||
|
||||
got = read (descriptor, view->base, size);
|
||||
if (got < 0)
|
||||
{
|
||||
error_callback (data, "read", errno);
|
||||
free (view->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((size_t) got < size)
|
||||
{
|
||||
error_callback (data, "file too short", 0);
|
||||
free (view->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Release a view read by backtrace_get_view. */
|
||||
|
||||
void
|
||||
backtrace_release_view (struct backtrace_state *state,
|
||||
struct backtrace_view *view,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
backtrace_free (state, view->base, view->len, error_callback, data);
|
||||
view->data = NULL;
|
||||
view->base = NULL;
|
||||
}
|
||||
108
simple.c
Normal file
108
simple.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/* simple.c -- The backtrace_simple 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 "unwind.h"
|
||||
#include "backtrace.h"
|
||||
|
||||
/* The simple_backtrace routine. */
|
||||
|
||||
/* Data passed through _Unwind_Backtrace. */
|
||||
|
||||
struct backtrace_simple_data
|
||||
{
|
||||
/* Number of frames to skip. */
|
||||
int skip;
|
||||
/* Library state. */
|
||||
struct backtrace_state *state;
|
||||
/* Callback routine. */
|
||||
backtrace_simple_callback callback;
|
||||
/* Error callback routine. */
|
||||
backtrace_error_callback error_callback;
|
||||
/* Data to pass to callback routine. */
|
||||
void *data;
|
||||
/* Value to return from backtrace. */
|
||||
int ret;
|
||||
};
|
||||
|
||||
/* Unwind library callback routine. This is passd to
|
||||
_Unwind_Backtrace. */
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
simple_unwind (struct _Unwind_Context *context, void *vdata)
|
||||
{
|
||||
struct backtrace_simple_data *bdata = (struct backtrace_simple_data *) vdata;
|
||||
uintptr_t pc;
|
||||
int ip_before_insn = 0;
|
||||
|
||||
#ifdef HAVE_GETIPINFO
|
||||
pc = _Unwind_GetIPInfo (context, &ip_before_insn);
|
||||
#else
|
||||
pc = _Unwind_GetIP (context);
|
||||
#endif
|
||||
|
||||
if (bdata->skip > 0)
|
||||
{
|
||||
--bdata->skip;
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
if (!ip_before_insn)
|
||||
--pc;
|
||||
|
||||
bdata->ret = bdata->callback (bdata->data, pc);
|
||||
|
||||
if (bdata->ret != 0)
|
||||
return _URC_END_OF_STACK;
|
||||
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
/* Get a simple stack backtrace. */
|
||||
|
||||
int
|
||||
backtrace_simple (struct backtrace_state *state, int skip,
|
||||
backtrace_simple_callback callback,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
struct backtrace_simple_data bdata;
|
||||
|
||||
bdata.skip = skip + 1;
|
||||
bdata.state = state;
|
||||
bdata.callback = callback;
|
||||
bdata.error_callback = error_callback;
|
||||
bdata.data = data;
|
||||
bdata.ret = 0;
|
||||
_Unwind_Backtrace (simple_unwind, &bdata);
|
||||
return bdata.ret;
|
||||
}
|
||||
108
sort.c
Normal file
108
sort.c
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
72
state.c
Normal file
72
state.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/* state.c -- Create the backtrace state.
|
||||
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 <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "backtrace-supported.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Create the backtrace state. This will then be passed to all the
|
||||
other routines. */
|
||||
|
||||
struct backtrace_state *
|
||||
backtrace_create_state (const char *filename, int threaded,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
struct backtrace_state init_state;
|
||||
struct backtrace_state *state;
|
||||
|
||||
#ifndef HAVE_SYNC_FUNCTIONS
|
||||
if (threaded)
|
||||
{
|
||||
error_callback (data, "backtrace library does not support threads", 0);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset (&init_state, 0, sizeof init_state);
|
||||
init_state.filename = filename;
|
||||
init_state.threaded = threaded;
|
||||
|
||||
state = ((struct backtrace_state *)
|
||||
backtrace_alloc (&init_state, sizeof *state, error_callback, data));
|
||||
if (state == NULL)
|
||||
return NULL;
|
||||
*state = init_state;
|
||||
|
||||
return state;
|
||||
}
|
||||
137
stest.c
Normal file
137
stest.c
Normal file
@@ -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);
|
||||
}
|
||||
64
unknown.c
Normal file
64
unknown.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/* unknown.c -- used when backtrace configury does not know file format.
|
||||
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 <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* A trivial routine that always fails to find fileline data. */
|
||||
|
||||
static int
|
||||
unknown_fileline (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
uintptr_t pc, backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data)
|
||||
|
||||
{
|
||||
return callback (data, pc, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
/* Initialize the backtrace data when we don't know how to read the
|
||||
debug info. */
|
||||
|
||||
int
|
||||
backtrace_initialize (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
int descriptor ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED, fileline *fileline_fn)
|
||||
{
|
||||
state->fileline_data = NULL;
|
||||
*fileline_fn = unknown_fileline;
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user