Commit c926fd82 by Ian Lance Taylor Committed by Ian Lance Taylor

libbacktrace: 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.

From-SVN: r279380
parent 510873f9
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> 2019-12-08 Ian Lance Taylor <iant@golang.org>
* dwarf.c (struct pcrange): Define. * dwarf.c (struct pcrange): Define.
......
...@@ -385,12 +385,33 @@ BUILDTESTS += ctestg_alloc ctesta_alloc ...@@ -385,12 +385,33 @@ BUILDTESTS += ctestg_alloc ctesta_alloc
endif 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 endif NATIVE
check_PROGRAMS += $(BUILDTESTS) check_PROGRAMS += $(BUILDTESTS)
TESTS += $(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 # We can't use automake's automatic dependency tracking, because it
# breaks when using bootstrap-lean. Automatic dependency tracking # breaks when using bootstrap-lean. Automatic dependency tracking
# with GCC bootstrap will cause some of the objects to depend on # with GCC bootstrap will cause some of the objects to depend on
......
...@@ -121,10 +121,10 @@ build_triplet = @build@ ...@@ -121,10 +121,10 @@ build_triplet = @build@
host_triplet = @host@ host_triplet = @host@
target_triplet = @target@ target_triplet = @target@
check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ 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) \ TESTS = $(am__append_4) $(am__append_6) $(am__append_8) \
$(am__append_11) $(am__append_12) $(am__append_18) \ $(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 @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@am__append_2 = test_elf_32 test_elf_64 test_xcoff_32 \
@NATIVE_TRUE@ test_xcoff_64 test_pecoff test_unknown unittest \ @NATIVE_TRUE@ test_xcoff_64 test_pecoff test_unknown unittest \
...@@ -148,6 +148,7 @@ TESTS = $(am__append_4) $(am__append_6) $(am__append_8) \ ...@@ -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@am__append_19 = ctestg ctesta \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctestg_alloc \ @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctestg_alloc \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta_alloc @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta_alloc
@HAVE_DWARF5_TRUE@@NATIVE_TRUE@am__append_20 = dwarf5 dwarf5_alloc
subdir = . subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/cet.m4 \ am__aclocal_m4_deps = $(top_srcdir)/../config/cet.m4 \
...@@ -224,9 +225,11 @@ libbacktrace_noformat_la_OBJECTS = \ ...@@ -224,9 +225,11 @@ libbacktrace_noformat_la_OBJECTS = \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta$(EXEEXT) \ @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta$(EXEEXT) \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctestg_alloc$(EXEEXT) \ @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctestg_alloc$(EXEEXT) \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta_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_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@am_allocfail_OBJECTS = allocfail.$(OBJEXT) \
@NATIVE_TRUE@ testlib.$(OBJEXT) @NATIVE_TRUE@ testlib.$(OBJEXT)
allocfail_OBJECTS = $(am_allocfail_OBJECTS) allocfail_OBJECTS = $(am_allocfail_OBJECTS)
...@@ -305,20 +308,39 @@ ctestg_alloc_OBJECTS = $(am_ctestg_alloc_OBJECTS) ...@@ -305,20 +308,39 @@ ctestg_alloc_OBJECTS = $(am_ctestg_alloc_OBJECTS)
ctestg_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ ctestg_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ctestg_alloc_CFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ctestg_alloc_CFLAGS) \
$(CFLAGS) $(ctestg_alloc_LDFLAGS) $(LDFLAGS) -o $@ $(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@am_edtest_OBJECTS = edtest.$(OBJEXT) \
@NATIVE_TRUE@ edtest2_build.$(OBJEXT) testlib.$(OBJEXT) @NATIVE_TRUE@ edtest2_build.$(OBJEXT) testlib.$(OBJEXT)
edtest_OBJECTS = $(am_edtest_OBJECTS) edtest_OBJECTS = $(am_edtest_OBJECTS)
@NATIVE_TRUE@edtest_DEPENDENCIES = libbacktrace.la @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@ 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) edtest_alloc_OBJECTS = $(am_edtest_alloc_OBJECTS)
@NATIVE_TRUE@edtest_alloc_DEPENDENCIES = libbacktrace_alloc.la @NATIVE_TRUE@edtest_alloc_DEPENDENCIES = libbacktrace_alloc.la
@NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT) @NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
stest_OBJECTS = $(am_stest_OBJECTS) stest_OBJECTS = $(am_stest_OBJECTS)
@NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
@NATIVE_TRUE@am__objects_8 = stest.$(OBJEXT) @NATIVE_TRUE@am__objects_9 = stest.$(OBJEXT)
@NATIVE_TRUE@am_stest_alloc_OBJECTS = $(am__objects_8) @NATIVE_TRUE@am_stest_alloc_OBJECTS = $(am__objects_9)
stest_alloc_OBJECTS = $(am_stest_alloc_OBJECTS) stest_alloc_OBJECTS = $(am_stest_alloc_OBJECTS)
@NATIVE_TRUE@stest_alloc_DEPENDENCIES = libbacktrace_alloc.la @NATIVE_TRUE@stest_alloc_DEPENDENCIES = libbacktrace_alloc.la
@NATIVE_TRUE@am_test_elf_32_OBJECTS = test_format.$(OBJEXT) \ @NATIVE_TRUE@am_test_elf_32_OBJECTS = test_format.$(OBJEXT) \
...@@ -359,11 +381,11 @@ ttest_OBJECTS = $(am_ttest_OBJECTS) ...@@ -359,11 +381,11 @@ ttest_OBJECTS = $(am_ttest_OBJECTS)
ttest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ ttest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ttest_CFLAGS) $(CFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ttest_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@ $(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-ttest.$(OBJEXT) \
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ ttest_alloc-testlib.$(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_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) ttest_alloc_OBJECTS = $(am_ttest_alloc_OBJECTS)
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_alloc_DEPENDENCIES = \ @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_alloc_DEPENDENCIES = \
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ libbacktrace_alloc.la @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ libbacktrace_alloc.la
...@@ -374,8 +396,8 @@ ttest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ ...@@ -374,8 +396,8 @@ ttest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@NATIVE_TRUE@ testlib.$(OBJEXT) @NATIVE_TRUE@ testlib.$(OBJEXT)
unittest_OBJECTS = $(am_unittest_OBJECTS) unittest_OBJECTS = $(am_unittest_OBJECTS)
@NATIVE_TRUE@unittest_DEPENDENCIES = libbacktrace.la @NATIVE_TRUE@unittest_DEPENDENCIES = libbacktrace.la
@NATIVE_TRUE@am__objects_10 = unittest.$(OBJEXT) testlib.$(OBJEXT) @NATIVE_TRUE@am__objects_11 = unittest.$(OBJEXT) testlib.$(OBJEXT)
@NATIVE_TRUE@am_unittest_alloc_OBJECTS = $(am__objects_10) @NATIVE_TRUE@am_unittest_alloc_OBJECTS = $(am__objects_11)
unittest_alloc_OBJECTS = $(am_unittest_alloc_OBJECTS) unittest_alloc_OBJECTS = $(am_unittest_alloc_OBJECTS)
@NATIVE_TRUE@unittest_alloc_DEPENDENCIES = libbacktrace_alloc.la @NATIVE_TRUE@unittest_alloc_DEPENDENCIES = libbacktrace_alloc.la
@HAVE_ELF_TRUE@@NATIVE_TRUE@am_ztest_OBJECTS = ztest-ztest.$(OBJEXT) \ @HAVE_ELF_TRUE@@NATIVE_TRUE@am_ztest_OBJECTS = ztest-ztest.$(OBJEXT) \
...@@ -387,11 +409,11 @@ ztest_OBJECTS = $(am_ztest_OBJECTS) ...@@ -387,11 +409,11 @@ ztest_OBJECTS = $(am_ztest_OBJECTS)
ztest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ ztest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ztest_CFLAGS) $(CFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ztest_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@ $(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-ztest.$(OBJEXT) \
@HAVE_ELF_TRUE@@NATIVE_TRUE@ ztest_alloc-testlib.$(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_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) ztest_alloc_OBJECTS = $(am_ztest_alloc_OBJECTS)
@HAVE_ELF_TRUE@@NATIVE_TRUE@ztest_alloc_DEPENDENCIES = \ @HAVE_ELF_TRUE@@NATIVE_TRUE@ztest_alloc_DEPENDENCIES = \
@HAVE_ELF_TRUE@@NATIVE_TRUE@ libbacktrace_alloc.la \ @HAVE_ELF_TRUE@@NATIVE_TRUE@ libbacktrace_alloc.la \
...@@ -441,7 +463,8 @@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \ ...@@ -441,7 +463,8 @@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
$(b2test_SOURCES) $(b3test_SOURCES) $(btest_SOURCES) \ $(b2test_SOURCES) $(b3test_SOURCES) $(btest_SOURCES) \
$(btest_alloc_SOURCES) $(btest_lto_SOURCES) $(ctesta_SOURCES) \ $(btest_alloc_SOURCES) $(btest_lto_SOURCES) $(ctesta_SOURCES) \
$(ctesta_alloc_SOURCES) $(ctestg_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) \ $(edtest_alloc_SOURCES) $(stest_SOURCES) \
$(stest_alloc_SOURCES) $(test_elf_32_SOURCES) \ $(stest_alloc_SOURCES) $(test_elf_32_SOURCES) \
$(test_elf_64_SOURCES) $(test_pecoff_SOURCES) \ $(test_elf_64_SOURCES) $(test_pecoff_SOURCES) \
...@@ -863,7 +886,7 @@ libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD) ...@@ -863,7 +886,7 @@ libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
# Add test to this variable, if you want it to be build and run. # Add test to this variable, if you want it to be build and run.
BUILDTESTS = $(am__append_2) $(am__append_9) $(am__append_10) \ BUILDTESTS = $(am__append_2) $(am__append_9) $(am__append_10) \
$(am__append_15) $(am__append_16) $(am__append_17) \ $(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@check_LTLIBRARIES = libbacktrace_alloc.la \
@NATIVE_TRUE@ libbacktrace_noformat.la $(am__append_1) \ @NATIVE_TRUE@ libbacktrace_noformat.la $(am__append_1) \
@NATIVE_TRUE@ libbacktrace_instrumented_alloc.la @NATIVE_TRUE@ libbacktrace_instrumented_alloc.la
...@@ -960,6 +983,13 @@ BUILDTESTS = $(am__append_2) $(am__append_9) $(am__append_10) \ ...@@ -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_CFLAGS = $(ctesta_CFLAGS)
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_alloc_LDFLAGS = $(ctesta_LDFLAGS) @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_alloc_LDFLAGS = $(ctesta_LDFLAGS)
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_alloc_LDADD = libbacktrace_alloc.la @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 # We can't use automake's automatic dependency tracking, because it
# breaks when using bootstrap-lean. Automatic dependency tracking # breaks when using bootstrap-lean. Automatic dependency tracking
...@@ -1124,6 +1154,14 @@ ctestg_alloc$(EXEEXT): $(ctestg_alloc_OBJECTS) $(ctestg_alloc_DEPENDENCIES) $(EX ...@@ -1124,6 +1154,14 @@ ctestg_alloc$(EXEEXT): $(ctestg_alloc_OBJECTS) $(ctestg_alloc_DEPENDENCIES) $(EX
@rm -f ctestg_alloc$(EXEEXT) @rm -f ctestg_alloc$(EXEEXT)
$(AM_V_CCLD)$(ctestg_alloc_LINK) $(ctestg_alloc_OBJECTS) $(ctestg_alloc_LDADD) $(LIBS) $(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) edtest$(EXEEXT): $(edtest_OBJECTS) $(edtest_DEPENDENCIES) $(EXTRA_edtest_DEPENDENCIES)
@rm -f edtest$(EXEEXT) @rm -f edtest$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(edtest_OBJECTS) $(edtest_LDADD) $(LIBS) $(AM_V_CCLD)$(LINK) $(edtest_OBJECTS) $(edtest_LDADD) $(LIBS)
...@@ -1311,6 +1349,30 @@ ctestg_alloc-testlib.o: testlib.c ...@@ -1311,6 +1349,30 @@ ctestg_alloc-testlib.o: testlib.c
ctestg_alloc-testlib.obj: 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` $(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 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 $(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) ...@@ -1771,6 +1833,20 @@ ctesta_alloc.log: ctesta_alloc$(EXEEXT)
--log-file $$b.log --trs-file $$b.trs \ --log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT) "$$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: .test.log:
@p='$<'; \ @p='$<'; \
$(am__set_b); \ $(am__set_b); \
...@@ -1816,6 +1892,7 @@ mostlyclean-generic: ...@@ -1816,6 +1892,7 @@ mostlyclean-generic:
-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
clean-generic: clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic: distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
...@@ -1973,6 +2050,9 @@ uninstall-am: ...@@ -1973,6 +2050,9 @@ uninstall-am:
@NATIVE_TRUE@ "$(TEST_BUILD_ID_DIR)" \ @NATIVE_TRUE@ "$(TEST_BUILD_ID_DIR)" \
@NATIVE_TRUE@ $< @NATIVE_TRUE@ $<
@NATIVE_TRUE@ $(OBJCOPY) --strip-debug $< $@ @NATIVE_TRUE@ $(OBJCOPY) --strip-debug $< $@
clean-local:
-rm -rf usr
alloc.lo: config.h backtrace.h internal.h alloc.lo: config.h backtrace.h internal.h
backtrace.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 btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h
......
...@@ -643,6 +643,8 @@ HAVE_COMPRESSED_DEBUG_FALSE ...@@ -643,6 +643,8 @@ HAVE_COMPRESSED_DEBUG_FALSE
HAVE_COMPRESSED_DEBUG_TRUE HAVE_COMPRESSED_DEBUG_TRUE
HAVE_ZLIB_FALSE HAVE_ZLIB_FALSE
HAVE_ZLIB_TRUE HAVE_ZLIB_TRUE
HAVE_DWARF5_FALSE
HAVE_DWARF5_TRUE
HAVE_PTHREAD_FALSE HAVE_PTHREAD_FALSE
HAVE_PTHREAD_TRUE HAVE_PTHREAD_TRUE
PTHREAD_CFLAGS PTHREAD_CFLAGS
...@@ -11497,7 +11499,7 @@ else ...@@ -11497,7 +11499,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF cat > conftest.$ac_ext <<_LT_EOF
#line 11500 "configure" #line 11502 "configure"
#include "confdefs.h" #include "confdefs.h"
#if HAVE_DLFCN_H #if HAVE_DLFCN_H
...@@ -11603,7 +11605,7 @@ else ...@@ -11603,7 +11605,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF cat > conftest.$ac_ext <<_LT_EOF
#line 11606 "configure" #line 11608 "configure"
#include "confdefs.h" #include "confdefs.h"
#if HAVE_DLFCN_H #if HAVE_DLFCN_H
...@@ -13280,6 +13282,36 @@ else ...@@ -13280,6 +13282,36 @@ else
fi 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 "$as_me:${as_lineno-$LINENO}: checking for compress in -lz" >&5
$as_echo_n "checking for compress in -lz... " >&6; } $as_echo_n "checking for compress in -lz... " >&6; }
if ${ac_cv_lib_z_compress+:} false; then : if ${ac_cv_lib_z_compress+:} false; then :
...@@ -13665,6 +13697,10 @@ if test -z "${HAVE_PTHREAD_TRUE}" && test -z "${HAVE_PTHREAD_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. as_fn_error $? "conditional \"HAVE_PTHREAD\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5 Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi 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 if test -z "${HAVE_ZLIB_TRUE}" && test -z "${HAVE_ZLIB_FALSE}"; then
as_fn_error $? "conditional \"HAVE_ZLIB\" was never defined. as_fn_error $? "conditional \"HAVE_ZLIB\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5 Usually this means the macro was only invoked conditionally." "$LINENO" 5
......
...@@ -420,6 +420,17 @@ AC_SUBST(PTHREAD_CFLAGS) ...@@ -420,6 +420,17 @@ AC_SUBST(PTHREAD_CFLAGS)
AM_CONDITIONAL(HAVE_PTHREAD, test "$libgo_cv_lib_pthread" = yes) 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_CHECK_LIB([z], [compress],
[AC_DEFINE(HAVE_ZLIB, 1, [Define if -lz is available.])]) [AC_DEFINE(HAVE_ZLIB, 1, [Define if -lz is available.])])
AM_CONDITIONAL(HAVE_ZLIB, test "$ac_cv_lib_z_compress" = yes) AM_CONDITIONAL(HAVE_ZLIB, test "$ac_cv_lib_z_compress" = yes)
......
...@@ -92,6 +92,8 @@ struct attr ...@@ -92,6 +92,8 @@ struct attr
enum dwarf_attribute name; enum dwarf_attribute name;
/* The attribute form. */ /* The attribute form. */
enum dwarf_form form; enum dwarf_form form;
/* The attribute value, for DW_FORM_implicit_const. */
int64_t val;
}; };
/* A single DWARF abbreviation. */ /* A single DWARF abbreviation. */
...@@ -133,22 +135,29 @@ enum attr_val_encoding ...@@ -133,22 +135,29 @@ enum attr_val_encoding
ATTR_VAL_NONE, ATTR_VAL_NONE,
/* An address. */ /* An address. */
ATTR_VAL_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. */ /* A unsigned integer. */
ATTR_VAL_UINT, ATTR_VAL_UINT,
/* A sigd integer. */ /* A sigd integer. */
ATTR_VAL_SINT, ATTR_VAL_SINT,
/* A string. */ /* A string. */
ATTR_VAL_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. */ /* An offset to other data in the containing unit. */
ATTR_VAL_REF_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, 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, ATTR_VAL_REF_ALT_INFO,
/* An offset to data in some other section. */ /* An offset to data in some other section. */
ATTR_VAL_REF_SECTION, ATTR_VAL_REF_SECTION,
/* A type signature. */ /* A type signature. */
ATTR_VAL_REF_TYPE, ATTR_VAL_REF_TYPE,
/* An index into the .debug_rnglists section. */
ATTR_VAL_RNGLISTS_INDEX,
/* A block of data (not represented). */ /* A block of data (not represented). */
ATTR_VAL_BLOCK, ATTR_VAL_BLOCK,
/* An expression (not represented). */ /* An expression (not represented). */
...@@ -163,7 +172,7 @@ struct attr_val ...@@ -163,7 +172,7 @@ struct attr_val
enum attr_val_encoding encoding; enum attr_val_encoding encoding;
union union
{ {
/* ATTR_VAL_ADDRESS, ATTR_VAL_UINT, ATTR_VAL_REF*. */ /* ATTR_VAL_ADDRESS*, ATTR_VAL_UINT, ATTR_VAL_REF*. */
uint64_t uint; uint64_t uint;
/* ATTR_VAL_SINT. */ /* ATTR_VAL_SINT. */
int64_t sint; int64_t sint;
...@@ -179,6 +188,8 @@ struct line_header ...@@ -179,6 +188,8 @@ struct line_header
{ {
/* The version of the line number information. */ /* The version of the line number information. */
int version; int version;
/* Address size. */
int addrsize;
/* The minimum instruction length. */ /* The minimum instruction length. */
unsigned int min_insn_len; unsigned int min_insn_len;
/* The maximum number of ops per instruction. */ /* The maximum number of ops per instruction. */
...@@ -201,6 +212,14 @@ struct line_header ...@@ -201,6 +212,14 @@ struct line_header
const char **filenames; 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 /* 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 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 PC up to the PC of the next entry if there is one. We allocate one
...@@ -297,6 +316,12 @@ struct unit ...@@ -297,6 +316,12 @@ struct unit
int addrsize; int addrsize;
/* Offset into line number information. */ /* Offset into line number information. */
off_t lineoff; 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. */ /* Primary source file. */
const char *filename; const char *filename;
/* Compilation command working directory. */ /* Compilation command working directory. */
...@@ -483,6 +508,23 @@ read_uint16 (struct dwarf_buf *buf) ...@@ -483,6 +508,23 @@ read_uint16 (struct dwarf_buf *buf)
return ((uint16_t) p[1] << 8) | (uint16_t) p[0]; 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. */ /* Read a uint32 from BUF and advance 4 bytes. */
static uint32_t static uint32_t
...@@ -709,9 +751,9 @@ free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs, ...@@ -709,9 +751,9 @@ free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs,
forms, because we don't care about them. */ forms, because we don't care about them. */
static int static int
read_attribute (enum dwarf_form form, struct dwarf_buf *buf, read_attribute (enum dwarf_form form, uint64_t implicit_val,
int is_dwarf64, int version, int addrsize, struct dwarf_buf *buf, int is_dwarf64, int version,
const unsigned char *dwarf_str, size_t dwarf_str_size, int addrsize, const struct dwarf_sections *dwarf_sections,
struct dwarf_data *altlink, struct attr_val *val) struct dwarf_data *altlink, struct attr_val *val)
{ {
/* Avoid warnings about val.u.FIELD may be used uninitialized if /* 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, ...@@ -744,6 +786,9 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
val->encoding = ATTR_VAL_UINT; val->encoding = ATTR_VAL_UINT;
val->u.uint = read_uint64 (buf); val->u.uint = read_uint64 (buf);
return 1; return 1;
case DW_FORM_data16:
val->encoding = ATTR_VAL_BLOCK;
return advance (buf, 16);
case DW_FORM_string: case DW_FORM_string:
val->encoding = ATTR_VAL_STRING; val->encoding = ATTR_VAL_STRING;
val->u.string = read_string (buf); val->u.string = read_string (buf);
...@@ -771,13 +816,29 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf, ...@@ -771,13 +816,29 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
uint64_t offset; uint64_t offset;
offset = read_offset (buf, is_dwarf64); 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"); dwarf_buf_error (buf, "DW_FORM_strp out of range");
return 0; return 0;
} }
val->encoding = ATTR_VAL_STRING; 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; return 1;
} }
case DW_FORM_udata: case DW_FORM_udata:
...@@ -816,9 +877,15 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf, ...@@ -816,9 +877,15 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
uint64_t form; uint64_t form;
form = read_uleb128 (buf); form = read_uleb128 (buf);
return read_attribute ((enum dwarf_form) form, buf, is_dwarf64, if (form == DW_FORM_implicit_const)
version, addrsize, dwarf_str, dwarf_str_size, {
altlink, val); 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: case DW_FORM_sec_offset:
val->encoding = ATTR_VAL_REF_SECTION; val->encoding = ATTR_VAL_REF_SECTION;
...@@ -835,6 +902,88 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf, ...@@ -835,6 +902,88 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
val->encoding = ATTR_VAL_REF_TYPE; val->encoding = ATTR_VAL_REF_TYPE;
val->u.uint = read_uint64 (buf); val->u.uint = read_uint64 (buf);
return 1; 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: case DW_FORM_GNU_addr_index:
val->encoding = ATTR_VAL_REF_SECTION; val->encoding = ATTR_VAL_REF_SECTION;
val->u.uint = read_uleb128 (buf); val->u.uint = read_uleb128 (buf);
...@@ -852,9 +1001,10 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf, ...@@ -852,9 +1001,10 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
} }
val->encoding = ATTR_VAL_REF_ALT_INFO; val->encoding = ATTR_VAL_REF_ALT_INFO;
return 1; return 1;
case DW_FORM_GNU_strp_alt: case DW_FORM_strp_sup: case DW_FORM_GNU_strp_alt:
{ {
uint64_t offset; uint64_t offset;
offset = read_offset (buf, is_dwarf64); offset = read_offset (buf, is_dwarf64);
if (altlink == NULL) if (altlink == NULL)
{ {
...@@ -863,7 +1013,7 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf, ...@@ -863,7 +1013,7 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
} }
if (offset >= altlink->dwarf_sections.size[DEBUG_STR]) 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; return 0;
} }
val->encoding = ATTR_VAL_STRING; val->encoding = ATTR_VAL_STRING;
...@@ -877,6 +1027,95 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf, ...@@ -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. */ /* Compare a unit offset against a unit for bsearch. */
static int static int
...@@ -1142,7 +1381,13 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, ...@@ -1142,7 +1381,13 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
read_byte (&count_buf); read_byte (&count_buf);
// Skip attributes. // Skip attributes.
while (read_uleb128 (&count_buf) != 0) 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. // Skip form of last attribute.
read_uleb128 (&count_buf); read_uleb128 (&count_buf);
} }
...@@ -1185,8 +1430,12 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, ...@@ -1185,8 +1430,12 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
num_attrs = 0; num_attrs = 0;
while (read_uleb128 (&count_buf) != 0) while (read_uleb128 (&count_buf) != 0)
{ {
uint64_t form;
++num_attrs; ++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) if (num_attrs == 0)
...@@ -1214,6 +1463,10 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, ...@@ -1214,6 +1463,10 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
break; break;
attrs[num_attrs].name = (enum dwarf_attribute) name; attrs[num_attrs].name = (enum dwarf_attribute) name;
attrs[num_attrs].form = (enum dwarf_form) form; 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; ++num_attrs;
} }
} }
...@@ -1272,11 +1525,14 @@ lookup_abbrev (struct abbrevs *abbrevs, uint64_t code, ...@@ -1272,11 +1525,14 @@ lookup_abbrev (struct abbrevs *abbrevs, uint64_t code,
struct pcrange { struct pcrange {
uint64_t lowpc; /* The low PC value. */ uint64_t lowpc; /* The low PC value. */
int have_lowpc; /* Whether a low PC value was found. */ 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. */ uint64_t highpc; /* The high PC value. */
int have_highpc; /* Whether a high PC value was found. */ int have_highpc; /* Whether a high PC value was found. */
int highpc_is_relative; /* Whether highpc is relative to lowpc. */ 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. */ uint64_t ranges; /* Offset in ranges section. */
int have_ranges; /* Whether ranges is valid. */ int have_ranges; /* Whether ranges is valid. */
int ranges_is_index; /* Whether ranges is DW_FORM_rnglistx. */
}; };
/* Update PCRANGE from an attribute value. */ /* Update PCRANGE from an attribute value. */
...@@ -1293,6 +1549,12 @@ update_pcrange (const struct attr* attr, const struct attr_val* val, ...@@ -1293,6 +1549,12 @@ update_pcrange (const struct attr* attr, const struct attr_val* val,
pcrange->lowpc = val->u.uint; pcrange->lowpc = val->u.uint;
pcrange->have_lowpc = 1; 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; break;
case DW_AT_high_pc: case DW_AT_high_pc:
...@@ -1307,6 +1569,12 @@ update_pcrange (const struct attr* attr, const struct attr_val* val, ...@@ -1307,6 +1569,12 @@ update_pcrange (const struct attr* attr, const struct attr_val* val,
pcrange->have_highpc = 1; pcrange->have_highpc = 1;
pcrange->highpc_is_relative = 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; break;
case DW_AT_ranges: case DW_AT_ranges:
...@@ -1316,6 +1584,12 @@ update_pcrange (const struct attr* attr, const struct attr_val* val, ...@@ -1316,6 +1584,12 @@ update_pcrange (const struct attr* attr, const struct attr_val* val,
pcrange->ranges = val->u.uint; pcrange->ranges = val->u.uint;
pcrange->have_ranges = 1; 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; break;
default: default:
...@@ -1323,51 +1597,73 @@ update_pcrange (const struct attr* attr, const struct attr_val* val, ...@@ -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 /* Call ADD_RANGE for a low/high PC pair. Returns 1 on success, 0 on
passed to ADD_RANGE, and is either a struct unit * or a struct error. */
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 static int
add_ranges (struct backtrace_state *state, add_low_high_range (struct backtrace_state *state,
const struct dwarf_sections *dwarf_sections, const struct dwarf_sections *dwarf_sections,
uintptr_t base_address, int is_bigendian, uintptr_t base_address, int is_bigendian,
struct unit *u, uint64_t base, const struct pcrange *pcrange, struct unit *u, const struct pcrange *pcrange,
int (*add_range) (struct backtrace_state *state, void *rdata, int (*add_range) (struct backtrace_state *state,
uint64_t lowpc, uint64_t highpc, void *rdata, uint64_t lowpc,
backtrace_error_callback error_callback, uint64_t highpc,
void *data, void *vec), backtrace_error_callback error_callback,
void *rdata, void *data, void *vec),
backtrace_error_callback error_callback, void *data, void *rdata,
void *vec) 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; if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,
uint64_t highpc; is_bigendian, lowpc, error_callback, data,
&lowpc))
lowpc = pcrange->lowpc; return 0;
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 (!pcrange->have_ranges) highpc = pcrange->highpc;
if (pcrange->highpc_is_addr_index)
{ {
/* Did not find any address ranges to add. */ if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,
return 1; 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]) if (pcrange->ranges >= dwarf_sections->size[DEBUG_RANGES])
{ {
...@@ -1416,6 +1712,220 @@ add_ranges (struct backtrace_state *state, ...@@ -1416,6 +1712,220 @@ add_ranges (struct backtrace_state *state,
return 1; 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 /* 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 UNIT_BUF and adding values to U. Returns 1 if all data could be
read, 0 if there is some error. */ read, 0 if there is some error. */
...@@ -1434,6 +1944,10 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, ...@@ -1434,6 +1944,10 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
uint64_t code; uint64_t code;
const struct abbrev *abbrev; const struct abbrev *abbrev;
struct pcrange pcrange; 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; size_t i;
code = read_uleb128 (unit_buf); code = read_uleb128 (unit_buf);
...@@ -1448,15 +1962,17 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, ...@@ -1448,15 +1962,17 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
*unit_tag = abbrev->tag; *unit_tag = abbrev->tag;
memset (&pcrange, 0, sizeof pcrange); 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) for (i = 0; i < abbrev->num_attrs; ++i)
{ {
struct attr_val val; struct attr_val val;
if (!read_attribute (abbrev->attrs[i].form, unit_buf, if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
u->is_dwarf64, u->version, u->addrsize, unit_buf, u->is_dwarf64, u->version,
dwarf_sections->data[DEBUG_STR], u->addrsize, dwarf_sections, altlink, &val))
dwarf_sections->size[DEBUG_STR],
altlink, &val))
return 0; return 0;
switch (abbrev->attrs[i].name) switch (abbrev->attrs[i].name)
...@@ -1473,15 +1989,37 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, ...@@ -1473,15 +1989,37 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
break; break;
case DW_AT_name: case DW_AT_name:
if (abbrev->tag == DW_TAG_compile_unit if (abbrev->tag == DW_TAG_compile_unit)
&& val.encoding == ATTR_VAL_STRING) {
u->filename = val.u.string; name_val = val;
have_name_val = 1;
}
break; break;
case DW_AT_comp_dir: 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 if (abbrev->tag == DW_TAG_compile_unit
&& val.encoding == ATTR_VAL_STRING) && val.encoding == ATTR_VAL_REF_SECTION)
u->comp_dir = val.u.string; 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; break;
default: default:
...@@ -1489,6 +2027,23 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, ...@@ -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 if (abbrev->tag == DW_TAG_compile_unit
|| abbrev->tag == DW_TAG_subprogram) || abbrev->tag == DW_TAG_subprogram)
{ {
...@@ -1565,6 +2120,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1565,6 +2120,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
int is_dwarf64; int is_dwarf64;
struct dwarf_buf unit_buf; struct dwarf_buf unit_buf;
int version; int version;
int unit_type;
uint64_t abbrev_offset; uint64_t abbrev_offset;
int addrsize; int addrsize;
struct unit *u; struct unit *u;
...@@ -1583,12 +2139,24 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1583,12 +2139,24 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
goto fail; goto fail;
version = read_uint16 (&unit_buf); version = read_uint16 (&unit_buf);
if (version < 2 || version > 4) if (version < 2 || version > 5)
{ {
dwarf_buf_error (&unit_buf, "unrecognized DWARF version"); dwarf_buf_error (&unit_buf, "unrecognized DWARF version");
goto fail; 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 **) pu = ((struct unit **)
backtrace_vector_grow (state, sizeof (struct unit *), backtrace_vector_grow (state, sizeof (struct unit *),
error_callback, data, &units)); error_callback, data, &units));
...@@ -1603,6 +2171,11 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1603,6 +2171,11 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
*pu = u; *pu = u;
++units_count; ++units_count;
if (version < 5)
addrsize = 0; /* Set below. */
else
addrsize = read_byte (&unit_buf);
memset (&u->abbrevs, 0, sizeof u->abbrevs); memset (&u->abbrevs, 0, sizeof u->abbrevs);
abbrev_offset = read_offset (&unit_buf, is_dwarf64); abbrev_offset = read_offset (&unit_buf, is_dwarf64);
if (!read_abbrevs (state, abbrev_offset, if (!read_abbrevs (state, abbrev_offset,
...@@ -1611,7 +2184,21 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1611,7 +2184,21 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
is_bigendian, error_callback, data, &u->abbrevs)) is_bigendian, error_callback, data, &u->abbrevs))
goto fail; 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; u->low_offset = unit_offset;
unit_offset += len + (is_dwarf64 ? 12 : 4); unit_offset += len + (is_dwarf64 ? 12 : 4);
...@@ -1720,55 +2307,21 @@ free_line_header (struct backtrace_state *state, struct line_header *hdr, ...@@ -1720,55 +2307,21 @@ free_line_header (struct backtrace_state *state, struct line_header *hdr,
error_callback, data); 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 static int
read_line_header (struct backtrace_state *state, struct unit *u, read_v2_paths (struct backtrace_state *state, struct unit *u,
int is_dwarf64, struct dwarf_buf *line_buf, struct dwarf_buf *hdr_buf, struct line_header *hdr)
struct line_header *hdr)
{ {
uint64_t hdrlen;
struct dwarf_buf hdr_buf;
const unsigned char *p; const unsigned char *p;
const unsigned char *pend; const unsigned char *pend;
size_t i; 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. */ /* Count the number of directory entries. */
hdr->dirs_count = 0; hdr->dirs_count = 0;
p = hdr_buf.buf; p = hdr_buf->buf;
pend = p + hdr_buf.left; pend = p + hdr_buf->left;
while (p < pend && *p != '\0') while (p < pend && *p != '\0')
{ {
p += strnlen((const char *) p, pend - p) + 1; p += strnlen((const char *) p, pend - p) + 1;
...@@ -1781,29 +2334,30 @@ read_line_header (struct backtrace_state *state, struct unit *u, ...@@ -1781,29 +2334,30 @@ read_line_header (struct backtrace_state *state, struct unit *u,
hdr->dirs = ((const char **) hdr->dirs = ((const char **)
backtrace_alloc (state, backtrace_alloc (state,
hdr->dirs_count * sizeof (const char *), hdr->dirs_count * sizeof (const char *),
line_buf->error_callback, line_buf->data)); hdr_buf->error_callback,
hdr_buf->data));
if (hdr->dirs == NULL) if (hdr->dirs == NULL)
return 0; return 0;
} }
i = 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; return 0;
hdr->dirs[i] = read_string (&hdr_buf); hdr->dirs[i] = read_string (hdr_buf);
if (hdr->dirs[i] == NULL) if (hdr->dirs[i] == NULL)
return 0; return 0;
++i; ++i;
} }
if (!advance (&hdr_buf, 1)) if (!advance (hdr_buf, 1))
return 0; return 0;
/* Count the number of file entries. */ /* Count the number of file entries. */
hdr->filenames_count = 0; hdr->filenames_count = 0;
p = hdr_buf.buf; p = hdr_buf->buf;
pend = p + hdr_buf.left; pend = p + hdr_buf->left;
while (p < pend && *p != '\0') while (p < pend && *p != '\0')
{ {
p += strnlen ((const char *) p, pend - p) + 1; p += strnlen ((const char *) p, pend - p) + 1;
...@@ -1816,23 +2370,23 @@ read_line_header (struct backtrace_state *state, struct unit *u, ...@@ -1816,23 +2370,23 @@ read_line_header (struct backtrace_state *state, struct unit *u,
hdr->filenames = ((const char **) hdr->filenames = ((const char **)
backtrace_alloc (state, backtrace_alloc (state,
hdr->filenames_count * sizeof (char *), hdr->filenames_count * sizeof (char *),
line_buf->error_callback, hdr_buf->error_callback,
line_buf->data)); hdr_buf->data));
if (hdr->filenames == NULL) if (hdr->filenames == NULL)
return 0; return 0;
i = 0; i = 0;
while (*hdr_buf.buf != '\0') while (*hdr_buf->buf != '\0')
{ {
const char *filename; const char *filename;
uint64_t dir_index; uint64_t dir_index;
if (hdr_buf.reported_underflow) if (hdr_buf->reported_underflow)
return 0; return 0;
filename = read_string (&hdr_buf); filename = read_string (hdr_buf);
if (filename == NULL) if (filename == NULL)
return 0; return 0;
dir_index = read_uleb128 (&hdr_buf); dir_index = read_uleb128 (hdr_buf);
if (IS_ABSOLUTE_PATH (filename) if (IS_ABSOLUTE_PATH (filename)
|| (dir_index == 0 && u->comp_dir == NULL)) || (dir_index == 0 && u->comp_dir == NULL))
hdr->filenames[i] = filename; hdr->filenames[i] = filename;
...@@ -1849,16 +2403,16 @@ read_line_header (struct backtrace_state *state, struct unit *u, ...@@ -1849,16 +2403,16 @@ read_line_header (struct backtrace_state *state, struct unit *u,
dir = hdr->dirs[dir_index - 1]; dir = hdr->dirs[dir_index - 1];
else else
{ {
dwarf_buf_error (line_buf, dwarf_buf_error (hdr_buf,
("invalid directory index in " ("invalid directory index in "
"line number program header")); "line number program header"));
return 0; return 0;
} }
dir_len = strlen (dir); dir_len = strlen (dir);
filename_len = strlen (filename); filename_len = strlen (filename);
s = ((char *) s = ((char *) backtrace_alloc (state, dir_len + filename_len + 2,
backtrace_alloc (state, dir_len + filename_len + 2, hdr_buf->error_callback,
line_buf->error_callback, line_buf->data)); hdr_buf->data));
if (s == NULL) if (s == NULL)
return 0; return 0;
memcpy (s, dir, dir_len); memcpy (s, dir, dir_len);
...@@ -1871,12 +2425,258 @@ read_line_header (struct backtrace_state *state, struct unit *u, ...@@ -1871,12 +2425,258 @@ read_line_header (struct backtrace_state *state, struct unit *u,
} }
/* Ignore the modification time and size. */ /* Ignore the modification time and size. */
read_uleb128 (&hdr_buf); read_uleb128 (hdr_buf);
read_uleb128 (&hdr_buf); read_uleb128 (hdr_buf);
++i; ++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) if (hdr_buf.reported_underflow)
return 0; return 0;
...@@ -1942,7 +2742,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, ...@@ -1942,7 +2742,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
lineno = 1; lineno = 1;
break; break;
case DW_LNE_set_address: case DW_LNE_set_address:
address = read_address (line_buf, u->addrsize); address = read_address (line_buf, hdr->addrsize);
break; break;
case DW_LNE_define_file: case DW_LNE_define_file:
{ {
...@@ -1965,7 +2765,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, ...@@ -1965,7 +2765,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
size_t f_len; size_t f_len;
char *p; char *p;
if (dir_index == 0) if (dir_index == 0 && hdr->version < 5)
dir = u->comp_dir; dir = u->comp_dir;
else if (dir_index - 1 < hdr->dirs_count) else if (dir_index - 1 < hdr->dirs_count)
dir = hdr->dirs[dir_index - 1]; dir = hdr->dirs[dir_index - 1];
...@@ -2129,7 +2929,7 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata, ...@@ -2129,7 +2929,7 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata,
len = read_initial_length (&line_buf, &is_dwarf64); len = read_initial_length (&line_buf, &is_dwarf64);
line_buf.left = len; 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; goto fail;
if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec)) 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, ...@@ -2287,11 +3087,9 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
{ {
struct attr_val val; struct attr_val val;
if (!read_attribute (abbrev->attrs[i].form, &unit_buf, if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
u->is_dwarf64, u->version, u->addrsize, &unit_buf, u->is_dwarf64, u->version, u->addrsize,
ddata->dwarf_sections.data[DEBUG_STR], &ddata->dwarf_sections, ddata->altlink, &val))
ddata->dwarf_sections.size[DEBUG_STR],
ddata->altlink, &val))
return NULL; return NULL;
switch (abbrev->attrs[i].name) switch (abbrev->attrs[i].name)
...@@ -2302,15 +3100,26 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u, ...@@ -2302,15 +3100,26 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
normally not mangled. */ normally not mangled. */
if (ret != NULL) if (ret != NULL)
break; break;
if (val.encoding == ATTR_VAL_STRING) if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
ret = val.u.string; ddata->is_bigendian, u->str_offsets_base,
&val, error_callback, data, &ret))
return NULL;
break; break;
case DW_AT_linkage_name: case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name: case DW_AT_MIPS_linkage_name:
/* First name preference: override all. */ /* 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; break;
case DW_AT_specification: case DW_AT_specification:
...@@ -2430,19 +3239,28 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, ...@@ -2430,19 +3239,28 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
{ {
struct attr_val val; struct attr_val val;
if (!read_attribute (abbrev->attrs[i].form, unit_buf, if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
u->is_dwarf64, u->version, u->addrsize, unit_buf, u->is_dwarf64, u->version,
ddata->dwarf_sections.data[DEBUG_STR], u->addrsize, &ddata->dwarf_sections,
ddata->dwarf_sections.size[DEBUG_STR],
ddata->altlink, &val)) ddata->altlink, &val))
return 0; return 0;
/* The compile unit sets the base address for any address /* The compile unit sets the base address for any address
ranges in the function entries. */ ranges in the function entries. */
if (abbrev->tag == DW_TAG_compile_unit if (abbrev->tag == DW_TAG_compile_unit
&& abbrev->attrs[i].name == DW_AT_low_pc && abbrev->attrs[i].name == DW_AT_low_pc)
&& val.encoding == ATTR_VAL_ADDRESS) {
base = val.u.uint; 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) if (is_function)
{ {
...@@ -2495,18 +3313,31 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, ...@@ -2495,18 +3313,31 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
/* Third name preference: don't override. */ /* Third name preference: don't override. */
if (function->name != NULL) if (function->name != NULL)
break; break;
if (val.encoding == ATTR_VAL_STRING) if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
function->name = val.u.string; ddata->is_bigendian,
u->str_offsets_base, &val,
error_callback, data, &function->name))
return 0;
break; break;
case DW_AT_linkage_name: case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name: case DW_AT_MIPS_linkage_name:
/* First name preference: override all. */ /* First name preference: override all. */
if (val.encoding == ATTR_VAL_STRING) {
{ const char *s;
function->name = val.u.string;
have_linkage_name = 1; 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; break;
case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges: case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:
......
...@@ -346,6 +346,10 @@ static const char * const dwarf_section_names[DEBUG_MAX] = ...@@ -346,6 +346,10 @@ static const char * const dwarf_section_names[DEBUG_MAX] =
".debug_abbrev", ".debug_abbrev",
".debug_ranges", ".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. */ /* Information we gather for the sections we care about. */
......
...@@ -295,6 +295,10 @@ enum dwarf_section ...@@ -295,6 +295,10 @@ enum dwarf_section
DEBUG_ABBREV, DEBUG_ABBREV,
DEBUG_RANGES, DEBUG_RANGES,
DEBUG_STR, DEBUG_STR,
DEBUG_ADDR,
DEBUG_STR_OFFSETS,
DEBUG_LINE_STR,
DEBUG_RNGLISTS,
DEBUG_MAX DEBUG_MAX
}; };
......
...@@ -141,7 +141,11 @@ static const char * const debug_section_names[DEBUG_MAX] = ...@@ -141,7 +141,11 @@ static const char * const debug_section_names[DEBUG_MAX] =
".debug_line", ".debug_line",
".debug_abbrev", ".debug_abbrev",
".debug_ranges", ".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. */ /* Information we gather for the sections we care about. */
......
...@@ -1286,6 +1286,8 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset, ...@@ -1286,6 +1286,8 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
+ (dwsect[i].offset - min_offset)); + (dwsect[i].offset - min_offset));
} }
memset (&dwarf_sections, 0, sizeof dwarf_sections);
dwarf_sections.data[DEBUG_INFO] = dwsect[DEBUG_INFO].data; dwarf_sections.data[DEBUG_INFO] = dwsect[DEBUG_INFO].data;
dwarf_sections.size[DEBUG_INFO] = dwsect[DEBUG_INFO].size; dwarf_sections.size[DEBUG_INFO] = dwsect[DEBUG_INFO].size;
#if BACKTRACE_XCOFF_SIZE == 32 #if BACKTRACE_XCOFF_SIZE == 32
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment