aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorted.mielczarek@gmail.com <ted.mielczarek@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2013-03-06 15:32:53 +0000
committerted.mielczarek@gmail.com <ted.mielczarek@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2013-03-06 15:32:53 +0000
commit983903ee0aef76f7a277ce09de6b12164eba8a32 (patch)
tree2156b673c7b77dc1cd056ce730d0995fb0f90f41
parentMinor Android fixup for symbol dumping code (diff)
downloadbreakpad-983903ee0aef76f7a277ce09de6b12164eba8a32.tar.xz
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
-rw-r--r--src/common/linux/dump_symbols.cc197
-rw-r--r--src/common/linux/dump_symbols.h7
-rw-r--r--src/common/linux/dump_symbols_unittest.cc12
-rw-r--r--src/common/mac/dump_syms.h15
-rw-r--r--src/common/mac/dump_syms.mm36
-rw-r--r--src/common/module.cc84
-rw-r--r--src/common/module.h7
-rw-r--r--src/common/module_unittest.cc22
-rw-r--r--src/common/symbol_data.h42
-rw-r--r--src/tools/linux/dump_syms/dump_syms.cc3
-rw-r--r--src/tools/mac/dump_syms/dump_syms_tool.mm4
11 files changed, 251 insertions, 178 deletions
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
index fed27b7a..f2d42660 100644
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -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());
- }
-
- // 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,
+ 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 (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);
- const Shdr* text_section =
- FindElfSectionByName<ElfClass>(".text", SHT_PROGBITS,
+ 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);
- 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");
-
- 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;
+ 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;
+ }
}
// 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
diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h
index 8765ffdb..f3c92cd5 100644
--- a/src/common/linux/dump_symbols.h
+++ b/src/common/linux/dump_symbols.h
@@ -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
diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc
index d48512f7..6f5aef2e 100644
--- a/src/common/linux/dump_symbols_unittest.cc
+++ b/src/common/linux/dump_symbols_unittest.cc
@@ -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());
diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
index 0e2f464d..af12b778 100644
--- a/src/common/mac/dump_syms.h
+++ b/src/common/mac/dump_syms.h
@@ -47,13 +47,15 @@
#include "common/byte_cursor.h"
#include "common/mac/macho_reader.h"
#include "common/module.h"
+#include "common/symbol_data.h"
namespace google_breakpad {
class DumpSymbols {
public:
- DumpSymbols()
- : input_pathname_(),
+ explicit DumpSymbols(SymbolData symbol_data)
+ : symbol_data_(symbol_data),
+ input_pathname_(),
object_filename_(),
contents_(),
selected_object_file_(),
@@ -110,9 +112,9 @@ class DumpSymbols {
}
// 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;
- // if an error occurs, report it and return false.
- bool WriteSymbolFile(std::ostream &stream, bool cfi);
+ // |stream|. Return true on success; if an error occurs, report it and
+ // return false.
+ bool WriteSymbolFile(std::ostream &stream);
private:
// Used internally.
@@ -139,6 +141,9 @@ class DumpSymbols {
const mach_o::Section &section,
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.
// This is the path given to Read, for use in error messages.
NSString *input_pathname_;
diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
index e26b05ea..f1aab426 100644
--- a/src/common/mac/dump_syms.mm
+++ b/src/common/mac/dump_syms.mm
@@ -55,6 +55,7 @@
#include "common/module.h"
#include "common/stabs_reader.h"
#include "common/stabs_to_module.h"
+#include "common/symbol_data.h"
#ifndef CPU_TYPE_ARM
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
@@ -370,8 +371,12 @@ class DumpSymbols::LoadCommandDumper:
// file, and adding data to MODULE.
LoadCommandDumper(const DumpSymbols &dumper,
google_breakpad::Module *module,
- const mach_o::Reader &reader)
- : dumper_(dumper), module_(module), reader_(reader) { }
+ const mach_o::Reader &reader,
+ SymbolData symbol_data)
+ : dumper_(dumper),
+ module_(module),
+ reader_(reader),
+ symbol_data_(symbol_data) { }
bool SegmentCommand(const mach_o::Segment &segment);
bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
@@ -380,6 +385,7 @@ class DumpSymbols::LoadCommandDumper:
const DumpSymbols &dumper_;
google_breakpad::Module *module_; // WEAK
const mach_o::Reader &reader_;
+ const SymbolData symbol_data_;
};
bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
@@ -387,7 +393,7 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
if (!reader_.MapSegmentSections(segment, &section_map))
return false;
- if (segment.name == "__TEXT") {
+ if (segment.name == "__TEXT" && symbol_data_ != NO_CFI) {
module_->SetLoadAddress(segment.vmaddr);
mach_o::SectionMap::const_iterator eh_frame =
section_map.find("__eh_frame");
@@ -399,13 +405,17 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
}
if (segment.name == "__DWARF") {
- if (!dumper_.ReadDwarf(module_, reader_, section_map))
- return false;
- mach_o::SectionMap::const_iterator debug_frame
- = 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);
+ if (symbol_data_ != ONLY_CFI) {
+ if (!dumper_.ReadDwarf(module_, reader_, section_map))
+ return false;
+ }
+ if (symbol_data_ != NO_CFI) {
+ mach_o::SectionMap::const_iterator debug_frame
+ = 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;
}
-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
// explicitly.
if (!selected_object_file_) {
@@ -494,11 +504,11 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
return false;
// 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))
return false;
- return module.Write(stream, cfi);
+ return module.Write(stream, symbol_data_);
}
} // namespace google_breakpad
diff --git a/src/common/module.cc b/src/common/module.cc
index 4e257d1d..2d2e4efc 100644
--- a/src/common/module.cc
+++ b/src/common/module.cc
@@ -204,62 +204,62 @@ bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
return stream.good();
}
-bool Module::Write(std::ostream &stream, bool cfi) {
+bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
stream << "MODULE " << os_ << " " << architecture_ << " "
<< id_ << " " << name_ << endl;
if (!stream.good())
return ReportError();
- AssignSourceIds();
+ if (symbol_data != ONLY_CFI) {
+ AssignSourceIds();
- // Write out files.
- for (FileByNameMap::iterator file_it = files_.begin();
- file_it != files_.end(); ++file_it) {
- File *file = file_it->second;
- if (file->source_id >= 0) {
- stream << "FILE " << file->source_id << " " << file->name << endl;
- if (!stream.good())
- return ReportError();
+ // Write out files.
+ for (FileByNameMap::iterator file_it = files_.begin();
+ file_it != files_.end(); ++file_it) {
+ File *file = file_it->second;
+ if (file->source_id >= 0) {
+ 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())
- 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;
+ // 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())
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();
+ // 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 (cfi) {
+ if (symbol_data != NO_CFI) {
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
vector<StackFrameEntry *>::const_iterator frame_it;
for (frame_it = stack_frame_entries_.begin();
diff --git a/src/common/module.h b/src/common/module.h
index cecab32f..398bc315 100644
--- a/src/common/module.h
+++ b/src/common/module.h
@@ -44,6 +44,7 @@
#include <string>
#include <vector>
+#include "common/symbol_data.h"
#include "common/using_std_string.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
// an error occurs. This method writes out:
// - 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 functions added via AddFunctions, each with its lines,
// - 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
// established by SetLoadAddress.
- bool Write(std::ostream &stream, bool cfi);
+ bool Write(std::ostream &stream, SymbolData symbol_data);
private:
// Report an error that has occurred writing the symbol file, using
diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
index 04dc4041..5c0c6975 100644
--- a/src/common/module_unittest.cc
+++ b/src/common/module_unittest.cc
@@ -70,7 +70,7 @@ static Module::Function *generate_duplicate_function(const string &name) {
TEST(Write, Header) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
contents.c_str());
@@ -91,7 +91,7 @@ TEST(Write, OneLineFunc) {
function->lines.push_back(line);
m.AddFunction(function);
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 file_name.cc\n"
@@ -141,7 +141,7 @@ TEST(Write, RelativeLoadAddress) {
// the module must work fine.
m.SetLoadAddress(0x2ab698b0b6407073LL);
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 filename-a.cc\n"
@@ -197,7 +197,7 @@ TEST(Write, OmitUnusedFiles) {
EXPECT_NE(-1, vec[2]->source_id);
stringstream s;
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 filename1\n"
@@ -245,7 +245,7 @@ TEST(Write, NoCFI) {
// the module must work fine.
m.SetLoadAddress(0x2ab698b0b6407073LL);
- m.Write(s, false);
+ m.Write(s, NO_CFI);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 filename.cc\n"
@@ -279,7 +279,7 @@ TEST(Construct, AddFunctions) {
m.AddFunctions(vec.begin(), vec.end());
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
@@ -331,7 +331,7 @@ TEST(Construct, AddFrames) {
m.AddStackFrameEntry(entry3);
// Check that Write writes STACK CFI records properly.
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
@@ -407,7 +407,7 @@ TEST(Construct, DuplicateFunctions) {
m.AddFunction(function1);
m.AddFunction(function2);
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
@@ -426,7 +426,7 @@ TEST(Construct, FunctionsWithSameAddress) {
m.AddFunction(function1);
m.AddFunction(function2);
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
@@ -453,7 +453,7 @@ TEST(Construct, Externs) {
m.AddExtern(extern1);
m.AddExtern(extern2);
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
@@ -480,7 +480,7 @@ TEST(Construct, DuplicateExterns) {
m.AddExtern(extern1);
m.AddExtern(extern2);
- m.Write(s, true);
+ m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
diff --git a/src/common/symbol_data.h b/src/common/symbol_data.h
new file mode 100644
index 00000000..2cf15a85
--- /dev/null
+++ b/src/common/symbol_data.h
@@ -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_
diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/dump_syms.cc
index aa504589..f58952ed 100644
--- a/src/tools/linux/dump_syms/dump_syms.cc
+++ b/src/tools/linux/dump_syms/dump_syms.cc
@@ -68,7 +68,8 @@ int main(int argc, char **argv) {
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");
return 1;
}
diff --git a/src/tools/mac/dump_syms/dump_syms_tool.mm b/src/tools/mac/dump_syms/dump_syms_tool.mm
index 14bbcbbd..68321db3 100644
--- a/src/tools/mac/dump_syms/dump_syms_tool.mm
+++ b/src/tools/mac/dump_syms/dump_syms_tool.mm
@@ -54,7 +54,7 @@ struct 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))
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);
}
//=============================================================================