aboutsummaryrefslogtreecommitdiff
path: root/src/common/linux/dump_symbols.cc
diff options
context:
space:
mode:
authorjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-03-16 16:31:49 +0000
committerjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-03-16 16:31:49 +0000
commit3e768ed9c01a244cdb1bc0d6aec34fb25821fbcc (patch)
treebc77f789150d26cb57c7743d15b9e0f7b052bc49 /src/common/linux/dump_symbols.cc
parentBreakpad: Add minidump processor support for DWARF Call Frame Information. (diff)
downloadbreakpad-3e768ed9c01a244cdb1bc0d6aec34fb25821fbcc.tar.xz
Breakpad Linux dumper: Add support for dumping DWARF CFI as STACK CFI records.
Define a new DWARF parser class, dwarf2reader::CallFrameInfo. Extend google_breakpad::Module to store and write out 'STACK CFI' records. Define a new google_breakpad::DwarfCFIToModule class, to accept DWARF CFI data from the parser and populate a Module with the equivalent STACK CFI records. Extend the Linux symbol dumping tool, dump_syms, to use dwarf2reader::CallFrameInfo, google_breakpad::DwarfCFIToModule, and google_breakpad::Module to extract DWARF CFI from the executable or shared library files and write it to the Breakpad symbol file. Define CFISection, a new class derived from TestAssembler::Section, for use in creating DWARF CFI data for test cases. a=jimblandy, r=nealsid git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@550 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/common/linux/dump_symbols.cc')
-rw-r--r--src/common/linux/dump_symbols.cc133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
index 993bdbd5..79d7ad36 100644
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -49,6 +49,7 @@
#include "common/dwarf/dwarf2diehandler.h"
#include "common/linux/dump_stabs.h"
#include "common/linux/dump_symbols.h"
+#include "common/linux/dwarf_cfi_to_module.h"
#include "common/linux/dwarf_cu_to_module.h"
#include "common/linux/dwarf_line_to_module.h"
#include "common/linux/file_id.h"
@@ -59,6 +60,7 @@
namespace {
using google_breakpad::DumpStabsHandler;
+using google_breakpad::DwarfCFIToModule;
using google_breakpad::DwarfCUToModule;
using google_breakpad::DwarfLineToModule;
using google_breakpad::Module;
@@ -215,6 +217,119 @@ static bool LoadDwarf(const string &dwarf_filename,
return true;
}
+// Fill REGISTER_NAMES with the register names appropriate to the
+// machine architecture given in HEADER, indexed by the register
+// numbers used in DWARF call frame information. Return true on
+// success, or false if we don't recognize HEADER's machine
+// architecture.
+static bool DwarfCFIRegisterNames(const ElfW(Ehdr) *elf_header,
+ vector<string> *register_names)
+{
+ static const char *const i386_names[] = {
+ "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
+ "$eip", "$eflags", "$unused1",
+ "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
+ "$unused2", "$unused3",
+ "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
+ "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
+ "$fcw", "$fsw", "$mxcsr",
+ "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
+ "$tr", "$ldtr",
+ NULL
+ };
+
+ static const char *const x86_64_names[] = {
+ "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
+ "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
+ "$rip",
+ "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
+ "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
+ "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
+ "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
+ "$rflags",
+ "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
+ "$fs.base", "$gs.base", "$unused3", "$unused4",
+ "$tr", "$ldtr",
+ "$mxcsr", "$fcw", "$fsw",
+ NULL
+ };
+
+ const char * const *name_table;
+ switch (elf_header->e_machine) {
+ case EM_386:
+ name_table = i386_names;
+ break;
+
+ case EM_X86_64:
+ name_table = x86_64_names;
+ break;
+
+ default:
+ return false;
+ }
+
+ register_names->clear();
+ for (int i = 0; name_table[i]; i++)
+ register_names->push_back(name_table[i]);
+ return true;
+}
+
+static bool LoadDwarfCFI(const string &dwarf_filename,
+ const ElfW(Ehdr) *elf_header,
+ const char *section_name,
+ const ElfW(Shdr) *section,
+ Module *module) {
+ // Find the appropriate set of register names for this file's
+ // architecture.
+ vector<string> register_names;
+ if (!DwarfCFIRegisterNames(elf_header, &register_names)) {
+ fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';"
+ " cannot convert DWARF call frame information\n",
+ dwarf_filename.c_str(), elf_header->e_machine);
+ return false;
+ }
+
+ // Figure out what endianness this file is.
+ dwarf2reader::Endianness endianness;
+ if (elf_header->e_ident[EI_DATA] == ELFDATA2LSB)
+ endianness = dwarf2reader::ENDIANNESS_LITTLE;
+ else if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB)
+ endianness = dwarf2reader::ENDIANNESS_BIG;
+ else {
+ fprintf(stderr, "%s: bad data encoding in ELF header: %d\n",
+ dwarf_filename.c_str(), elf_header->e_ident[EI_DATA]);
+ return false;
+ }
+
+ // Find the call frame information and its size.
+ const char *cfi = reinterpret_cast<const char *>(section->sh_offset);
+ size_t cfi_size = section->sh_size;
+
+ // Plug together the parser, handler, and their entourages.
+ DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name);
+ DwarfCFIToModule handler(module, register_names, &module_reporter);
+ dwarf2reader::ByteReader byte_reader(endianness);
+ // Since we're using the ElfW macro, we're not actually capable of
+ // processing both ELF32 and ELF64 files with the same program; that
+ // would take a bit more work. But this will work out well enough.
+ if (elf_header->e_ident[EI_CLASS] == ELFCLASS32)
+ byte_reader.SetAddressSize(4);
+ else if (elf_header->e_ident[EI_CLASS] == ELFCLASS64)
+ byte_reader.SetAddressSize(8);
+ else {
+ fprintf(stderr, "%s: bad file class in ELF header: %d\n",
+ dwarf_filename.c_str(), elf_header->e_ident[EI_CLASS]);
+ return false;
+ }
+
+ dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename,
+ section_name);
+ dwarf2reader::CallFrameInfo parser(cfi, cfi_size, &byte_reader,
+ &handler, &dwarf_reporter);
+ parser.Start();
+ return true;
+}
+
static bool LoadSymbols(const std::string &obj_file, ElfW(Ehdr) *elf_header,
Module *module) {
// Translate all offsets in section headers into address.
@@ -228,6 +343,8 @@ static bool LoadSymbols(const std::string &obj_file, ElfW(Ehdr) *elf_header,
reinterpret_cast<ElfW(Shdr) *>(elf_header->e_shoff);
const ElfW(Shdr) *section_names = sections + elf_header->e_shstrndx;
bool found_debug_info_section = false;
+
+ // Look for STABS debugging information, and load it if present.
const ElfW(Shdr) *stab_section
= FindSectionByName(".stab", sections, section_names,
elf_header->e_shnum);
@@ -240,6 +357,8 @@ static bool LoadSymbols(const std::string &obj_file, ElfW(Ehdr) *elf_header,
" debugging information\n");
}
}
+
+ // Look for DWARF debugging information, and load it if present.
const ElfW(Shdr) *dwarf_section
= FindSectionByName(".debug_info", sections, section_names,
elf_header->e_shnum);
@@ -249,6 +368,20 @@ static bool LoadSymbols(const std::string &obj_file, ElfW(Ehdr) *elf_header,
fprintf(stderr, "\".debug_info\" section found, but failed to load "
"DWARF debugging information\n");
}
+
+ // Dwarf Call Frame Information (CFI) is actually independent from
+ // the other DWARF debugging information, and can be used alone.
+ const ElfW(Shdr) *dwarf_cfi_section =
+ FindSectionByName(".debug_frame", sections, section_names,
+ elf_header->e_shnum);
+ if (dwarf_cfi_section) {
+ // Ignore the return value of this function; even without call frame
+ // information, the other debugging information could be perfectly
+ // useful.
+ LoadDwarfCFI(obj_file, elf_header, ".debug_frame",
+ dwarf_cfi_section, module);
+ }
+
if (!found_debug_info_section) {
fprintf(stderr, "file contains no debugging information"
" (no \".stab\" or \".debug_info\" sections)\n");