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>
* dwarf.c (struct pcrange): Define.
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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)
......
......@@ -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,
add_low_high_range (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,
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;
if (pcrange->have_lowpc && pcrange->have_highpc)
{
uint64_t lowpc;
uint64_t highpc;
lowpc = pcrange->lowpc;
if (pcrange->lowpc_is_addr_index)
{
if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,
is_bigendian, lowpc, error_callback, data,
&lowpc))
return 0;
}
highpc = pcrange->highpc;
if (pcrange->highpc_is_addr_index)
{
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. */
/* 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);
}
return add_range (state, rdata, lowpc, highpc, error_callback, data, vec);
}
if (!pcrange->have_ranges)
{
/* Did not find any address ranges to add. */
return 1;
}
/* 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,77 +1712,336 @@ add_ranges (struct backtrace_state *state,
return 1;
}
/* 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. */
/* Call ADD_RANGE for each range read from .debug_rnglists, as used in
DWARF version 5. */
static int
find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
struct dwarf_buf *unit_buf,
add_ranges_from_rnglists (
struct backtrace_state *state,
const struct dwarf_sections *dwarf_sections,
int is_bigendian, struct dwarf_data *altlink,
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,
struct unit *u, struct unit_addrs_vector *addrs,
enum dwarf_tag *unit_tag)
void *vec),
void *rdata,
backtrace_error_callback error_callback, void *data,
void *vec)
{
while (unit_buf->left > 0)
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])
{
uint64_t code;
const struct abbrev *abbrev;
struct pcrange pcrange;
size_t i;
error_callback (data, "rnglists offset out of range", 0);
return 0;
}
code = read_uleb128 (unit_buf);
if (code == 0)
return 1;
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;
abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
if (abbrev == NULL)
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;
}
if (unit_tag != NULL)
*unit_tag = abbrev->tag;
while (1)
{
unsigned char rle;
memset (&pcrange, 0, sizeof pcrange);
for (i = 0; i < abbrev->num_attrs; ++i)
rle = read_byte (&rnglists_buf);
if (rle == DW_RLE_end_of_list)
break;
switch (rle)
{
struct attr_val val;
case DW_RLE_base_addressx:
{
uint64_t index;
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))
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;
switch (abbrev->attrs[i].name)
case DW_RLE_startx_endx:
{
case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:
update_pcrange (&abbrev->attrs[i], &val, &pcrange);
break;
uint64_t index;
uint64_t low;
uint64_t high;
case DW_AT_stmt_list:
if (abbrev->tag == DW_TAG_compile_unit
&& (val.encoding == ATTR_VAL_UINT
|| val.encoding == ATTR_VAL_REF_SECTION))
u->lineoff = val.u.uint;
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_AT_name:
if (abbrev->tag == DW_TAG_compile_unit
&& val.encoding == ATTR_VAL_STRING)
u->filename = val.u.string;
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_AT_comp_dir:
if (abbrev->tag == DW_TAG_compile_unit
&& val.encoding == ATTR_VAL_STRING)
u->comp_dir = val.u.string;
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;
default:
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. */
static int
find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
struct dwarf_buf *unit_buf,
const struct dwarf_sections *dwarf_sections,
int is_bigendian, struct dwarf_data *altlink,
backtrace_error_callback error_callback, void *data,
struct unit *u, struct unit_addrs_vector *addrs,
enum dwarf_tag *unit_tag)
{
while (unit_buf->left > 0)
{
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);
if (code == 0)
return 1;
abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
if (abbrev == NULL)
return 0;
if (unit_tag != NULL)
*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, abbrev->attrs[i].val,
unit_buf, u->is_dwarf64, u->version,
u->addrsize, dwarf_sections, altlink, &val))
return 0;
switch (abbrev->attrs[i].name)
{
case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:
update_pcrange (&abbrev->attrs[i], &val, &pcrange);
break;
case DW_AT_stmt_list:
if (abbrev->tag == DW_TAG_compile_unit
&& (val.encoding == ATTR_VAL_UINT
|| val.encoding == ATTR_VAL_REF_SECTION))
u->lineoff = val.u.uint;
break;
case DW_AT_name:
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_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:
break;
}
}
// 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
......@@ -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,8 +2184,22 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
is_bigendian, error_callback, data, &u->abbrevs))
goto fail;
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);
u->high_offset = unit_offset;
......@@ -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)
&& 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;
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:
......
......@@ -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. */
......
......@@ -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
};
......
......@@ -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. */
......
......@@ -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
......
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