libbacktrace: add DWARF 5 support
authorIan Lance Taylor <iant@golang.org>
Fri, 13 Dec 2019 20:04:47 +0000 (20:04 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 13 Dec 2019 20:04:47 +0000 (20:04 +0000)
* 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.

From-SVN: r279380

libbacktrace/ChangeLog
libbacktrace/Makefile.am
libbacktrace/Makefile.in
libbacktrace/configure
libbacktrace/configure.ac
libbacktrace/dwarf.c
libbacktrace/elf.c
libbacktrace/internal.h
libbacktrace/pecoff.c
libbacktrace/xcoff.c

index 7d91aadb818483a08f70dacdacf84c8888c64fbb..b63d216c8c40d35a7e5eb7027c8a19efb34857e4 100644 (file)
@@ -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.
index e989d8e9f6c4bbb68af0c338f7fe4ed982689671..79abcc9174b9096eb554df1110bac62f112b950b 100644 (file)
@@ -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
index 4ade8e9efcf51caa1e8ce5879816efb997655c05..01855bfac07691ae653facec102f34f7236bbd46 100644 (file)
@@ -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
index 03c6d2ef58bc39627a6bfea506ac38ac866bac42..676adb89224e23a78bf406e02f32edbce8fc1ebc 100755 (executable)
@@ -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
index a657ef6097a085eb9fcb73a58ebfbc0abcb3f32c..cda4f09f72e667d205e81ef032cd2d616413489f 100644 (file)
@@ -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)
index 9e00792da506df6228e5475f52d97dd831582452..d27376860a59f018a54af0a04b1d086691b5256c 100644 (file)
@@ -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:
index 89e0ab7169db0d5a185a054f7de7db223c6eed3e..d1d257b1399265b920c30a8ebe3c6df67178850e 100644 (file)
@@ -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.  */
index 31004bbd954a1df7b0b69ab018b109b8f2a44790..a9c6688251aa14ea169522d3fbd28591e89557c1 100644 (file)
@@ -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
 };
index fe64a7e695bcb4f524d9f2203dcdb588107c95f7..f932f35d4cf5736c3d4d37907269a7dd6656c0be 100644 (file)
@@ -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.  */
index 468b24c418d7cfd98ae37ba9b0dfd309e5ea7c05..a0030f07184d4e19150fb8fcd9db2427a1b48ba5 100644 (file)
@@ -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