Breakpad Linux dumper: Parse the .eh_frame section.

Extend google_breakpad::CFISection with the ability to produce
.eh_frame data. Entry headers have a different format, and pointers
can be encoded in new and fascinating ways.

Extend dwarf2reader::CallFrameInfo to be able to parse either DWARF
CFI or .eh_frame data, as determined by an argument to the
constructor. Cope with variations in header formats, encoded pointers,
and additional data in 'z' augmentation data blocks. Extend the unit
tests appropriately.

Extend dump_syms to look for a .eh_frame section, and if it is
present, find the necessary base addresess and parse its contents.

There's no need for DwarfCFIToModule to check the version numbers; if
CallFrameInfo can parse it, DwarfCFIToModule should be able to handle
it. Adjust tests accordingly.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@552 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
jimblandy 2010-03-16 16:37:50 +00:00
parent 0de9f43b87
commit a76aaa1442
11 changed files with 1335 additions and 142 deletions

View file

@ -46,6 +46,7 @@
#include <cstring>
#include <string>
#include "common/dwarf/bytereader-inl.h"
#include "common/dwarf/dwarf2diehandler.h"
#include "common/linux/dump_stabs.h"
#include "common/linux/dump_symbols.h"
@ -278,6 +279,9 @@ static bool LoadDwarfCFI(const string &dwarf_filename,
const ElfW(Ehdr) *elf_header,
const char *section_name,
const ElfW(Shdr) *section,
bool eh_frame,
const ElfW(Shdr) *got_section,
const ElfW(Shdr) *text_section,
Module *module) {
// Find the appropriate set of register names for this file's
// architecture.
@ -321,11 +325,19 @@ static bool LoadDwarfCFI(const string &dwarf_filename,
dwarf_filename.c_str(), elf_header->e_ident[EI_CLASS]);
return false;
}
// Provide the base addresses for .eh_frame encoded pointers, if
// possible.
byte_reader.SetCFIDataBase(section->sh_addr, cfi);
if (got_section)
byte_reader.SetDataBase(got_section->sh_addr);
if (text_section)
byte_reader.SetTextBase(got_section->sh_addr);
dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename,
section_name);
dwarf2reader::CallFrameInfo parser(cfi, cfi_size, &byte_reader,
&handler, &dwarf_reporter);
dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
&byte_reader, &handler, &dwarf_reporter,
eh_frame);
parser.Start();
return true;
}
@ -379,7 +391,25 @@ static bool LoadSymbols(const std::string &obj_file, ElfW(Ehdr) *elf_header,
// information, the other debugging information could be perfectly
// useful.
LoadDwarfCFI(obj_file, elf_header, ".debug_frame",
dwarf_cfi_section, module);
dwarf_cfi_section, false, 0, 0, module);
}
// Linux C++ exception handling information can also provide
// unwinding data.
const ElfW(Shdr) *eh_frame_section =
FindSectionByName(".eh_frame", sections, section_names,
elf_header->e_shnum);
if (eh_frame_section) {
// Pointers in .eh_frame data may be relative to the base addresses of
// certain sections. Provide those sections if present.
const ElfW(Shdr) *got_section =
FindSectionByName(".got", sections, section_names, elf_header->e_shnum);
const ElfW(Shdr) *text_section =
FindSectionByName(".text", sections, section_names,
elf_header->e_shnum);
// As above, ignore the return value of this function.
LoadDwarfCFI(obj_file, elf_header, ".eh_frame",
eh_frame_section, true, got_section, text_section, module);
}
if (!found_debug_info_section) {

View file

@ -46,12 +46,10 @@ bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
uint8 version, const string &augmentation,
unsigned return_address) {
assert(!entry_);
// The latest CFI format version we understand is version 3.
if (version > 3)
return false;
// We only handle non-augmented DWARF unwinding data at the moment.
if (!augmentation.empty())
return false;
// If dwarf2reader::CallFrameInfo can handle this version and
// augmentation, then we should be okay with that, so there's no
// need to check them here.
// Get ready to collect entries.
entry_ = new Module::StackFrameEntry;

View file

@ -78,20 +78,6 @@ struct DwarfCFIToModuleFixture {
class Entry: public DwarfCFIToModuleFixture, public Test { };
TEST_F(Entry, IgnoreVersion) {
ASSERT_FALSE(handler.Entry(0xf120e638, 0x2851bc1f7a181d6dULL,
0x40589a48d66e5a88ULL, 4, "", 0x1ad80491));
module.GetStackFrameEntries(&entries);
EXPECT_EQ(0U, entries.size());
}
TEST_F(Entry, IgnoreAugmentation) {
ASSERT_FALSE(handler.Entry(0x3f9d228a, 0xcf9a94bb805cf5a4ULL,
0xe6c41bf958d4c171ULL, 3, "snazzy", 0x444a14f3));
module.GetStackFrameEntries(&entries);
EXPECT_EQ(0U, entries.size());
}
TEST_F(Entry, Accept) {
ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL,
0xb440ce248169c8d6ULL, 3, "", 0xea93c106));