mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2025-12-31 19:54:30 +01:00
Allow reading just CFI data when reading symbols
R=thestig at https://breakpad.appspot.com/517002/ git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1124 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
46cbbb847e
commit
983903ee0a
11 changed files with 252 additions and 179 deletions
|
|
@ -515,6 +515,7 @@ bool LoadSymbols(const string& obj_file,
|
|||
const typename ElfClass::Ehdr* elf_header,
|
||||
const bool read_gnu_debug_link,
|
||||
LoadSymbolsInfo<ElfClass>* info,
|
||||
SymbolData symbol_data,
|
||||
Module* module) {
|
||||
typedef typename ElfClass::Addr Addr;
|
||||
typedef typename ElfClass::Phdr Phdr;
|
||||
|
|
@ -535,81 +536,85 @@ bool LoadSymbols(const string& obj_file,
|
|||
bool found_debug_info_section = false;
|
||||
bool found_usable_info = false;
|
||||
|
||||
// Look for STABS debugging information, and load it if present.
|
||||
const Shdr* stab_section =
|
||||
if (symbol_data != ONLY_CFI) {
|
||||
// Look for STABS debugging information, and load it if present.
|
||||
const Shdr* stab_section =
|
||||
FindElfSectionByName<ElfClass>(".stab", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
if (stab_section) {
|
||||
const Shdr* stabstr_section = stab_section->sh_link + sections;
|
||||
if (stabstr_section) {
|
||||
found_debug_info_section = true;
|
||||
found_usable_info = true;
|
||||
info->LoadedSection(".stab");
|
||||
if (!LoadStabs<ElfClass>(elf_header, stab_section, stabstr_section,
|
||||
big_endian, module)) {
|
||||
fprintf(stderr, "%s: \".stab\" section found, but failed to load STABS"
|
||||
" debugging information\n", obj_file.c_str());
|
||||
if (stab_section) {
|
||||
const Shdr* stabstr_section = stab_section->sh_link + sections;
|
||||
if (stabstr_section) {
|
||||
found_debug_info_section = true;
|
||||
found_usable_info = true;
|
||||
info->LoadedSection(".stab");
|
||||
if (!LoadStabs<ElfClass>(elf_header, stab_section, stabstr_section,
|
||||
big_endian, module)) {
|
||||
fprintf(stderr, "%s: \".stab\" section found, but failed to load"
|
||||
" STABS debugging information\n", obj_file.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for DWARF debugging information, and load it if present.
|
||||
const Shdr* dwarf_section =
|
||||
// Look for DWARF debugging information, and load it if present.
|
||||
const Shdr* dwarf_section =
|
||||
FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
if (dwarf_section) {
|
||||
found_debug_info_section = true;
|
||||
found_usable_info = true;
|
||||
info->LoadedSection(".debug_info");
|
||||
if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian, module))
|
||||
fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
|
||||
"DWARF debugging information\n", obj_file.c_str());
|
||||
if (dwarf_section) {
|
||||
found_debug_info_section = true;
|
||||
found_usable_info = true;
|
||||
info->LoadedSection(".debug_info");
|
||||
if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian, module))
|
||||
fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
|
||||
"DWARF debugging information\n", obj_file.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Dwarf Call Frame Information (CFI) is actually independent from
|
||||
// the other DWARF debugging information, and can be used alone.
|
||||
const Shdr* dwarf_cfi_section =
|
||||
FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
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.
|
||||
info->LoadedSection(".debug_frame");
|
||||
bool result =
|
||||
LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".debug_frame",
|
||||
dwarf_cfi_section, false, 0, 0, big_endian,
|
||||
module);
|
||||
found_usable_info = found_usable_info || result;
|
||||
}
|
||||
if (symbol_data != NO_CFI) {
|
||||
// Dwarf Call Frame Information (CFI) is actually independent from
|
||||
// the other DWARF debugging information, and can be used alone.
|
||||
const Shdr* dwarf_cfi_section =
|
||||
FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
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.
|
||||
info->LoadedSection(".debug_frame");
|
||||
bool result =
|
||||
LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".debug_frame",
|
||||
dwarf_cfi_section, false, 0, 0, big_endian,
|
||||
module);
|
||||
found_usable_info = found_usable_info || result;
|
||||
}
|
||||
|
||||
// Linux C++ exception handling information can also provide
|
||||
// unwinding data.
|
||||
const Shdr* eh_frame_section =
|
||||
FindElfSectionByName<ElfClass>(".eh_frame", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
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 Shdr* got_section =
|
||||
FindElfSectionByName<ElfClass>(".got", SHT_PROGBITS,
|
||||
// Linux C++ exception handling information can also provide
|
||||
// unwinding data.
|
||||
const Shdr* eh_frame_section =
|
||||
FindElfSectionByName<ElfClass>(".eh_frame", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
const Shdr* text_section =
|
||||
FindElfSectionByName<ElfClass>(".text", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
info->LoadedSection(".eh_frame");
|
||||
// As above, ignore the return value of this function.
|
||||
bool result =
|
||||
LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".eh_frame",
|
||||
eh_frame_section, true,
|
||||
got_section, text_section, big_endian, module);
|
||||
found_usable_info = found_usable_info || result;
|
||||
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 Shdr* got_section =
|
||||
FindElfSectionByName<ElfClass>(".got", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
const Shdr* text_section =
|
||||
FindElfSectionByName<ElfClass>(".text", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
info->LoadedSection(".eh_frame");
|
||||
// As above, ignore the return value of this function.
|
||||
bool result =
|
||||
LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".eh_frame",
|
||||
eh_frame_section, true,
|
||||
got_section, text_section, big_endian, module);
|
||||
found_usable_info = found_usable_info || result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_debug_info_section) {
|
||||
|
|
@ -642,32 +647,36 @@ bool LoadSymbols(const string& obj_file,
|
|||
obj_file.c_str());
|
||||
}
|
||||
} else {
|
||||
// The caller doesn't want to consult .gnu_debuglink.
|
||||
// See if there are export symbols available.
|
||||
const Shdr* dynsym_section =
|
||||
if (symbol_data != ONLY_CFI) {
|
||||
// The caller doesn't want to consult .gnu_debuglink.
|
||||
// See if there are export symbols available.
|
||||
const Shdr* dynsym_section =
|
||||
FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
const Shdr* dynstr_section =
|
||||
const Shdr* dynstr_section =
|
||||
FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
if (dynsym_section && dynstr_section) {
|
||||
info->LoadedSection(".dynsym");
|
||||
if (dynsym_section && dynstr_section) {
|
||||
info->LoadedSection(".dynsym");
|
||||
|
||||
const uint8_t* dynsyms =
|
||||
GetOffset<ElfClass, uint8_t>(elf_header, dynsym_section->sh_offset);
|
||||
const uint8_t* dynstrs =
|
||||
GetOffset<ElfClass, uint8_t>(elf_header, dynstr_section->sh_offset);
|
||||
bool result =
|
||||
ELFSymbolsToModule(dynsyms,
|
||||
dynsym_section->sh_size,
|
||||
dynstrs,
|
||||
dynstr_section->sh_size,
|
||||
big_endian,
|
||||
ElfClass::kAddrSize,
|
||||
module);
|
||||
found_usable_info = found_usable_info || result;
|
||||
const uint8_t* dynsyms =
|
||||
GetOffset<ElfClass, uint8_t>(elf_header,
|
||||
dynsym_section->sh_offset);
|
||||
const uint8_t* dynstrs =
|
||||
GetOffset<ElfClass, uint8_t>(elf_header,
|
||||
dynstr_section->sh_offset);
|
||||
bool result =
|
||||
ELFSymbolsToModule(dynsyms,
|
||||
dynsym_section->sh_size,
|
||||
dynstrs,
|
||||
dynstr_section->sh_size,
|
||||
big_endian,
|
||||
ElfClass::kAddrSize,
|
||||
module);
|
||||
found_usable_info = found_usable_info || result;
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if some usable information was found, since
|
||||
|
|
@ -736,7 +745,7 @@ template<typename ElfClass>
|
|||
bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||
const string& obj_filename,
|
||||
const std::vector<string>& debug_dirs,
|
||||
bool cfi,
|
||||
SymbolData symbol_data,
|
||||
Module** out_module) {
|
||||
typedef typename ElfClass::Ehdr Ehdr;
|
||||
typedef typename ElfClass::Shdr Shdr;
|
||||
|
|
@ -770,7 +779,8 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
|||
LoadSymbolsInfo<ElfClass> info(debug_dirs);
|
||||
scoped_ptr<Module> module(new Module(name, os, architecture, id));
|
||||
if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header,
|
||||
!debug_dirs.empty(), &info, module.get())) {
|
||||
!debug_dirs.empty(), &info,
|
||||
symbol_data, module.get())) {
|
||||
const string debuglink_file = info.debuglink_file();
|
||||
if (debuglink_file.empty())
|
||||
return false;
|
||||
|
|
@ -808,7 +818,8 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
|||
}
|
||||
|
||||
if (!LoadSymbols<ElfClass>(debuglink_file, debug_big_endian,
|
||||
debug_elf_header, false, &info, module.get())) {
|
||||
debug_elf_header, false, &info,
|
||||
symbol_data, module.get())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -825,7 +836,7 @@ namespace google_breakpad {
|
|||
bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||
const string& obj_filename,
|
||||
const std::vector<string>& debug_dirs,
|
||||
bool cfi,
|
||||
SymbolData symbol_data,
|
||||
Module** module) {
|
||||
|
||||
if (!IsValidElf(obj_file)) {
|
||||
|
|
@ -837,12 +848,12 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
|||
if (elfclass == ELFCLASS32) {
|
||||
return ReadSymbolDataElfClass<ElfClass32>(
|
||||
reinterpret_cast<const Elf32_Ehdr*>(obj_file), obj_filename, debug_dirs,
|
||||
cfi, module);
|
||||
symbol_data, module);
|
||||
}
|
||||
if (elfclass == ELFCLASS64) {
|
||||
return ReadSymbolDataElfClass<ElfClass64>(
|
||||
reinterpret_cast<const Elf64_Ehdr*>(obj_file), obj_filename, debug_dirs,
|
||||
cfi, module);
|
||||
symbol_data, module);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -850,20 +861,20 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
|||
|
||||
bool WriteSymbolFile(const string &obj_file,
|
||||
const std::vector<string>& debug_dirs,
|
||||
bool cfi,
|
||||
SymbolData symbol_data,
|
||||
std::ostream &sym_stream) {
|
||||
Module* module;
|
||||
if (!ReadSymbolData(obj_file, debug_dirs, cfi, &module))
|
||||
if (!ReadSymbolData(obj_file, debug_dirs, symbol_data, &module))
|
||||
return false;
|
||||
|
||||
bool result = module->Write(sym_stream, cfi);
|
||||
bool result = module->Write(sym_stream, symbol_data);
|
||||
delete module;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ReadSymbolData(const string& obj_file,
|
||||
const std::vector<string>& debug_dirs,
|
||||
bool cfi,
|
||||
SymbolData symbol_data,
|
||||
Module** module) {
|
||||
MmapWrapper map_wrapper;
|
||||
void* elf_header = NULL;
|
||||
|
|
@ -871,7 +882,7 @@ bool ReadSymbolData(const string& obj_file,
|
|||
return false;
|
||||
|
||||
return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header),
|
||||
obj_file, debug_dirs, cfi, module);
|
||||
obj_file, debug_dirs, symbol_data, module);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/symbol_data.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
|
@ -50,10 +51,10 @@ class Module;
|
|||
// file format.
|
||||
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
|
||||
// then look for the debug file in DEBUG_DIRS.
|
||||
// If CFI is set to false, then omit the CFI section.
|
||||
// SYMBOL_DATA allows limiting the type of symbol data written.
|
||||
bool WriteSymbolFile(const string &obj_file,
|
||||
const std::vector<string>& debug_dirs,
|
||||
bool cfi,
|
||||
SymbolData symbol_data,
|
||||
std::ostream &sym_stream);
|
||||
|
||||
// As above, but simply return the debugging information in MODULE
|
||||
|
|
@ -61,7 +62,7 @@ bool WriteSymbolFile(const string &obj_file,
|
|||
// Module object and must delete it when finished.
|
||||
bool ReadSymbolData(const string& obj_file,
|
||||
const std::vector<string>& debug_dirs,
|
||||
bool cfi,
|
||||
SymbolData symbol_data,
|
||||
Module** module);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace google_breakpad {
|
|||
bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||
const string& obj_filename,
|
||||
const std::vector<string>& debug_dir,
|
||||
bool cfi,
|
||||
SymbolData symbol_data,
|
||||
Module** module);
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ TEST_F(DumpSymbols, Invalid) {
|
|||
EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
|
||||
"foo",
|
||||
vector<string>(),
|
||||
true,
|
||||
ALL_SYMBOL_DATA,
|
||||
&module));
|
||||
}
|
||||
|
||||
|
|
@ -118,11 +118,11 @@ TEST_F(DumpSymbols, SimplePublic32) {
|
|||
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
||||
"foo",
|
||||
vector<string>(),
|
||||
true,
|
||||
ALL_SYMBOL_DATA,
|
||||
&module));
|
||||
|
||||
stringstream s;
|
||||
module->Write(s, true);
|
||||
module->Write(s, ALL_SYMBOL_DATA);
|
||||
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
|
||||
"PUBLIC 1000 0 superfunc\n",
|
||||
s.str());
|
||||
|
|
@ -157,11 +157,11 @@ TEST_F(DumpSymbols, SimplePublic64) {
|
|||
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
||||
"foo",
|
||||
vector<string>(),
|
||||
true,
|
||||
ALL_SYMBOL_DATA,
|
||||
&module));
|
||||
|
||||
stringstream s;
|
||||
module->Write(s, true);
|
||||
module->Write(s, ALL_SYMBOL_DATA);
|
||||
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
|
||||
"PUBLIC 1000 0 superfunc\n",
|
||||
s.str());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue