Hello everyone,
I've fixed some issues and implemented functionality
to search debug file by build-id.
Can someone please review my patch.
> As far as I know all the debuglink code is ELF-specific. I would do
> it all in elf.c. While reading the sections of the executable, look
> for a debuglink section, and use it if present. Keep the readlink
> code in posix.c, I suppose. Apologies if this doesn't make sense.
I've moved backtrace_open_debugfile() function into elf.c.
This function checks debug sections (build-id/debuglink),
and if one of them exist - the function starts to search and open debug
files.
Also I'll be very appreciated if someone give me advise about issues:
1.
| Skimming over the patch I noticed you duplicate libiberties xcrc32
| functionality.
To verify that debug file is valid, we should
verify crc32 sum, I took that algorithm from gdb, and
put it in the libbacktrace sources. However
this functionality is implemented by libiberty.
In case if libbactrace is being built as a static library,
I can't just link libbacktrace against static libbiberty.
Libtool can do it with objects which has "la" suffix,
but in time when libbacktrace build process happens
libiberty.la already removed.
Should i extract *.o files from the libiberty archive
and create libbacktrace archive with crc32.o from
libiberty or just keep this code in libbacktrace ?
2.
> > +clean_separate:glinktest.debug
> > + rm -f glinktest.debug
> > +
> > +separate: glinktest
> > + if test -n "$(OBJCOPY)" && test -n "$(STRIP)"; \
> > + then \
> > + $(OBJCOPY) --only-keep-debug glinktest glinktest.debug;\
> > + $(STRIP) glinktest;\
> > + $(OBJCOPY) --add-gnu-debuglink=glinktest.debug glinktest;\
> > + fi;
>
> |As far as I know "separate" is not a special thing in automake. We
> | should always run (and clean) this test if the necessary objcopy
> | option is available.
>
In the attached patch I overrode default target check-TESTS
to use objcopy and strip, before test suite will run.
But the solution to move all test suite code from Makefile.in to
Makefile.am seems not really good.
I searched for default target, which can be run before test suite logic,
but can't find it for Makefile.am.
Should I keep current solution, or we have better alternative?
Thanks.
On 03/14/2017 04:49 PM, Ian Lance Taylor wrote:
On Mon, Mar 13, 2017 at 10:16 AM, Denis Khalikov
<d.khali...@partner.samsung.com> wrote:
Hello everyone, i have a patch for this issue.
List of implemented functionality:
1.Reading .gnu_debuglink section from ELF file:
a. Reading name of debug info file.
b. Verifying crc32 sum.
2. Searching for separate debug info file from paths:
a. /usr/lib/debug/path/to/executable
b. /path/to/executable
c. /path/to/executable/.debug
Assumed that debug info file generated by objcopy from binutils.
objcopy --only-keep-debug foo foo.debug
strip -g foo
objcopy --add-gnu-debuglink=foo.debug foo
+clean_separate:glinktest.debug
+ rm -f glinktest.debug
+
+separate: glinktest
+ if test -n "$(OBJCOPY)" && test -n "$(STRIP)"; \
+ then \
+ $(OBJCOPY) --only-keep-debug glinktest glinktest.debug;\
+ $(STRIP) glinktest;\
+ $(OBJCOPY) --add-gnu-debuglink=glinktest.debug glinktest;\
+ fi;
As far as I know "separate" is not a special thing in automake. We
should always run (and clean) this test if the necessary objcopy
option is available.
+glinktest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h
Missing '$' in "$(INCDIR)".
+/* Return 1 if header is valid and -1 on fail */
This comment does not explain what the function actually does.
+/* Return the pointer to char array with data from .gnudebuglink section
inside. */
Line too long, we use 80 column lines.
+unsigned char *
+elf_gnu_debuglink_section (struct backtrace_state *state, int descriptor,
+ backtrace_error_callback error_callback, void *data,
+ int exe, int *gnulink_data_len_out)
This should be static. I see that you are calling it elsewhere, but
it doesn't make sense to call an "elf" function outside of elf.c.
This library is used on non-ELF systems.
+ /* Look for for the .gnu_debuglink section */
Period at end of sentence.
/* To translate PC to file/line when using DWARF, we need to find
- the .debug_info and .debug_line sections. */
+ the .debug_info and .debug_line sections. */
Why change the indentation like this? I think the original was correct.
- descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
- pd->data, &does_not_exist);
+ descriptor
+ = backtrace_open_debugfile (info->dlpi_name, pd->error_callback, pd->data,
+ &debugfile_does_not_exist, pd->state, 0);
+ if (descriptor < 0)
+ descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
+ pd->data, &does_not_exist);
This seems like unnecessary work. Shouldn't we only try to open the
debug file if we find a .gnu_debuglink section?
+/*Just a simple test copied from btest.c, but in this case we don't have debug
+ * info in the executable and test should verify that we can read debug info
+ * from separate file. See Makefile check-TESTS target. */
No leading '*' on subsequent lines of multi-line comments, see existing code.
I'm not sure I see the point of glinktest.c. Why don't we just use btest.c?
+#define MAX_PATH_LEN 4096 /* from linux/limits.h */
This library works on systems other than GNU/Linux. We should
dynamically allocate the buffer.
+ while (len > 1 && !IS_DIR_SEPARATOR (*(buffer + (len - 1))))
while (len > 1 && !IS_DIR_SEPARATOR(buffer[len-1]))
or just call basename. I'm not sure why you bother with the count
variable; doesn't full_filename_len - count exactly == len?
+ sign_byte = 0x00;
+ count = 0;
+ while (*(buffer + count) != sign_byte && size > count)
+ ++count;
+ return count;
This looks like `return strnlen(buffer, size)`.
Ian
commit 7eeee7478019bdb6c843cccd566cb4d0176ec47e
Author: Denis Khalikov <d.khali...@partner.samsung.com>
Date: Tue Mar 14 13:45:11 2017 +0300
PR sanitizer/77631
* Makefile.am: Update to support test for gnu link
* Makefile.in: Regenerated.
* configure.ac: Add searching for limits.h and sys/param.h
* config.h.in: Regenerated.
* configure: Regenerated.
* elf.c (enum type_of_file): New enum.
(enum debug_path): New enum.
(getl32): New function.
(gnu_debuglink_crc32): New function. Generate crc32 sum.
(get_crc32): New function.
(pathlen): New function.
(check_sum): New function. Verify sum.
(elf_header_is_valid): New function. Verify elf header.
(elf_get_section_by_name): New function. Get section by name.
(backtrace_readlink): New function. Get type of file from filename.
(resolve_realname): New function. Resolve real name if file is link.
(backtrace_resolve_realname): New function. Resolve real name for any
file type.
(search_for_debugfile): New function. Search for debug file in known
paths.
(open_debugfile_by_gnulink): New function. Open debug file with
gnulink.
(hex): New function. Convert to hex.
(get_build_id_name): New function. Generate build-id name.
(open_debugfile_by_build_id): New function. Open debug file with
build-id.
(backtrace_open_debugfile): New function. Open debug file.
(elf_add): Move code which reads elf header to elf_header_is_valid.
(phdr_callback): Call backtrace_open_debugfile function for shared
library.
* fileline.c (fileline_initialize): Call backtrace_open_debugfile for
executable.
* internal.h: Updated.
diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog
index 25cd921..154be2f 100644
--- a/libbacktrace/ChangeLog
+++ b/libbacktrace/ChangeLog
@@ -1,3 +1,40 @@
+2017-03-14 Denis Khalikov <d.khali...@partner.samsung.com>
+
+ PR sanitizer/77631
+ * Makefile.am: Update to support test for gnu link
+ * Makefile.in: Regenerated.
+ * configure.ac: Add searching for limits.h and sys/param.h
+ * config.h.in: Regenerated.
+ * configure: Regenerated.
+ * elf.c (enum type_of_file): New enum.
+ (enum debug_path): New enum.
+ (getl32): New function.
+ (gnu_debuglink_crc32): New function. Generate crc32 sum.
+ (get_crc32): New function.
+ (pathlen): New function.
+ (check_sum): New function. Verify sum.
+ (elf_header_is_valid): New function. Verify elf header.
+ (elf_get_section_by_name): New function. Get section by name.
+ (backtrace_readlink): New function. Get type of file from filename.
+ (resolve_realname): New function. Resolve real name if file is link.
+ (backtrace_resolve_realname): New function. Resolve real name for any
+ file type.
+ (search_for_debugfile): New function. Search for debug file in known
+ paths.
+ (open_debugfile_by_gnulink): New function. Open debug file with
+ gnulink.
+ (hex): New function. Convert to hex.
+ (get_build_id_name): New function. Generate build-id name.
+ (open_debugfile_by_build_id): New function. Open debug file with
+ build-id.
+ (backtrace_open_debugfile): New function. Open debug file.
+ (elf_add): Move code which reads elf header to elf_header_is_valid.
+ (phdr_callback): Call backtrace_open_debugfile function for shared
+ library.
+ * fileline.c (fileline_initialize): Call backtrace_open_debugfile for
+ executable.
+ * internal.h: Updated.
+
2017-03-08 Sam Thursfield <sam.thursfi...@codethink.co.uk>
* btest.c (test5): Replace #ifdef guard with 'unused' attribute
diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 344dad5..548d5c7 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -100,8 +100,150 @@ stest_LDADD = libbacktrace.la
check_PROGRAMS += stest
-endif NATIVE
+glinktest_SOURCES = btest.c
+glinktest_CFLAGS = $(AM_CFLAGS) -g -O
+glinktest_LDADD = libbacktrace.la
+
+check_PROGRAMS += glinktest
+
+bidtest_SOURCES = btest.c
+bidtest_CFLAGS = $(AM_CFLAGS) -g -O -Wl,--build-id=0x0123456789abcdef0123456789abcdef01234567
+bidtest_LDADD = libbacktrace.la
+
+check_PROGRAMS += bidtest
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if ! test -e glinktest.debug; then \
+ $(OBJCOPY) --only-keep-debug glinktest glinktest.debug; \
+ $(STRIP) glinktest; \
+ $(OBJCOPY) --add-gnu-debuglink=glinktest.debug glinktest; \
+ fi; \
+ if ! test -e .build-id; then \
+ mkdir .build-id; \
+ mkdir .build-id/01/; \
+ mkdir temp; \
+ $(OBJCOPY) --only-keep-debug bidtest bidtest.debug; \
+ $(STRIP) bidtest; \
+ touch temp; \
+ mv bidtest.debug temp;\
+ ln -s ../../temp/bidtest.debug .build-id/01/23456789abcdef0123456789abcdef01234567.debug; \
+ fi; \
+ 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
+
+
+clean-checkPROGRAMS:
+ @if test -e glinktest.debug; then \
+ echo "rm -f glinktest.debug"; \
+ rm -f glinktest.debug; \
+ fi; \
+ if test -d temp; then \
+ echo "rm -rf temp"; \
+ rm -rf temp; \
+ fi; \
+ if test -d .build-id; then \
+ echo "rm -rf .build-id"; \
+ rm -rf .build-id; \
+ fi; \
+ 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;
+
+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
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index de74b5d..a5b8fe5 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -16,7 +16,7 @@
@SET_MAKE@
# Makefile.am -- Backtrace Makefile.
-# Copyright (C) 2012-2016 Free Software Foundation, Inc.
+# Copyright (C) 2012-2017 Free Software Foundation, Inc.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -84,7 +84,7 @@ build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
check_PROGRAMS = $(am__EXEEXT_1)
-@NATIVE_TRUE@am__append_1 = btest stest
+@NATIVE_TRUE@am__append_1 = btest stest glinktest bidtest
subdir = .
DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \
$(srcdir)/Makefile.am $(top_srcdir)/configure \
@@ -113,13 +113,26 @@ 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__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) \
+@NATIVE_TRUE@ glinktest$(EXEEXT) bidtest$(EXEEXT)
+@NATIVE_TRUE@am_bidtest_OBJECTS = bidtest-btest.$(OBJEXT)
+bidtest_OBJECTS = $(am_bidtest_OBJECTS)
+@NATIVE_TRUE@bidtest_DEPENDENCIES = libbacktrace.la
+bidtest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(bidtest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
@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_glinktest_OBJECTS = glinktest-btest.$(OBJEXT)
+glinktest_OBJECTS = $(am_glinktest_OBJECTS)
+@NATIVE_TRUE@glinktest_DEPENDENCIES = libbacktrace.la
+glinktest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(glinktest_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
@NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
stest_OBJECTS = $(am_stest_OBJECTS)
@NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
@@ -136,7 +149,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
- $(btest_SOURCES) $(stest_SOURCES)
+ $(bidtest_SOURCES) $(btest_SOURCES) $(glinktest_SOURCES) \
+ $(stest_SOURCES)
MULTISRCTOP =
MULTIBUILDTOP =
MULTIDIRS =
@@ -200,6 +214,7 @@ MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
+OBJCOPY = @OBJCOPY@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
@@ -330,6 +345,12 @@ TESTS = $(check_PROGRAMS)
@NATIVE_TRUE@btest_LDADD = libbacktrace.la
@NATIVE_TRUE@stest_SOURCES = stest.c
@NATIVE_TRUE@stest_LDADD = libbacktrace.la
+@NATIVE_TRUE@glinktest_SOURCES = btest.c
+@NATIVE_TRUE@glinktest_CFLAGS = $(AM_CFLAGS) -g -O
+@NATIVE_TRUE@glinktest_LDADD = libbacktrace.la
+@NATIVE_TRUE@bidtest_SOURCES = btest.c
+@NATIVE_TRUE@bidtest_CFLAGS = $(AM_CFLAGS) -g -O -Wl,--build-id=0x0123456789abcdef0123456789abcdef01234567
+@NATIVE_TRUE@bidtest_LDADD = libbacktrace.la
# We can't use automake's automatic dependency tracking, because it
# breaks when using bootstrap-lean. Automatic dependency tracking
@@ -411,17 +432,23 @@ clean-noinstLTLIBRARIES:
libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES)
$(LINK) $(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
+@NATIVE_FALSE@clean-checkPROGRAMS:
+@NATIVE_FALSE@ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+@NATIVE_FALSE@ echo " rm -f" $$list; \
+@NATIVE_FALSE@ rm -f $$list || exit $$?; \
+@NATIVE_FALSE@ test -n "$(EXEEXT)" || exit 0; \
+@NATIVE_FALSE@ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+@NATIVE_FALSE@ echo " rm -f" $$list; \
+@NATIVE_FALSE@ rm -f $$list
+bidtest$(EXEEXT): $(bidtest_OBJECTS) $(bidtest_DEPENDENCIES) $(EXTRA_bidtest_DEPENDENCIES)
+ @rm -f bidtest$(EXEEXT)
+ $(bidtest_LINK) $(bidtest_OBJECTS) $(bidtest_LDADD) $(LIBS)
btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES)
@rm -f btest$(EXEEXT)
$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
+glinktest$(EXEEXT): $(glinktest_OBJECTS) $(glinktest_DEPENDENCIES) $(EXTRA_glinktest_DEPENDENCIES)
+ @rm -f glinktest$(EXEEXT)
+ $(glinktest_LINK) $(glinktest_OBJECTS) $(glinktest_LDADD) $(LIBS)
stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES)
@rm -f stest$(EXEEXT)
$(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
@@ -441,12 +468,24 @@ distclean-compile:
.c.lo:
$(LTCOMPILE) -c -o $@ $<
+bidtest-btest.o: btest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(bidtest_CFLAGS) $(CFLAGS) -c -o bidtest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+bidtest-btest.obj: btest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(bidtest_CFLAGS) $(CFLAGS) -c -o bidtest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
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`
+glinktest-btest.o: btest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(glinktest_CFLAGS) $(CFLAGS) -c -o glinktest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+glinktest-btest.obj: btest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(glinktest_CFLAGS) $(CFLAGS) -c -o glinktest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
mostlyclean-libtool:
-rm -f *.lo
@@ -525,98 +564,98 @@ GTAGS:
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
+@NATIVE_FALSE@check-TESTS: $(TESTS)
+@NATIVE_FALSE@ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+@NATIVE_FALSE@ srcdir=$(srcdir); export srcdir; \
+@NATIVE_FALSE@ list=' $(TESTS) '; \
+@NATIVE_FALSE@ $(am__tty_colors); \
+@NATIVE_FALSE@ if test -n "$$list"; then \
+@NATIVE_FALSE@ for tst in $$list; do \
+@NATIVE_FALSE@ if test -f ./$$tst; then dir=./; \
+@NATIVE_FALSE@ elif test -f $$tst; then dir=; \
+@NATIVE_FALSE@ else dir="$(srcdir)/"; fi; \
+@NATIVE_FALSE@ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+@NATIVE_FALSE@ all=`expr $$all + 1`; \
+@NATIVE_FALSE@ case " $(XFAIL_TESTS) " in \
+@NATIVE_FALSE@ *[\ \ ]$$tst[\ \ ]*) \
+@NATIVE_FALSE@ xpass=`expr $$xpass + 1`; \
+@NATIVE_FALSE@ failed=`expr $$failed + 1`; \
+@NATIVE_FALSE@ col=$$red; res=XPASS; \
+@NATIVE_FALSE@ ;; \
+@NATIVE_FALSE@ *) \
+@NATIVE_FALSE@ col=$$grn; res=PASS; \
+@NATIVE_FALSE@ ;; \
+@NATIVE_FALSE@ esac; \
+@NATIVE_FALSE@ elif test $$? -ne 77; then \
+@NATIVE_FALSE@ all=`expr $$all + 1`; \
+@NATIVE_FALSE@ case " $(XFAIL_TESTS) " in \
+@NATIVE_FALSE@ *[\ \ ]$$tst[\ \ ]*) \
+@NATIVE_FALSE@ xfail=`expr $$xfail + 1`; \
+@NATIVE_FALSE@ col=$$lgn; res=XFAIL; \
+@NATIVE_FALSE@ ;; \
+@NATIVE_FALSE@ *) \
+@NATIVE_FALSE@ failed=`expr $$failed + 1`; \
+@NATIVE_FALSE@ col=$$red; res=FAIL; \
+@NATIVE_FALSE@ ;; \
+@NATIVE_FALSE@ esac; \
+@NATIVE_FALSE@ else \
+@NATIVE_FALSE@ skip=`expr $$skip + 1`; \
+@NATIVE_FALSE@ col=$$blu; res=SKIP; \
+@NATIVE_FALSE@ fi; \
+@NATIVE_FALSE@ echo "$${col}$$res$${std}: $$tst"; \
+@NATIVE_FALSE@ done; \
+@NATIVE_FALSE@ if test "$$all" -eq 1; then \
+@NATIVE_FALSE@ tests="test"; \
+@NATIVE_FALSE@ All=""; \
+@NATIVE_FALSE@ else \
+@NATIVE_FALSE@ tests="tests"; \
+@NATIVE_FALSE@ All="All "; \
+@NATIVE_FALSE@ fi; \
+@NATIVE_FALSE@ if test "$$failed" -eq 0; then \
+@NATIVE_FALSE@ if test "$$xfail" -eq 0; then \
+@NATIVE_FALSE@ banner="$$All$$all $$tests passed"; \
+@NATIVE_FALSE@ else \
+@NATIVE_FALSE@ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+@NATIVE_FALSE@ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+@NATIVE_FALSE@ fi; \
+@NATIVE_FALSE@ else \
+@NATIVE_FALSE@ if test "$$xpass" -eq 0; then \
+@NATIVE_FALSE@ banner="$$failed of $$all $$tests failed"; \
+@NATIVE_FALSE@ else \
+@NATIVE_FALSE@ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+@NATIVE_FALSE@ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+@NATIVE_FALSE@ fi; \
+@NATIVE_FALSE@ fi; \
+@NATIVE_FALSE@ dashes="$$banner"; \
+@NATIVE_FALSE@ skipped=""; \
+@NATIVE_FALSE@ if test "$$skip" -ne 0; then \
+@NATIVE_FALSE@ if test "$$skip" -eq 1; then \
+@NATIVE_FALSE@ skipped="($$skip test was not run)"; \
+@NATIVE_FALSE@ else \
+@NATIVE_FALSE@ skipped="($$skip tests were not run)"; \
+@NATIVE_FALSE@ fi; \
+@NATIVE_FALSE@ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+@NATIVE_FALSE@ dashes="$$skipped"; \
+@NATIVE_FALSE@ fi; \
+@NATIVE_FALSE@ report=""; \
+@NATIVE_FALSE@ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+@NATIVE_FALSE@ report="Please report to $(PACKAGE_BUGREPORT)"; \
+@NATIVE_FALSE@ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+@NATIVE_FALSE@ dashes="$$report"; \
+@NATIVE_FALSE@ fi; \
+@NATIVE_FALSE@ dashes=`echo "$$dashes" | sed s/./=/g`; \
+@NATIVE_FALSE@ if test "$$failed" -eq 0; then \
+@NATIVE_FALSE@ col="$$grn"; \
+@NATIVE_FALSE@ else \
+@NATIVE_FALSE@ col="$$red"; \
+@NATIVE_FALSE@ fi; \
+@NATIVE_FALSE@ echo "$${col}$$dashes$${std}"; \
+@NATIVE_FALSE@ echo "$${col}$$banner$${std}"; \
+@NATIVE_FALSE@ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+@NATIVE_FALSE@ test -z "$$report" || echo "$${col}$$report$${std}"; \
+@NATIVE_FALSE@ echo "$${col}$$dashes$${std}"; \
+@NATIVE_FALSE@ test "$$failed" -eq 0; \
+@NATIVE_FALSE@ else :; fi
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
@@ -745,6 +784,136 @@ uninstall-am:
mostlyclean-multi pdf pdf-am ps ps-am tags uninstall \
uninstall-am
+
+@NATIVE_TRUE@check-TESTS: $(TESTS)
+@NATIVE_TRUE@ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+@NATIVE_TRUE@ srcdir=$(srcdir); export srcdir; \
+@NATIVE_TRUE@ list=' $(TESTS) '; \
+@NATIVE_TRUE@ $(am__tty_colors); \
+@NATIVE_TRUE@ if ! test -e glinktest.debug; then \
+@NATIVE_TRUE@ $(OBJCOPY) --only-keep-debug glinktest glinktest.debug; \
+@NATIVE_TRUE@ $(STRIP) glinktest; \
+@NATIVE_TRUE@ $(OBJCOPY) --add-gnu-debuglink=glinktest.debug glinktest; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ if ! test -e .build-id; then \
+@NATIVE_TRUE@ mkdir .build-id; \
+@NATIVE_TRUE@ mkdir .build-id/01/; \
+@NATIVE_TRUE@ mkdir temp; \
+@NATIVE_TRUE@ $(OBJCOPY) --only-keep-debug bidtest bidtest.debug; \
+@NATIVE_TRUE@ $(STRIP) bidtest; \
+@NATIVE_TRUE@ touch temp; \
+@NATIVE_TRUE@ mv bidtest.debug temp;\
+@NATIVE_TRUE@ ln -s ../../temp/bidtest.debug .build-id/01/23456789abcdef0123456789abcdef01234567.debug; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ if test -n "$$list"; then \
+@NATIVE_TRUE@ for tst in $$list; do \
+@NATIVE_TRUE@ if test -f ./$$tst; then dir=./; \
+@NATIVE_TRUE@ elif test -f $$tst; then dir=; \
+@NATIVE_TRUE@ else dir="$(srcdir)/"; fi; \
+@NATIVE_TRUE@ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+@NATIVE_TRUE@ all=`expr $$all + 1`; \
+@NATIVE_TRUE@ case " $(XFAIL_TESTS) " in \
+@NATIVE_TRUE@ *[\ \ ]$$tst[\ \ ]*) \
+@NATIVE_TRUE@ xpass=`expr $$xpass + 1`; \
+@NATIVE_TRUE@ failed=`expr $$failed + 1`; \
+@NATIVE_TRUE@ col=$$red; res=XPASS; \
+@NATIVE_TRUE@ ;; \
+@NATIVE_TRUE@ *) \
+@NATIVE_TRUE@ col=$$grn; res=PASS; \
+@NATIVE_TRUE@ ;; \
+@NATIVE_TRUE@ esac; \
+@NATIVE_TRUE@ elif test $$? -ne 77; then \
+@NATIVE_TRUE@ all=`expr $$all + 1`; \
+@NATIVE_TRUE@ case " $(XFAIL_TESTS) " in \
+@NATIVE_TRUE@ *[\ \ ]$$tst[\ \ ]*) \
+@NATIVE_TRUE@ xfail=`expr $$xfail + 1`; \
+@NATIVE_TRUE@ col=$$lgn; res=XFAIL; \
+@NATIVE_TRUE@ ;; \
+@NATIVE_TRUE@ *) \
+@NATIVE_TRUE@ failed=`expr $$failed + 1`; \
+@NATIVE_TRUE@ col=$$red; res=FAIL; \
+@NATIVE_TRUE@ ;; \
+@NATIVE_TRUE@ esac; \
+@NATIVE_TRUE@ else \
+@NATIVE_TRUE@ skip=`expr $$skip + 1`; \
+@NATIVE_TRUE@ col=$$blu; res=SKIP; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ echo "$${col}$$res$${std}: $$tst"; \
+@NATIVE_TRUE@ done; \
+@NATIVE_TRUE@ if test "$$all" -eq 1; then \
+@NATIVE_TRUE@ tests="test"; \
+@NATIVE_TRUE@ All=""; \
+@NATIVE_TRUE@ else \
+@NATIVE_TRUE@ tests="tests"; \
+@NATIVE_TRUE@ All="All "; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ if test "$$failed" -eq 0; then \
+@NATIVE_TRUE@ if test "$$xfail" -eq 0; then \
+@NATIVE_TRUE@ banner="$$All$$all $$tests passed"; \
+@NATIVE_TRUE@ else \
+@NATIVE_TRUE@ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+@NATIVE_TRUE@ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ else \
+@NATIVE_TRUE@ if test "$$xpass" -eq 0; then \
+@NATIVE_TRUE@ banner="$$failed of $$all $$tests failed"; \
+@NATIVE_TRUE@ else \
+@NATIVE_TRUE@ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+@NATIVE_TRUE@ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ dashes="$$banner"; \
+@NATIVE_TRUE@ skipped=""; \
+@NATIVE_TRUE@ if test "$$skip" -ne 0; then \
+@NATIVE_TRUE@ if test "$$skip" -eq 1; then \
+@NATIVE_TRUE@ skipped="($$skip test was not run)"; \
+@NATIVE_TRUE@ else \
+@NATIVE_TRUE@ skipped="($$skip tests were not run)"; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+@NATIVE_TRUE@ dashes="$$skipped"; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ report=""; \
+@NATIVE_TRUE@ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+@NATIVE_TRUE@ report="Please report to $(PACKAGE_BUGREPORT)"; \
+@NATIVE_TRUE@ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+@NATIVE_TRUE@ dashes="$$report"; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ dashes=`echo "$$dashes" | sed s/./=/g`; \
+@NATIVE_TRUE@ if test "$$failed" -eq 0; then \
+@NATIVE_TRUE@ col="$$grn"; \
+@NATIVE_TRUE@ else \
+@NATIVE_TRUE@ col="$$red"; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ echo "$${col}$$dashes$${std}"; \
+@NATIVE_TRUE@ echo "$${col}$$banner$${std}"; \
+@NATIVE_TRUE@ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+@NATIVE_TRUE@ test -z "$$report" || echo "$${col}$$report$${std}"; \
+@NATIVE_TRUE@ echo "$${col}$$dashes$${std}"; \
+@NATIVE_TRUE@ test "$$failed" -eq 0; \
+@NATIVE_TRUE@ else :; fi
+
+@NATIVE_TRUE@clean-checkPROGRAMS:
+@NATIVE_TRUE@ @if test -e glinktest.debug; then \
+@NATIVE_TRUE@ echo "rm -f glinktest.debug"; \
+@NATIVE_TRUE@ rm -f glinktest.debug; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ if test -d temp; then \
+@NATIVE_TRUE@ echo "rm -rf temp"; \
+@NATIVE_TRUE@ rm -rf temp; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ if test -d .build-id; then \
+@NATIVE_TRUE@ echo "rm -rf .build-id"; \
+@NATIVE_TRUE@ rm -rf .build-id; \
+@NATIVE_TRUE@ fi; \
+@NATIVE_TRUE@ list='$(check_PROGRAMS)'; \
+@NATIVE_TRUE@ test -n "$$list" || exit 0; \
+@NATIVE_TRUE@ echo " rm -f" $$list; \
+@NATIVE_TRUE@ rm -f $$list || exit $$?; \
+@NATIVE_TRUE@ test -n "$(EXEEXT)" || exit 0; \
+@NATIVE_TRUE@ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+@NATIVE_TRUE@ echo " rm -f" $$list; \
+@NATIVE_TRUE@ rm -f $$list;
alloc.lo: config.h backtrace.h internal.h
backtrace.lo: config.h backtrace.h internal.h
btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h
diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index 87cb805..edbd9af 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -28,6 +28,9 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
+/* Define 1 if <limits.h> is available. */
+#undef HAVE_LIMITS_H
+
/* Define to 1 if you have the <link.h> header file. */
#undef HAVE_LINK_H
@@ -52,6 +55,9 @@
/* Define to 1 if you have the <sys/mman.h> header file. */
#undef HAVE_SYS_MMAN_H
+/* Define 1 if <sys/param.h> is available. */
+#undef HAVE_SYS_PARAM_H
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
diff --git a/libbacktrace/configure b/libbacktrace/configure
index ee90bc6..562cede 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -630,6 +630,7 @@ LD
FGREP
SED
LIBTOOL
+OBJCOPY
RANLIB
MAINT
MAINTAINER_MODE_FALSE
@@ -5011,6 +5012,44 @@ else
fi
+# Extract the first word of "objcopy", so it can be a program name with args.
+set dummy objcopy; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJCOPY+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJCOPY"; then
+ ac_cv_prog_OBJCOPY="$OBJCOPY" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJCOPY="objcopy"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJCOPY=$ac_cv_prog_OBJCOPY
+if test -n "$OBJCOPY"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJCOPY" >&5
+$as_echo "$OBJCOPY" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
for ac_prog in gawk mawk nawk awk
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
@@ -11131,7 +11170,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11134 "configure"
+#line 11173 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11237,7 +11276,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11240 "configure"
+#line 11279 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12350,6 +12389,24 @@ if test "$ALLOC_FILE" = "alloc.lo"; then
fi
+ac_fn_c_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default"
+if test "x$ac_cv_header_limits_h" = x""yes; then :
+
+$as_echo "#define HAVE_LIMITS_H 1" >>confdefs.h
+
+fi
+
+
+
+ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_param_h" = x""yes; then :
+
+$as_echo "#define HAVE_SYS_PARAM_H 1" >>confdefs.h
+
+fi
+
+
+
# Check for dl_iterate_phdr.
for ac_header in link.h
do :
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index f9cad21..67cce41 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -74,6 +74,8 @@ AC_SUBST(CFLAGS)
AC_PROG_RANLIB
+AC_CHECK_PROG(OBJCOPY, objcopy, objcopy)
+
AC_PROG_AWK
case "$AWK" in
"") AC_MSG_ERROR([can't build without awk]) ;;
@@ -301,6 +303,12 @@ if test "$ALLOC_FILE" = "alloc.lo"; then
fi
AC_SUBST(BACKTRACE_USES_MALLOC)
+AC_CHECK_HEADER(limits.h,
+AC_DEFINE(HAVE_LIMITS_H, 1,[Define 1 if <limits.h> is available.]))
+
+AC_CHECK_HEADER(sys/param.h,
+AC_DEFINE(HAVE_SYS_PARAM_H, 1,[Define 1 if <sys/param.h> is available.]))
+
# Check for dl_iterate_phdr.
AC_CHECK_HEADERS(link.h)
if test "$ac_cv_header_link_h" = "no"; then
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 89ed42b..3f33d51 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -35,6 +35,9 @@ POSSIBILITY OF SUCH DAMAGE. */
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
#ifdef HAVE_DL_ITERATE_PHDR
#include <link.h>
@@ -42,6 +45,34 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "backtrace.h"
#include "internal.h"
+#include "filenames.h"
+
+
+/* The following is from pathmax.h. */
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+ PATH_MAX but might cause redefinition warnings when sys/param.h is
+ later included (as on MORE/BSD 4.3). */
+#if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
+# include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+# define _POSIX_PATH_MAX 255
+#endif
+
+/* Don't include sys/param.h if it already has been. */
+#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
+# include <sys/param.h>
+#endif
+
+#if !defined PATH_MAX && defined MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+#endif
+
#ifndef HAVE_DL_ITERATE_PHDR
@@ -283,6 +314,827 @@ struct elf_syminfo_data
size_t count;
};
+/* Information to read ELF note section */
+
+typedef struct
+{
+ unsigned char namesz[4];
+ unsigned char descsz[4];
+ unsigned char type[4];
+ unsigned char name[1];
+} Elf_External_Note;
+
+/* Information about type of the file */
+
+enum type_of_file
+{
+ LINK = 1,
+ REGULAR = 2
+};
+
+/* Information about debug paths */
+
+enum debug_path
+{
+ CURRENT,
+ CURRENT_DEBUG,
+ USR_LIB_DEBUG,
+ USR_LIB_DEBUG_PATH_TO_EXE,
+ DEBUG_PATH_MAX
+};
+
+/* Paths to debug file */
+
+static const char *const debug_file_path[DEBUG_PATH_MAX]
+ = {"", ".debug/", "/usr/lib/debug/", "/usr/lib/debug"};
+
+
+/* Cast from void pointer to uint32_t */
+
+static uint32_t
+getl32 (void *p)
+{
+ char *addr = (char *) p;
+ uint32_t v = 0;
+ v = *((uint32_t *) addr);
+ return v;
+}
+
+/* Function that produce crc32 value for input buffer */
+
+static unsigned long
+gnu_debuglink_crc32 (unsigned long crc, const unsigned char *buf, size_t len)
+{
+ static const unsigned long crc32_table[256]
+ = {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
+ const unsigned char *end;
+
+ crc = ~crc & 0xffffffff;
+ for (end = buf + len; buf < end; ++buf)
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return ~crc & 0xffffffff;
+}
+
+/* Generate crc32 sum from the file */
+
+static unsigned long
+get_crc32 (int descriptor)
+{
+ static unsigned char buffer[8 * 1024];
+ unsigned long file_crc = 0;
+ ssize_t count;
+
+ while ((count = read (descriptor, buffer, sizeof (buffer))) > 0)
+ file_crc = gnu_debuglink_crc32 (file_crc, buffer, count);
+
+ return file_crc;
+}
+
+/* Get length of the path */
+
+static int
+pathlen (const char *buffer)
+{
+ int len;
+ int full_filename_len;
+
+ len = full_filename_len = strlen (buffer);
+ while (len > 1 && !IS_DIR_SEPARATOR (buffer[len - 1]))
+ --len;
+ return len > 1 ? len : -1;
+}
+
+/* Verify crc32 sum */
+
+static int
+check_sum (int descriptor, char *debug_link, int offset, int section_size)
+{
+ unsigned long crc32_debug_link;
+ unsigned long crc32_debug_file;
+ offset += 1;
+ offset = (offset + 3) & ~3;
+ if (offset >= section_size)
+ return -1;
+ crc32_debug_link = getl32 (debug_link + offset);
+ crc32_debug_file = get_crc32 (descriptor);
+ return crc32_debug_link == crc32_debug_file;
+}
+
+/* Verify magic number, version, etc, of the ELF header,
+ return 1 if header is valid and -1 on fail */
+
+static int
+elf_header_is_valid (struct backtrace_state *state, int descriptor,
+ backtrace_error_callback error_callback, void *data,
+ int exe, off_t *shoff_out, unsigned int *shnum_out,
+ unsigned int *shstrndx_out, b_elf_ehdr *ehdr_out)
+{
+
+ struct backtrace_view ehdr_view;
+
+ if (!backtrace_get_view (state, descriptor, 0, sizeof *ehdr_out,
+ error_callback, data, &ehdr_view))
+ goto fail;
+
+ memcpy (ehdr_out, ehdr_view.data, sizeof *ehdr_out);
+
+ backtrace_release_view (state, &ehdr_view, error_callback, data);
+
+ if (ehdr_out->e_ident[EI_MAG0] != ELFMAG0
+ || ehdr_out->e_ident[EI_MAG1] != ELFMAG1
+ || ehdr_out->e_ident[EI_MAG2] != ELFMAG2
+ || ehdr_out->e_ident[EI_MAG3] != ELFMAG3)
+ {
+ error_callback (data, "executable file is not ELF", 0);
+ goto fail;
+ }
+ if (ehdr_out->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_out->e_ident[EI_CLASS] != BACKTRACE_ELFCLASS)
+ {
+ error_callback (data, "executable file is unexpected ELF class", 0);
+ goto fail;
+ }
+
+ if (ehdr_out->e_ident[EI_DATA] != ELFDATA2LSB
+ && ehdr_out->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_out->e_type == ET_DYN)
+ return -1;
+
+ *shoff_out = ehdr_out->e_shoff;
+ *shnum_out = ehdr_out->e_shnum;
+ *shstrndx_out = ehdr_out->e_shstrndx;
+
+ if ((*shnum_out == 0 || *shstrndx_out == SHN_XINDEX) && *shoff_out != 0)
+ {
+ struct backtrace_view shdr_view;
+ const b_elf_shdr *shdr;
+
+ if (!backtrace_get_view (state, descriptor, *shoff_out, sizeof shdr,
+ error_callback, data, &shdr_view))
+ goto fail;
+
+ shdr = (const b_elf_shdr *) shdr_view.data;
+
+ if (*shnum_out == 0)
+ *shnum_out = shdr->sh_size;
+
+ if (*shstrndx_out == SHN_XINDEX)
+ {
+ *shstrndx_out = 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_out >= *shnum_out
+ && *shstrndx_out >= SHN_LORESERVE + 0x100)
+ *shstrndx_out -= 0x100;
+ }
+ backtrace_release_view (state, &shdr_view, error_callback, data);
+ }
+ return 1;
+fail:
+ return -1;
+}
+
+
+/* Get content of the specifying section */
+
+static unsigned char *
+elf_get_section_by_name (struct backtrace_state *state, int descriptor,
+ backtrace_error_callback error_callback, void *data,
+ int exe, int *section_data_len_out,
+ const char *section_name)
+{
+ 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;
+ struct backtrace_view section_view;
+ int names_view_valid;
+ const char *names;
+ unsigned int i;
+ int section_view_valid;
+ unsigned char *section_data;
+
+ section_view_valid = 0;
+ shdrs_view_valid = 0;
+ names_view_valid = 0;
+ section_data = NULL;
+
+ if (!elf_header_is_valid (state, descriptor, error_callback, data, exe,
+ &shoff, &shnum, &shstrndx, &ehdr))
+ goto exit;
+
+ if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr),
+ (shnum - 1) * sizeof (b_elf_shdr), error_callback,
+ data, &shdrs_view))
+ goto exit;
+
+ 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 exit;
+
+ names_view_valid = 1;
+ names = (const char *) names_view.data;
+
+ /* Look for for the .gnu_debuglink section */
+ for (i = 1; i < shnum; ++i)
+ {
+ const b_elf_shdr *shdr;
+ unsigned int sh_name;
+ const char *name;
+ shdr = &shdrs[i - 1];
+ sh_name = shdr->sh_name;
+ if (sh_name >= shstr_size)
+ {
+ error_callback (data, "ELF section name out of range", 0);
+ goto exit;
+ }
+
+ name = names + sh_name;
+
+ if (strcmp (name, section_name) == 0)
+ {
+ if (backtrace_get_view (state, descriptor, shdr->sh_offset,
+ shdr->sh_size, error_callback, data,
+ §ion_view))
+ {
+
+ section_view_valid = 1;
+ section_data
+ = backtrace_alloc (state, shdr->sh_size, error_callback, data);
+ if (section_data == NULL)
+ goto exit;
+ memcpy (section_data, section_view.data, shdr->sh_size);
+ *section_data_len_out = shdr->sh_size;
+ }
+ break;
+ }
+ }
+
+exit:
+ 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 (section_view_valid)
+ backtrace_release_view (state, §ion_view, error_callback, data);
+ return section_data;
+}
+
+
+/* Verify type of the file */
+
+static int
+backtrace_readlink (const char *filename,
+ backtrace_error_callback error_callback, void *data,
+ int *does_not_exist)
+{
+ struct stat link_stat;
+ int file_type;
+ mode_t mode;
+
+ memset (&link_stat, 0, sizeof (struct stat));
+
+ if (lstat (filename, &link_stat) == -1)
+ {
+ if (does_not_exist != NULL && errno == ENOENT)
+ *does_not_exist = 1;
+ else
+ error_callback (data, filename, errno);
+ file_type = -1;
+ }
+
+ mode = link_stat.st_mode & S_IFMT;
+
+ switch (mode)
+ {
+ case S_IFLNK:
+ file_type = LINK;
+ break;
+ case S_IFREG:
+ file_type = REGULAR;
+ break;
+ default:
+ file_type = -1;
+ }
+ return file_type;
+}
+
+/* Resolve full name of the link. In this case we can't use realpath function
+ because it could be undefined on some platfroms, also it allocates memory
+ by malloc, which we can't use. */
+
+static int
+resolve_realname (const char *filename, char *buffer, int *does_not_exist,
+ struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data)
+{
+ char *temp_buffer;
+ int file_type;
+ int filename_len;
+ int temp_filename_len;
+ int valid_temp_buffer;
+ int path_len;
+
+ valid_temp_buffer = 0;
+ filename_len = -1;
+ file_type = LINK;
+
+ /* allocate memory for sizeof(PATH_MAX) + 1 bytes because at this time
+ we don't know how long path could be */
+ temp_buffer = backtrace_alloc (state, PATH_MAX + 1, error_callback, data);
+ if (temp_buffer == NULL)
+ return -1;
+
+ valid_temp_buffer = 1;
+
+ memset (temp_buffer, 0, PATH_MAX + 1);
+ memcpy (temp_buffer, filename, strlen (filename));
+
+ while (file_type == LINK)
+ {
+ filename_len = readlink (temp_buffer, buffer, PATH_MAX);
+ if (filename_len < 1)
+ goto exit;
+
+ temp_filename_len = strlen (buffer);
+
+ /* full path */
+ if (buffer[0] == '/')
+ {
+ memset (temp_buffer, 0, PATH_MAX);
+ memcpy (temp_buffer, buffer, temp_filename_len);
+ }
+ else
+ {
+ /* relative path */
+ path_len = pathlen (temp_buffer);
+ if (path_len < 1)
+ goto exit;
+
+ memcpy (temp_buffer + path_len, buffer, filename_len);
+ temp_buffer[path_len + filename_len] = '\0';
+ }
+
+ file_type = backtrace_readlink (temp_buffer, error_callback,
+ does_not_exist, data);
+ memset (buffer, 0, filename_len);
+ }
+
+ if (file_type != REGULAR)
+ {
+ filename_len = -1;
+ goto exit;
+ }
+
+ filename_len = strlen (temp_buffer);
+ memcpy (buffer, temp_buffer, filename_len);
+
+exit:
+ if (valid_temp_buffer)
+ backtrace_free (state, temp_buffer, PATH_MAX + 1, error_callback, data);
+ return filename_len;
+}
+
+/* Resolve realname of the filename. This function verifies filename.
+ If filename is name of the file it populate realname buffer.
+ If filename is link, it calls resolve_realname function. */
+
+static char *
+backtrace_resolve_realname (const char *filename, int *filename_len,
+ struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data,
+ int *does_not_exist)
+{
+ int file_type;
+ char *realname;
+
+ *filename_len = -1;
+
+ realname = backtrace_alloc (state, PATH_MAX + 1, error_callback, data);
+ if (realname == NULL)
+ goto exit;
+
+ file_type
+ = backtrace_readlink (filename, error_callback, does_not_exist, data);
+
+ if (file_type == LINK)
+ {
+ /* read the actual filename */
+ *filename_len = resolve_realname (filename, realname, does_not_exist,
+ state, error_callback, data);
+ if (*filename_len < 0)
+ goto exit;
+ }
+ else if (file_type == REGULAR)
+ {
+ *filename_len = strlen (filename);
+ if (*filename_len > PATH_MAX)
+ goto exit;
+
+ memcpy (realname, filename, *filename_len);
+ }
+
+exit:
+ return realname;
+}
+
+/* Search for debug file into specifying directorires */
+
+static int
+search_for_debugfile (char *realname, char *debug_filename,
+ backtrace_error_callback error_callback, void *data,
+ struct backtrace_state *state)
+{
+ int debug_filename_len;
+ int pass;
+ int debug_path_len;
+ int debug_does_not_exist;
+ int debug_descriptor;
+ int path_len;
+ char *buffer;
+ int buffer_len;
+ int valid_buffer;
+
+ debug_descriptor = -1;
+ valid_buffer = 0;
+
+ path_len = pathlen (realname);
+ debug_filename_len = strlen ((const char *) debug_filename);
+
+ if (debug_filename_len < 1)
+ goto exit;
+
+ buffer_len = path_len + strlen (debug_file_path[USR_LIB_DEBUG])
+ + debug_filename_len + 1;
+
+ buffer = backtrace_alloc (state, buffer_len, error_callback, data);
+
+ if (buffer == NULL)
+ goto exit;
+ memset (buffer, 0, buffer_len);
+ memcpy (buffer, realname, path_len);
+
+ valid_buffer = 1;
+ for (pass = 0; pass < DEBUG_PATH_MAX; ++pass)
+ {
+ switch (pass)
+ {
+ case CURRENT:
+ {
+ memcpy (buffer + path_len, debug_filename, debug_filename_len);
+ break;
+ }
+ case CURRENT_DEBUG:
+ {
+ debug_path_len = strlen (debug_file_path[CURRENT_DEBUG]);
+ memcpy (buffer + path_len, debug_file_path[CURRENT_DEBUG],
+ debug_path_len);
+ memcpy (buffer + path_len + debug_path_len, debug_filename,
+ debug_filename_len);
+ break;
+ }
+ case USR_LIB_DEBUG:
+ {
+ debug_path_len = strlen (debug_file_path[USR_LIB_DEBUG]);
+ memset (buffer, 0, buffer_len);
+ memcpy (buffer, debug_file_path[USR_LIB_DEBUG], debug_path_len);
+ memcpy (buffer + debug_path_len, debug_filename,
+ debug_filename_len);
+ break;
+ }
+ case USR_LIB_DEBUG_PATH_TO_EXE:
+ {
+ debug_path_len
+ = strlen (debug_file_path[USR_LIB_DEBUG_PATH_TO_EXE]);
+ memset (buffer, 0, buffer_len);
+ memcpy (buffer, debug_file_path[USR_LIB_DEBUG_PATH_TO_EXE],
+ debug_path_len);
+ memcpy (buffer + debug_path_len, realname, path_len);
+ memcpy (buffer + debug_path_len + path_len, debug_filename,
+ debug_filename_len);
+ break;
+ }
+ default:
+ goto exit;
+ }
+
+ debug_descriptor
+ = backtrace_open (buffer, error_callback, data, &debug_does_not_exist);
+
+ if (debug_descriptor > 0)
+ break;
+ }
+exit:
+ if (valid_buffer)
+ backtrace_free (state, buffer, buffer_len, error_callback, data);
+ return debug_descriptor;
+}
+
+/* Open debug file by gnulink */
+
+static int
+open_debugfile_by_gnulink (char *realname, unsigned char *section_data,
+ int section_data_len, struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data)
+{
+ int debug_descriptor;
+
+ debug_descriptor = search_for_debugfile (realname, (char *) section_data,
+ error_callback, data, state);
+ if (debug_descriptor < 0)
+ goto exit;
+
+ /* check the crc32 checksum if it not the same return -1 */
+
+ if (!check_sum (debug_descriptor, (char *) section_data,
+ strlen ((char *) section_data), section_data_len))
+ debug_descriptor = -1;
+
+exit:
+ return debug_descriptor;
+}
+
+/* Convert char to hex */
+
+static char
+hex (char ch)
+{
+ return ch > 9 ? ('a' + (ch - 10)) : ('0' + ch);
+}
+
+/* Get build-id name */
+
+static char *
+get_build_id_name (unsigned char *section_data, int *len,
+ struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data)
+{
+ Elf_External_Note *build_id_section;
+ char *build_id_name;
+ char *temp;
+ const char *debug_postfix;
+ const char *debug_prefix;
+ size_t debug_postfix_len;
+ size_t debug_prefix_len;
+ size_t name_size;
+ int offset;
+ unsigned char *hash_start;
+ unsigned long hash_size;
+ unsigned long identifier;
+
+ debug_postfix_len = 6;
+ debug_prefix_len = 10;
+ debug_postfix = ".debug";
+ debug_prefix = ".build-id/";
+ *len = 0;
+
+ build_id_section = (Elf_External_Note *) section_data;
+ hash_size = getl32 (build_id_section->descsz);
+ identifier = getl32 (build_id_section->type);
+ name_size = getl32 (build_id_section->namesz);
+
+ if (identifier != NT_GNU_BUILD_ID || hash_size == 0 || name_size != 4
+ || strncmp ((char *) build_id_section->name, "GNU", 3) != 0)
+ return NULL;
+
+ offset = 16;
+ hash_start = section_data + offset;
+ *len = hash_size * 2 + debug_postfix_len + debug_prefix_len + 1;
+ build_id_name = backtrace_alloc (state, *len, error_callback, data);
+
+ memset (build_id_name, 0, *len);
+ memcpy (build_id_name, debug_prefix, debug_prefix_len);
+ temp = build_id_name + debug_prefix_len;
+
+ *temp++ = hex ((*hash_start & 0xF0) >> 4);
+ *temp++ = hex (*hash_start & 0x0F);
+ ++hash_start;
+ --hash_size;
+
+ memcpy (temp, "/", 1);
+ ++temp;
+
+ while (hash_size--)
+ {
+ *temp++ = hex ((*hash_start & 0xF0) >> 4);
+ *temp++ = hex (*hash_start & 0x0F);
+ ++hash_start;
+ }
+
+ memcpy (temp, debug_postfix, debug_postfix_len);
+ return build_id_name;
+}
+
+/* Open file by build-id */
+
+static int
+open_debugfile_by_build_id (char *realname, unsigned char *section_data,
+ struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data)
+
+{
+ char *build_id_name;
+ int debug_descriptor;
+ int build_id_name_len;
+ int valid_build_id_name;
+
+ debug_descriptor = -1;
+ valid_build_id_name = 0;
+
+ build_id_name = get_build_id_name (section_data, &build_id_name_len, state,
+ error_callback, data);
+
+ if (build_id_name == NULL || build_id_name_len <= 0)
+ goto exit;
+
+ valid_build_id_name = 1;
+
+ debug_descriptor = search_for_debugfile (realname, build_id_name,
+ error_callback, data, state);
+
+exit:
+ if (valid_build_id_name)
+ backtrace_free (state, build_id_name, build_id_name_len, error_callback,
+ data);
+ return debug_descriptor;
+}
+
+/* Open debug file */
+
+int
+backtrace_open_debugfile (const char *filename,
+ backtrace_error_callback error_callback, void *data,
+ int *does_not_exist, struct backtrace_state *state,
+ int exe)
+{
+ int descriptor;
+ int debug_descriptor;
+ unsigned char *gnulink_section_data;
+ unsigned char *build_id_section_data;
+ size_t valid_descriptor;
+ size_t valid_gnulink_section_data;
+ size_t valid_build_id_section_data;
+ size_t valid_realname;
+ int build_id_section_data_len;
+ int gnu_link_section_data_len;
+ char *realname;
+ int filename_len;
+
+ valid_realname = 0;
+ valid_descriptor = 0;
+ valid_gnulink_section_data = 0;
+ valid_build_id_section_data = 0;
+ build_id_section_data_len = 0;
+ gnu_link_section_data_len = 0;
+ debug_descriptor = -1;
+
+ descriptor = backtrace_open (filename, error_callback, data, does_not_exist);
+
+ if (descriptor < 0)
+ goto exit;
+
+ valid_descriptor = 1;
+
+ realname = backtrace_resolve_realname (filename, &filename_len, state,
+ error_callback, data, does_not_exist);
+
+ if (realname == NULL || filename_len < 0)
+ goto exit;
+
+ valid_realname = 1;
+
+ /* check if build-id section does exist */
+ build_id_section_data
+ = elf_get_section_by_name (state, descriptor, error_callback, data, exe,
+ &build_id_section_data_len,
+ ".note.gnu.build-id");
+
+ if (build_id_section_data != NULL && build_id_section_data_len > 0)
+ {
+ valid_build_id_section_data = 1;
+ debug_descriptor
+ = open_debugfile_by_build_id (realname, build_id_section_data, state,
+ error_callback, data);
+ }
+
+ if (debug_descriptor < 0)
+ {
+ gnulink_section_data
+ = elf_get_section_by_name (state, descriptor, error_callback, data, exe,
+ &gnu_link_section_data_len,
+ ".gnu_debuglink");
+
+ if (gnulink_section_data != NULL && gnu_link_section_data_len > 0)
+ {
+ valid_gnulink_section_data = 1;
+ debug_descriptor
+ = open_debugfile_by_gnulink (realname, gnulink_section_data,
+ gnu_link_section_data_len, state,
+ error_callback, data);
+ }
+ }
+
+exit:
+ if (valid_descriptor)
+ backtrace_close (descriptor, error_callback, data);
+ if (valid_gnulink_section_data)
+ backtrace_free (state, gnulink_section_data, gnu_link_section_data_len,
+ error_callback, data);
+ if (valid_build_id_section_data)
+ backtrace_free (state, build_id_section_data, build_id_section_data_len,
+ error_callback, data);
+ if (valid_realname)
+ backtrace_free (state, realname, PATH_MAX + 1, error_callback, data);
+ return debug_descriptor;
+}
+
/* A dummy callback function used when we can't find any debug info. */
static int
@@ -521,7 +1373,6 @@ 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;
@@ -557,102 +1408,18 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
strtab_view_valid = 0;
debug_view_valid = 0;
- if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
- data, &ehdr_view))
+ if (!elf_header_is_valid (state, descriptor, error_callback, data, exe, &shoff,
+ &shnum, &shstrndx, &ehdr))
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))
+ (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;
@@ -877,6 +1644,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
int does_not_exist;
fileline elf_fileline_fn;
int found_dwarf;
+ int debugfile_does_not_exist;
/* 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
@@ -896,8 +1664,12 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
pd->exe_descriptor = -1;
}
- descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
- pd->data, &does_not_exist);
+ descriptor
+ = backtrace_open_debugfile (info->dlpi_name, pd->error_callback, pd->data,
+ &debugfile_does_not_exist, pd->state, 0);
+ if (descriptor < 0)
+ descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
+ pd->data, &does_not_exist);
if (descriptor < 0)
return 0;
}
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index 0fd350a..5699a8e 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -84,6 +84,7 @@ fileline_initialize (struct backtrace_state *state,
{
const char *filename;
int does_not_exist;
+ int debugfile_does_not_exist;
switch (pass)
{
@@ -106,8 +107,14 @@ fileline_initialize (struct backtrace_state *state,
if (filename == NULL)
continue;
- descriptor = backtrace_open (filename, error_callback, data,
- &does_not_exist);
+ descriptor
+ = backtrace_open_debugfile (filename, error_callback, data,
+ &debugfile_does_not_exist, state, 1);
+
+ if (descriptor < 0)
+ descriptor
+ = backtrace_open (filename, error_callback, data, &does_not_exist);
+
if (descriptor < 0 && !does_not_exist)
{
called_error_callback = 1;
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 89b7bf7..80a75ed 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -176,6 +176,15 @@ struct backtrace_view
size_t len;
};
+/* Open debug file which name is placed in gnu_debuglink section.
+ Check the crc32 sum and search file with debug data. On success returns
+ descriptor of that file on fail -1 */
+
+extern int backtrace_open_debugfile (const char *filename,
+ backtrace_error_callback, void *data,
+ int *does_not_exist,
+ struct backtrace_state *state, int exe);
+
/* 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,