Add support for compressed section headers to dump_syms.
Change-Id: I019cc9ffd66850ec5259f6dfcd9af8ac6c37d2c0 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3938926 Reviewed-by: Manoj Gupta <manojgupta@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
7ea7ded187
commit
de086a9859
6 changed files with 134 additions and 6 deletions
|
@ -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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -123,6 +123,10 @@ DwarfCUToModule::FileContext::FileContext(const string& filename,
|
|||
}
|
||||
|
||||
DwarfCUToModule::FileContext::~FileContext() {
|
||||
for (std::vector<uint8_t *>::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();
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<FilePrivate> file_private_;
|
||||
std::vector<uint8_t *> uncompressed_sections_;
|
||||
};
|
||||
|
||||
// An abstract base class for handlers that handle DWARF range lists for
|
||||
|
|
|
@ -46,8 +46,8 @@
|
|||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
@ -281,6 +281,55 @@ class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler {
|
|||
google_breakpad::ByteReader* byte_reader_;
|
||||
};
|
||||
|
||||
template<typename ElfClass>
|
||||
bool IsCompressedHeader(const typename ElfClass::Shdr* section) {
|
||||
return (section->sh_flags & SHF_COMPRESSED) != 0;
|
||||
}
|
||||
|
||||
template<typename ElfClass>
|
||||
uint32_t GetCompressionHeader(
|
||||
typename ElfClass::Chdr& compression_header,
|
||||
const uint8_t* content, uint64_t size) {
|
||||
const typename ElfClass::Chdr* header =
|
||||
reinterpret_cast<const typename ElfClass::Chdr *>(content);
|
||||
|
||||
if (size < sizeof (*header)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
compression_header = *header;
|
||||
return sizeof (*header);
|
||||
}
|
||||
|
||||
std::pair<uint8_t *, uint64_t> 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<uint8_t *>(compressed_buffer);
|
||||
|
||||
google_breakpad::scoped_array<uint8_t> 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<typename ElfClass>
|
||||
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<ElfClass, uint8_t>(elf_header,
|
||||
section->sh_offset);
|
||||
file_context.AddSectionToSectionMap(name, contents, section->sh_size);
|
||||
uint64_t size = section->sh_size;
|
||||
|
||||
if (!IsCompressedHeader<ElfClass>(section)) {
|
||||
file_context.AddSectionToSectionMap(name, contents, size);
|
||||
continue;
|
||||
}
|
||||
|
||||
typename ElfClass::Chdr chdr;
|
||||
|
||||
uint32_t compression_header_size =
|
||||
GetCompressionHeader<ElfClass>(chdr, contents, size);
|
||||
|
||||
if (compression_header_size == 0 || chdr.ch_size == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
contents += compression_header_size;
|
||||
size -= compression_header_size;
|
||||
|
||||
std::pair<uint8_t *, uint64_t> 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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue