mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-01-10 23:25:27 +00: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
|
@ -515,6 +515,7 @@ bool LoadSymbols(const string& obj_file,
|
||||||
const typename ElfClass::Ehdr* elf_header,
|
const typename ElfClass::Ehdr* elf_header,
|
||||||
const bool read_gnu_debug_link,
|
const bool read_gnu_debug_link,
|
||||||
LoadSymbolsInfo<ElfClass>* info,
|
LoadSymbolsInfo<ElfClass>* info,
|
||||||
|
SymbolData symbol_data,
|
||||||
Module* module) {
|
Module* module) {
|
||||||
typedef typename ElfClass::Addr Addr;
|
typedef typename ElfClass::Addr Addr;
|
||||||
typedef typename ElfClass::Phdr Phdr;
|
typedef typename ElfClass::Phdr Phdr;
|
||||||
|
@ -535,81 +536,85 @@ bool LoadSymbols(const string& obj_file,
|
||||||
bool found_debug_info_section = false;
|
bool found_debug_info_section = false;
|
||||||
bool found_usable_info = false;
|
bool found_usable_info = false;
|
||||||
|
|
||||||
// Look for STABS debugging information, and load it if present.
|
if (symbol_data != ONLY_CFI) {
|
||||||
const Shdr* stab_section =
|
// Look for STABS debugging information, and load it if present.
|
||||||
|
const Shdr* stab_section =
|
||||||
FindElfSectionByName<ElfClass>(".stab", SHT_PROGBITS,
|
FindElfSectionByName<ElfClass>(".stab", SHT_PROGBITS,
|
||||||
sections, names, names_end,
|
sections, names, names_end,
|
||||||
elf_header->e_shnum);
|
elf_header->e_shnum);
|
||||||
if (stab_section) {
|
if (stab_section) {
|
||||||
const Shdr* stabstr_section = stab_section->sh_link + sections;
|
const Shdr* stabstr_section = stab_section->sh_link + sections;
|
||||||
if (stabstr_section) {
|
if (stabstr_section) {
|
||||||
found_debug_info_section = true;
|
found_debug_info_section = true;
|
||||||
found_usable_info = true;
|
found_usable_info = true;
|
||||||
info->LoadedSection(".stab");
|
info->LoadedSection(".stab");
|
||||||
if (!LoadStabs<ElfClass>(elf_header, stab_section, stabstr_section,
|
if (!LoadStabs<ElfClass>(elf_header, stab_section, stabstr_section,
|
||||||
big_endian, module)) {
|
big_endian, module)) {
|
||||||
fprintf(stderr, "%s: \".stab\" section found, but failed to load STABS"
|
fprintf(stderr, "%s: \".stab\" section found, but failed to load"
|
||||||
" debugging information\n", obj_file.c_str());
|
" STABS debugging information\n", obj_file.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Look for DWARF debugging information, and load it if present.
|
// Look for DWARF debugging information, and load it if present.
|
||||||
const Shdr* dwarf_section =
|
const Shdr* dwarf_section =
|
||||||
FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
|
FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
|
||||||
sections, names, names_end,
|
sections, names, names_end,
|
||||||
elf_header->e_shnum);
|
elf_header->e_shnum);
|
||||||
if (dwarf_section) {
|
if (dwarf_section) {
|
||||||
found_debug_info_section = true;
|
found_debug_info_section = true;
|
||||||
found_usable_info = true;
|
found_usable_info = true;
|
||||||
info->LoadedSection(".debug_info");
|
info->LoadedSection(".debug_info");
|
||||||
if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian, module))
|
if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian, module))
|
||||||
fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
|
fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
|
||||||
"DWARF debugging information\n", obj_file.c_str());
|
"DWARF debugging information\n", obj_file.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dwarf Call Frame Information (CFI) is actually independent from
|
if (symbol_data != NO_CFI) {
|
||||||
// the other DWARF debugging information, and can be used alone.
|
// Dwarf Call Frame Information (CFI) is actually independent from
|
||||||
const Shdr* dwarf_cfi_section =
|
// the other DWARF debugging information, and can be used alone.
|
||||||
FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS,
|
const Shdr* dwarf_cfi_section =
|
||||||
sections, names, names_end,
|
FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS,
|
||||||
elf_header->e_shnum);
|
sections, names, names_end,
|
||||||
if (dwarf_cfi_section) {
|
elf_header->e_shnum);
|
||||||
// Ignore the return value of this function; even without call frame
|
if (dwarf_cfi_section) {
|
||||||
// information, the other debugging information could be perfectly
|
// Ignore the return value of this function; even without call frame
|
||||||
// useful.
|
// information, the other debugging information could be perfectly
|
||||||
info->LoadedSection(".debug_frame");
|
// useful.
|
||||||
bool result =
|
info->LoadedSection(".debug_frame");
|
||||||
LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".debug_frame",
|
bool result =
|
||||||
dwarf_cfi_section, false, 0, 0, big_endian,
|
LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".debug_frame",
|
||||||
module);
|
dwarf_cfi_section, false, 0, 0, big_endian,
|
||||||
found_usable_info = found_usable_info || result;
|
module);
|
||||||
}
|
found_usable_info = found_usable_info || result;
|
||||||
|
}
|
||||||
|
|
||||||
// Linux C++ exception handling information can also provide
|
// Linux C++ exception handling information can also provide
|
||||||
// unwinding data.
|
// unwinding data.
|
||||||
const Shdr* eh_frame_section =
|
const Shdr* eh_frame_section =
|
||||||
FindElfSectionByName<ElfClass>(".eh_frame", SHT_PROGBITS,
|
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,
|
|
||||||
sections, names, names_end,
|
sections, names, names_end,
|
||||||
elf_header->e_shnum);
|
elf_header->e_shnum);
|
||||||
const Shdr* text_section =
|
if (eh_frame_section) {
|
||||||
FindElfSectionByName<ElfClass>(".text", SHT_PROGBITS,
|
// Pointers in .eh_frame data may be relative to the base addresses of
|
||||||
sections, names, names_end,
|
// certain sections. Provide those sections if present.
|
||||||
elf_header->e_shnum);
|
const Shdr* got_section =
|
||||||
info->LoadedSection(".eh_frame");
|
FindElfSectionByName<ElfClass>(".got", SHT_PROGBITS,
|
||||||
// As above, ignore the return value of this function.
|
sections, names, names_end,
|
||||||
bool result =
|
elf_header->e_shnum);
|
||||||
LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".eh_frame",
|
const Shdr* text_section =
|
||||||
eh_frame_section, true,
|
FindElfSectionByName<ElfClass>(".text", SHT_PROGBITS,
|
||||||
got_section, text_section, big_endian, module);
|
sections, names, names_end,
|
||||||
found_usable_info = found_usable_info || result;
|
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) {
|
if (!found_debug_info_section) {
|
||||||
|
@ -642,32 +647,36 @@ bool LoadSymbols(const string& obj_file,
|
||||||
obj_file.c_str());
|
obj_file.c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The caller doesn't want to consult .gnu_debuglink.
|
if (symbol_data != ONLY_CFI) {
|
||||||
// See if there are export symbols available.
|
// The caller doesn't want to consult .gnu_debuglink.
|
||||||
const Shdr* dynsym_section =
|
// See if there are export symbols available.
|
||||||
|
const Shdr* dynsym_section =
|
||||||
FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
|
FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
|
||||||
sections, names, names_end,
|
sections, names, names_end,
|
||||||
elf_header->e_shnum);
|
elf_header->e_shnum);
|
||||||
const Shdr* dynstr_section =
|
const Shdr* dynstr_section =
|
||||||
FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
|
FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
|
||||||
sections, names, names_end,
|
sections, names, names_end,
|
||||||
elf_header->e_shnum);
|
elf_header->e_shnum);
|
||||||
if (dynsym_section && dynstr_section) {
|
if (dynsym_section && dynstr_section) {
|
||||||
info->LoadedSection(".dynsym");
|
info->LoadedSection(".dynsym");
|
||||||
|
|
||||||
const uint8_t* dynsyms =
|
const uint8_t* dynsyms =
|
||||||
GetOffset<ElfClass, uint8_t>(elf_header, dynsym_section->sh_offset);
|
GetOffset<ElfClass, uint8_t>(elf_header,
|
||||||
const uint8_t* dynstrs =
|
dynsym_section->sh_offset);
|
||||||
GetOffset<ElfClass, uint8_t>(elf_header, dynstr_section->sh_offset);
|
const uint8_t* dynstrs =
|
||||||
bool result =
|
GetOffset<ElfClass, uint8_t>(elf_header,
|
||||||
ELFSymbolsToModule(dynsyms,
|
dynstr_section->sh_offset);
|
||||||
dynsym_section->sh_size,
|
bool result =
|
||||||
dynstrs,
|
ELFSymbolsToModule(dynsyms,
|
||||||
dynstr_section->sh_size,
|
dynsym_section->sh_size,
|
||||||
big_endian,
|
dynstrs,
|
||||||
ElfClass::kAddrSize,
|
dynstr_section->sh_size,
|
||||||
module);
|
big_endian,
|
||||||
found_usable_info = found_usable_info || result;
|
ElfClass::kAddrSize,
|
||||||
|
module);
|
||||||
|
found_usable_info = found_usable_info || result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if some usable information was found, since
|
// Return true if some usable information was found, since
|
||||||
|
@ -736,7 +745,7 @@ template<typename ElfClass>
|
||||||
bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||||
const string& obj_filename,
|
const string& obj_filename,
|
||||||
const std::vector<string>& debug_dirs,
|
const std::vector<string>& debug_dirs,
|
||||||
bool cfi,
|
SymbolData symbol_data,
|
||||||
Module** out_module) {
|
Module** out_module) {
|
||||||
typedef typename ElfClass::Ehdr Ehdr;
|
typedef typename ElfClass::Ehdr Ehdr;
|
||||||
typedef typename ElfClass::Shdr Shdr;
|
typedef typename ElfClass::Shdr Shdr;
|
||||||
|
@ -770,7 +779,8 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||||
LoadSymbolsInfo<ElfClass> info(debug_dirs);
|
LoadSymbolsInfo<ElfClass> info(debug_dirs);
|
||||||
scoped_ptr<Module> module(new Module(name, os, architecture, id));
|
scoped_ptr<Module> module(new Module(name, os, architecture, id));
|
||||||
if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header,
|
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();
|
const string debuglink_file = info.debuglink_file();
|
||||||
if (debuglink_file.empty())
|
if (debuglink_file.empty())
|
||||||
return false;
|
return false;
|
||||||
|
@ -808,7 +818,8 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LoadSymbols<ElfClass>(debuglink_file, debug_big_endian,
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -825,7 +836,7 @@ namespace google_breakpad {
|
||||||
bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||||
const string& obj_filename,
|
const string& obj_filename,
|
||||||
const std::vector<string>& debug_dirs,
|
const std::vector<string>& debug_dirs,
|
||||||
bool cfi,
|
SymbolData symbol_data,
|
||||||
Module** module) {
|
Module** module) {
|
||||||
|
|
||||||
if (!IsValidElf(obj_file)) {
|
if (!IsValidElf(obj_file)) {
|
||||||
|
@ -837,12 +848,12 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||||
if (elfclass == ELFCLASS32) {
|
if (elfclass == ELFCLASS32) {
|
||||||
return ReadSymbolDataElfClass<ElfClass32>(
|
return ReadSymbolDataElfClass<ElfClass32>(
|
||||||
reinterpret_cast<const Elf32_Ehdr*>(obj_file), obj_filename, debug_dirs,
|
reinterpret_cast<const Elf32_Ehdr*>(obj_file), obj_filename, debug_dirs,
|
||||||
cfi, module);
|
symbol_data, module);
|
||||||
}
|
}
|
||||||
if (elfclass == ELFCLASS64) {
|
if (elfclass == ELFCLASS64) {
|
||||||
return ReadSymbolDataElfClass<ElfClass64>(
|
return ReadSymbolDataElfClass<ElfClass64>(
|
||||||
reinterpret_cast<const Elf64_Ehdr*>(obj_file), obj_filename, debug_dirs,
|
reinterpret_cast<const Elf64_Ehdr*>(obj_file), obj_filename, debug_dirs,
|
||||||
cfi, module);
|
symbol_data, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -850,20 +861,20 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||||
|
|
||||||
bool WriteSymbolFile(const string &obj_file,
|
bool WriteSymbolFile(const string &obj_file,
|
||||||
const std::vector<string>& debug_dirs,
|
const std::vector<string>& debug_dirs,
|
||||||
bool cfi,
|
SymbolData symbol_data,
|
||||||
std::ostream &sym_stream) {
|
std::ostream &sym_stream) {
|
||||||
Module* module;
|
Module* module;
|
||||||
if (!ReadSymbolData(obj_file, debug_dirs, cfi, &module))
|
if (!ReadSymbolData(obj_file, debug_dirs, symbol_data, &module))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool result = module->Write(sym_stream, cfi);
|
bool result = module->Write(sym_stream, symbol_data);
|
||||||
delete module;
|
delete module;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadSymbolData(const string& obj_file,
|
bool ReadSymbolData(const string& obj_file,
|
||||||
const std::vector<string>& debug_dirs,
|
const std::vector<string>& debug_dirs,
|
||||||
bool cfi,
|
SymbolData symbol_data,
|
||||||
Module** module) {
|
Module** module) {
|
||||||
MmapWrapper map_wrapper;
|
MmapWrapper map_wrapper;
|
||||||
void* elf_header = NULL;
|
void* elf_header = NULL;
|
||||||
|
@ -871,7 +882,7 @@ bool ReadSymbolData(const string& obj_file,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header),
|
return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header),
|
||||||
obj_file, debug_dirs, cfi, module);
|
obj_file, debug_dirs, symbol_data, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/symbol_data.h"
|
||||||
#include "common/using_std_string.h"
|
#include "common/using_std_string.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
@ -50,10 +51,10 @@ class Module;
|
||||||
// file format.
|
// file format.
|
||||||
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
|
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
|
||||||
// then look for the debug file in DEBUG_DIRS.
|
// 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,
|
bool WriteSymbolFile(const string &obj_file,
|
||||||
const std::vector<string>& debug_dirs,
|
const std::vector<string>& debug_dirs,
|
||||||
bool cfi,
|
SymbolData symbol_data,
|
||||||
std::ostream &sym_stream);
|
std::ostream &sym_stream);
|
||||||
|
|
||||||
// As above, but simply return the debugging information in MODULE
|
// 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.
|
// Module object and must delete it when finished.
|
||||||
bool ReadSymbolData(const string& obj_file,
|
bool ReadSymbolData(const string& obj_file,
|
||||||
const std::vector<string>& debug_dirs,
|
const std::vector<string>& debug_dirs,
|
||||||
bool cfi,
|
SymbolData symbol_data,
|
||||||
Module** module);
|
Module** module);
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -48,7 +48,7 @@ namespace google_breakpad {
|
||||||
bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||||
const string& obj_filename,
|
const string& obj_filename,
|
||||||
const std::vector<string>& debug_dir,
|
const std::vector<string>& debug_dir,
|
||||||
bool cfi,
|
SymbolData symbol_data,
|
||||||
Module** module);
|
Module** module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ TEST_F(DumpSymbols, Invalid) {
|
||||||
EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
|
EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
|
||||||
"foo",
|
"foo",
|
||||||
vector<string>(),
|
vector<string>(),
|
||||||
true,
|
ALL_SYMBOL_DATA,
|
||||||
&module));
|
&module));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,11 +118,11 @@ TEST_F(DumpSymbols, SimplePublic32) {
|
||||||
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
||||||
"foo",
|
"foo",
|
||||||
vector<string>(),
|
vector<string>(),
|
||||||
true,
|
ALL_SYMBOL_DATA,
|
||||||
&module));
|
&module));
|
||||||
|
|
||||||
stringstream s;
|
stringstream s;
|
||||||
module->Write(s, true);
|
module->Write(s, ALL_SYMBOL_DATA);
|
||||||
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
|
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
|
||||||
"PUBLIC 1000 0 superfunc\n",
|
"PUBLIC 1000 0 superfunc\n",
|
||||||
s.str());
|
s.str());
|
||||||
|
@ -157,11 +157,11 @@ TEST_F(DumpSymbols, SimplePublic64) {
|
||||||
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
||||||
"foo",
|
"foo",
|
||||||
vector<string>(),
|
vector<string>(),
|
||||||
true,
|
ALL_SYMBOL_DATA,
|
||||||
&module));
|
&module));
|
||||||
|
|
||||||
stringstream s;
|
stringstream s;
|
||||||
module->Write(s, true);
|
module->Write(s, ALL_SYMBOL_DATA);
|
||||||
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
|
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
|
||||||
"PUBLIC 1000 0 superfunc\n",
|
"PUBLIC 1000 0 superfunc\n",
|
||||||
s.str());
|
s.str());
|
||||||
|
|
|
@ -47,13 +47,15 @@
|
||||||
#include "common/byte_cursor.h"
|
#include "common/byte_cursor.h"
|
||||||
#include "common/mac/macho_reader.h"
|
#include "common/mac/macho_reader.h"
|
||||||
#include "common/module.h"
|
#include "common/module.h"
|
||||||
|
#include "common/symbol_data.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
class DumpSymbols {
|
class DumpSymbols {
|
||||||
public:
|
public:
|
||||||
DumpSymbols()
|
explicit DumpSymbols(SymbolData symbol_data)
|
||||||
: input_pathname_(),
|
: symbol_data_(symbol_data),
|
||||||
|
input_pathname_(),
|
||||||
object_filename_(),
|
object_filename_(),
|
||||||
contents_(),
|
contents_(),
|
||||||
selected_object_file_(),
|
selected_object_file_(),
|
||||||
|
@ -110,9 +112,9 @@ class DumpSymbols {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the selected object file's debugging information, and write it out to
|
// Read the selected object file's debugging information, and write it out to
|
||||||
// |stream|. Write the CFI section if |cfi| is true. Return true on success;
|
// |stream|. Return true on success; if an error occurs, report it and
|
||||||
// if an error occurs, report it and return false.
|
// return false.
|
||||||
bool WriteSymbolFile(std::ostream &stream, bool cfi);
|
bool WriteSymbolFile(std::ostream &stream);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Used internally.
|
// Used internally.
|
||||||
|
@ -139,6 +141,9 @@ class DumpSymbols {
|
||||||
const mach_o::Section §ion,
|
const mach_o::Section §ion,
|
||||||
bool eh_frame) const;
|
bool eh_frame) const;
|
||||||
|
|
||||||
|
// The selection of what type of symbol data to read/write.
|
||||||
|
const SymbolData symbol_data_;
|
||||||
|
|
||||||
// The name of the file or bundle whose symbols this will dump.
|
// The name of the file or bundle whose symbols this will dump.
|
||||||
// This is the path given to Read, for use in error messages.
|
// This is the path given to Read, for use in error messages.
|
||||||
NSString *input_pathname_;
|
NSString *input_pathname_;
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "common/module.h"
|
#include "common/module.h"
|
||||||
#include "common/stabs_reader.h"
|
#include "common/stabs_reader.h"
|
||||||
#include "common/stabs_to_module.h"
|
#include "common/stabs_to_module.h"
|
||||||
|
#include "common/symbol_data.h"
|
||||||
|
|
||||||
#ifndef CPU_TYPE_ARM
|
#ifndef CPU_TYPE_ARM
|
||||||
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
|
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
|
||||||
|
@ -370,8 +371,12 @@ class DumpSymbols::LoadCommandDumper:
|
||||||
// file, and adding data to MODULE.
|
// file, and adding data to MODULE.
|
||||||
LoadCommandDumper(const DumpSymbols &dumper,
|
LoadCommandDumper(const DumpSymbols &dumper,
|
||||||
google_breakpad::Module *module,
|
google_breakpad::Module *module,
|
||||||
const mach_o::Reader &reader)
|
const mach_o::Reader &reader,
|
||||||
: dumper_(dumper), module_(module), reader_(reader) { }
|
SymbolData symbol_data)
|
||||||
|
: dumper_(dumper),
|
||||||
|
module_(module),
|
||||||
|
reader_(reader),
|
||||||
|
symbol_data_(symbol_data) { }
|
||||||
|
|
||||||
bool SegmentCommand(const mach_o::Segment &segment);
|
bool SegmentCommand(const mach_o::Segment &segment);
|
||||||
bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
|
bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
|
||||||
|
@ -380,6 +385,7 @@ class DumpSymbols::LoadCommandDumper:
|
||||||
const DumpSymbols &dumper_;
|
const DumpSymbols &dumper_;
|
||||||
google_breakpad::Module *module_; // WEAK
|
google_breakpad::Module *module_; // WEAK
|
||||||
const mach_o::Reader &reader_;
|
const mach_o::Reader &reader_;
|
||||||
|
const SymbolData symbol_data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
|
bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
|
||||||
|
@ -387,7 +393,7 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
|
||||||
if (!reader_.MapSegmentSections(segment, §ion_map))
|
if (!reader_.MapSegmentSections(segment, §ion_map))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (segment.name == "__TEXT") {
|
if (segment.name == "__TEXT" && symbol_data_ != NO_CFI) {
|
||||||
module_->SetLoadAddress(segment.vmaddr);
|
module_->SetLoadAddress(segment.vmaddr);
|
||||||
mach_o::SectionMap::const_iterator eh_frame =
|
mach_o::SectionMap::const_iterator eh_frame =
|
||||||
section_map.find("__eh_frame");
|
section_map.find("__eh_frame");
|
||||||
|
@ -399,13 +405,17 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segment.name == "__DWARF") {
|
if (segment.name == "__DWARF") {
|
||||||
if (!dumper_.ReadDwarf(module_, reader_, section_map))
|
if (symbol_data_ != ONLY_CFI) {
|
||||||
return false;
|
if (!dumper_.ReadDwarf(module_, reader_, section_map))
|
||||||
mach_o::SectionMap::const_iterator debug_frame
|
return false;
|
||||||
= section_map.find("__debug_frame");
|
}
|
||||||
if (debug_frame != section_map.end()) {
|
if (symbol_data_ != NO_CFI) {
|
||||||
// If there is a problem reading this, don't treat it as a fatal error.
|
mach_o::SectionMap::const_iterator debug_frame
|
||||||
dumper_.ReadCFI(module_, reader_, debug_frame->second, false);
|
= section_map.find("__debug_frame");
|
||||||
|
if (debug_frame != section_map.end()) {
|
||||||
|
// If there is a problem reading this, don't treat it as a fatal error.
|
||||||
|
dumper_.ReadCFI(module_, reader_, debug_frame->second, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,7 +439,7 @@ bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
|
bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||||
// Select an object file, if SetArchitecture hasn't been called to set one
|
// Select an object file, if SetArchitecture hasn't been called to set one
|
||||||
// explicitly.
|
// explicitly.
|
||||||
if (!selected_object_file_) {
|
if (!selected_object_file_) {
|
||||||
|
@ -494,11 +504,11 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Walk its load commands, and deal with whatever is there.
|
// Walk its load commands, and deal with whatever is there.
|
||||||
LoadCommandDumper load_command_dumper(*this, &module, reader);
|
LoadCommandDumper load_command_dumper(*this, &module, reader, symbol_data_);
|
||||||
if (!reader.WalkLoadCommands(&load_command_dumper))
|
if (!reader.WalkLoadCommands(&load_command_dumper))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return module.Write(stream, cfi);
|
return module.Write(stream, symbol_data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -204,62 +204,62 @@ bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
|
||||||
return stream.good();
|
return stream.good();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Module::Write(std::ostream &stream, bool cfi) {
|
bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
|
||||||
stream << "MODULE " << os_ << " " << architecture_ << " "
|
stream << "MODULE " << os_ << " " << architecture_ << " "
|
||||||
<< id_ << " " << name_ << endl;
|
<< id_ << " " << name_ << endl;
|
||||||
if (!stream.good())
|
if (!stream.good())
|
||||||
return ReportError();
|
return ReportError();
|
||||||
|
|
||||||
AssignSourceIds();
|
if (symbol_data != ONLY_CFI) {
|
||||||
|
AssignSourceIds();
|
||||||
|
|
||||||
// Write out files.
|
// Write out files.
|
||||||
for (FileByNameMap::iterator file_it = files_.begin();
|
for (FileByNameMap::iterator file_it = files_.begin();
|
||||||
file_it != files_.end(); ++file_it) {
|
file_it != files_.end(); ++file_it) {
|
||||||
File *file = file_it->second;
|
File *file = file_it->second;
|
||||||
if (file->source_id >= 0) {
|
if (file->source_id >= 0) {
|
||||||
stream << "FILE " << file->source_id << " " << file->name << endl;
|
stream << "FILE " << file->source_id << " " << file->name << endl;
|
||||||
|
if (!stream.good())
|
||||||
|
return ReportError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write out functions and their lines.
|
||||||
|
for (FunctionSet::const_iterator func_it = functions_.begin();
|
||||||
|
func_it != functions_.end(); ++func_it) {
|
||||||
|
Function *func = *func_it;
|
||||||
|
stream << "FUNC " << hex
|
||||||
|
<< (func->address - load_address_) << " "
|
||||||
|
<< func->size << " "
|
||||||
|
<< func->parameter_size << " "
|
||||||
|
<< func->name << dec << endl;
|
||||||
if (!stream.good())
|
if (!stream.good())
|
||||||
return ReportError();
|
return ReportError();
|
||||||
|
|
||||||
|
for (vector<Line>::iterator line_it = func->lines.begin();
|
||||||
|
line_it != func->lines.end(); ++line_it) {
|
||||||
|
stream << hex
|
||||||
|
<< (line_it->address - load_address_) << " "
|
||||||
|
<< line_it->size << " "
|
||||||
|
<< dec
|
||||||
|
<< line_it->number << " "
|
||||||
|
<< line_it->file->source_id << endl;
|
||||||
|
if (!stream.good())
|
||||||
|
return ReportError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write out 'PUBLIC' records.
|
||||||
|
for (ExternSet::const_iterator extern_it = externs_.begin();
|
||||||
|
extern_it != externs_.end(); ++extern_it) {
|
||||||
|
Extern *ext = *extern_it;
|
||||||
|
stream << "PUBLIC " << hex
|
||||||
|
<< (ext->address - load_address_) << " 0 "
|
||||||
|
<< ext->name << dec << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out functions and their lines.
|
if (symbol_data != NO_CFI) {
|
||||||
for (FunctionSet::const_iterator func_it = functions_.begin();
|
|
||||||
func_it != functions_.end(); ++func_it) {
|
|
||||||
Function *func = *func_it;
|
|
||||||
stream << "FUNC " << hex
|
|
||||||
<< (func->address - load_address_) << " "
|
|
||||||
<< func->size << " "
|
|
||||||
<< func->parameter_size << " "
|
|
||||||
<< func->name << dec << endl;
|
|
||||||
|
|
||||||
if (!stream.good())
|
|
||||||
return ReportError();
|
|
||||||
for (vector<Line>::iterator line_it = func->lines.begin();
|
|
||||||
line_it != func->lines.end(); ++line_it) {
|
|
||||||
stream << hex
|
|
||||||
<< (line_it->address - load_address_) << " "
|
|
||||||
<< line_it->size << " "
|
|
||||||
<< dec
|
|
||||||
<< line_it->number << " "
|
|
||||||
<< line_it->file->source_id << endl;
|
|
||||||
if (!stream.good())
|
|
||||||
return ReportError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out 'PUBLIC' records.
|
|
||||||
for (ExternSet::const_iterator extern_it = externs_.begin();
|
|
||||||
extern_it != externs_.end(); ++extern_it) {
|
|
||||||
Extern *ext = *extern_it;
|
|
||||||
stream << "PUBLIC " << hex
|
|
||||||
<< (ext->address - load_address_) << " 0 "
|
|
||||||
<< ext->name << dec << endl;
|
|
||||||
if (!stream.good())
|
|
||||||
return ReportError();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cfi) {
|
|
||||||
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
|
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
|
||||||
vector<StackFrameEntry *>::const_iterator frame_it;
|
vector<StackFrameEntry *>::const_iterator frame_it;
|
||||||
for (frame_it = stack_frame_entries_.begin();
|
for (frame_it = stack_frame_entries_.begin();
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/symbol_data.h"
|
||||||
#include "common/using_std_string.h"
|
#include "common/using_std_string.h"
|
||||||
#include "google_breakpad/common/breakpad_types.h"
|
#include "google_breakpad/common/breakpad_types.h"
|
||||||
|
|
||||||
|
@ -259,13 +260,15 @@ class Module {
|
||||||
// breakpad symbol format. Return true if all goes well, or false if
|
// breakpad symbol format. Return true if all goes well, or false if
|
||||||
// an error occurs. This method writes out:
|
// an error occurs. This method writes out:
|
||||||
// - a header based on the values given to the constructor,
|
// - a header based on the values given to the constructor,
|
||||||
|
// If symbol_data is not ONLY_CFI then:
|
||||||
// - the source files added via FindFile,
|
// - the source files added via FindFile,
|
||||||
// - the functions added via AddFunctions, each with its lines,
|
// - the functions added via AddFunctions, each with its lines,
|
||||||
// - all public records,
|
// - all public records,
|
||||||
// - and if CFI is true, all CFI records.
|
// If symbol_data is not NO_CFI then:
|
||||||
|
// - all CFI records.
|
||||||
// Addresses in the output are all relative to the load address
|
// Addresses in the output are all relative to the load address
|
||||||
// established by SetLoadAddress.
|
// established by SetLoadAddress.
|
||||||
bool Write(std::ostream &stream, bool cfi);
|
bool Write(std::ostream &stream, SymbolData symbol_data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Report an error that has occurred writing the symbol file, using
|
// Report an error that has occurred writing the symbol file, using
|
||||||
|
|
|
@ -70,7 +70,7 @@ static Module::Function *generate_duplicate_function(const string &name) {
|
||||||
TEST(Write, Header) {
|
TEST(Write, Header) {
|
||||||
stringstream s;
|
stringstream s;
|
||||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
|
||||||
contents.c_str());
|
contents.c_str());
|
||||||
|
@ -91,7 +91,7 @@ TEST(Write, OneLineFunc) {
|
||||||
function->lines.push_back(line);
|
function->lines.push_back(line);
|
||||||
m.AddFunction(function);
|
m.AddFunction(function);
|
||||||
|
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FILE 0 file_name.cc\n"
|
"FILE 0 file_name.cc\n"
|
||||||
|
@ -141,7 +141,7 @@ TEST(Write, RelativeLoadAddress) {
|
||||||
// the module must work fine.
|
// the module must work fine.
|
||||||
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
||||||
|
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FILE 0 filename-a.cc\n"
|
"FILE 0 filename-a.cc\n"
|
||||||
|
@ -197,7 +197,7 @@ TEST(Write, OmitUnusedFiles) {
|
||||||
EXPECT_NE(-1, vec[2]->source_id);
|
EXPECT_NE(-1, vec[2]->source_id);
|
||||||
|
|
||||||
stringstream s;
|
stringstream s;
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FILE 0 filename1\n"
|
"FILE 0 filename1\n"
|
||||||
|
@ -245,7 +245,7 @@ TEST(Write, NoCFI) {
|
||||||
// the module must work fine.
|
// the module must work fine.
|
||||||
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
||||||
|
|
||||||
m.Write(s, false);
|
m.Write(s, NO_CFI);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FILE 0 filename.cc\n"
|
"FILE 0 filename.cc\n"
|
||||||
|
@ -279,7 +279,7 @@ TEST(Construct, AddFunctions) {
|
||||||
|
|
||||||
m.AddFunctions(vec.begin(), vec.end());
|
m.AddFunctions(vec.begin(), vec.end());
|
||||||
|
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
|
"FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
|
||||||
|
@ -331,7 +331,7 @@ TEST(Construct, AddFrames) {
|
||||||
m.AddStackFrameEntry(entry3);
|
m.AddStackFrameEntry(entry3);
|
||||||
|
|
||||||
// Check that Write writes STACK CFI records properly.
|
// Check that Write writes STACK CFI records properly.
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
|
"STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
|
||||||
|
@ -407,7 +407,7 @@ TEST(Construct, DuplicateFunctions) {
|
||||||
m.AddFunction(function1);
|
m.AddFunction(function1);
|
||||||
m.AddFunction(function2);
|
m.AddFunction(function2);
|
||||||
|
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
||||||
|
@ -426,7 +426,7 @@ TEST(Construct, FunctionsWithSameAddress) {
|
||||||
m.AddFunction(function1);
|
m.AddFunction(function1);
|
||||||
m.AddFunction(function2);
|
m.AddFunction(function2);
|
||||||
|
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
||||||
|
@ -453,7 +453,7 @@ TEST(Construct, Externs) {
|
||||||
m.AddExtern(extern1);
|
m.AddExtern(extern1);
|
||||||
m.AddExtern(extern2);
|
m.AddExtern(extern2);
|
||||||
|
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
|
|
||||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||||
|
@ -480,7 +480,7 @@ TEST(Construct, DuplicateExterns) {
|
||||||
m.AddExtern(extern1);
|
m.AddExtern(extern1);
|
||||||
m.AddExtern(extern2);
|
m.AddExtern(extern2);
|
||||||
|
|
||||||
m.Write(s, true);
|
m.Write(s, ALL_SYMBOL_DATA);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
|
|
||||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||||
|
|
42
src/common/symbol_data.h
Normal file
42
src/common/symbol_data.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// -*- mode: c++ -*-
|
||||||
|
|
||||||
|
// Copyright (c) 2013 Google Inc.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef COMMON_SYMBOL_DATA_H_
|
||||||
|
#define COMMON_SYMBOL_DATA_H_
|
||||||
|
|
||||||
|
// Control what data is used from the symbol file.
|
||||||
|
enum SymbolData {
|
||||||
|
ALL_SYMBOL_DATA,
|
||||||
|
NO_CFI,
|
||||||
|
ONLY_CFI
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COMMON_SYMBOL_DATA_H_
|
|
@ -68,7 +68,8 @@ int main(int argc, char **argv) {
|
||||||
debug_dirs.push_back(argv[debug_dir_index]);
|
debug_dirs.push_back(argv[debug_dir_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WriteSymbolFile(binary, debug_dirs, cfi, std::cout)) {
|
SymbolData symbol_data = cfi ? ALL_SYMBOL_DATA : NO_CFI;
|
||||||
|
if (!WriteSymbolFile(binary, debug_dirs, symbol_data, std::cout)) {
|
||||||
fprintf(stderr, "Failed to write symbol file.\n");
|
fprintf(stderr, "Failed to write symbol file.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ struct Options {
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
static bool Start(const Options &options) {
|
static bool Start(const Options &options) {
|
||||||
DumpSymbols dump_symbols;
|
DumpSymbols dump_symbols(options.cfi ? ALL_SYMBOL_DATA : NO_CFI);
|
||||||
|
|
||||||
if (!dump_symbols.Read(options.srcPath))
|
if (!dump_symbols.Read(options.srcPath))
|
||||||
return false;
|
return false;
|
||||||
|
@ -86,7 +86,7 @@ static bool Start(const Options &options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dump_symbols.WriteSymbolFile(std::cout, options.cfi);
|
return dump_symbols.WriteSymbolFile(std::cout);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
Loading…
Reference in a new issue