aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbacktrace/ChangeLog53
-rw-r--r--libbacktrace/Makefile.am21
-rw-r--r--libbacktrace/Makefile.in112
-rwxr-xr-xlibbacktrace/configure40
-rw-r--r--libbacktrace/configure.ac11
-rw-r--r--libbacktrace/dwarf.c1127
-rw-r--r--libbacktrace/elf.c4
-rw-r--r--libbacktrace/internal.h4
-rw-r--r--libbacktrace/pecoff.c6
-rw-r--r--libbacktrace/xcoff.c2
10 files changed, 1213 insertions, 167 deletions
diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog
index 7d91aad..b63d216 100644
--- a/libbacktrace/ChangeLog
+++ b/libbacktrace/ChangeLog
@@ -1,3 +1,56 @@
+2019-12-13 Ian Lance Taylor <iant@golang.org>
+
+ Add DWARF 5 support.
+ * dwarf.c (struct attr): Add val field.
+ (enum attr_val_encoding): Add ATTR_VAL_ADDDRESS_INDEX,
+ ATTR_VAL_STRING_INDEX, ATTR_VAL_RNGLISTS_INDEX.
+ (struct line_header): Add addrsize field.
+ (struct line_header_format): Define.
+ (struct unit): Add str_offsets_base, addr_base, and rnglists_base
+ fields.
+ (read_uint24): New static function.
+ (read_attribute): Add implicit_val parameter. Replace dwarf_str
+ and dwarf_str_size parameters with dwarf_sections parameter. Add
+ support for new DWARF 5 forms. Change all callers.
+ (resolve_string): New static function.
+ (resolve_addr_index): Likewise.
+ (read_abbrevs): Support DW_FORM_implicit_const.
+ (struct pcrange): Add lowpc_is_addr_index, highpc_is_addr_Index,
+ and ranges_is_index fields.
+ (update_pcrange): Support DWARF 5 encodings.
+ (add_high_low_range): New static function, split out of
+ add_ranges.
+ (add_ranges_from_ranges): Likewise.
+ (add_ranges_from_rnglists): New static function.
+ (add_ranges): Just call new helper functions.
+ (find_address_ranges): Use resolve_string for strings, after
+ reading all attributes. Handle new DWARF 5 attributes.
+ (build_address_map): Support DWARF 5 compilation units.
+ (read_v2_paths): New static function, split out of
+ read_line_header.
+ (read_lnct): New static function.
+ (read_line_header_format_entries): Likewise.
+ (read_line_header): Add ddata parameter. Support DWARF 5 line
+ headers. Call new helper functions. Change all callers.
+ (read_line_program): Use addrsize from line program header. Don't
+ special case directory index 0 for DWARF 5.
+ (read_referenced_name): Use resolve_string.
+ (read_function_entry): Handle DWARF 5 encodings. Use
+ resolve_string.
+ * internal.h (enum dwarf_section): Add DEBUG_ADDR,
+ DEBUG_STR_OFFSETS, DEBUG_LINE_STR, DEBUG_RNGLISTS.
+ * elf.c (dwarf_section_names): Add new section names.
+ * pecoff.c (dwarf_section_names): Likewise.
+ * xcoff.c (xcoff_add): Clear dwarf_sections before setting
+ fields.
+ * configure.ac: Define HAVE_DWARF5 automake conditional.
+ * Makefile.am (dwarf5_SOURCES): New variable if HAVE_DWARF5.
+ (dwarf5_CFLAGS, dwarf5_LDADD): Likewise.
+ (dwarf5_alloc_SOURCES, dwarf5_alloc_CFLAGS): Likewise.
+ (dwarf5_alloc_LDADD): Likewise.
+ (BUILDTESTS): Add dwarf5 tests if HAVE_DWARF5.
+ (CLEANFILES, clean-local): Define.
+
2019-12-08 Ian Lance Taylor <iant@golang.org>
* dwarf.c (struct pcrange): Define.
diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index e989d8e..79abcc9 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -385,12 +385,33 @@ BUILDTESTS += ctestg_alloc ctesta_alloc
endif
+if HAVE_DWARF5
+
+dwarf5_SOURCES = btest.c testlib.c
+dwarf5_CFLAGS = $(AM_CFLAGS) -gdwarf-5
+dwarf5_LDADD = libbacktrace.la
+
+BUILDTESTS += dwarf5
+
+dwarf5_alloc_SOURCES = $(dwarf5_SOURCES)
+dwarf5_alloc_CFLAGS = $(dwarf5_CFLAGS)
+dwarf5_alloc_LDADD = libbacktrace_alloc.la
+
+BUILDTESTS += dwarf5_alloc
+
+endif
+
endif NATIVE
check_PROGRAMS += $(BUILDTESTS)
TESTS += $(BUILDTESTS)
+CLEANFILES = $(TESTS) *.debug elf_for_test.c edtest2_build.c gen_edtest2_build
+
+clean-local:
+ -rm -rf usr
+
# 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 4ade8e9..01855bf 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -121,10 +121,10 @@ build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
- $(am__EXEEXT_11)
+ $(am__EXEEXT_12)
TESTS = $(am__append_4) $(am__append_6) $(am__append_8) \
$(am__append_11) $(am__append_12) $(am__append_18) \
- $(am__EXEEXT_11)
+ $(am__EXEEXT_12)
@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_1 = libbacktrace_elf_for_test.la
@NATIVE_TRUE@am__append_2 = test_elf_32 test_elf_64 test_xcoff_32 \
@NATIVE_TRUE@ test_xcoff_64 test_pecoff test_unknown unittest \
@@ -148,6 +148,7 @@ TESTS = $(am__append_4) $(am__append_6) $(am__append_8) \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_19 = ctestg ctesta \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctestg_alloc \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta_alloc
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@am__append_20 = dwarf5 dwarf5_alloc
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/cet.m4 \
@@ -224,9 +225,11 @@ libbacktrace_noformat_la_OBJECTS = \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta$(EXEEXT) \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctestg_alloc$(EXEEXT) \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta_alloc$(EXEEXT)
-am__EXEEXT_11 = $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@am__EXEEXT_11 = dwarf5$(EXEEXT) \
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@ dwarf5_alloc$(EXEEXT)
+am__EXEEXT_12 = $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
$(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \
- $(am__EXEEXT_10)
+ $(am__EXEEXT_10) $(am__EXEEXT_11)
@NATIVE_TRUE@am_allocfail_OBJECTS = allocfail.$(OBJEXT) \
@NATIVE_TRUE@ testlib.$(OBJEXT)
allocfail_OBJECTS = $(am_allocfail_OBJECTS)
@@ -305,20 +308,39 @@ ctestg_alloc_OBJECTS = $(am_ctestg_alloc_OBJECTS)
ctestg_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ctestg_alloc_CFLAGS) \
$(CFLAGS) $(ctestg_alloc_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@am_dwarf5_OBJECTS = \
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@ dwarf5-btest.$(OBJEXT) \
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@ dwarf5-testlib.$(OBJEXT)
+dwarf5_OBJECTS = $(am_dwarf5_OBJECTS)
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_DEPENDENCIES = libbacktrace.la
+dwarf5_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(dwarf5_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@am__objects_7 = \
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@ dwarf5_alloc-btest.$(OBJEXT) \
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@ dwarf5_alloc-testlib.$(OBJEXT)
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@am_dwarf5_alloc_OBJECTS = \
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@ $(am__objects_7)
+dwarf5_alloc_OBJECTS = $(am_dwarf5_alloc_OBJECTS)
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_alloc_DEPENDENCIES = \
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@ libbacktrace_alloc.la
+dwarf5_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(dwarf5_alloc_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
@NATIVE_TRUE@am_edtest_OBJECTS = edtest.$(OBJEXT) \
@NATIVE_TRUE@ edtest2_build.$(OBJEXT) testlib.$(OBJEXT)
edtest_OBJECTS = $(am_edtest_OBJECTS)
@NATIVE_TRUE@edtest_DEPENDENCIES = libbacktrace.la
-@NATIVE_TRUE@am__objects_7 = edtest.$(OBJEXT) edtest2_build.$(OBJEXT) \
+@NATIVE_TRUE@am__objects_8 = edtest.$(OBJEXT) edtest2_build.$(OBJEXT) \
@NATIVE_TRUE@ testlib.$(OBJEXT)
-@NATIVE_TRUE@am_edtest_alloc_OBJECTS = $(am__objects_7)
+@NATIVE_TRUE@am_edtest_alloc_OBJECTS = $(am__objects_8)
edtest_alloc_OBJECTS = $(am_edtest_alloc_OBJECTS)
@NATIVE_TRUE@edtest_alloc_DEPENDENCIES = libbacktrace_alloc.la
@NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
stest_OBJECTS = $(am_stest_OBJECTS)
@NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
-@NATIVE_TRUE@am__objects_8 = stest.$(OBJEXT)
-@NATIVE_TRUE@am_stest_alloc_OBJECTS = $(am__objects_8)
+@NATIVE_TRUE@am__objects_9 = stest.$(OBJEXT)
+@NATIVE_TRUE@am_stest_alloc_OBJECTS = $(am__objects_9)
stest_alloc_OBJECTS = $(am_stest_alloc_OBJECTS)
@NATIVE_TRUE@stest_alloc_DEPENDENCIES = libbacktrace_alloc.la
@NATIVE_TRUE@am_test_elf_32_OBJECTS = test_format.$(OBJEXT) \
@@ -359,11 +381,11 @@ ttest_OBJECTS = $(am_ttest_OBJECTS)
ttest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ttest_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__objects_9 = \
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__objects_10 = \
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ ttest_alloc-ttest.$(OBJEXT) \
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ ttest_alloc-testlib.$(OBJEXT)
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am_ttest_alloc_OBJECTS = \
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ $(am__objects_9)
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ $(am__objects_10)
ttest_alloc_OBJECTS = $(am_ttest_alloc_OBJECTS)
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_alloc_DEPENDENCIES = \
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ libbacktrace_alloc.la
@@ -374,8 +396,8 @@ ttest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@NATIVE_TRUE@ testlib.$(OBJEXT)
unittest_OBJECTS = $(am_unittest_OBJECTS)
@NATIVE_TRUE@unittest_DEPENDENCIES = libbacktrace.la
-@NATIVE_TRUE@am__objects_10 = unittest.$(OBJEXT) testlib.$(OBJEXT)
-@NATIVE_TRUE@am_unittest_alloc_OBJECTS = $(am__objects_10)
+@NATIVE_TRUE@am__objects_11 = unittest.$(OBJEXT) testlib.$(OBJEXT)
+@NATIVE_TRUE@am_unittest_alloc_OBJECTS = $(am__objects_11)
unittest_alloc_OBJECTS = $(am_unittest_alloc_OBJECTS)
@NATIVE_TRUE@unittest_alloc_DEPENDENCIES = libbacktrace_alloc.la
@HAVE_ELF_TRUE@@NATIVE_TRUE@am_ztest_OBJECTS = ztest-ztest.$(OBJEXT) \
@@ -387,11 +409,11 @@ ztest_OBJECTS = $(am_ztest_OBJECTS)
ztest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ztest_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_ELF_TRUE@@NATIVE_TRUE@am__objects_11 = \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am__objects_12 = \
@HAVE_ELF_TRUE@@NATIVE_TRUE@ ztest_alloc-ztest.$(OBJEXT) \
@HAVE_ELF_TRUE@@NATIVE_TRUE@ ztest_alloc-testlib.$(OBJEXT)
@HAVE_ELF_TRUE@@NATIVE_TRUE@am_ztest_alloc_OBJECTS = \
-@HAVE_ELF_TRUE@@NATIVE_TRUE@ $(am__objects_11)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@ $(am__objects_12)
ztest_alloc_OBJECTS = $(am_ztest_alloc_OBJECTS)
@HAVE_ELF_TRUE@@NATIVE_TRUE@ztest_alloc_DEPENDENCIES = \
@HAVE_ELF_TRUE@@NATIVE_TRUE@ libbacktrace_alloc.la \
@@ -441,7 +463,8 @@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
$(b2test_SOURCES) $(b3test_SOURCES) $(btest_SOURCES) \
$(btest_alloc_SOURCES) $(btest_lto_SOURCES) $(ctesta_SOURCES) \
$(ctesta_alloc_SOURCES) $(ctestg_SOURCES) \
- $(ctestg_alloc_SOURCES) $(edtest_SOURCES) \
+ $(ctestg_alloc_SOURCES) $(dwarf5_SOURCES) \
+ $(dwarf5_alloc_SOURCES) $(edtest_SOURCES) \
$(edtest_alloc_SOURCES) $(stest_SOURCES) \
$(stest_alloc_SOURCES) $(test_elf_32_SOURCES) \
$(test_elf_64_SOURCES) $(test_pecoff_SOURCES) \
@@ -863,7 +886,7 @@ libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
# Add test to this variable, if you want it to be build and run.
BUILDTESTS = $(am__append_2) $(am__append_9) $(am__append_10) \
$(am__append_15) $(am__append_16) $(am__append_17) \
- $(am__append_19)
+ $(am__append_19) $(am__append_20)
@NATIVE_TRUE@check_LTLIBRARIES = libbacktrace_alloc.la \
@NATIVE_TRUE@ libbacktrace_noformat.la $(am__append_1) \
@NATIVE_TRUE@ libbacktrace_instrumented_alloc.la
@@ -960,6 +983,13 @@ BUILDTESTS = $(am__append_2) $(am__append_9) $(am__append_10) \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_alloc_CFLAGS = $(ctesta_CFLAGS)
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_alloc_LDFLAGS = $(ctesta_LDFLAGS)
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_alloc_LDADD = libbacktrace_alloc.la
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_SOURCES = btest.c testlib.c
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_CFLAGS = $(AM_CFLAGS) -gdwarf-5
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_LDADD = libbacktrace.la
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_alloc_SOURCES = $(dwarf5_SOURCES)
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_alloc_CFLAGS = $(dwarf5_CFLAGS)
+@HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_alloc_LDADD = libbacktrace_alloc.la
+CLEANFILES = $(TESTS) *.debug elf_for_test.c edtest2_build.c gen_edtest2_build
# We can't use automake's automatic dependency tracking, because it
# breaks when using bootstrap-lean. Automatic dependency tracking
@@ -1124,6 +1154,14 @@ ctestg_alloc$(EXEEXT): $(ctestg_alloc_OBJECTS) $(ctestg_alloc_DEPENDENCIES) $(EX
@rm -f ctestg_alloc$(EXEEXT)
$(AM_V_CCLD)$(ctestg_alloc_LINK) $(ctestg_alloc_OBJECTS) $(ctestg_alloc_LDADD) $(LIBS)
+dwarf5$(EXEEXT): $(dwarf5_OBJECTS) $(dwarf5_DEPENDENCIES) $(EXTRA_dwarf5_DEPENDENCIES)
+ @rm -f dwarf5$(EXEEXT)
+ $(AM_V_CCLD)$(dwarf5_LINK) $(dwarf5_OBJECTS) $(dwarf5_LDADD) $(LIBS)
+
+dwarf5_alloc$(EXEEXT): $(dwarf5_alloc_OBJECTS) $(dwarf5_alloc_DEPENDENCIES) $(EXTRA_dwarf5_alloc_DEPENDENCIES)
+ @rm -f dwarf5_alloc$(EXEEXT)
+ $(AM_V_CCLD)$(dwarf5_alloc_LINK) $(dwarf5_alloc_OBJECTS) $(dwarf5_alloc_LDADD) $(LIBS)
+
edtest$(EXEEXT): $(edtest_OBJECTS) $(edtest_DEPENDENCIES) $(EXTRA_edtest_DEPENDENCIES)
@rm -f edtest$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(edtest_OBJECTS) $(edtest_LDADD) $(LIBS)
@@ -1311,6 +1349,30 @@ ctestg_alloc-testlib.o: testlib.c
ctestg_alloc-testlib.obj: testlib.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctestg_alloc_CFLAGS) $(CFLAGS) -c -o ctestg_alloc-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+dwarf5-btest.o: btest.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dwarf5_CFLAGS) $(CFLAGS) -c -o dwarf5-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+dwarf5-btest.obj: btest.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dwarf5_CFLAGS) $(CFLAGS) -c -o dwarf5-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+dwarf5-testlib.o: testlib.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dwarf5_CFLAGS) $(CFLAGS) -c -o dwarf5-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+dwarf5-testlib.obj: testlib.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dwarf5_CFLAGS) $(CFLAGS) -c -o dwarf5-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
+dwarf5_alloc-btest.o: btest.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dwarf5_alloc_CFLAGS) $(CFLAGS) -c -o dwarf5_alloc-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+dwarf5_alloc-btest.obj: btest.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dwarf5_alloc_CFLAGS) $(CFLAGS) -c -o dwarf5_alloc-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+dwarf5_alloc-testlib.o: testlib.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dwarf5_alloc_CFLAGS) $(CFLAGS) -c -o dwarf5_alloc-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+dwarf5_alloc-testlib.obj: testlib.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dwarf5_alloc_CFLAGS) $(CFLAGS) -c -o dwarf5_alloc-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
ttest-ttest.o: ttest.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-ttest.o `test -f 'ttest.c' || echo '$(srcdir)/'`ttest.c
@@ -1771,6 +1833,20 @@ ctesta_alloc.log: ctesta_alloc$(EXEEXT)
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
+dwarf5.log: dwarf5$(EXEEXT)
+ @p='dwarf5$(EXEEXT)'; \
+ b='dwarf5'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+dwarf5_alloc.log: dwarf5_alloc$(EXEEXT)
+ @p='dwarf5_alloc$(EXEEXT)'; \
+ b='dwarf5_alloc'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
.test.log:
@p='$<'; \
$(am__set_b); \
@@ -1816,6 +1892,7 @@ mostlyclean-generic:
-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -1973,6 +2050,9 @@ uninstall-am:
@NATIVE_TRUE@ "$(TEST_BUILD_ID_DIR)" \
@NATIVE_TRUE@ $<
@NATIVE_TRUE@ $(OBJCOPY) --strip-debug $< $@
+
+clean-local:
+ -rm -rf usr
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/configure b/libbacktrace/configure
index 03c6d2e..676adb8 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -643,6 +643,8 @@ HAVE_COMPRESSED_DEBUG_FALSE
HAVE_COMPRESSED_DEBUG_TRUE
HAVE_ZLIB_FALSE
HAVE_ZLIB_TRUE
+HAVE_DWARF5_FALSE
+HAVE_DWARF5_TRUE
HAVE_PTHREAD_FALSE
HAVE_PTHREAD_TRUE
PTHREAD_CFLAGS
@@ -11497,7 +11499,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11500 "configure"
+#line 11502 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11603,7 +11605,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11606 "configure"
+#line 11608 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -13280,6 +13282,36 @@ else
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -gdwarf-5 is supported" >&5
+$as_echo_n "checking whether -gdwarf-5 is supported... " >&6; }
+if ${libbacktrace_cv_lib_dwarf5+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -gdwarf-5"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int i;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ libbacktrace_cv_lib_dwarf5=yes
+else
+ libbacktrace_cv_lib_dwarf5=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS=$CFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_lib_dwarf5" >&5
+$as_echo "$libbacktrace_cv_lib_dwarf5" >&6; }
+ if test "$libbacktrace_cv_lib_dwarf5" = yes; then
+ HAVE_DWARF5_TRUE=
+ HAVE_DWARF5_FALSE='#'
+else
+ HAVE_DWARF5_TRUE='#'
+ HAVE_DWARF5_FALSE=
+fi
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compress in -lz" >&5
$as_echo_n "checking for compress in -lz... " >&6; }
if ${ac_cv_lib_z_compress+:} false; then :
@@ -13665,6 +13697,10 @@ if test -z "${HAVE_PTHREAD_TRUE}" && test -z "${HAVE_PTHREAD_FALSE}"; then
as_fn_error $? "conditional \"HAVE_PTHREAD\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_DWARF5_TRUE}" && test -z "${HAVE_DWARF5_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_DWARF5\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${HAVE_ZLIB_TRUE}" && test -z "${HAVE_ZLIB_FALSE}"; then
as_fn_error $? "conditional \"HAVE_ZLIB\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index a657ef6..cda4f09 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -420,6 +420,17 @@ AC_SUBST(PTHREAD_CFLAGS)
AM_CONDITIONAL(HAVE_PTHREAD, test "$libgo_cv_lib_pthread" = yes)
+dnl Test whether the compiler supports the -gdwarf-5 option.
+AC_CACHE_CHECK([whether -gdwarf-5 is supported],
+[libbacktrace_cv_lib_dwarf5],
+[CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -gdwarf-5"
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([int i;])],
+[libbacktrace_cv_lib_dwarf5=yes],
+[libbacktrace_cv_lib_dwarf5=no])
+CFLAGS=$CFLAGS_hold])
+AM_CONDITIONAL(HAVE_DWARF5, test "$libbacktrace_cv_lib_dwarf5" = yes)
+
AC_CHECK_LIB([z], [compress],
[AC_DEFINE(HAVE_ZLIB, 1, [Define if -lz is available.])])
AM_CONDITIONAL(HAVE_ZLIB, test "$ac_cv_lib_z_compress" = yes)
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index 9e00792..d273768 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -92,6 +92,8 @@ struct attr
enum dwarf_attribute name;
/* The attribute form. */
enum dwarf_form form;
+ /* The attribute value, for DW_FORM_implicit_const. */
+ int64_t val;
};
/* A single DWARF abbreviation. */
@@ -133,22 +135,29 @@ enum attr_val_encoding
ATTR_VAL_NONE,
/* An address. */
ATTR_VAL_ADDRESS,
+ /* An index into the .debug_addr section, whose value is relative to
+ * the DW_AT_addr_base attribute of the compilation unit. */
+ ATTR_VAL_ADDRESS_INDEX,
/* A unsigned integer. */
ATTR_VAL_UINT,
/* A sigd integer. */
ATTR_VAL_SINT,
/* A string. */
ATTR_VAL_STRING,
+ /* An index into the .debug_str_offsets section. */
+ ATTR_VAL_STRING_INDEX,
/* An offset to other data in the containing unit. */
ATTR_VAL_REF_UNIT,
- /* An offset to other data within the .dwarf_info section. */
+ /* An offset to other data within the .debug_info section. */
ATTR_VAL_REF_INFO,
- /* An offset to other data within the alt .dwarf_info section. */
+ /* An offset to other data within the alt .debug_info section. */
ATTR_VAL_REF_ALT_INFO,
/* An offset to data in some other section. */
ATTR_VAL_REF_SECTION,
/* A type signature. */
ATTR_VAL_REF_TYPE,
+ /* An index into the .debug_rnglists section. */
+ ATTR_VAL_RNGLISTS_INDEX,
/* A block of data (not represented). */
ATTR_VAL_BLOCK,
/* An expression (not represented). */
@@ -163,7 +172,7 @@ struct attr_val
enum attr_val_encoding encoding;
union
{
- /* ATTR_VAL_ADDRESS, ATTR_VAL_UINT, ATTR_VAL_REF*. */
+ /* ATTR_VAL_ADDRESS*, ATTR_VAL_UINT, ATTR_VAL_REF*. */
uint64_t uint;
/* ATTR_VAL_SINT. */
int64_t sint;
@@ -179,6 +188,8 @@ struct line_header
{
/* The version of the line number information. */
int version;
+ /* Address size. */
+ int addrsize;
/* The minimum instruction length. */
unsigned int min_insn_len;
/* The maximum number of ops per instruction. */
@@ -201,6 +212,14 @@ struct line_header
const char **filenames;
};
+/* A format description from a line header. */
+
+struct line_header_format
+{
+ int lnct; /* LNCT code. */
+ enum dwarf_form form; /* Form of entry data. */
+};
+
/* Map a single PC value to a file/line. We will keep a vector of
these sorted by PC value. Each file/line will be correct from the
PC up to the PC of the next entry if there is one. We allocate one
@@ -297,6 +316,12 @@ struct unit
int addrsize;
/* Offset into line number information. */
off_t lineoff;
+ /* Offset of compilation unit in .debug_str_offsets. */
+ uint64_t str_offsets_base;
+ /* Offset of compilation unit in .debug_addr. */
+ uint64_t addr_base;
+ /* Offset of compilation unit in .debug_rnglists. */
+ uint64_t rnglists_base;
/* Primary source file. */
const char *filename;
/* Compilation command working directory. */
@@ -483,6 +508,23 @@ read_uint16 (struct dwarf_buf *buf)
return ((uint16_t) p[1] << 8) | (uint16_t) p[0];
}
+/* Read a 24 bit value from BUF and advance 3 bytes. */
+
+static uint32_t
+read_uint24 (struct dwarf_buf *buf)
+{
+ const unsigned char *p = buf->buf;
+
+ if (!advance (buf, 3))
+ return 0;
+ if (buf->is_bigendian)
+ return (((uint32_t) p[0] << 16) | ((uint32_t) p[1] << 8)
+ | (uint32_t) p[2]);
+ else
+ return (((uint32_t) p[2] << 16) | ((uint32_t) p[1] << 8)
+ | (uint32_t) p[0]);
+}
+
/* Read a uint32 from BUF and advance 4 bytes. */
static uint32_t
@@ -709,9 +751,9 @@ free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs,
forms, because we don't care about them. */
static int
-read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
- int is_dwarf64, int version, int addrsize,
- const unsigned char *dwarf_str, size_t dwarf_str_size,
+read_attribute (enum dwarf_form form, uint64_t implicit_val,
+ struct dwarf_buf *buf, int is_dwarf64, int version,
+ int addrsize, const struct dwarf_sections *dwarf_sections,
struct dwarf_data *altlink, struct attr_val *val)
{
/* Avoid warnings about val.u.FIELD may be used uninitialized if
@@ -744,6 +786,9 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
val->encoding = ATTR_VAL_UINT;
val->u.uint = read_uint64 (buf);
return 1;
+ case DW_FORM_data16:
+ val->encoding = ATTR_VAL_BLOCK;
+ return advance (buf, 16);
case DW_FORM_string:
val->encoding = ATTR_VAL_STRING;
val->u.string = read_string (buf);
@@ -771,13 +816,29 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
uint64_t offset;
offset = read_offset (buf, is_dwarf64);
- if (offset >= dwarf_str_size)
+ if (offset >= dwarf_sections->size[DEBUG_STR])
{
dwarf_buf_error (buf, "DW_FORM_strp out of range");
return 0;
}
val->encoding = ATTR_VAL_STRING;
- val->u.string = (const char *) dwarf_str + offset;
+ val->u.string =
+ (const char *) dwarf_sections->data[DEBUG_STR] + offset;
+ return 1;
+ }
+ case DW_FORM_line_strp:
+ {
+ uint64_t offset;
+
+ offset = read_offset (buf, is_dwarf64);
+ if (offset >= dwarf_sections->size[DEBUG_LINE_STR])
+ {
+ dwarf_buf_error (buf, "DW_FORM_line_strp out of range");
+ return 0;
+ }
+ val->encoding = ATTR_VAL_STRING;
+ val->u.string =
+ (const char *) dwarf_sections->data[DEBUG_LINE_STR] + offset;
return 1;
}
case DW_FORM_udata:
@@ -816,9 +877,15 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
uint64_t form;
form = read_uleb128 (buf);
- return read_attribute ((enum dwarf_form) form, buf, is_dwarf64,
- version, addrsize, dwarf_str, dwarf_str_size,
- altlink, val);
+ if (form == DW_FORM_implicit_const)
+ {
+ dwarf_buf_error (buf,
+ "DW_FORM_indirect to DW_FORM_implicit_const");
+ return 0;
+ }
+ return read_attribute ((enum dwarf_form) form, 0, buf, is_dwarf64,
+ version, addrsize, dwarf_sections, altlink,
+ val);
}
case DW_FORM_sec_offset:
val->encoding = ATTR_VAL_REF_SECTION;
@@ -835,6 +902,88 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
val->encoding = ATTR_VAL_REF_TYPE;
val->u.uint = read_uint64 (buf);
return 1;
+ case DW_FORM_strx: case DW_FORM_strx1: case DW_FORM_strx2:
+ case DW_FORM_strx3: case DW_FORM_strx4:
+ {
+ uint64_t offset;
+
+ switch (form)
+ {
+ case DW_FORM_strx:
+ offset = read_uleb128 (buf);
+ break;
+ case DW_FORM_strx1:
+ offset = read_byte (buf);
+ break;
+ case DW_FORM_strx2:
+ offset = read_uint16 (buf);
+ break;
+ case DW_FORM_strx3:
+ offset = read_uint24 (buf);
+ break;
+ case DW_FORM_strx4:
+ offset = read_uint32 (buf);
+ break;
+ default:
+ /* This case can't happen. */
+ return 0;
+ }
+ val->encoding = ATTR_VAL_STRING_INDEX;
+ val->u.uint = offset;
+ return 1;
+ }
+ case DW_FORM_addrx: case DW_FORM_addrx1: case DW_FORM_addrx2:
+ case DW_FORM_addrx3: case DW_FORM_addrx4:
+ {
+ uint64_t offset;
+
+ switch (form)
+ {
+ case DW_FORM_addrx:
+ offset = read_uleb128 (buf);
+ break;
+ case DW_FORM_addrx1:
+ offset = read_byte (buf);
+ break;
+ case DW_FORM_addrx2:
+ offset = read_uint16 (buf);
+ break;
+ case DW_FORM_addrx3:
+ offset = read_uint24 (buf);
+ break;
+ case DW_FORM_addrx4:
+ offset = read_uint32 (buf);
+ break;
+ default:
+ /* This case can't happen. */
+ return 0;
+ }
+ val->encoding = ATTR_VAL_ADDRESS_INDEX;
+ val->u.uint = offset;
+ return 1;
+ }
+ case DW_FORM_ref_sup4:
+ val->encoding = ATTR_VAL_REF_SECTION;
+ val->u.uint = read_uint32 (buf);
+ return 1;
+ case DW_FORM_ref_sup8:
+ val->encoding = ATTR_VAL_REF_SECTION;
+ val->u.uint = read_uint64 (buf);
+ return 1;
+ case DW_FORM_implicit_const:
+ val->encoding = ATTR_VAL_UINT;
+ val->u.uint = implicit_val;
+ return 1;
+ case DW_FORM_loclistx:
+ /* We don't distinguish this from DW_FORM_sec_offset. It
+ * shouldn't matter since we don't care about loclists. */
+ val->encoding = ATTR_VAL_REF_SECTION;
+ val->u.uint = read_uleb128 (buf);
+ return 1;
+ case DW_FORM_rnglistx:
+ val->encoding = ATTR_VAL_RNGLISTS_INDEX;
+ val->u.uint = read_uleb128 (buf);
+ return 1;
case DW_FORM_GNU_addr_index:
val->encoding = ATTR_VAL_REF_SECTION;
val->u.uint = read_uleb128 (buf);
@@ -852,9 +1001,10 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
}
val->encoding = ATTR_VAL_REF_ALT_INFO;
return 1;
- case DW_FORM_GNU_strp_alt:
+ case DW_FORM_strp_sup: case DW_FORM_GNU_strp_alt:
{
uint64_t offset;
+
offset = read_offset (buf, is_dwarf64);
if (altlink == NULL)
{
@@ -863,7 +1013,7 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
}
if (offset >= altlink->dwarf_sections.size[DEBUG_STR])
{
- dwarf_buf_error (buf, "DW_FORM_GNU_strp_alt out of range");
+ dwarf_buf_error (buf, "DW_FORM_strp_sup out of range");
return 0;
}
val->encoding = ATTR_VAL_STRING;
@@ -877,6 +1027,95 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
}
}
+/* If we can determine the value of a string attribute, set *STRING to
+ point to the string. Return 1 on success, 0 on error. If we don't
+ know the value, we consider that a success, and we don't change
+ *STRING. An error is only reported for some sort of out of range
+ offset. */
+
+static int
+resolve_string (const struct dwarf_sections *dwarf_sections, int is_dwarf64,
+ int is_bigendian, uint64_t str_offsets_base,
+ const struct attr_val *val,
+ backtrace_error_callback error_callback, void *data,
+ const char **string)
+{
+ switch (val->encoding)
+ {
+ case ATTR_VAL_STRING:
+ *string = val->u.string;
+ return 1;
+
+ case ATTR_VAL_STRING_INDEX:
+ {
+ uint64_t offset;
+ struct dwarf_buf offset_buf;
+
+ offset = val->u.uint * (is_dwarf64 ? 8 : 4) + str_offsets_base;
+ if (offset + (is_dwarf64 ? 8 : 4)
+ >= dwarf_sections->size[DEBUG_STR_OFFSETS])
+ {
+ error_callback (data, "DW_FORM_strx value out of range", 0);
+ return 0;
+ }
+
+ offset_buf.name = ".debug_str_offsets";
+ offset_buf.start = dwarf_sections->data[DEBUG_STR_OFFSETS];
+ offset_buf.buf = dwarf_sections->data[DEBUG_STR_OFFSETS] + offset;
+ offset_buf.left = dwarf_sections->size[DEBUG_STR_OFFSETS] - offset;
+ offset_buf.is_bigendian = is_bigendian;
+ offset_buf.error_callback = error_callback;
+ offset_buf.data = data;
+ offset_buf.reported_underflow = 0;
+
+ offset = read_offset (&offset_buf, is_dwarf64);
+ if (offset >= dwarf_sections->size[DEBUG_STR])
+ {
+ dwarf_buf_error (&offset_buf, "DW_FORM_strx offset out of range");
+ return 0;
+ }
+ *string = (const char *) dwarf_sections->data[DEBUG_STR] + offset;
+ return 1;
+ }
+
+ default:
+ return 1;
+ }
+}
+
+/* Set *ADDRESS to the real address for a ATTR_VAL_ADDRESS_INDEX.
+ Return 1 on success, 0 on error. */
+
+static int
+resolve_addr_index (const struct dwarf_sections *dwarf_sections,
+ uint64_t addr_base, int addrsize, int is_bigendian,
+ uint64_t addr_index,
+ backtrace_error_callback error_callback, void *data,
+ uint64_t *address)
+{
+ uint64_t offset;
+ struct dwarf_buf addr_buf;
+
+ offset = addr_index * addrsize + addr_base;
+ if (offset + addrsize >= dwarf_sections->size[DEBUG_ADDR])
+ {
+ error_callback (data, "DW_FORM_addrx value out of range", 0);
+ return 0;
+ }
+
+ addr_buf.name = ".debug_addr";
+ addr_buf.start = dwarf_sections->data[DEBUG_ADDR];
+ addr_buf.buf = dwarf_sections->data[DEBUG_ADDR] + offset;
+ addr_buf.left = dwarf_sections->size[DEBUG_ADDR] - offset;
+ addr_buf.is_bigendian = is_bigendian;
+ addr_buf.error_callback = error_callback;
+ addr_buf.data = data;
+ addr_buf.reported_underflow = 0;
+
+ *address = read_address (&addr_buf, addrsize);
+ return 1;
+}
+
/* Compare a unit offset against a unit for bsearch. */
static int
@@ -1142,7 +1381,13 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
read_byte (&count_buf);
// Skip attributes.
while (read_uleb128 (&count_buf) != 0)
- read_uleb128 (&count_buf);
+ {
+ uint64_t form;
+
+ form = read_uleb128 (&count_buf);
+ if ((enum dwarf_form) form == DW_FORM_implicit_const)
+ read_sleb128 (&count_buf);
+ }
// Skip form of last attribute.
read_uleb128 (&count_buf);
}
@@ -1185,8 +1430,12 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
num_attrs = 0;
while (read_uleb128 (&count_buf) != 0)
{
+ uint64_t form;
+
++num_attrs;
- read_uleb128 (&count_buf);
+ form = read_uleb128 (&count_buf);
+ if ((enum dwarf_form) form == DW_FORM_implicit_const)
+ read_sleb128 (&count_buf);
}
if (num_attrs == 0)
@@ -1214,6 +1463,10 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
break;
attrs[num_attrs].name = (enum dwarf_attribute) name;
attrs[num_attrs].form = (enum dwarf_form) form;
+ if ((enum dwarf_form) form == DW_FORM_implicit_const)
+ attrs[num_attrs].val = read_sleb128 (&abbrev_buf);
+ else
+ attrs[num_attrs].val = 0;
++num_attrs;
}
}
@@ -1272,11 +1525,14 @@ lookup_abbrev (struct abbrevs *abbrevs, uint64_t code,
struct pcrange {
uint64_t lowpc; /* The low PC value. */
int have_lowpc; /* Whether a low PC value was found. */
+ int lowpc_is_addr_index; /* Whether lowpc is in .debug_addr. */
uint64_t highpc; /* The high PC value. */
int have_highpc; /* Whether a high PC value was found. */
int highpc_is_relative; /* Whether highpc is relative to lowpc. */
+ int highpc_is_addr_index; /* Whether highpc is in .debug_addr. */
uint64_t ranges; /* Offset in ranges section. */
int have_ranges; /* Whether ranges is valid. */
+ int ranges_is_index; /* Whether ranges is DW_FORM_rnglistx. */
};
/* Update PCRANGE from an attribute value. */
@@ -1293,6 +1549,12 @@ update_pcrange (const struct attr* attr, const struct attr_val* val,
pcrange->lowpc = val->u.uint;
pcrange->have_lowpc = 1;
}
+ else if (val->encoding == ATTR_VAL_ADDRESS_INDEX)
+ {
+ pcrange->lowpc = val->u.uint;
+ pcrange->have_lowpc = 1;
+ pcrange->lowpc_is_addr_index = 1;
+ }
break;
case DW_AT_high_pc:
@@ -1307,6 +1569,12 @@ update_pcrange (const struct attr* attr, const struct attr_val* val,
pcrange->have_highpc = 1;
pcrange->highpc_is_relative = 1;
}
+ else if (val->encoding == ATTR_VAL_ADDRESS_INDEX)
+ {
+ pcrange->highpc = val->u.uint;
+ pcrange->have_highpc = 1;
+ pcrange->highpc_is_addr_index = 1;
+ }
break;
case DW_AT_ranges:
@@ -1316,6 +1584,12 @@ update_pcrange (const struct attr* attr, const struct attr_val* val,
pcrange->ranges = val->u.uint;
pcrange->have_ranges = 1;
}
+ else if (val->encoding == ATTR_VAL_RNGLISTS_INDEX)
+ {
+ pcrange->ranges = val->u.uint;
+ pcrange->have_ranges = 1;
+ pcrange->ranges_is_index = 1;
+ }
break;
default:
@@ -1323,51 +1597,73 @@ update_pcrange (const struct attr* attr, const struct attr_val* val,
}
}
-/* Call ADD_RANGE for each lowpc/highpc pair in PCRANGE. RDATA is
- passed to ADD_RANGE, and is either a struct unit * or a struct
- function *. VEC is the vector we are adding ranges to, and is
- either a struct unit_addrs_vector * or a struct function_vector *.
- Returns 1 on success, 0 on error. */
+/* Call ADD_RANGE for a low/high PC pair. Returns 1 on success, 0 on
+ error. */
static int
-add_ranges (struct backtrace_state *state,
- const struct dwarf_sections *dwarf_sections,
- uintptr_t base_address, int is_bigendian,
- struct unit *u, uint64_t base, const struct pcrange *pcrange,
- int (*add_range) (struct backtrace_state *state, void *rdata,
- uint64_t lowpc, uint64_t highpc,
- backtrace_error_callback error_callback,
- void *data, void *vec),
- void *rdata,
- backtrace_error_callback error_callback, void *data,
- void *vec)
+add_low_high_range (struct backtrace_state *state,
+ const struct dwarf_sections *dwarf_sections,
+ uintptr_t base_address, int is_bigendian,
+ struct unit *u, const struct pcrange *pcrange,
+ int (*add_range) (struct backtrace_state *state,
+ void *rdata, uint64_t lowpc,
+ uint64_t highpc,
+ backtrace_error_callback error_callback,
+ void *data, void *vec),
+ void *rdata,
+ backtrace_error_callback error_callback, void *data,
+ void *vec)
{
- struct dwarf_buf ranges_buf;
+ uint64_t lowpc;
+ uint64_t highpc;
- if (pcrange->have_lowpc && pcrange->have_highpc)
+ lowpc = pcrange->lowpc;
+ if (pcrange->lowpc_is_addr_index)
{
- uint64_t lowpc;
- uint64_t highpc;
-
- lowpc = pcrange->lowpc;
- highpc = pcrange->highpc;
- if (pcrange->highpc_is_relative)
- highpc += lowpc;
-
- /* Add in the base address of the module when recording PC
- values, so that we can look up the PC directly. */
- lowpc += base_address;
- highpc += base_address;
-
- return add_range (state, rdata, lowpc, highpc, error_callback, data,
- vec);
+ if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,
+ is_bigendian, lowpc, error_callback, data,
+ &lowpc))
+ return 0;
}
- if (!pcrange->have_ranges)
+ highpc = pcrange->highpc;
+ if (pcrange->highpc_is_addr_index)
{
- /* Did not find any address ranges to add. */
- return 1;
+ if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,
+ is_bigendian, highpc, error_callback, data,
+ &highpc))
+ return 0;
}
+ if (pcrange->highpc_is_relative)
+ highpc += lowpc;
+
+ /* Add in the base address of the module when recording PC values,
+ so that we can look up the PC directly. */
+ lowpc += base_address;
+ highpc += base_address;
+
+ return add_range (state, rdata, lowpc, highpc, error_callback, data, vec);
+}
+
+/* Call ADD_RANGE for each range read from .debug_ranges, as used in
+ DWARF versions 2 through 4. */
+
+static int
+add_ranges_from_ranges (
+ struct backtrace_state *state,
+ const struct dwarf_sections *dwarf_sections,
+ uintptr_t base_address, int is_bigendian,
+ struct unit *u, uint64_t base,
+ const struct pcrange *pcrange,
+ int (*add_range) (struct backtrace_state *state, void *rdata,
+ uint64_t lowpc, uint64_t highpc,
+ backtrace_error_callback error_callback, void *data,
+ void *vec),
+ void *rdata,
+ backtrace_error_callback error_callback, void *data,
+ void *vec)
+{
+ struct dwarf_buf ranges_buf;
if (pcrange->ranges >= dwarf_sections->size[DEBUG_RANGES])
{
@@ -1416,6 +1712,220 @@ add_ranges (struct backtrace_state *state,
return 1;
}
+/* Call ADD_RANGE for each range read from .debug_rnglists, as used in
+ DWARF version 5. */
+
+static int
+add_ranges_from_rnglists (
+ struct backtrace_state *state,
+ const struct dwarf_sections *dwarf_sections,
+ uintptr_t base_address, int is_bigendian,
+ struct unit *u, uint64_t base,
+ const struct pcrange *pcrange,
+ int (*add_range) (struct backtrace_state *state, void *rdata,
+ uint64_t lowpc, uint64_t highpc,
+ backtrace_error_callback error_callback, void *data,
+ void *vec),
+ void *rdata,
+ backtrace_error_callback error_callback, void *data,
+ void *vec)
+{
+ uint64_t offset;
+ struct dwarf_buf rnglists_buf;
+
+ if (!pcrange->ranges_is_index)
+ offset = pcrange->ranges;
+ else
+ offset = u->rnglists_base + pcrange->ranges * (u->is_dwarf64 ? 8 : 4);
+ if (offset >= dwarf_sections->size[DEBUG_RNGLISTS])
+ {
+ error_callback (data, "rnglists offset out of range", 0);
+ return 0;
+ }
+
+ rnglists_buf.name = ".debug_rnglists";
+ rnglists_buf.start = dwarf_sections->data[DEBUG_RNGLISTS];
+ rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset;
+ rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset;
+ rnglists_buf.is_bigendian = is_bigendian;
+ rnglists_buf.error_callback = error_callback;
+ rnglists_buf.data = data;
+ rnglists_buf.reported_underflow = 0;
+
+ if (pcrange->ranges_is_index)
+ {
+ offset = read_offset (&rnglists_buf, u->is_dwarf64);
+ offset += u->rnglists_base;
+ if (offset >= dwarf_sections->size[DEBUG_RNGLISTS])
+ {
+ error_callback (data, "rnglists index offset out of range", 0);
+ return 0;
+ }
+ rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset;
+ rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset;
+ }
+
+ while (1)
+ {
+ unsigned char rle;
+
+ rle = read_byte (&rnglists_buf);
+ if (rle == DW_RLE_end_of_list)
+ break;
+ switch (rle)
+ {
+ case DW_RLE_base_addressx:
+ {
+ uint64_t index;
+
+ index = read_uleb128 (&rnglists_buf);
+ if (!resolve_addr_index (dwarf_sections, u->addr_base,
+ u->addrsize, is_bigendian, index,
+ error_callback, data, &base))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_startx_endx:
+ {
+ uint64_t index;
+ uint64_t low;
+ uint64_t high;
+
+ index = read_uleb128 (&rnglists_buf);
+ if (!resolve_addr_index (dwarf_sections, u->addr_base,
+ u->addrsize, is_bigendian, index,
+ error_callback, data, &low))
+ return 0;
+ index = read_uleb128 (&rnglists_buf);
+ if (!resolve_addr_index (dwarf_sections, u->addr_base,
+ u->addrsize, is_bigendian, index,
+ error_callback, data, &high))
+ return 0;
+ if (!add_range (state, rdata, low + base_address,
+ high + base_address, error_callback, data,
+ vec))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_startx_length:
+ {
+ uint64_t index;
+ uint64_t low;
+ uint64_t length;
+
+ index = read_uleb128 (&rnglists_buf);
+ if (!resolve_addr_index (dwarf_sections, u->addr_base,
+ u->addrsize, is_bigendian, index,
+ error_callback, data, &low))
+ return 0;
+ length = read_uleb128 (&rnglists_buf);
+ low += base_address;
+ if (!add_range (state, rdata, low, low + length,
+ error_callback, data, vec))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_offset_pair:
+ {
+ uint64_t low;
+ uint64_t high;
+
+ low = read_uleb128 (&rnglists_buf);
+ high = read_uleb128 (&rnglists_buf);
+ if (!add_range (state, rdata, low + base + base_address,
+ high + base + base_address,
+ error_callback, data, vec))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_base_address:
+ base = read_address (&rnglists_buf, u->addrsize);
+ break;
+
+ case DW_RLE_start_end:
+ {
+ uint64_t low;
+ uint64_t high;
+
+ low = read_address (&rnglists_buf, u->addrsize);
+ high = read_address (&rnglists_buf, u->addrsize);
+ if (!add_range (state, rdata, low + base_address,
+ high + base_address, error_callback, data,
+ vec))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_start_length:
+ {
+ uint64_t low;
+ uint64_t length;
+
+ low = read_address (&rnglists_buf, u->addrsize);
+ length = read_uleb128 (&rnglists_buf);
+ low += base_address;
+ if (!add_range (state, rdata, low, low + length,
+ error_callback, data, vec))
+ return 0;
+ }
+ break;
+
+ default:
+ dwarf_buf_error (&rnglists_buf, "unrecognized DW_RLE value");
+ return 0;
+ }
+ }
+
+ if (rnglists_buf.reported_underflow)
+ return 0;
+
+ return 1;
+}
+
+/* Call ADD_RANGE for each lowpc/highpc pair in PCRANGE. RDATA is
+ passed to ADD_RANGE, and is either a struct unit * or a struct
+ function *. VEC is the vector we are adding ranges to, and is
+ either a struct unit_addrs_vector * or a struct function_vector *.
+ Returns 1 on success, 0 on error. */
+
+static int
+add_ranges (struct backtrace_state *state,
+ const struct dwarf_sections *dwarf_sections,
+ uintptr_t base_address, int is_bigendian,
+ struct unit *u, uint64_t base, const struct pcrange *pcrange,
+ int (*add_range) (struct backtrace_state *state, void *rdata,
+ uint64_t lowpc, uint64_t highpc,
+ backtrace_error_callback error_callback,
+ void *data, void *vec),
+ void *rdata,
+ backtrace_error_callback error_callback, void *data,
+ void *vec)
+{
+ if (pcrange->have_lowpc && pcrange->have_highpc)
+ return add_low_high_range (state, dwarf_sections, base_address,
+ is_bigendian, u, pcrange, add_range, rdata,
+ error_callback, data, vec);
+
+ if (!pcrange->have_ranges)
+ {
+ /* Did not find any address ranges to add. */
+ return 1;
+ }
+
+ if (u->version < 5)
+ return add_ranges_from_ranges (state, dwarf_sections, base_address,
+ is_bigendian, u, base, pcrange, add_range,
+ rdata, error_callback, data, vec);
+ else
+ return add_ranges_from_rnglists (state, dwarf_sections, base_address,
+ is_bigendian, u, base, pcrange, add_range,
+ rdata, error_callback, data, vec);
+}
+
/* Find the address range covered by a compilation unit, reading from
UNIT_BUF and adding values to U. Returns 1 if all data could be
read, 0 if there is some error. */
@@ -1434,6 +1944,10 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
uint64_t code;
const struct abbrev *abbrev;
struct pcrange pcrange;
+ struct attr_val name_val;
+ int have_name_val;
+ struct attr_val comp_dir_val;
+ int have_comp_dir_val;
size_t i;
code = read_uleb128 (unit_buf);
@@ -1448,15 +1962,17 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
*unit_tag = abbrev->tag;
memset (&pcrange, 0, sizeof pcrange);
+ memset (&name_val, 0, sizeof name_val);
+ have_name_val = 0;
+ memset (&comp_dir_val, 0, sizeof comp_dir_val);
+ have_comp_dir_val = 0;
for (i = 0; i < abbrev->num_attrs; ++i)
{
struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, unit_buf,
- u->is_dwarf64, u->version, u->addrsize,
- dwarf_sections->data[DEBUG_STR],
- dwarf_sections->size[DEBUG_STR],
- altlink, &val))
+ if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
+ unit_buf, u->is_dwarf64, u->version,
+ u->addrsize, dwarf_sections, altlink, &val))
return 0;
switch (abbrev->attrs[i].name)
@@ -1473,15 +1989,37 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
break;
case DW_AT_name:
- if (abbrev->tag == DW_TAG_compile_unit
- && val.encoding == ATTR_VAL_STRING)
- u->filename = val.u.string;
+ if (abbrev->tag == DW_TAG_compile_unit)
+ {
+ name_val = val;
+ have_name_val = 1;
+ }
break;
case DW_AT_comp_dir:
+ if (abbrev->tag == DW_TAG_compile_unit)
+ {
+ comp_dir_val = val;
+ have_comp_dir_val = 1;
+ }
+ break;
+
+ case DW_AT_str_offsets_base:
if (abbrev->tag == DW_TAG_compile_unit
- && val.encoding == ATTR_VAL_STRING)
- u->comp_dir = val.u.string;
+ && val.encoding == ATTR_VAL_REF_SECTION)
+ u->str_offsets_base = val.u.uint;
+ break;
+
+ case DW_AT_addr_base:
+ if (abbrev->tag == DW_TAG_compile_unit
+ && val.encoding == ATTR_VAL_REF_SECTION)
+ u->addr_base = val.u.uint;
+ break;
+
+ case DW_AT_rnglists_base:
+ if (abbrev->tag == DW_TAG_compile_unit
+ && val.encoding == ATTR_VAL_REF_SECTION)
+ u->rnglists_base = val.u.uint;
break;
default:
@@ -1489,6 +2027,23 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
}
}
+ // Resolve strings after we're sure that we have seen
+ // DW_AT_str_offsets_base.
+ if (have_name_val)
+ {
+ if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian,
+ u->str_offsets_base, &name_val,
+ error_callback, data, &u->filename))
+ return 0;
+ }
+ if (have_comp_dir_val)
+ {
+ if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian,
+ u->str_offsets_base, &comp_dir_val,
+ error_callback, data, &u->comp_dir))
+ return 0;
+ }
+
if (abbrev->tag == DW_TAG_compile_unit
|| abbrev->tag == DW_TAG_subprogram)
{
@@ -1565,6 +2120,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
int is_dwarf64;
struct dwarf_buf unit_buf;
int version;
+ int unit_type;
uint64_t abbrev_offset;
int addrsize;
struct unit *u;
@@ -1583,12 +2139,24 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
goto fail;
version = read_uint16 (&unit_buf);
- if (version < 2 || version > 4)
+ if (version < 2 || version > 5)
{
dwarf_buf_error (&unit_buf, "unrecognized DWARF version");
goto fail;
}
+ if (version < 5)
+ unit_type = 0;
+ else
+ {
+ unit_type = read_byte (&unit_buf);
+ if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
+ {
+ /* This unit doesn't have anything we need. */
+ continue;
+ }
+ }
+
pu = ((struct unit **)
backtrace_vector_grow (state, sizeof (struct unit *),
error_callback, data, &units));
@@ -1603,6 +2171,11 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
*pu = u;
++units_count;
+ if (version < 5)
+ addrsize = 0; /* Set below. */
+ else
+ addrsize = read_byte (&unit_buf);
+
memset (&u->abbrevs, 0, sizeof u->abbrevs);
abbrev_offset = read_offset (&unit_buf, is_dwarf64);
if (!read_abbrevs (state, abbrev_offset,
@@ -1611,7 +2184,21 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
is_bigendian, error_callback, data, &u->abbrevs))
goto fail;
- addrsize = read_byte (&unit_buf);
+ if (version < 5)
+ addrsize = read_byte (&unit_buf);
+
+ switch (unit_type)
+ {
+ case 0:
+ break;
+ case DW_UT_compile: case DW_UT_partial:
+ break;
+ case DW_UT_skeleton: case DW_UT_split_compile:
+ read_uint64 (&unit_buf); /* dwo_id */
+ break;
+ default:
+ break;
+ }
u->low_offset = unit_offset;
unit_offset += len + (is_dwarf64 ? 12 : 4);
@@ -1720,55 +2307,21 @@ free_line_header (struct backtrace_state *state, struct line_header *hdr,
error_callback, data);
}
-/* Read the line header. Return 1 on success, 0 on failure. */
+/* Read the directories and file names for a line header for version
+ 2, setting fields in HDR. Return 1 on success, 0 on failure. */
static int
-read_line_header (struct backtrace_state *state, struct unit *u,
- int is_dwarf64, struct dwarf_buf *line_buf,
- struct line_header *hdr)
+read_v2_paths (struct backtrace_state *state, struct unit *u,
+ struct dwarf_buf *hdr_buf, struct line_header *hdr)
{
- uint64_t hdrlen;
- struct dwarf_buf hdr_buf;
const unsigned char *p;
const unsigned char *pend;
size_t i;
- hdr->version = read_uint16 (line_buf);
- if (hdr->version < 2 || hdr->version > 4)
- {
- dwarf_buf_error (line_buf, "unsupported line number version");
- return 0;
- }
-
- hdrlen = read_offset (line_buf, is_dwarf64);
-
- hdr_buf = *line_buf;
- hdr_buf.left = hdrlen;
-
- if (!advance (line_buf, hdrlen))
- return 0;
-
- hdr->min_insn_len = read_byte (&hdr_buf);
- if (hdr->version < 4)
- hdr->max_ops_per_insn = 1;
- else
- hdr->max_ops_per_insn = read_byte (&hdr_buf);
-
- /* We don't care about default_is_stmt. */
- read_byte (&hdr_buf);
-
- hdr->line_base = read_sbyte (&hdr_buf);
- hdr->line_range = read_byte (&hdr_buf);
-
- hdr->opcode_base = read_byte (&hdr_buf);
- hdr->opcode_lengths = hdr_buf.buf;
- if (!advance (&hdr_buf, hdr->opcode_base - 1))
- return 0;
-
/* Count the number of directory entries. */
hdr->dirs_count = 0;
- p = hdr_buf.buf;
- pend = p + hdr_buf.left;
+ p = hdr_buf->buf;
+ pend = p + hdr_buf->left;
while (p < pend && *p != '\0')
{
p += strnlen((const char *) p, pend - p) + 1;
@@ -1781,29 +2334,30 @@ read_line_header (struct backtrace_state *state, struct unit *u,
hdr->dirs = ((const char **)
backtrace_alloc (state,
hdr->dirs_count * sizeof (const char *),
- line_buf->error_callback, line_buf->data));
+ hdr_buf->error_callback,
+ hdr_buf->data));
if (hdr->dirs == NULL)
return 0;
}
i = 0;
- while (*hdr_buf.buf != '\0')
+ while (*hdr_buf->buf != '\0')
{
- if (hdr_buf.reported_underflow)
+ if (hdr_buf->reported_underflow)
return 0;
- hdr->dirs[i] = read_string (&hdr_buf);
+ hdr->dirs[i] = read_string (hdr_buf);
if (hdr->dirs[i] == NULL)
return 0;
++i;
}
- if (!advance (&hdr_buf, 1))
+ if (!advance (hdr_buf, 1))
return 0;
/* Count the number of file entries. */
hdr->filenames_count = 0;
- p = hdr_buf.buf;
- pend = p + hdr_buf.left;
+ p = hdr_buf->buf;
+ pend = p + hdr_buf->left;
while (p < pend && *p != '\0')
{
p += strnlen ((const char *) p, pend - p) + 1;
@@ -1816,23 +2370,23 @@ read_line_header (struct backtrace_state *state, struct unit *u,
hdr->filenames = ((const char **)
backtrace_alloc (state,
hdr->filenames_count * sizeof (char *),
- line_buf->error_callback,
- line_buf->data));
+ hdr_buf->error_callback,
+ hdr_buf->data));
if (hdr->filenames == NULL)
return 0;
i = 0;
- while (*hdr_buf.buf != '\0')
+ while (*hdr_buf->buf != '\0')
{
const char *filename;
uint64_t dir_index;
- if (hdr_buf.reported_underflow)
+ if (hdr_buf->reported_underflow)
return 0;
- filename = read_string (&hdr_buf);
+ filename = read_string (hdr_buf);
if (filename == NULL)
return 0;
- dir_index = read_uleb128 (&hdr_buf);
+ dir_index = read_uleb128 (hdr_buf);
if (IS_ABSOLUTE_PATH (filename)
|| (dir_index == 0 && u->comp_dir == NULL))
hdr->filenames[i] = filename;
@@ -1849,16 +2403,16 @@ read_line_header (struct backtrace_state *state, struct unit *u,
dir = hdr->dirs[dir_index - 1];
else
{
- dwarf_buf_error (line_buf,
+ dwarf_buf_error (hdr_buf,
("invalid directory index in "
"line number program header"));
return 0;
}
dir_len = strlen (dir);
filename_len = strlen (filename);
- s = ((char *)
- backtrace_alloc (state, dir_len + filename_len + 2,
- line_buf->error_callback, line_buf->data));
+ s = ((char *) backtrace_alloc (state, dir_len + filename_len + 2,
+ hdr_buf->error_callback,
+ hdr_buf->data));
if (s == NULL)
return 0;
memcpy (s, dir, dir_len);
@@ -1871,12 +2425,258 @@ read_line_header (struct backtrace_state *state, struct unit *u,
}
/* Ignore the modification time and size. */
- read_uleb128 (&hdr_buf);
- read_uleb128 (&hdr_buf);
+ read_uleb128 (hdr_buf);
+ read_uleb128 (hdr_buf);
++i;
}
+ return 1;
+}
+
+/* Read a single version 5 LNCT entry for a directory or file name in a
+ line header. Sets *STRING to the resulting name, ignoring other
+ data. Return 1 on success, 0 on failure. */
+
+static int
+read_lnct (struct backtrace_state *state, struct dwarf_data *ddata,
+ struct unit *u, struct dwarf_buf *hdr_buf,
+ const struct line_header *hdr, size_t formats_count,
+ const struct line_header_format *formats, const char **string)
+{
+ size_t i;
+ const char *dir;
+ const char *path;
+
+ dir = NULL;
+ path = NULL;
+ for (i = 0; i < formats_count; i++)
+ {
+ struct attr_val val;
+
+ if (!read_attribute (formats[i].form, 0, hdr_buf, u->is_dwarf64,
+ u->version, hdr->addrsize, &ddata->dwarf_sections,
+ ddata->altlink, &val))
+ return 0;
+ switch (formats[i].lnct)
+ {
+ case DW_LNCT_path:
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian, u->str_offsets_base,
+ &val, hdr_buf->error_callback, hdr_buf->data,
+ &path))
+ return 0;
+ break;
+ case DW_LNCT_directory_index:
+ if (val.encoding == ATTR_VAL_UINT)
+ {
+ if (val.u.uint >= hdr->dirs_count)
+ {
+ dwarf_buf_error (hdr_buf,
+ ("invalid directory index in "
+ "line number program header"));
+ return 0;
+ }
+ dir = hdr->dirs[val.u.uint];
+ }
+ break;
+ default:
+ /* We don't care about timestamps or sizes or hashes. */
+ break;
+ }
+ }
+
+ if (path == NULL)
+ {
+ dwarf_buf_error (hdr_buf,
+ "missing file name in line number program header");
+ return 0;
+ }
+
+ if (dir == NULL)
+ *string = path;
+ else
+ {
+ size_t dir_len;
+ size_t path_len;
+ char *s;
+
+ dir_len = strlen (dir);
+ path_len = strlen (path);
+ s = (char *) backtrace_alloc (state, dir_len + path_len + 2,
+ hdr_buf->error_callback, hdr_buf->data);
+ if (s == NULL)
+ return 0;
+ memcpy (s, dir, dir_len);
+ /* FIXME: If we are on a DOS-based file system, and the
+ directory or the path name use backslashes, then we should
+ use a backslash here. */
+ s[dir_len] = '/';
+ memcpy (s + dir_len + 1, path, path_len + 1);
+ *string = s;
+ }
+
+ return 1;
+}
+
+/* Read a set of DWARF 5 line header format entries, setting *PCOUNT
+ and *PPATHS. Return 1 on success, 0 on failure. */
+
+static int
+read_line_header_format_entries (struct backtrace_state *state,
+ struct dwarf_data *ddata,
+ struct unit *u,
+ struct dwarf_buf *hdr_buf,
+ struct line_header *hdr,
+ size_t *pcount,
+ const char ***ppaths)
+{
+ size_t formats_count;
+ struct line_header_format *formats;
+ size_t paths_count;
+ const char **paths;
+ size_t i;
+ int ret;
+
+ formats_count = read_byte (hdr_buf);
+ if (formats_count == 0)
+ formats = NULL;
+ else
+ {
+ formats = ((struct line_header_format *)
+ backtrace_alloc (state,
+ (formats_count
+ * sizeof (struct line_header_format)),
+ hdr_buf->error_callback,
+ hdr_buf->data));
+ if (formats == NULL)
+ return 0;
+
+ for (i = 0; i < formats_count; i++)
+ {
+ formats[i].lnct = (int) read_uleb128(hdr_buf);
+ formats[i].form = (enum dwarf_form) read_uleb128 (hdr_buf);
+ }
+ }
+
+ paths_count = read_uleb128 (hdr_buf);
+ if (paths_count == 0)
+ {
+ *pcount = 0;
+ *ppaths = NULL;
+ ret = 1;
+ goto exit;
+ }
+
+ paths = ((const char **)
+ backtrace_alloc (state, paths_count * sizeof (const char *),
+ hdr_buf->error_callback, hdr_buf->data));
+ if (paths == NULL)
+ {
+ ret = 0;
+ goto exit;
+ }
+ for (i = 0; i < paths_count; i++)
+ {
+ if (!read_lnct (state, ddata, u, hdr_buf, hdr, formats_count,
+ formats, &paths[i]))
+ {
+ backtrace_free (state, paths,
+ paths_count * sizeof (const char *),
+ hdr_buf->error_callback, hdr_buf->data);
+ ret = 0;
+ goto exit;
+ }
+ }
+
+ *pcount = paths_count;
+ *ppaths = paths;
+
+ ret = 1;
+
+ exit:
+ if (formats != NULL)
+ backtrace_free (state, formats,
+ formats_count * sizeof (struct line_header_format),
+ hdr_buf->error_callback, hdr_buf->data);
+
+ return ret;
+}
+
+/* Read the line header. Return 1 on success, 0 on failure. */
+
+static int
+read_line_header (struct backtrace_state *state, struct dwarf_data *ddata,
+ struct unit *u, int is_dwarf64, struct dwarf_buf *line_buf,
+ struct line_header *hdr)
+{
+ uint64_t hdrlen;
+ struct dwarf_buf hdr_buf;
+
+ hdr->version = read_uint16 (line_buf);
+ if (hdr->version < 2 || hdr->version > 5)
+ {
+ dwarf_buf_error (line_buf, "unsupported line number version");
+ return 0;
+ }
+
+ if (hdr->version < 5)
+ hdr->addrsize = u->addrsize;
+ else
+ {
+ hdr->addrsize = read_byte (line_buf);
+ /* We could support a non-zero segment_selector_size but I doubt
+ we'll ever see it. */
+ if (read_byte (line_buf) != 0)
+ {
+ dwarf_buf_error (line_buf,
+ "non-zero segment_selector_size not supported");
+ return 0;
+ }
+ }
+
+ hdrlen = read_offset (line_buf, is_dwarf64);
+
+ hdr_buf = *line_buf;
+ hdr_buf.left = hdrlen;
+
+ if (!advance (line_buf, hdrlen))
+ return 0;
+
+ hdr->min_insn_len = read_byte (&hdr_buf);
+ if (hdr->version < 4)
+ hdr->max_ops_per_insn = 1;
+ else
+ hdr->max_ops_per_insn = read_byte (&hdr_buf);
+
+ /* We don't care about default_is_stmt. */
+ read_byte (&hdr_buf);
+
+ hdr->line_base = read_sbyte (&hdr_buf);
+ hdr->line_range = read_byte (&hdr_buf);
+
+ hdr->opcode_base = read_byte (&hdr_buf);
+ hdr->opcode_lengths = hdr_buf.buf;
+ if (!advance (&hdr_buf, hdr->opcode_base - 1))
+ return 0;
+
+ if (hdr->version < 5)
+ {
+ if (!read_v2_paths (state, u, &hdr_buf, hdr))
+ return 0;
+ }
+ else
+ {
+ if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr,
+ &hdr->dirs_count,
+ &hdr->dirs))
+ return 0;
+ if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr,
+ &hdr->filenames_count,
+ &hdr->filenames))
+ return 0;
+ }
+
if (hdr_buf.reported_underflow)
return 0;
@@ -1942,7 +2742,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
lineno = 1;
break;
case DW_LNE_set_address:
- address = read_address (line_buf, u->addrsize);
+ address = read_address (line_buf, hdr->addrsize);
break;
case DW_LNE_define_file:
{
@@ -1965,7 +2765,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
size_t f_len;
char *p;
- if (dir_index == 0)
+ if (dir_index == 0 && hdr->version < 5)
dir = u->comp_dir;
else if (dir_index - 1 < hdr->dirs_count)
dir = hdr->dirs[dir_index - 1];
@@ -2129,7 +2929,7 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata,
len = read_initial_length (&line_buf, &is_dwarf64);
line_buf.left = len;
- if (!read_line_header (state, u, is_dwarf64, &line_buf, hdr))
+ if (!read_line_header (state, ddata, u, is_dwarf64, &line_buf, hdr))
goto fail;
if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec))
@@ -2287,11 +3087,9 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
{
struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, &unit_buf,
- u->is_dwarf64, u->version, u->addrsize,
- ddata->dwarf_sections.data[DEBUG_STR],
- ddata->dwarf_sections.size[DEBUG_STR],
- ddata->altlink, &val))
+ if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
+ &unit_buf, u->is_dwarf64, u->version, u->addrsize,
+ &ddata->dwarf_sections, ddata->altlink, &val))
return NULL;
switch (abbrev->attrs[i].name)
@@ -2302,15 +3100,26 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
normally not mangled. */
if (ret != NULL)
break;
- if (val.encoding == ATTR_VAL_STRING)
- ret = val.u.string;
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian, u->str_offsets_base,
+ &val, error_callback, data, &ret))
+ return NULL;
break;
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
/* First name preference: override all. */
- if (val.encoding == ATTR_VAL_STRING)
- return val.u.string;
+ {
+ const char *s;
+
+ s = NULL;
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian, u->str_offsets_base,
+ &val, error_callback, data, &s))
+ return NULL;
+ if (s != NULL)
+ return s;
+ }
break;
case DW_AT_specification:
@@ -2430,19 +3239,28 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
{
struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, unit_buf,
- u->is_dwarf64, u->version, u->addrsize,
- ddata->dwarf_sections.data[DEBUG_STR],
- ddata->dwarf_sections.size[DEBUG_STR],
+ if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
+ unit_buf, u->is_dwarf64, u->version,
+ u->addrsize, &ddata->dwarf_sections,
ddata->altlink, &val))
return 0;
/* The compile unit sets the base address for any address
ranges in the function entries. */
if (abbrev->tag == DW_TAG_compile_unit
- && abbrev->attrs[i].name == DW_AT_low_pc
- && val.encoding == ATTR_VAL_ADDRESS)
- base = val.u.uint;
+ && abbrev->attrs[i].name == DW_AT_low_pc)
+ {
+ if (val.encoding == ATTR_VAL_ADDRESS)
+ base = val.u.uint;
+ else if (val.encoding == ATTR_VAL_ADDRESS_INDEX)
+ {
+ if (!resolve_addr_index (&ddata->dwarf_sections,
+ u->addr_base, u->addrsize,
+ ddata->is_bigendian, val.u.uint,
+ error_callback, data, &base))
+ return 0;
+ }
+ }
if (is_function)
{
@@ -2495,18 +3313,31 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
/* Third name preference: don't override. */
if (function->name != NULL)
break;
- if (val.encoding == ATTR_VAL_STRING)
- function->name = val.u.string;
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian,
+ u->str_offsets_base, &val,
+ error_callback, data, &function->name))
+ return 0;
break;
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
/* First name preference: override all. */
- if (val.encoding == ATTR_VAL_STRING)
- {
- function->name = val.u.string;
- have_linkage_name = 1;
- }
+ {
+ const char *s;
+
+ s = NULL;
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian,
+ u->str_offsets_base, &val,
+ error_callback, data, &s))
+ return 0;
+ if (s != NULL)
+ {
+ function->name = s;
+ have_linkage_name = 1;
+ }
+ }
break;
case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 89e0ab7..d1d257b 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -346,6 +346,10 @@ static const char * const dwarf_section_names[DEBUG_MAX] =
".debug_abbrev",
".debug_ranges",
".debug_str",
+ ".debug_addr",
+ ".debug_str_offsets",
+ ".debug_line_str",
+ ".debug_rnglists"
};
/* Information we gather for the sections we care about. */
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 31004bb..a9c6688 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -295,6 +295,10 @@ enum dwarf_section
DEBUG_ABBREV,
DEBUG_RANGES,
DEBUG_STR,
+ DEBUG_ADDR,
+ DEBUG_STR_OFFSETS,
+ DEBUG_LINE_STR,
+ DEBUG_RNGLISTS,
DEBUG_MAX
};
diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c
index fe64a7e..f932f35 100644
--- a/libbacktrace/pecoff.c
+++ b/libbacktrace/pecoff.c
@@ -141,7 +141,11 @@ static const char * const debug_section_names[DEBUG_MAX] =
".debug_line",
".debug_abbrev",
".debug_ranges",
- ".debug_str"
+ ".debug_str",
+ ".debug_addr",
+ ".debug_str_offsets",
+ ".debug_line_str",
+ ".debug_rnglists"
};
/* Information we gather for the sections we care about. */
diff --git a/libbacktrace/xcoff.c b/libbacktrace/xcoff.c
index 468b24c..a0030f0 100644
--- a/libbacktrace/xcoff.c
+++ b/libbacktrace/xcoff.c
@@ -1286,6 +1286,8 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
+ (dwsect[i].offset - min_offset));
}
+ memset (&dwarf_sections, 0, sizeof dwarf_sections);
+
dwarf_sections.data[DEBUG_INFO] = dwsect[DEBUG_INFO].data;
dwarf_sections.size[DEBUG_INFO] = dwsect[DEBUG_INFO].size;
#if BACKTRACE_XCOFF_SIZE == 32