Add debug fission support.
This added debug fission support. It tries to find the dwp file from the debug dir /usr/lib/debug/*/debug and read symbols from them. Most of this patch comes from https://critique.corp.google.com/#review/52048295 and some fixes after that. The elf_reader.cc comes from TOT google code. I just removed some google dependency. Current problems from this patch 1: Some type mismatch: from uint8_t * to char *. 2: Some hack to find the .dwp file. (replace .debug with .dwp) BUG=chromium:604440 R=dehao@google.com, ivanpe@chromium.org Review URL: https://codereview.chromium.org/1884283002 .
This commit is contained in:
parent
b5712766f6
commit
764c21f752
@ -564,6 +564,7 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \
|
||||
src/common/dwarf/bytereader.cc \
|
||||
src/common/dwarf/dwarf2diehandler.cc \
|
||||
src/common/dwarf/dwarf2reader.cc \
|
||||
src/common/dwarf/elf_reader.cc \
|
||||
src/common/linux/crc32.cc \
|
||||
src/common/linux/dump_symbols.cc \
|
||||
src/common/linux/elf_symbols_to_module.cc \
|
||||
@ -601,6 +602,7 @@ src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \
|
||||
src/common/dwarf/bytereader.cc \
|
||||
src/common/dwarf/dwarf2diehandler.cc \
|
||||
src/common/dwarf/dwarf2reader.cc \
|
||||
src/common/dwarf/elf_reader.cc \
|
||||
src/common/mac/arch_utilities.cc \
|
||||
src/common/mac/dump_syms.cc \
|
||||
src/common/mac/file_id.cc \
|
||||
@ -636,6 +638,7 @@ src_common_dumper_unittest_SOURCES = \
|
||||
src/common/dwarf/dwarf2diehandler.cc \
|
||||
src/common/dwarf/dwarf2diehandler_unittest.cc \
|
||||
src/common/dwarf/dwarf2reader.cc \
|
||||
src/common/dwarf/elf_reader.cc \
|
||||
src/common/dwarf/dwarf2reader_cfi_unittest.cc \
|
||||
src/common/dwarf/dwarf2reader_die_unittest.cc \
|
||||
src/common/linux/crc32.cc \
|
||||
@ -678,6 +681,7 @@ src_common_mac_macho_reader_unittest_SOURCES = \
|
||||
src/common/dwarf/cfi_assembler.cc \
|
||||
src/common/dwarf/dwarf2diehandler.cc \
|
||||
src/common/dwarf/dwarf2reader.cc \
|
||||
src/common/dwarf/elf_reader.cc \
|
||||
src/common/mac/arch_utilities.cc \
|
||||
src/common/mac/file_id.cc \
|
||||
src/common/mac/macho_id.cc \
|
||||
|
44
Makefile.in
44
Makefile.in
@ -691,6 +691,7 @@ am__src_common_dumper_unittest_SOURCES_DIST = \
|
||||
src/common/dwarf/dwarf2reader.cc \
|
||||
src/common/dwarf/dwarf2reader_cfi_unittest.cc \
|
||||
src/common/dwarf/dwarf2reader_die_unittest.cc \
|
||||
src/common/dwarf/elf_reader.cc \
|
||||
src/common/linux/crc32.cc src/common/linux/dump_symbols.cc \
|
||||
src/common/linux/dump_symbols_unittest.cc \
|
||||
src/common/linux/elf_core_dump.cc \
|
||||
@ -732,6 +733,7 @@ am__src_common_dumper_unittest_SOURCES_DIST = \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-elf_reader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-crc32.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-dump_symbols.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.$(OBJEXT) \
|
||||
@ -767,6 +769,7 @@ am__src_common_mac_macho_reader_unittest_SOURCES_DIST = \
|
||||
src/common/dwarf/cfi_assembler.cc \
|
||||
src/common/dwarf/dwarf2diehandler.cc \
|
||||
src/common/dwarf/dwarf2reader.cc \
|
||||
src/common/dwarf/elf_reader.cc \
|
||||
src/common/mac/arch_utilities.cc src/common/mac/file_id.cc \
|
||||
src/common/mac/macho_id.cc src/common/mac/macho_reader.cc \
|
||||
src/common/mac/macho_reader_unittest.cc \
|
||||
@ -785,6 +788,7 @@ am__src_common_mac_macho_reader_unittest_SOURCES_DIST = \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-file_id.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-macho_id.$(OBJEXT) \
|
||||
@ -1343,7 +1347,8 @@ am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST = \
|
||||
src/common/module.cc src/common/stabs_reader.cc \
|
||||
src/common/stabs_to_module.cc src/common/dwarf/bytereader.cc \
|
||||
src/common/dwarf/dwarf2diehandler.cc \
|
||||
src/common/dwarf/dwarf2reader.cc src/common/linux/crc32.cc \
|
||||
src/common/dwarf/dwarf2reader.cc \
|
||||
src/common/dwarf/elf_reader.cc src/common/linux/crc32.cc \
|
||||
src/common/linux/dump_symbols.cc \
|
||||
src/common/linux/elf_symbols_to_module.cc \
|
||||
src/common/linux/elfutils.cc src/common/linux/file_id.cc \
|
||||
@ -1361,6 +1366,7 @@ am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST = \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/crc32.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.$(OBJEXT) \
|
||||
@ -1415,6 +1421,7 @@ am__src_tools_mac_dump_syms_dump_syms_mac_SOURCES_DIST = \
|
||||
src/common/dwarf/bytereader.cc \
|
||||
src/common/dwarf/dwarf2diehandler.cc \
|
||||
src/common/dwarf/dwarf2reader.cc \
|
||||
src/common/dwarf/elf_reader.cc \
|
||||
src/common/mac/arch_utilities.cc src/common/mac/dump_syms.cc \
|
||||
src/common/mac/file_id.cc src/common/mac/macho_id.cc \
|
||||
src/common/mac/macho_reader.cc \
|
||||
@ -1432,6 +1439,7 @@ am__src_tools_mac_dump_syms_dump_syms_mac_SOURCES_DIST = \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.$(OBJEXT) \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.$(OBJEXT) \
|
||||
@ -2306,6 +2314,7 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/crc32.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.cc \
|
||||
@ -2343,6 +2352,7 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/arch_utilities.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/dump_syms.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/file_id.cc \
|
||||
@ -2381,6 +2391,7 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_cfi_unittest.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_die_unittest.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/crc32.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols_unittest.cc \
|
||||
@ -2423,6 +2434,7 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/cfi_assembler.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/arch_utilities.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/file_id.cc \
|
||||
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_id.cc \
|
||||
@ -3790,6 +3802,9 @@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT):
|
||||
src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.$(OBJEXT): \
|
||||
src/common/dwarf/$(am__dirstamp) \
|
||||
src/common/dwarf/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/dwarf/src_common_dumper_unittest-elf_reader.$(OBJEXT): \
|
||||
src/common/dwarf/$(am__dirstamp) \
|
||||
src/common/dwarf/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/linux/src_common_dumper_unittest-crc32.$(OBJEXT): \
|
||||
src/common/linux/$(am__dirstamp) \
|
||||
src/common/linux/$(DEPDIR)/$(am__dirstamp)
|
||||
@ -3890,6 +3905,9 @@ src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.$(OBJEXT)
|
||||
src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.$(OBJEXT): \
|
||||
src/common/dwarf/$(am__dirstamp) \
|
||||
src/common/dwarf/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.$(OBJEXT): \
|
||||
src/common/dwarf/$(am__dirstamp) \
|
||||
src/common/dwarf/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/mac/$(am__dirstamp):
|
||||
@$(MKDIR_P) src/common/mac
|
||||
@: > src/common/mac/$(am__dirstamp)
|
||||
@ -4222,6 +4240,9 @@ src/common/dwarf/dwarf2diehandler.$(OBJEXT): \
|
||||
src/common/dwarf/dwarf2reader.$(OBJEXT): \
|
||||
src/common/dwarf/$(am__dirstamp) \
|
||||
src/common/dwarf/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/dwarf/elf_reader.$(OBJEXT): \
|
||||
src/common/dwarf/$(am__dirstamp) \
|
||||
src/common/dwarf/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/linux/crc32.$(OBJEXT): src/common/linux/$(am__dirstamp) \
|
||||
src/common/linux/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/linux/dump_symbols.$(OBJEXT): \
|
||||
@ -4322,6 +4343,9 @@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.$(OBJEXT
|
||||
src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.$(OBJEXT): \
|
||||
src/common/dwarf/$(am__dirstamp) \
|
||||
src/common/dwarf/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.$(OBJEXT): \
|
||||
src/common/dwarf/$(am__dirstamp) \
|
||||
src/common/dwarf/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.$(OBJEXT): \
|
||||
src/common/mac/$(am__dirstamp) \
|
||||
src/common/mac/$(DEPDIR)/$(am__dirstamp)
|
||||
@ -4472,6 +4496,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/bytereader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/dwarf2diehandler.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/dwarf2reader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/elf_reader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-cfi_assembler.Po@am__quote@
|
||||
@ -4480,13 +4505,16 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_cfi_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_die_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-elf_reader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-bytereader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-cfi_assembler.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2diehandler.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2reader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-elf_reader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-bytereader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/crc32.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/dump_symbols.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/elf_core_dump.Po@am__quote@
|
||||
@ -6707,6 +6735,20 @@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.obj: src/com
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.obj `if test -f 'src/common/dwarf/dwarf2reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader.cc'; fi`
|
||||
|
||||
src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o: src/common/dwarf/elf_reader.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o `test -f 'src/common/dwarf/elf_reader.cc' || echo '$(srcdir)/'`src/common/dwarf/elf_reader.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/elf_reader.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o `test -f 'src/common/dwarf/elf_reader.cc' || echo '$(srcdir)/'`src/common/dwarf/elf_reader.cc
|
||||
|
||||
src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj: src/common/dwarf/elf_reader.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj `if test -f 'src/common/dwarf/elf_reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/elf_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/elf_reader.cc'; fi`
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/elf_reader.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj `if test -f 'src/common/dwarf/elf_reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/elf_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/elf_reader.cc'; fi`
|
||||
|
||||
src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.o: src/common/mac/arch_utilities.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.o `test -f 'src/common/mac/arch_utilities.cc' || echo '$(srcdir)/'`src/common/mac/arch_utilities.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Po
|
||||
|
@ -75,6 +75,8 @@
|
||||
'dwarf/dwarf2reader.cc',
|
||||
'dwarf/dwarf2reader.h',
|
||||
'dwarf/dwarf2reader_test_common.h',
|
||||
'dwarf/elf_reader.cc',
|
||||
'dwarf/elf_reader.h',
|
||||
'dwarf/functioninfo.cc',
|
||||
'dwarf/functioninfo.h',
|
||||
'dwarf/line_state_machine.h',
|
||||
|
@ -243,4 +243,8 @@ uint64 ByteReader::ReadEncodedPointer(const uint8_t *buffer,
|
||||
return pointer;
|
||||
}
|
||||
|
||||
Endianness ByteReader::GetEndianness() const {
|
||||
return endian_;
|
||||
}
|
||||
|
||||
} // namespace dwarf2reader
|
||||
|
@ -280,6 +280,7 @@ class ByteReader {
|
||||
DwarfPointerEncoding encoding,
|
||||
size_t *len) const;
|
||||
|
||||
Endianness GetEndianness() const;
|
||||
private:
|
||||
|
||||
// Function pointer type for our address and offset readers.
|
||||
|
@ -149,7 +149,10 @@ enum DwarfForm {
|
||||
DW_FORM_sec_offset = 0x17,
|
||||
DW_FORM_exprloc = 0x18,
|
||||
DW_FORM_flag_present = 0x19,
|
||||
DW_FORM_ref_sig8 = 0x20
|
||||
DW_FORM_ref_sig8 = 0x20,
|
||||
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
DW_FORM_GNU_addr_index = 0x1f01,
|
||||
DW_FORM_GNU_str_index = 0x1f02
|
||||
};
|
||||
|
||||
// Attribute names and codes
|
||||
@ -264,6 +267,13 @@ enum DwarfAttribute {
|
||||
DW_AT_body_begin = 0x2105,
|
||||
DW_AT_body_end = 0x2106,
|
||||
DW_AT_GNU_vector = 0x2107,
|
||||
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
DW_AT_GNU_dwo_name = 0x2130,
|
||||
DW_AT_GNU_dwo_id = 0x2131,
|
||||
DW_AT_GNU_ranges_base = 0x2132,
|
||||
DW_AT_GNU_addr_base = 0x2133,
|
||||
DW_AT_GNU_pubnames = 0x2134,
|
||||
DW_AT_GNU_pubtypes = 0x2135,
|
||||
// VMS extensions.
|
||||
DW_AT_VMS_rtnbeg_pd_address = 0x2201,
|
||||
// UPC extension.
|
||||
@ -491,7 +501,22 @@ enum DwarfOpcode {
|
||||
DW_OP_lo_user =0xe0,
|
||||
DW_OP_hi_user =0xff,
|
||||
// GNU extensions
|
||||
DW_OP_GNU_push_tls_address =0xe0
|
||||
DW_OP_GNU_push_tls_address =0xe0,
|
||||
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
DW_OP_GNU_addr_index =0xfb,
|
||||
DW_OP_GNU_const_index =0xfc
|
||||
};
|
||||
|
||||
// Section identifiers for DWP files
|
||||
enum DwarfSectionId {
|
||||
DW_SECT_INFO = 1,
|
||||
DW_SECT_TYPES = 2,
|
||||
DW_SECT_ABBREV = 3,
|
||||
DW_SECT_LINE = 4,
|
||||
DW_SECT_LOC = 5,
|
||||
DW_SECT_STR_OFFSETS = 6,
|
||||
DW_SECT_MACINFO = 7,
|
||||
DW_SECT_MACRO = 8
|
||||
};
|
||||
|
||||
// Source languages. These are values for DW_AT_language.
|
||||
|
@ -44,6 +44,8 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "common/dwarf/bytereader-inl.h"
|
||||
#include "common/dwarf/bytereader.h"
|
||||
#include "common/dwarf/line_state_machine.h"
|
||||
@ -51,11 +53,38 @@
|
||||
|
||||
namespace dwarf2reader {
|
||||
|
||||
CompilationUnit::CompilationUnit(const SectionMap& sections, uint64 offset,
|
||||
CompilationUnit::CompilationUnit(const string& path,
|
||||
const SectionMap& sections, uint64 offset,
|
||||
ByteReader* reader, Dwarf2Handler* handler)
|
||||
: offset_from_section_start_(offset), reader_(reader),
|
||||
sections_(sections), handler_(handler), abbrevs_(NULL),
|
||||
string_buffer_(NULL), string_buffer_length_(0) {}
|
||||
: path_(path), offset_from_section_start_(offset), reader_(reader),
|
||||
sections_(sections), handler_(handler), abbrevs_(),
|
||||
string_buffer_(NULL), string_buffer_length_(0),
|
||||
str_offsets_buffer_(NULL), str_offsets_buffer_length_(0),
|
||||
addr_buffer_(NULL), addr_buffer_length_(0),
|
||||
is_split_dwarf_(false), dwo_id_(0), dwo_name_(),
|
||||
skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0),
|
||||
have_checked_for_dwp_(false), dwp_path_(),
|
||||
dwp_byte_reader_(), dwp_reader_() {}
|
||||
|
||||
// Initialize a compilation unit from a .dwo or .dwp file.
|
||||
// In this case, we need the .debug_addr section from the
|
||||
// executable file that contains the corresponding skeleton
|
||||
// compilation unit. We also inherit the Dwarf2Handler from
|
||||
// the executable file, and call it as if we were still
|
||||
// processing the original compilation unit.
|
||||
|
||||
void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer,
|
||||
uint64 addr_buffer_length,
|
||||
uint64 addr_base,
|
||||
uint64 ranges_base,
|
||||
uint64 dwo_id) {
|
||||
is_split_dwarf_ = true;
|
||||
addr_buffer_ = addr_buffer;
|
||||
addr_buffer_length_ = addr_buffer_length;
|
||||
addr_base_ = addr_base;
|
||||
ranges_base_ = ranges_base;
|
||||
skeleton_dwo_id_ = dwo_id;
|
||||
}
|
||||
|
||||
// Read a DWARF2/3 abbreviation section.
|
||||
// Each abbrev consists of a abbreviation number, a tag, a byte
|
||||
@ -174,6 +203,8 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
|
||||
return start + strlen(reinterpret_cast<const char *>(start)) + 1;
|
||||
case DW_FORM_udata:
|
||||
case DW_FORM_ref_udata:
|
||||
case DW_FORM_GNU_str_index:
|
||||
case DW_FORM_GNU_addr_index:
|
||||
reader_->ReadUnsignedLEB128(start, &len);
|
||||
return start + len;
|
||||
|
||||
@ -296,9 +327,31 @@ uint64 CompilationUnit::Start() {
|
||||
string_buffer_length_ = iter->second.second;
|
||||
}
|
||||
|
||||
// Set the string offsets section if we have one.
|
||||
iter = sections_.find(".debug_str_offsets");
|
||||
if (iter != sections_.end()) {
|
||||
str_offsets_buffer_ = iter->second.first;
|
||||
str_offsets_buffer_length_ = iter->second.second;
|
||||
}
|
||||
|
||||
// Set the address section if we have one.
|
||||
iter = sections_.find(".debug_addr");
|
||||
if (iter != sections_.end()) {
|
||||
addr_buffer_ = iter->second.first;
|
||||
addr_buffer_length_ = iter->second.second;
|
||||
}
|
||||
|
||||
// Now that we have our abbreviations, start processing DIE's.
|
||||
ProcessDIEs();
|
||||
|
||||
// If this is a skeleton compilation unit generated with split DWARF,
|
||||
// and the client needs the full debug info, we need to find the full
|
||||
// compilation unit in a .dwo or .dwp file.
|
||||
if (!is_split_dwarf_
|
||||
&& dwo_name_ != NULL
|
||||
&& handler_->NeedSplitDebugInfo())
|
||||
ProcessSplitDwarf();
|
||||
|
||||
return ourlength;
|
||||
}
|
||||
|
||||
@ -320,47 +373,45 @@ const uint8_t *CompilationUnit::ProcessAttribute(
|
||||
return ProcessAttribute(dieoffset, start, attr, form);
|
||||
|
||||
case DW_FORM_flag_present:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form, 1);
|
||||
ProcessAttributeUnsigned(dieoffset, attr, form, 1);
|
||||
return start;
|
||||
case DW_FORM_data1:
|
||||
case DW_FORM_flag:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadOneByte(start));
|
||||
return start + 1;
|
||||
case DW_FORM_data2:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadTwoBytes(start));
|
||||
return start + 2;
|
||||
case DW_FORM_data4:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadFourBytes(start));
|
||||
return start + 4;
|
||||
case DW_FORM_data8:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadEightBytes(start));
|
||||
return start + 8;
|
||||
case DW_FORM_string: {
|
||||
const char *str = reinterpret_cast<const char *>(start);
|
||||
handler_->ProcessAttributeString(dieoffset, attr, form,
|
||||
str);
|
||||
ProcessAttributeString(dieoffset, attr, form, str);
|
||||
return start + strlen(str) + 1;
|
||||
}
|
||||
case DW_FORM_udata:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadUnsignedLEB128(start,
|
||||
&len));
|
||||
ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadUnsignedLEB128(start, &len));
|
||||
return start + len;
|
||||
|
||||
case DW_FORM_sdata:
|
||||
handler_->ProcessAttributeSigned(dieoffset, attr, form,
|
||||
ProcessAttributeSigned(dieoffset, attr, form,
|
||||
reader_->ReadSignedLEB128(start, &len));
|
||||
return start + len;
|
||||
case DW_FORM_addr:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadAddress(start));
|
||||
return start + reader_->AddressSize();
|
||||
case DW_FORM_sec_offset:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadOffset(start));
|
||||
return start + reader_->OffsetSize();
|
||||
|
||||
@ -441,10 +492,32 @@ const uint8_t *CompilationUnit::ProcessAttribute(
|
||||
assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_);
|
||||
|
||||
const char *str = reinterpret_cast<const char *>(string_buffer_ + offset);
|
||||
handler_->ProcessAttributeString(dieoffset, attr, form,
|
||||
str);
|
||||
ProcessAttributeString(dieoffset, attr, form, str);
|
||||
return start + reader_->OffsetSize();
|
||||
}
|
||||
|
||||
case DW_FORM_GNU_str_index: {
|
||||
uint64 str_index = reader_->ReadUnsignedLEB128(start, &len);
|
||||
const uint8_t* offset_ptr =
|
||||
str_offsets_buffer_ + str_index * reader_->OffsetSize();
|
||||
const uint64 offset = reader_->ReadOffset(offset_ptr);
|
||||
if (offset >= string_buffer_length_) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* str = reinterpret_cast<const char *>(string_buffer_) + offset;
|
||||
ProcessAttributeString(dieoffset, attr, form, str);
|
||||
return start + len;
|
||||
break;
|
||||
}
|
||||
case DW_FORM_GNU_addr_index: {
|
||||
uint64 addr_index = reader_->ReadUnsignedLEB128(start, &len);
|
||||
const uint8_t* addr_ptr =
|
||||
addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize();
|
||||
ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadAddress(addr_ptr));
|
||||
return start + len;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Unhandled form type\n");
|
||||
return NULL;
|
||||
@ -458,6 +531,16 @@ const uint8_t *CompilationUnit::ProcessDIE(uint64 dieoffset,
|
||||
i++) {
|
||||
start = ProcessAttribute(dieoffset, start, i->first, i->second);
|
||||
}
|
||||
|
||||
// If this is a compilation unit in a split DWARF object, verify that
|
||||
// the dwo_id matches. If it does not match, we will ignore this
|
||||
// compilation unit.
|
||||
if (abbrev.tag == DW_TAG_compile_unit
|
||||
&& is_split_dwarf_
|
||||
&& dwo_id_ != skeleton_dwo_id_) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
@ -515,6 +598,307 @@ void CompilationUnit::ProcessDIEs() {
|
||||
}
|
||||
}
|
||||
|
||||
// Check for a valid ELF file and return the Address size.
|
||||
// Returns 0 if not a valid ELF file.
|
||||
inline int GetElfWidth(const ElfReader& elf) {
|
||||
if (elf.IsElf32File())
|
||||
return 4;
|
||||
if (elf.IsElf64File())
|
||||
return 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CompilationUnit::ProcessSplitDwarf() {
|
||||
struct stat statbuf;
|
||||
if (!have_checked_for_dwp_) {
|
||||
// Look for a .dwp file in the same directory as the executable.
|
||||
have_checked_for_dwp_ = true;
|
||||
string dwp_suffix(".dwp");
|
||||
dwp_path_ = path_ + dwp_suffix;
|
||||
if (stat(dwp_path_.c_str(), &statbuf) != 0) {
|
||||
// Fall back to a split .debug file in the same directory.
|
||||
string debug_suffix(".debug");
|
||||
dwp_path_ = path_;
|
||||
size_t found = path_.rfind(debug_suffix);
|
||||
if (found + debug_suffix.length() == path_.length())
|
||||
dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix);
|
||||
}
|
||||
if (stat(dwp_path_.c_str(), &statbuf) == 0) {
|
||||
ElfReader* elf = new ElfReader(dwp_path_);
|
||||
int width = GetElfWidth(*elf);
|
||||
if (width != 0) {
|
||||
dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness()));
|
||||
dwp_byte_reader_->SetAddressSize(width);
|
||||
dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf));
|
||||
dwp_reader_->Initialize();
|
||||
} else {
|
||||
delete elf;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool found_in_dwp = false;
|
||||
if (dwp_reader_ != NULL) {
|
||||
// If we have a .dwp file, read the debug sections for the requested CU.
|
||||
SectionMap sections;
|
||||
dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions);
|
||||
if (!sections.empty()) {
|
||||
found_in_dwp = true;
|
||||
CompilationUnit dwp_comp_unit(dwp_path_, sections, 0,
|
||||
dwp_byte_reader_.get(), handler_);
|
||||
dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_,
|
||||
ranges_base_, dwo_id_);
|
||||
dwp_comp_unit.Start();
|
||||
}
|
||||
}
|
||||
if (!found_in_dwp) {
|
||||
// If no .dwp file, try to open the .dwo file.
|
||||
if (stat(dwo_name_, &statbuf) == 0) {
|
||||
ElfReader elf(dwo_name_);
|
||||
int width = GetElfWidth(elf);
|
||||
if (width != 0) {
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(width);
|
||||
SectionMap sections;
|
||||
ReadDebugSectionsFromDwo(&elf, §ions);
|
||||
CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader,
|
||||
handler_);
|
||||
dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_,
|
||||
addr_base_, ranges_base_, dwo_id_);
|
||||
dwo_comp_unit.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader,
|
||||
SectionMap* sections) {
|
||||
static const char* const section_names[] = {
|
||||
".debug_abbrev",
|
||||
".debug_info",
|
||||
".debug_str_offsets",
|
||||
".debug_str"
|
||||
};
|
||||
for (unsigned int i = 0u;
|
||||
i < sizeof(section_names)/sizeof(*(section_names)); ++i) {
|
||||
string base_name = section_names[i];
|
||||
string dwo_name = base_name + ".dwo";
|
||||
size_t section_size;
|
||||
const char* section_data = elf_reader->GetSectionByName(dwo_name,
|
||||
§ion_size);
|
||||
if (section_data != NULL)
|
||||
sections->insert(std::make_pair(
|
||||
base_name, std::make_pair(
|
||||
reinterpret_cast<const uint8_t *>(section_data),
|
||||
section_size)));
|
||||
}
|
||||
}
|
||||
|
||||
DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader)
|
||||
: elf_reader_(elf_reader), byte_reader_(byte_reader),
|
||||
cu_index_(NULL), cu_index_size_(0), string_buffer_(NULL),
|
||||
string_buffer_size_(0), version_(0), ncolumns_(0), nunits_(0),
|
||||
nslots_(0), phash_(NULL), pindex_(NULL), shndx_pool_(NULL),
|
||||
offset_table_(NULL), size_table_(NULL), abbrev_data_(NULL),
|
||||
abbrev_size_(0), info_data_(NULL), info_size_(0),
|
||||
str_offsets_data_(NULL), str_offsets_size_(0) {}
|
||||
|
||||
DwpReader::~DwpReader() {
|
||||
if (elf_reader_) delete elf_reader_;
|
||||
}
|
||||
|
||||
void DwpReader::Initialize() {
|
||||
cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index",
|
||||
&cu_index_size_);
|
||||
if (cu_index_ == NULL) {
|
||||
return;
|
||||
}
|
||||
// The .debug_str.dwo section is shared by all CUs in the file.
|
||||
string_buffer_ = elf_reader_->GetSectionByName(".debug_str.dwo",
|
||||
&string_buffer_size_);
|
||||
|
||||
version_ = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(cu_index_));
|
||||
|
||||
if (version_ == 1) {
|
||||
nslots_ = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(cu_index_)
|
||||
+ 3 * sizeof(uint32));
|
||||
phash_ = cu_index_ + 4 * sizeof(uint32);
|
||||
pindex_ = phash_ + nslots_ * sizeof(uint64);
|
||||
shndx_pool_ = pindex_ + nslots_ * sizeof(uint32);
|
||||
if (shndx_pool_ >= cu_index_ + cu_index_size_) {
|
||||
version_ = 0;
|
||||
}
|
||||
} else if (version_ == 2) {
|
||||
ncolumns_ = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(cu_index_) + sizeof(uint32));
|
||||
nunits_ = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(cu_index_) + 2 * sizeof(uint32));
|
||||
nslots_ = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(cu_index_) + 3 * sizeof(uint32));
|
||||
phash_ = cu_index_ + 4 * sizeof(uint32);
|
||||
pindex_ = phash_ + nslots_ * sizeof(uint64);
|
||||
offset_table_ = pindex_ + nslots_ * sizeof(uint32);
|
||||
size_table_ = offset_table_ + ncolumns_ * (nunits_ + 1) * sizeof(uint32);
|
||||
abbrev_data_ = elf_reader_->GetSectionByName(".debug_abbrev.dwo",
|
||||
&abbrev_size_);
|
||||
info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_);
|
||||
str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo",
|
||||
&str_offsets_size_);
|
||||
if (size_table_ >= cu_index_ + cu_index_size_) {
|
||||
version_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DwpReader::ReadDebugSectionsForCU(uint64 dwo_id,
|
||||
SectionMap* sections) {
|
||||
if (version_ == 1) {
|
||||
int slot = LookupCU(dwo_id);
|
||||
if (slot == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The index table points to the section index pool, where we
|
||||
// can read a list of section indexes for the debug sections
|
||||
// for the CU whose dwo_id we are looking for.
|
||||
int index = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(pindex_)
|
||||
+ slot * sizeof(uint32));
|
||||
const char* shndx_list = shndx_pool_ + index * sizeof(uint32);
|
||||
for (;;) {
|
||||
if (shndx_list >= cu_index_ + cu_index_size_) {
|
||||
version_ = 0;
|
||||
return;
|
||||
}
|
||||
unsigned int shndx = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(shndx_list));
|
||||
shndx_list += sizeof(uint32);
|
||||
if (shndx == 0)
|
||||
break;
|
||||
const char* section_name = elf_reader_->GetSectionName(shndx);
|
||||
size_t section_size;
|
||||
const char* section_data;
|
||||
// We're only interested in these four debug sections.
|
||||
// The section names in the .dwo file end with ".dwo", but we
|
||||
// add them to the sections table with their normal names.
|
||||
if (!strncmp(section_name, ".debug_abbrev", strlen(".debug_abbrev"))) {
|
||||
section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size);
|
||||
sections->insert(std::make_pair(
|
||||
".debug_abbrev",
|
||||
std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
|
||||
section_size)));
|
||||
} else if (!strncmp(section_name, ".debug_info", strlen(".debug_info"))) {
|
||||
section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size);
|
||||
sections->insert(std::make_pair(
|
||||
".debug_info",
|
||||
std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
|
||||
section_size)));
|
||||
} else if (!strncmp(section_name, ".debug_str_offsets",
|
||||
strlen(".debug_str_offsets"))) {
|
||||
section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size);
|
||||
sections->insert(std::make_pair(
|
||||
".debug_str_offsets",
|
||||
std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
|
||||
section_size)));
|
||||
}
|
||||
}
|
||||
sections->insert(std::make_pair(
|
||||
".debug_str",
|
||||
std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_),
|
||||
string_buffer_size_)));
|
||||
} else if (version_ == 2) {
|
||||
uint32 index = LookupCUv2(dwo_id);
|
||||
if (index == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The index points to a row in each of the section offsets table
|
||||
// and the section size table, where we can read the offsets and sizes
|
||||
// of the contributions to each debug section from the CU whose dwo_id
|
||||
// we are looking for. Row 0 of the section offsets table has the
|
||||
// section ids for each column of the table. The size table begins
|
||||
// with row 1.
|
||||
const char* id_row = offset_table_;
|
||||
const char* offset_row = offset_table_
|
||||
+ index * ncolumns_ * sizeof(uint32);
|
||||
const char* size_row =
|
||||
size_table_ + (index - 1) * ncolumns_ * sizeof(uint32);
|
||||
if (size_row + ncolumns_ * sizeof(uint32) > cu_index_ + cu_index_size_) {
|
||||
version_ = 0;
|
||||
return;
|
||||
}
|
||||
for (unsigned int col = 0u; col < ncolumns_; ++col) {
|
||||
uint32 section_id =
|
||||
byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t *>(id_row)
|
||||
+ col * sizeof(uint32));
|
||||
uint32 offset = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(offset_row)
|
||||
+ col * sizeof(uint32));
|
||||
uint32 size = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(size_row) + col * sizeof(uint32));
|
||||
if (section_id == DW_SECT_ABBREV) {
|
||||
sections->insert(std::make_pair(
|
||||
".debug_abbrev",
|
||||
std::make_pair(reinterpret_cast<const uint8_t *> (abbrev_data_)
|
||||
+ offset, size)));
|
||||
} else if (section_id == DW_SECT_INFO) {
|
||||
sections->insert(std::make_pair(
|
||||
".debug_info",
|
||||
std::make_pair(reinterpret_cast<const uint8_t *> (info_data_)
|
||||
+ offset, size)));
|
||||
} else if (section_id == DW_SECT_STR_OFFSETS) {
|
||||
sections->insert(std::make_pair(
|
||||
".debug_str_offsets",
|
||||
std::make_pair(reinterpret_cast<const uint8_t *> (str_offsets_data_)
|
||||
+ offset, size)));
|
||||
}
|
||||
}
|
||||
sections->insert(std::make_pair(
|
||||
".debug_str",
|
||||
std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_),
|
||||
string_buffer_size_)));
|
||||
}
|
||||
}
|
||||
|
||||
int DwpReader::LookupCU(uint64 dwo_id) {
|
||||
uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1);
|
||||
uint64 probe = byte_reader_.ReadEightBytes(
|
||||
reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
|
||||
if (probe != 0 && probe != dwo_id) {
|
||||
uint32 secondary_hash =
|
||||
(static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1;
|
||||
do {
|
||||
slot = (slot + secondary_hash) & (nslots_ - 1);
|
||||
probe = byte_reader_.ReadEightBytes(
|
||||
reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
|
||||
} while (probe != 0 && probe != dwo_id);
|
||||
}
|
||||
if (probe == 0)
|
||||
return -1;
|
||||
return slot;
|
||||
}
|
||||
|
||||
uint32 DwpReader::LookupCUv2(uint64 dwo_id) {
|
||||
uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1);
|
||||
uint64 probe = byte_reader_.ReadEightBytes(
|
||||
reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
|
||||
uint32 index = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32));
|
||||
if (index != 0 && probe != dwo_id) {
|
||||
uint32 secondary_hash =
|
||||
(static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1;
|
||||
do {
|
||||
slot = (slot + secondary_hash) & (nslots_ - 1);
|
||||
probe = byte_reader_.ReadEightBytes(
|
||||
reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
|
||||
index = byte_reader_.ReadFourBytes(
|
||||
reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32));
|
||||
} while (index != 0 && probe != dwo_id);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
LineInfo::LineInfo(const uint8_t *buffer, uint64 buffer_length,
|
||||
ByteReader* reader, LineInfoHandler* handler):
|
||||
handler_(handler), reader_(reader), buffer_(buffer) {
|
||||
|
@ -47,16 +47,19 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "common/dwarf/bytereader.h"
|
||||
#include "common/dwarf/dwarf2enums.h"
|
||||
#include "common/dwarf/types.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "common/dwarf/elf_reader.h"
|
||||
|
||||
namespace dwarf2reader {
|
||||
struct LineStateMachine;
|
||||
class Dwarf2Handler;
|
||||
class LineInfoHandler;
|
||||
class DwpReader;
|
||||
|
||||
// This maps from a string naming a section to a pair containing a
|
||||
// the data for the section, and the size of the section.
|
||||
@ -184,151 +187,10 @@ class LineInfoHandler {
|
||||
uint32 file_num, uint32 line_num, uint32 column_num) { }
|
||||
};
|
||||
|
||||
// The base of DWARF2/3 debug info is a DIE (Debugging Information
|
||||
// Entry.
|
||||
// DWARF groups DIE's into a tree and calls the root of this tree a
|
||||
// "compilation unit". Most of the time, there is one compilation
|
||||
// unit in the .debug_info section for each file that had debug info
|
||||
// generated.
|
||||
// Each DIE consists of
|
||||
|
||||
// 1. a tag specifying a thing that is being described (ie
|
||||
// DW_TAG_subprogram for functions, DW_TAG_variable for variables, etc
|
||||
// 2. attributes (such as DW_AT_location for location in memory,
|
||||
// DW_AT_name for name), and data for each attribute.
|
||||
// 3. A flag saying whether the DIE has children or not
|
||||
|
||||
// In order to gain some amount of compression, the format of
|
||||
// each DIE (tag name, attributes and data forms for the attributes)
|
||||
// are stored in a separate table called the "abbreviation table".
|
||||
// This is done because a large number of DIEs have the exact same tag
|
||||
// and list of attributes, but different data for those attributes.
|
||||
// As a result, the .debug_info section is just a stream of data, and
|
||||
// requires reading of the .debug_abbrev section to say what the data
|
||||
// means.
|
||||
|
||||
// As a warning to the user, it should be noted that the reason for
|
||||
// using absolute offsets from the beginning of .debug_info is that
|
||||
// DWARF2/3 supports referencing DIE's from other DIE's by their offset
|
||||
// from either the current compilation unit start, *or* the beginning
|
||||
// of the .debug_info section. This means it is possible to reference
|
||||
// a DIE in one compilation unit from a DIE in another compilation
|
||||
// unit. This style of reference is usually used to eliminate
|
||||
// duplicated information that occurs across compilation
|
||||
// units, such as base types, etc. GCC 3.4+ support this with
|
||||
// -feliminate-dwarf2-dups. Other toolchains will sometimes do
|
||||
// duplicate elimination in the linker.
|
||||
|
||||
class CompilationUnit {
|
||||
public:
|
||||
|
||||
// Initialize a compilation unit. This requires a map of sections,
|
||||
// the offset of this compilation unit in the .debug_info section, a
|
||||
// ByteReader, and a Dwarf2Handler class to call callbacks in.
|
||||
CompilationUnit(const SectionMap& sections, uint64 offset,
|
||||
ByteReader* reader, Dwarf2Handler* handler);
|
||||
virtual ~CompilationUnit() {
|
||||
if (abbrevs_) delete abbrevs_;
|
||||
}
|
||||
|
||||
// Begin reading a Dwarf2 compilation unit, and calling the
|
||||
// callbacks in the Dwarf2Handler
|
||||
|
||||
// Return the full length of the compilation unit, including
|
||||
// headers. This plus the starting offset passed to the constructor
|
||||
// is the offset of the end of the compilation unit --- and the
|
||||
// start of the next compilation unit, if there is one.
|
||||
uint64 Start();
|
||||
|
||||
private:
|
||||
|
||||
// This struct represents a single DWARF2/3 abbreviation
|
||||
// The abbreviation tells how to read a DWARF2/3 DIE, and consist of a
|
||||
// tag and a list of attributes, as well as the data form of each attribute.
|
||||
struct Abbrev {
|
||||
uint64 number;
|
||||
enum DwarfTag tag;
|
||||
bool has_children;
|
||||
AttributeList attributes;
|
||||
};
|
||||
|
||||
// A DWARF2/3 compilation unit header. This is not the same size as
|
||||
// in the actual file, as the one in the file may have a 32 bit or
|
||||
// 64 bit length.
|
||||
struct CompilationUnitHeader {
|
||||
uint64 length;
|
||||
uint16 version;
|
||||
uint64 abbrev_offset;
|
||||
uint8 address_size;
|
||||
} header_;
|
||||
|
||||
// Reads the DWARF2/3 header for this compilation unit.
|
||||
void ReadHeader();
|
||||
|
||||
// Reads the DWARF2/3 abbreviations for this compilation unit
|
||||
void ReadAbbrevs();
|
||||
|
||||
// Processes a single DIE for this compilation unit and return a new
|
||||
// pointer just past the end of it
|
||||
const uint8_t *ProcessDIE(uint64 dieoffset,
|
||||
const uint8_t *start,
|
||||
const Abbrev& abbrev);
|
||||
|
||||
// Processes a single attribute and return a new pointer just past the
|
||||
// end of it
|
||||
const uint8_t *ProcessAttribute(uint64 dieoffset,
|
||||
const uint8_t *start,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form);
|
||||
|
||||
// Processes all DIEs for this compilation unit
|
||||
void ProcessDIEs();
|
||||
|
||||
// Skips the die with attributes specified in ABBREV starting at
|
||||
// START, and return the new place to position the stream to.
|
||||
const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev);
|
||||
|
||||
// Skips the attribute starting at START, with FORM, and return the
|
||||
// new place to position the stream to.
|
||||
const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form);
|
||||
|
||||
// Offset from section start is the offset of this compilation unit
|
||||
// from the beginning of the .debug_info section.
|
||||
uint64 offset_from_section_start_;
|
||||
|
||||
// buffer is the buffer for our CU, starting at .debug_info + offset
|
||||
// passed in from constructor.
|
||||
// after_header points to right after the compilation unit header.
|
||||
const uint8_t *buffer_;
|
||||
uint64 buffer_length_;
|
||||
const uint8_t *after_header_;
|
||||
|
||||
// The associated ByteReader that handles endianness issues for us
|
||||
ByteReader* reader_;
|
||||
|
||||
// The map of sections in our file to buffers containing their data
|
||||
const SectionMap& sections_;
|
||||
|
||||
// The associated handler to call processing functions in
|
||||
Dwarf2Handler* handler_;
|
||||
|
||||
// Set of DWARF2/3 abbreviations for this compilation unit. Indexed
|
||||
// by abbreviation number, which means that abbrevs_[0] is not
|
||||
// valid.
|
||||
std::vector<Abbrev>* abbrevs_;
|
||||
|
||||
// String section buffer and length, if we have a string section.
|
||||
// This is here to avoid doing a section lookup for strings in
|
||||
// ProcessAttribute, which is in the hot path for DWARF2 reading.
|
||||
const uint8_t *string_buffer_;
|
||||
uint64 string_buffer_length_;
|
||||
};
|
||||
|
||||
// This class is the main interface between the reader and the
|
||||
// client. The virtual functions inside this get called for
|
||||
// interesting events that happen during DWARF2 reading.
|
||||
// The default implementation skips everything.
|
||||
|
||||
class Dwarf2Handler {
|
||||
public:
|
||||
Dwarf2Handler() { }
|
||||
@ -342,6 +204,19 @@ class Dwarf2Handler {
|
||||
uint8 offset_size, uint64 cu_length,
|
||||
uint8 dwarf_version) { return false; }
|
||||
|
||||
// When processing a skeleton compilation unit, resulting from a split
|
||||
// DWARF compilation, once the skeleton debug info has been read,
|
||||
// the reader will call this function to ask the client if it needs
|
||||
// the full debug info from the .dwo or .dwp file. Return true if
|
||||
// you need it, or false to skip processing the split debug info.
|
||||
virtual bool NeedSplitDebugInfo() { return true; }
|
||||
|
||||
// Start to process a split compilation unit at OFFSET from the beginning of
|
||||
// the debug_info section in the .dwp/.dwo file. Return false if you would
|
||||
// like to skip this compilation unit.
|
||||
virtual bool StartSplitCompilationUnit(uint64 offset,
|
||||
uint64 cu_length) { return false; }
|
||||
|
||||
// Start to process a DIE at OFFSET from the beginning of the .debug_info
|
||||
// section. Return false if you would like to skip this DIE.
|
||||
virtual bool StartDIE(uint64 offset, enum DwarfTag tag) { return false; }
|
||||
@ -412,6 +287,367 @@ class Dwarf2Handler {
|
||||
|
||||
};
|
||||
|
||||
// The base of DWARF2/3 debug info is a DIE (Debugging Information
|
||||
// Entry.
|
||||
// DWARF groups DIE's into a tree and calls the root of this tree a
|
||||
// "compilation unit". Most of the time, there is one compilation
|
||||
// unit in the .debug_info section for each file that had debug info
|
||||
// generated.
|
||||
// Each DIE consists of
|
||||
|
||||
// 1. a tag specifying a thing that is being described (ie
|
||||
// DW_TAG_subprogram for functions, DW_TAG_variable for variables, etc
|
||||
// 2. attributes (such as DW_AT_location for location in memory,
|
||||
// DW_AT_name for name), and data for each attribute.
|
||||
// 3. A flag saying whether the DIE has children or not
|
||||
|
||||
// In order to gain some amount of compression, the format of
|
||||
// each DIE (tag name, attributes and data forms for the attributes)
|
||||
// are stored in a separate table called the "abbreviation table".
|
||||
// This is done because a large number of DIEs have the exact same tag
|
||||
// and list of attributes, but different data for those attributes.
|
||||
// As a result, the .debug_info section is just a stream of data, and
|
||||
// requires reading of the .debug_abbrev section to say what the data
|
||||
// means.
|
||||
|
||||
// As a warning to the user, it should be noted that the reason for
|
||||
// using absolute offsets from the beginning of .debug_info is that
|
||||
// DWARF2/3 supports referencing DIE's from other DIE's by their offset
|
||||
// from either the current compilation unit start, *or* the beginning
|
||||
// of the .debug_info section. This means it is possible to reference
|
||||
// a DIE in one compilation unit from a DIE in another compilation
|
||||
// unit. This style of reference is usually used to eliminate
|
||||
// duplicated information that occurs across compilation
|
||||
// units, such as base types, etc. GCC 3.4+ support this with
|
||||
// -feliminate-dwarf2-dups. Other toolchains will sometimes do
|
||||
// duplicate elimination in the linker.
|
||||
|
||||
class CompilationUnit {
|
||||
public:
|
||||
|
||||
// Initialize a compilation unit. This requires a map of sections,
|
||||
// the offset of this compilation unit in the .debug_info section, a
|
||||
// ByteReader, and a Dwarf2Handler class to call callbacks in.
|
||||
CompilationUnit(const string& path, const SectionMap& sections, uint64 offset,
|
||||
ByteReader* reader, Dwarf2Handler* handler);
|
||||
virtual ~CompilationUnit() {
|
||||
if (abbrevs_) delete abbrevs_;
|
||||
}
|
||||
|
||||
// Initialize a compilation unit from a .dwo or .dwp file.
|
||||
// In this case, we need the .debug_addr section from the
|
||||
// executable file that contains the corresponding skeleton
|
||||
// compilation unit. We also inherit the Dwarf2Handler from
|
||||
// the executable file, and call it as if we were still
|
||||
// processing the original compilation unit.
|
||||
void SetSplitDwarf(const uint8_t* addr_buffer, uint64 addr_buffer_length,
|
||||
uint64 addr_base, uint64 ranges_base, uint64 dwo_id);
|
||||
|
||||
// Begin reading a Dwarf2 compilation unit, and calling the
|
||||
// callbacks in the Dwarf2Handler
|
||||
|
||||
// Return the full length of the compilation unit, including
|
||||
// headers. This plus the starting offset passed to the constructor
|
||||
// is the offset of the end of the compilation unit --- and the
|
||||
// start of the next compilation unit, if there is one.
|
||||
uint64 Start();
|
||||
|
||||
private:
|
||||
|
||||
// This struct represents a single DWARF2/3 abbreviation
|
||||
// The abbreviation tells how to read a DWARF2/3 DIE, and consist of a
|
||||
// tag and a list of attributes, as well as the data form of each attribute.
|
||||
struct Abbrev {
|
||||
uint64 number;
|
||||
enum DwarfTag tag;
|
||||
bool has_children;
|
||||
AttributeList attributes;
|
||||
};
|
||||
|
||||
// A DWARF2/3 compilation unit header. This is not the same size as
|
||||
// in the actual file, as the one in the file may have a 32 bit or
|
||||
// 64 bit length.
|
||||
struct CompilationUnitHeader {
|
||||
uint64 length;
|
||||
uint16 version;
|
||||
uint64 abbrev_offset;
|
||||
uint8 address_size;
|
||||
} header_;
|
||||
|
||||
// Reads the DWARF2/3 header for this compilation unit.
|
||||
void ReadHeader();
|
||||
|
||||
// Reads the DWARF2/3 abbreviations for this compilation unit
|
||||
void ReadAbbrevs();
|
||||
|
||||
// Processes a single DIE for this compilation unit and return a new
|
||||
// pointer just past the end of it
|
||||
const uint8_t *ProcessDIE(uint64 dieoffset,
|
||||
const uint8_t *start,
|
||||
const Abbrev& abbrev);
|
||||
|
||||
// Processes a single attribute and return a new pointer just past the
|
||||
// end of it
|
||||
const uint8_t *ProcessAttribute(uint64 dieoffset,
|
||||
const uint8_t *start,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form);
|
||||
|
||||
// Called when we have an attribute with unsigned data to give to
|
||||
// our handler. The attribute is for the DIE at OFFSET from the
|
||||
// beginning of compilation unit, has a name of ATTR, a form of
|
||||
// FORM, and the actual data of the attribute is in DATA.
|
||||
// If we see a DW_AT_GNU_dwo_id attribute, save the value so that
|
||||
// we can find the debug info in a .dwo or .dwp file.
|
||||
void ProcessAttributeUnsigned(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 data) {
|
||||
if (attr == DW_AT_GNU_dwo_id) {
|
||||
dwo_id_ = data;
|
||||
}
|
||||
else if (attr == DW_AT_GNU_addr_base) {
|
||||
addr_base_ = data;
|
||||
}
|
||||
else if (attr == DW_AT_GNU_ranges_base) {
|
||||
ranges_base_ = data;
|
||||
}
|
||||
// TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5,
|
||||
// that base will apply to DW_AT_ranges attributes in the
|
||||
// skeleton CU as well as in the .dwo/.dwp files.
|
||||
else if (attr == DW_AT_ranges && is_split_dwarf_) {
|
||||
data += ranges_base_;
|
||||
}
|
||||
handler_->ProcessAttributeUnsigned(offset, attr, form, data);
|
||||
}
|
||||
|
||||
// Called when we have an attribute with signed data to give to
|
||||
// our handler. The attribute is for the DIE at OFFSET from the
|
||||
// beginning of compilation unit, has a name of ATTR, a form of
|
||||
// FORM, and the actual data of the attribute is in DATA.
|
||||
void ProcessAttributeSigned(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
int64 data) {
|
||||
handler_->ProcessAttributeSigned(offset, attr, form, data);
|
||||
}
|
||||
|
||||
// Called when we have an attribute with a buffer of data to give to
|
||||
// our handler. The attribute is for the DIE at OFFSET from the
|
||||
// beginning of compilation unit, has a name of ATTR, a form of
|
||||
// FORM, and the actual data of the attribute is in DATA, and the
|
||||
// length of the buffer is LENGTH.
|
||||
void ProcessAttributeBuffer(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const uint8_t* data,
|
||||
uint64 len) {
|
||||
handler_->ProcessAttributeBuffer(offset, attr, form, data, len);
|
||||
}
|
||||
|
||||
// Called when we have an attribute with string data to give to
|
||||
// our handler. The attribute is for the DIE at OFFSET from the
|
||||
// beginning of compilation unit, has a name of ATTR, a form of
|
||||
// FORM, and the actual data of the attribute is in DATA.
|
||||
// If we see a DW_AT_GNU_dwo_name attribute, save the value so
|
||||
// that we can find the debug info in a .dwo or .dwp file.
|
||||
void ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const char* data) {
|
||||
if (attr == DW_AT_GNU_dwo_name)
|
||||
dwo_name_ = data;
|
||||
handler_->ProcessAttributeString(offset, attr, form, data);
|
||||
}
|
||||
|
||||
// Processes all DIEs for this compilation unit
|
||||
void ProcessDIEs();
|
||||
|
||||
// Skips the die with attributes specified in ABBREV starting at
|
||||
// START, and return the new place to position the stream to.
|
||||
const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev);
|
||||
|
||||
// Skips the attribute starting at START, with FORM, and return the
|
||||
// new place to position the stream to.
|
||||
const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form);
|
||||
|
||||
// Process the actual debug information in a split DWARF file.
|
||||
void ProcessSplitDwarf();
|
||||
|
||||
// Read the debug sections from a .dwo file.
|
||||
void ReadDebugSectionsFromDwo(ElfReader* elf_reader,
|
||||
SectionMap* sections);
|
||||
|
||||
// Path of the file containing the debug information.
|
||||
const string path_;
|
||||
|
||||
// Offset from section start is the offset of this compilation unit
|
||||
// from the beginning of the .debug_info section.
|
||||
uint64 offset_from_section_start_;
|
||||
|
||||
// buffer is the buffer for our CU, starting at .debug_info + offset
|
||||
// passed in from constructor.
|
||||
// after_header points to right after the compilation unit header.
|
||||
const uint8_t *buffer_;
|
||||
uint64 buffer_length_;
|
||||
const uint8_t *after_header_;
|
||||
|
||||
// The associated ByteReader that handles endianness issues for us
|
||||
ByteReader* reader_;
|
||||
|
||||
// The map of sections in our file to buffers containing their data
|
||||
const SectionMap& sections_;
|
||||
|
||||
// The associated handler to call processing functions in
|
||||
Dwarf2Handler* handler_;
|
||||
|
||||
// Set of DWARF2/3 abbreviations for this compilation unit. Indexed
|
||||
// by abbreviation number, which means that abbrevs_[0] is not
|
||||
// valid.
|
||||
std::vector<Abbrev>* abbrevs_;
|
||||
|
||||
// String section buffer and length, if we have a string section.
|
||||
// This is here to avoid doing a section lookup for strings in
|
||||
// ProcessAttribute, which is in the hot path for DWARF2 reading.
|
||||
const uint8_t *string_buffer_;
|
||||
uint64 string_buffer_length_;
|
||||
|
||||
// String offsets section buffer and length, if we have a string offsets
|
||||
// section (.debug_str_offsets or .debug_str_offsets.dwo).
|
||||
const uint8_t* str_offsets_buffer_;
|
||||
uint64 str_offsets_buffer_length_;
|
||||
|
||||
// Address section buffer and length, if we have an address section
|
||||
// (.debug_addr).
|
||||
const uint8_t* addr_buffer_;
|
||||
uint64 addr_buffer_length_;
|
||||
|
||||
// Flag indicating whether this compilation unit is part of a .dwo
|
||||
// or .dwp file. If true, we are reading this unit because a
|
||||
// skeleton compilation unit in an executable file had a
|
||||
// DW_AT_GNU_dwo_name or DW_AT_GNU_dwo_id attribute.
|
||||
// In a .dwo file, we expect the string offsets section to
|
||||
// have a ".dwo" suffix, and we will use the ".debug_addr" section
|
||||
// associated with the skeleton compilation unit.
|
||||
bool is_split_dwarf_;
|
||||
|
||||
// The value of the DW_AT_GNU_dwo_id attribute, if any.
|
||||
uint64 dwo_id_;
|
||||
|
||||
// The value of the DW_AT_GNU_dwo_name attribute, if any.
|
||||
const char* dwo_name_;
|
||||
|
||||
// If this is a split DWARF CU, the value of the DW_AT_GNU_dwo_id attribute
|
||||
// from the skeleton CU.
|
||||
uint64 skeleton_dwo_id_;
|
||||
|
||||
// The value of the DW_AT_GNU_ranges_base attribute, if any.
|
||||
uint64 ranges_base_;
|
||||
|
||||
// The value of the DW_AT_GNU_addr_base attribute, if any.
|
||||
uint64 addr_base_;
|
||||
|
||||
// True if we have already looked for a .dwp file.
|
||||
bool have_checked_for_dwp_;
|
||||
|
||||
// Path to the .dwp file.
|
||||
string dwp_path_;
|
||||
|
||||
// ByteReader for the DWP file.
|
||||
std::unique_ptr<ByteReader> dwp_byte_reader_;
|
||||
|
||||
// DWP reader.
|
||||
std::unique_ptr<DwpReader> dwp_reader_;
|
||||
};
|
||||
|
||||
// A Reader for a .dwp file. Supports the fetching of DWARF debug
|
||||
// info for a given dwo_id.
|
||||
//
|
||||
// There are two versions of .dwp files. In both versions, the
|
||||
// .dwp file is an ELF file containing only debug sections.
|
||||
// In Version 1, the file contains many copies of each debug
|
||||
// section, one for each .dwo file that is packaged in the .dwp
|
||||
// file, and the .debug_cu_index section maps from the dwo_id
|
||||
// to a set of section indexes. In Version 2, the file contains
|
||||
// one of each debug section, and the .debug_cu_index section
|
||||
// maps from the dwo_id to a set of offsets and lengths that
|
||||
// identify each .dwo file's contribution to the larger sections.
|
||||
|
||||
class DwpReader {
|
||||
public:
|
||||
DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader);
|
||||
|
||||
~DwpReader();
|
||||
|
||||
// Read the CU index and initialize data members.
|
||||
void Initialize();
|
||||
|
||||
// Read the debug sections for the given dwo_id.
|
||||
void ReadDebugSectionsForCU(uint64 dwo_id, SectionMap* sections);
|
||||
|
||||
private:
|
||||
// Search a v1 hash table for "dwo_id". Returns the slot index
|
||||
// where the dwo_id was found, or -1 if it was not found.
|
||||
int LookupCU(uint64 dwo_id);
|
||||
|
||||
// Search a v2 hash table for "dwo_id". Returns the row index
|
||||
// in the offsets and sizes tables, or 0 if it was not found.
|
||||
uint32 LookupCUv2(uint64 dwo_id);
|
||||
|
||||
// The ELF reader for the .dwp file.
|
||||
ElfReader* elf_reader_;
|
||||
|
||||
// The ByteReader for the .dwp file.
|
||||
const ByteReader& byte_reader_;
|
||||
|
||||
// Pointer to the .debug_cu_index section.
|
||||
const char* cu_index_;
|
||||
|
||||
// Size of the .debug_cu_index section.
|
||||
size_t cu_index_size_;
|
||||
|
||||
// Pointer to the .debug_str.dwo section.
|
||||
const char* string_buffer_;
|
||||
|
||||
// Size of the .debug_str.dwo section.
|
||||
size_t string_buffer_size_;
|
||||
|
||||
// Version of the .dwp file. We support versions 1 and 2 currently.
|
||||
int version_;
|
||||
|
||||
// Number of columns in the section tables (version 2).
|
||||
unsigned int ncolumns_;
|
||||
|
||||
// Number of units in the section tables (version 2).
|
||||
unsigned int nunits_;
|
||||
|
||||
// Number of slots in the hash table.
|
||||
unsigned int nslots_;
|
||||
|
||||
// Pointer to the beginning of the hash table.
|
||||
const char* phash_;
|
||||
|
||||
// Pointer to the beginning of the index table.
|
||||
const char* pindex_;
|
||||
|
||||
// Pointer to the beginning of the section index pool (version 1).
|
||||
const char* shndx_pool_;
|
||||
|
||||
// Pointer to the beginning of the section offset table (version 2).
|
||||
const char* offset_table_;
|
||||
|
||||
// Pointer to the beginning of the section size table (version 2).
|
||||
const char* size_table_;
|
||||
|
||||
// Contents of the sections of interest (version 2).
|
||||
const char* abbrev_data_;
|
||||
size_t abbrev_size_;
|
||||
const char* info_data_;
|
||||
size_t info_size_;
|
||||
const char* str_offsets_data_;
|
||||
size_t str_offsets_size_;
|
||||
};
|
||||
|
||||
// This class is a reader for DWARF's Call Frame Information. CFI
|
||||
// describes how to unwind stack frames --- even for functions that do
|
||||
// not follow fixed conventions for saving registers, whose frame size
|
||||
|
1258
src/common/dwarf/elf_reader.cc
Normal file
1258
src/common/dwarf/elf_reader.cc
Normal file
File diff suppressed because it is too large
Load Diff
166
src/common/dwarf/elf_reader.h
Normal file
166
src/common/dwarf/elf_reader.h
Normal file
@ -0,0 +1,166 @@
|
||||
// Copyright 2005 Google Inc. All Rights Reserved.
|
||||
// Author: chatham@google.com (Andrew Chatham)
|
||||
// Author: satorux@google.com (Satoru Takabayashi)
|
||||
//
|
||||
// ElfReader handles reading in ELF. It can extract symbols from the
|
||||
// current process, which may be used to symbolize stack traces
|
||||
// without having to make a potentially dangerous call to fork().
|
||||
//
|
||||
// ElfReader dynamically allocates memory, so it is not appropriate to
|
||||
// use once the address space might be corrupted, such as during
|
||||
// process death.
|
||||
//
|
||||
// ElfReader supports both 32-bit and 64-bit ELF binaries.
|
||||
|
||||
#ifndef COMMON_DWARF_ELF_READER_H__
|
||||
#define COMMON_DWARF_ELF_READER_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/dwarf/types.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::pair;
|
||||
|
||||
namespace dwarf2reader {
|
||||
|
||||
class SymbolMap;
|
||||
class Elf32;
|
||||
class Elf64;
|
||||
template<typename ElfArch>
|
||||
class ElfReaderImpl;
|
||||
|
||||
class ElfReader {
|
||||
public:
|
||||
explicit ElfReader(const string &path);
|
||||
~ElfReader();
|
||||
|
||||
// Parse the ELF prologue of this file and return whether it was
|
||||
// successfully parsed and matches the word size and byte order of
|
||||
// the current process.
|
||||
bool IsNativeElfFile() const;
|
||||
|
||||
// Similar to IsNativeElfFile but checks if it's a 32-bit ELF file.
|
||||
bool IsElf32File() const;
|
||||
|
||||
// Similar to IsNativeElfFile but checks if it's a 64-bit ELF file.
|
||||
bool IsElf64File() const;
|
||||
|
||||
// Checks if it's an ELF file of type ET_DYN (shared object file).
|
||||
bool IsDynamicSharedObject();
|
||||
|
||||
// Add symbols in the given ELF file into the provided SymbolMap,
|
||||
// assuming that the file has been loaded into the specified
|
||||
// offset.
|
||||
//
|
||||
// The remaining arguments are typically taken from a
|
||||
// ProcMapsIterator (base/sysinfo.h) and describe which portions of
|
||||
// the ELF file are mapped into which parts of memory:
|
||||
//
|
||||
// mem_offset - position at which the segment is mapped into memory
|
||||
// file_offset - offset in the file where the mapping begins
|
||||
// length - length of the mapped segment
|
||||
void AddSymbols(SymbolMap *symbols,
|
||||
uint64 mem_offset, uint64 file_offset,
|
||||
uint64 length);
|
||||
|
||||
class SymbolSink {
|
||||
public:
|
||||
virtual ~SymbolSink() {}
|
||||
virtual void AddSymbol(const char *name, uint64 address, uint64 size) = 0;
|
||||
};
|
||||
|
||||
// Like AddSymbols above, but with no address correction.
|
||||
// Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section.
|
||||
void VisitSymbols(SymbolSink *sink);
|
||||
|
||||
// Like VisitSymbols above, but for a specific symbol binding/type.
|
||||
// A negative value for the binding and type parameters means any
|
||||
// binding or type.
|
||||
void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type);
|
||||
|
||||
// Like VisitSymbols above but can optionally export raw symbol values instead
|
||||
// of adjusted ones.
|
||||
void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type,
|
||||
bool get_raw_symbol_values);
|
||||
|
||||
// p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD
|
||||
// segments are present. This is the address an ELF image was linked
|
||||
// (by static linker) to be loaded at. Usually (but not always) 0 for
|
||||
// shared libraries and position-independent executables.
|
||||
uint64 VaddrOfFirstLoadSegment();
|
||||
|
||||
// Return the name of section "shndx". Returns NULL if the section
|
||||
// is not found.
|
||||
const char *GetSectionName(int shndx);
|
||||
|
||||
// Return the number of sections in the given ELF file.
|
||||
uint64 GetNumSections();
|
||||
|
||||
// Get section "shndx" from the given ELF file. On success, return
|
||||
// the pointer to the section and store the size in "size".
|
||||
// On error, return NULL. The returned section data is only valid
|
||||
// until the ElfReader gets destroyed.
|
||||
const char *GetSectionByIndex(int shndx, size_t *size);
|
||||
|
||||
// Get section with "section_name" (ex. ".text", ".symtab") in the
|
||||
// given ELF file. On success, return the pointer to the section
|
||||
// and store the size in "size". On error, return NULL. The
|
||||
// returned section data is only valid until the ElfReader gets
|
||||
// destroyed.
|
||||
const char *GetSectionByName(const string §ion_name, size_t *size);
|
||||
|
||||
// This is like GetSectionByName() but it returns a lot of extra information
|
||||
// about the section. The SectionInfo structure is almost identical to
|
||||
// the typedef struct Elf64_Shdr defined in <elf.h>, but is redefined
|
||||
// here so that the many short macro names in <elf.h> don't have to be
|
||||
// added to our already cluttered namespace.
|
||||
struct SectionInfo {
|
||||
uint32 type; // Section type (SHT_xxx constant from elf.h).
|
||||
uint64 flags; // Section flags (SHF_xxx constants from elf.h).
|
||||
uint64 addr; // Section virtual address at execution.
|
||||
uint64 offset; // Section file offset.
|
||||
uint64 size; // Section size in bytes.
|
||||
uint32 link; // Link to another section.
|
||||
uint32 info; // Additional section information.
|
||||
uint64 addralign; // Section alignment.
|
||||
uint64 entsize; // Entry size if section holds a table.
|
||||
};
|
||||
const char *GetSectionInfoByName(const string §ion_name,
|
||||
SectionInfo *info);
|
||||
|
||||
// Check if "path" is an ELF binary that has not been stripped of symbol
|
||||
// tables. This function supports both 32-bit and 64-bit ELF binaries.
|
||||
static bool IsNonStrippedELFBinary(const string &path);
|
||||
|
||||
// Check if "path" is an ELF binary that has not been stripped of debug
|
||||
// info. Unlike IsNonStrippedELFBinary, this function will return
|
||||
// false for binaries passed through "strip -S".
|
||||
static bool IsNonDebugStrippedELFBinary(const string &path);
|
||||
|
||||
// Match a requested section name with the section name as it
|
||||
// appears in the elf-file, adjusting for compressed debug section
|
||||
// names. For example, returns true if name == ".debug_abbrev" and
|
||||
// sh_name == ".zdebug_abbrev"
|
||||
static bool SectionNamesMatch(const string &name, const string &sh_name);
|
||||
|
||||
private:
|
||||
// Lazily initialize impl32_ and return it.
|
||||
ElfReaderImpl<Elf32> *GetImpl32();
|
||||
// Ditto for impl64_.
|
||||
ElfReaderImpl<Elf64> *GetImpl64();
|
||||
|
||||
// Path of the file we're reading.
|
||||
const string path_;
|
||||
// Read-only file descriptor for the file. May be -1 if there was an
|
||||
// error during open.
|
||||
int fd_;
|
||||
ElfReaderImpl<Elf32> *impl32_;
|
||||
ElfReaderImpl<Elf64> *impl64_;
|
||||
};
|
||||
|
||||
} // namespace dwarf2reader
|
||||
|
||||
#endif // COMMON_DWARF_ELF_READER_H__
|
@ -288,7 +288,8 @@ bool LoadDwarf(const string& dwarf_filename,
|
||||
// Make a Dwarf2Handler that drives the DIEHandler.
|
||||
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
|
||||
// Make a DWARF parser for the compilation unit at OFFSET.
|
||||
dwarf2reader::CompilationUnit reader(file_context.section_map(),
|
||||
dwarf2reader::CompilationUnit reader(dwarf_filename,
|
||||
file_context.section_map(),
|
||||
offset,
|
||||
&byte_reader,
|
||||
&die_dispatcher);
|
||||
|
@ -437,7 +437,8 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
|
||||
// Make a Dwarf2Handler that drives our DIEHandler.
|
||||
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
|
||||
// Make a DWARF parser for the compilation unit at OFFSET.
|
||||
dwarf2reader::CompilationUnit dwarf_reader(file_context.section_map(),
|
||||
dwarf2reader::CompilationUnit dwarf_reader(selected_object_name_,
|
||||
file_context.section_map(),
|
||||
offset,
|
||||
&byte_reader,
|
||||
&die_dispatcher);
|
||||
|
Loading…
Reference in New Issue
Block a user