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:
Ian Lance Taylor
2016-09-10 07:59:09 -07:00
parent 6a5a5fcdda
commit 84241313f2
37 changed files with 44340 additions and 0 deletions

29
LICENSE Normal file
View 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
View 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
View 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:

View File

@@ -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
View 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

File diff suppressed because it is too large Load Diff

156
alloc.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

119
config.h.in Normal file
View 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

File diff suppressed because it is too large Load Diff

13874
configure vendored Executable file

File diff suppressed because it is too large Load Diff

408
configure.ac Normal file
View 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

3123
dwarf.c Normal file

File diff suppressed because it is too large Load Diff

979
elf.c Normal file
View 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
View 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
View 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
View 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
View 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

7874
ltmain.sh Executable file

File diff suppressed because it is too large Load Diff

331
missing Executable file
View 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
View 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
View 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
View 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
View 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, &sects_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, &sects_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, &sects_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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}