diff --git a/Makefile.am b/Makefile.am index 0f571bcf..7ef05e56 100644 --- a/Makefile.am +++ b/Makefile.am @@ -636,7 +636,8 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \ src_tools_linux_dump_syms_dump_syms_CXXFLAGS = \ $(RUSTC_DEMANGLE_CFLAGS) src_tools_linux_dump_syms_dump_syms_LDADD = \ - $(RUSTC_DEMANGLE_LIBS) + $(RUSTC_DEMANGLE_LIBS) \ + -lz src_tools_linux_md2core_minidump_2_core_SOURCES = \ src/common/linux/memory_mapped_file.cc \ @@ -773,7 +774,8 @@ src_common_dumper_unittest_CPPFLAGS = \ src_common_dumper_unittest_LDADD = \ $(TEST_LIBS) \ $(RUSTC_DEMANGLE_LIBS) \ - $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ + -lz src_common_mac_macho_reader_unittest_SOURCES = \ src/common/dwarf_cfi_to_module.cc \ diff --git a/Makefile.in b/Makefile.in index 0d0ccba2..c9a359f6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2945,7 +2945,8 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS) @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUSTC_DEMANGLE_CFLAGS) @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_dump_syms_dump_syms_LDADD = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUSTC_DEMANGLE_LIBS) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUSTC_DEMANGLE_LIBS) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -lz @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_SOURCES = \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \ @@ -3088,7 +3089,8 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS) @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_LDADD = \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(TEST_LIBS) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUSTC_DEMANGLE_LIBS) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -lz @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_mac_macho_reader_unittest_SOURCES = \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc index f5293de4..a5a1fd06 100644 --- a/src/common/dwarf_cu_to_module.cc +++ b/src/common/dwarf_cu_to_module.cc @@ -123,6 +123,10 @@ DwarfCUToModule::FileContext::FileContext(const string& filename, } DwarfCUToModule::FileContext::~FileContext() { + for (std::vector::iterator i = uncompressed_sections_.begin(); + i != uncompressed_sections_.end(); ++i) { + delete[] *i; + } } void DwarfCUToModule::FileContext::AddSectionToSectionMap( @@ -130,6 +134,12 @@ void DwarfCUToModule::FileContext::AddSectionToSectionMap( section_map_[name] = std::make_pair(contents, length); } +void DwarfCUToModule::FileContext::AddManagedSectionToSectionMap( + const string& name, uint8_t* contents, uint64_t length) { + section_map_[name] = std::make_pair(contents, length); + uncompressed_sections_.push_back(contents); +} + void DwarfCUToModule::FileContext::ClearSectionMapForTest() { section_map_.clear(); } diff --git a/src/common/dwarf_cu_to_module.h b/src/common/dwarf_cu_to_module.h index f44be8ce..5a800104 100644 --- a/src/common/dwarf_cu_to_module.h +++ b/src/common/dwarf_cu_to_module.h @@ -41,6 +41,7 @@ #include #include +#include #include "common/language.h" #include "common/module.h" @@ -82,6 +83,10 @@ class DwarfCUToModule: public RootDIEHandler { const uint8_t* contents, uint64_t length); + void AddManagedSectionToSectionMap(const string& name, + uint8_t* contents, + uint64_t length); + // Clear the section map for testing. void ClearSectionMapForTest(); @@ -114,6 +119,7 @@ class DwarfCUToModule: public RootDIEHandler { // Inter-compilation unit data used internally by the handlers. scoped_ptr file_private_; + std::vector uncompressed_sections_; }; // An abstract base class for handlers that handle DWARF range lists for diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index 8ccbbbd1..7e639b0a 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -46,8 +46,8 @@ #include #include #include +#include -#include #include #include #include @@ -281,6 +281,55 @@ class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler { google_breakpad::ByteReader* byte_reader_; }; +template +bool IsCompressedHeader(const typename ElfClass::Shdr* section) { + return (section->sh_flags & SHF_COMPRESSED) != 0; +} + +template +uint32_t GetCompressionHeader( + typename ElfClass::Chdr& compression_header, + const uint8_t* content, uint64_t size) { + const typename ElfClass::Chdr* header = + reinterpret_cast(content); + + if (size < sizeof (*header)) { + return 0; + } + + compression_header = *header; + return sizeof (*header); +} + +std::pair UncompressSectionContents( + const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) { + z_stream stream; + memset(&stream, 0, sizeof stream); + + stream.avail_in = compressed_size; + stream.avail_out = uncompressed_size; + stream.next_in = const_cast(compressed_buffer); + + google_breakpad::scoped_array uncompressed_buffer( + new uint8_t[uncompressed_size]); + + int status = inflateInit(&stream); + while (stream.avail_in != 0 && status == Z_OK) { + stream.next_out = + uncompressed_buffer.get() + uncompressed_size - stream.avail_out; + + if ((status = inflate(&stream, Z_FINISH)) != Z_STREAM_END) { + break; + } + + status = inflateReset(&stream); + } + + return inflateEnd(&stream) != Z_OK || status != Z_OK || stream.avail_out != 0 + ? std::make_pair(nullptr, 0) + : std::make_pair(uncompressed_buffer.release(), uncompressed_size); +} + template bool LoadDwarf(const string& dwarf_filename, const typename ElfClass::Ehdr* elf_header, @@ -311,7 +360,31 @@ bool LoadDwarf(const string& dwarf_filename, section->sh_name; const uint8_t* contents = GetOffset(elf_header, section->sh_offset); - file_context.AddSectionToSectionMap(name, contents, section->sh_size); + uint64_t size = section->sh_size; + + if (!IsCompressedHeader(section)) { + file_context.AddSectionToSectionMap(name, contents, size); + continue; + } + + typename ElfClass::Chdr chdr; + + uint32_t compression_header_size = + GetCompressionHeader(chdr, contents, size); + + if (compression_header_size == 0 || chdr.ch_size == 0) { + continue; + } + + contents += compression_header_size; + size -= compression_header_size; + + std::pair uncompressed = + UncompressSectionContents(contents, size, chdr.ch_size); + + if (uncompressed.first != nullptr && uncompressed.second != 0) { + file_context.AddManagedSectionToSectionMap(name, uncompressed.first, uncompressed.second); + } } // .debug_ranges and .debug_rnglists reader diff --git a/src/common/linux/elfutils.h b/src/common/linux/elfutils.h index d44d4762..c6f1267b 100644 --- a/src/common/linux/elfutils.h +++ b/src/common/linux/elfutils.h @@ -40,6 +40,39 @@ namespace google_breakpad { +typedef struct { + typedef Elf32_Word Type; + typedef Elf32_Word Size; + typedef Elf32_Addr Addr; + + static_assert(sizeof (Type) == 4); + static_assert(sizeof (Size) == 4); + static_assert(sizeof (Addr) == 4); + + Type ch_type; // Compression type + Size ch_size; // Uncompressed data size in bytes + Addr ch_addralign; // Uncompressed data alignment +} Elf32_Chdr; + +static_assert(sizeof (Elf32_Chdr) == 12); + +typedef struct { + typedef Elf64_Word Type; + typedef Elf64_Xword Size; + typedef Elf64_Addr Addr; + + static_assert(sizeof (Type) == 4); + static_assert(sizeof (Size) == 8); + static_assert(sizeof (Addr) == 8); + + Type ch_type; // Compression type + Type ch_reserved; // Padding + Size ch_size; // Uncompressed data size in bytes + Addr ch_addralign; // Uncompressed data alignment +} Elf64_Chdr; + +static_assert(sizeof (Elf64_Chdr) == 24); + // Traits classes so consumers can write templatized code to deal // with specific ELF bits. struct ElfClass32 { @@ -49,6 +82,7 @@ struct ElfClass32 { typedef Elf32_Nhdr Nhdr; typedef Elf32_Phdr Phdr; typedef Elf32_Shdr Shdr; + typedef Elf32_Chdr Chdr; typedef Elf32_Half Half; typedef Elf32_Off Off; typedef Elf32_Sym Sym; @@ -67,6 +101,7 @@ struct ElfClass64 { typedef Elf64_Nhdr Nhdr; typedef Elf64_Phdr Phdr; typedef Elf64_Shdr Shdr; + typedef Elf64_Chdr Chdr; typedef Elf64_Half Half; typedef Elf64_Off Off; typedef Elf64_Sym Sym;