mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-07-23 13:28:19 +00:00
Add an option to not handle DWARF inter-compilation unit references in Linux dump_syms.
This saves a lot of memory for dump_syms. Review URL: https://breakpad.appspot.com/565002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1163 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
ae3947e123
commit
f7566bd447
|
@ -91,7 +91,7 @@ struct DwarfCUToModule::Specification {
|
||||||
// An abstract origin -- base definition of an inline function.
|
// An abstract origin -- base definition of an inline function.
|
||||||
struct AbstractOrigin {
|
struct AbstractOrigin {
|
||||||
AbstractOrigin() : name() {}
|
AbstractOrigin() : name() {}
|
||||||
AbstractOrigin(const string& name) : name(name) {}
|
explicit AbstractOrigin(const string& name) : name(name) {}
|
||||||
|
|
||||||
string name;
|
string name;
|
||||||
};
|
};
|
||||||
|
@ -128,14 +128,43 @@ struct DwarfCUToModule::FilePrivate {
|
||||||
AbstractOriginByOffset origins;
|
AbstractOriginByOffset origins;
|
||||||
};
|
};
|
||||||
|
|
||||||
DwarfCUToModule::FileContext::FileContext(const string &filename_arg,
|
DwarfCUToModule::FileContext::FileContext(const string &filename,
|
||||||
Module *module_arg)
|
Module *module,
|
||||||
: filename(filename_arg), module(module_arg) {
|
bool handle_inter_cu_refs)
|
||||||
file_private = new FilePrivate();
|
: filename_(filename),
|
||||||
|
module_(module),
|
||||||
|
handle_inter_cu_refs_(handle_inter_cu_refs) {
|
||||||
|
file_private_ = new FilePrivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
DwarfCUToModule::FileContext::~FileContext() {
|
DwarfCUToModule::FileContext::~FileContext() {
|
||||||
delete file_private;
|
delete file_private_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DwarfCUToModule::FileContext::AddSectionToSectionMap(
|
||||||
|
const string& name, const char* contents, uint64 length) {
|
||||||
|
section_map_[name] = std::make_pair(contents, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DwarfCUToModule::FileContext::ClearSectionMapForTest() {
|
||||||
|
section_map_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const dwarf2reader::SectionMap&
|
||||||
|
DwarfCUToModule::FileContext::section_map() const {
|
||||||
|
return section_map_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DwarfCUToModule::FileContext::ClearSpecifications() {
|
||||||
|
if (!handle_inter_cu_refs_)
|
||||||
|
file_private_->specifications.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference(
|
||||||
|
uint64 offset, uint64 compilation_unit_start) const {
|
||||||
|
if (handle_inter_cu_refs_)
|
||||||
|
return false;
|
||||||
|
return offset < compilation_unit_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information global to the particular compilation unit we're
|
// Information global to the particular compilation unit we're
|
||||||
|
@ -146,10 +175,12 @@ struct DwarfCUToModule::CUContext {
|
||||||
: file_context(file_context_arg),
|
: file_context(file_context_arg),
|
||||||
reporter(reporter_arg),
|
reporter(reporter_arg),
|
||||||
language(Language::CPlusPlus) {}
|
language(Language::CPlusPlus) {}
|
||||||
|
|
||||||
~CUContext() {
|
~CUContext() {
|
||||||
for (vector<Module::Function *>::iterator it = functions.begin();
|
for (vector<Module::Function *>::iterator it = functions.begin();
|
||||||
it != functions.end(); it++)
|
it != functions.end(); ++it) {
|
||||||
delete *it;
|
delete *it;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// The DWARF-bearing file into which this CU was incorporated.
|
// The DWARF-bearing file into which this CU was incorporated.
|
||||||
|
@ -276,14 +307,19 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
|
||||||
uint64 data) {
|
uint64 data) {
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
case dwarf2reader::DW_AT_specification: {
|
case dwarf2reader::DW_AT_specification: {
|
||||||
|
FileContext *file_context = cu_context_->file_context;
|
||||||
|
if (file_context->IsUnhandledInterCUReference(
|
||||||
|
data, cu_context_->reporter->cu_offset())) {
|
||||||
|
cu_context_->reporter->UnhandledInterCUReference(offset_, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Find the Specification to which this attribute refers, and
|
// Find the Specification to which this attribute refers, and
|
||||||
// set specification_ appropriately. We could do more processing
|
// set specification_ appropriately. We could do more processing
|
||||||
// here, but it's better to leave the real work to our
|
// here, but it's better to leave the real work to our
|
||||||
// EndAttribute member function, at which point we know we have
|
// EndAttribute member function, at which point we know we have
|
||||||
// seen all the DIE's attributes.
|
// seen all the DIE's attributes.
|
||||||
FileContext *file_context = cu_context_->file_context;
|
SpecificationByOffset *specifications =
|
||||||
SpecificationByOffset *specifications
|
&file_context->file_private_->specifications;
|
||||||
= &file_context->file_private->specifications;
|
|
||||||
SpecificationByOffset::iterator spec = specifications->find(data);
|
SpecificationByOffset::iterator spec = specifications->find(data);
|
||||||
if (spec != specifications->end()) {
|
if (spec != specifications->end()) {
|
||||||
specification_ = &spec->second;
|
specification_ = &spec->second;
|
||||||
|
@ -303,7 +339,7 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
|
||||||
|
|
||||||
string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) {
|
string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) {
|
||||||
pair<set<string>::iterator, bool> result =
|
pair<set<string>::iterator, bool> result =
|
||||||
cu_context_->file_context->file_private->common_strings.insert(str);
|
cu_context_->file_context->file_private_->common_strings.insert(str);
|
||||||
return *result.first;
|
return *result.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,15 +401,14 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
|
||||||
// If this DIE was marked as a declaration, record its names in the
|
// If this DIE was marked as a declaration, record its names in the
|
||||||
// specification table.
|
// specification table.
|
||||||
if (declaration_) {
|
if (declaration_) {
|
||||||
FileContext *file_context = cu_context_->file_context;
|
|
||||||
Specification spec;
|
Specification spec;
|
||||||
if (qualified_name)
|
if (qualified_name) {
|
||||||
spec.qualified_name = *qualified_name;
|
spec.qualified_name = *qualified_name;
|
||||||
else {
|
} else {
|
||||||
spec.enclosing_name = *enclosing_name;
|
spec.enclosing_name = *enclosing_name;
|
||||||
spec.unqualified_name = *unqualified_name;
|
spec.unqualified_name = *unqualified_name;
|
||||||
}
|
}
|
||||||
file_context->file_private->specifications[offset_] = spec;
|
cu_context_->file_context->file_private_->specifications[offset_] = spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qualified_name)
|
if (qualified_name)
|
||||||
|
@ -460,7 +495,7 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeReference(
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
case dwarf2reader::DW_AT_abstract_origin: {
|
case dwarf2reader::DW_AT_abstract_origin: {
|
||||||
const AbstractOriginByOffset& origins =
|
const AbstractOriginByOffset& origins =
|
||||||
cu_context_->file_context->file_private->origins;
|
cu_context_->file_context->file_private_->origins;
|
||||||
AbstractOriginByOffset::const_iterator origin = origins.find(data);
|
AbstractOriginByOffset::const_iterator origin = origins.find(data);
|
||||||
if (origin != origins.end()) {
|
if (origin != origins.end()) {
|
||||||
abstract_origin_ = &(origin->second);
|
abstract_origin_ = &(origin->second);
|
||||||
|
@ -516,7 +551,7 @@ void DwarfCUToModule::FuncHandler::Finish() {
|
||||||
}
|
}
|
||||||
} else if (inline_) {
|
} else if (inline_) {
|
||||||
AbstractOrigin origin(name_);
|
AbstractOrigin origin(name_);
|
||||||
cu_context_->file_context->file_private->origins[offset_] = origin;
|
cu_context_->file_context->file_private_->origins[offset_] = origin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,6 +663,15 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
|
||||||
filename_.c_str(), offset);
|
filename_.c_str(), offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DwarfCUToModule::WarningReporter::UnhandledInterCUReference(
|
||||||
|
uint64 offset, uint64 target) {
|
||||||
|
CUHeading();
|
||||||
|
fprintf(stderr, "%s: warning: the DIE at offset 0x%llx has a "
|
||||||
|
"DW_FORM_ref_addr attribute with an inter-CU reference to "
|
||||||
|
"0x%llx, but inter-CU reference handling is turned off.\n",
|
||||||
|
filename_.c_str(), offset, target);
|
||||||
|
}
|
||||||
|
|
||||||
DwarfCUToModule::DwarfCUToModule(FileContext *file_context,
|
DwarfCUToModule::DwarfCUToModule(FileContext *file_context,
|
||||||
LineToModuleHandler *line_reader,
|
LineToModuleHandler *line_reader,
|
||||||
WarningReporter *reporter)
|
WarningReporter *reporter)
|
||||||
|
@ -741,7 +785,7 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
|
||||||
|
|
||||||
void DwarfCUToModule::ReadSourceLines(uint64 offset) {
|
void DwarfCUToModule::ReadSourceLines(uint64 offset) {
|
||||||
const dwarf2reader::SectionMap §ion_map
|
const dwarf2reader::SectionMap §ion_map
|
||||||
= cu_context_->file_context->section_map;
|
= cu_context_->file_context->section_map();
|
||||||
dwarf2reader::SectionMap::const_iterator map_entry
|
dwarf2reader::SectionMap::const_iterator map_entry
|
||||||
= section_map.find(".debug_line");
|
= section_map.find(".debug_line");
|
||||||
// Mac OS X puts DWARF data in sections whose names begin with "__"
|
// Mac OS X puts DWARF data in sections whose names begin with "__"
|
||||||
|
@ -759,7 +803,7 @@ void DwarfCUToModule::ReadSourceLines(uint64 offset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
line_reader_->ReadProgram(section_start + offset, section_length - offset,
|
line_reader_->ReadProgram(section_start + offset, section_length - offset,
|
||||||
cu_context_->file_context->module, &lines_);
|
cu_context_->file_context->module_, &lines_);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -984,12 +1028,14 @@ void DwarfCUToModule::Finish() {
|
||||||
|
|
||||||
// Add our functions, which now have source lines assigned to them,
|
// Add our functions, which now have source lines assigned to them,
|
||||||
// to module_.
|
// to module_.
|
||||||
cu_context_->file_context->module->AddFunctions(functions->begin(),
|
cu_context_->file_context->module_->AddFunctions(functions->begin(),
|
||||||
functions->end());
|
functions->end());
|
||||||
|
|
||||||
// Ownership of the function objects has shifted from cu_context to
|
// Ownership of the function objects has shifted from cu_context to
|
||||||
// the Module.
|
// the Module.
|
||||||
functions->clear();
|
functions->clear();
|
||||||
|
|
||||||
|
cu_context_->file_context->ClearSpecifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DwarfCUToModule::StartCompilationUnit(uint64 offset,
|
bool DwarfCUToModule::StartCompilationUnit(uint64 offset,
|
||||||
|
|
|
@ -65,7 +65,6 @@ using dwarf2reader::DwarfTag;
|
||||||
class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||||
struct FilePrivate;
|
struct FilePrivate;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Information global to the DWARF-bearing file we are processing,
|
// Information global to the DWARF-bearing file we are processing,
|
||||||
// for use by DwarfCUToModule. Each DwarfCUToModule instance deals
|
// for use by DwarfCUToModule. Each DwarfCUToModule instance deals
|
||||||
// with a single compilation unit within the file, but information
|
// with a single compilation unit within the file, but information
|
||||||
|
@ -73,23 +72,52 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||||
// for filling it in appropriately (except for the 'file_private'
|
// for filling it in appropriately (except for the 'file_private'
|
||||||
// field, which the constructor and destructor take care of), and
|
// field, which the constructor and destructor take care of), and
|
||||||
// then providing it to the DwarfCUToModule instance for each
|
// then providing it to the DwarfCUToModule instance for each
|
||||||
// compilation unit we process in that file.
|
// compilation unit we process in that file. Set HANDLE_INTER_CU_REFS
|
||||||
struct FileContext {
|
// to true to handle debugging symbols with DW_FORM_ref_addr entries.
|
||||||
FileContext(const string &filename_arg, Module *module_arg);
|
class FileContext {
|
||||||
|
public:
|
||||||
|
FileContext(const string &filename,
|
||||||
|
Module *module,
|
||||||
|
bool handle_inter_cu_refs);
|
||||||
~FileContext();
|
~FileContext();
|
||||||
|
|
||||||
|
// Add CONTENTS of size LENGTH to the section map as NAME.
|
||||||
|
void AddSectionToSectionMap(const string& name,
|
||||||
|
const char* contents,
|
||||||
|
uint64 length);
|
||||||
|
|
||||||
|
// Clear the section map for testing.
|
||||||
|
void ClearSectionMapForTest();
|
||||||
|
|
||||||
|
const dwarf2reader::SectionMap& section_map() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class DwarfCUToModule;
|
||||||
|
|
||||||
|
// Clears all the Specifications if HANDLE_INTER_CU_REFS_ is false.
|
||||||
|
void ClearSpecifications();
|
||||||
|
|
||||||
|
// Given an OFFSET and a CU that starts at COMPILATION_UNIT_START, returns
|
||||||
|
// true if this is an inter-compilation unit reference that is not being
|
||||||
|
// handled.
|
||||||
|
bool IsUnhandledInterCUReference(uint64 offset,
|
||||||
|
uint64 compilation_unit_start) const;
|
||||||
|
|
||||||
// The name of this file, for use in error messages.
|
// The name of this file, for use in error messages.
|
||||||
string filename;
|
const string filename_;
|
||||||
|
|
||||||
// A map of this file's sections, used for finding other DWARF
|
// A map of this file's sections, used for finding other DWARF
|
||||||
// sections that the .debug_info section may refer to.
|
// sections that the .debug_info section may refer to.
|
||||||
dwarf2reader::SectionMap section_map;
|
dwarf2reader::SectionMap section_map_;
|
||||||
|
|
||||||
// The Module to which we're contributing definitions.
|
// The Module to which we're contributing definitions.
|
||||||
Module *module;
|
Module *module_;
|
||||||
|
|
||||||
|
// True if we are handling references between compilation units.
|
||||||
|
const bool handle_inter_cu_refs_;
|
||||||
|
|
||||||
// Inter-compilation unit data used internally by the handlers.
|
// Inter-compilation unit data used internally by the handlers.
|
||||||
FilePrivate *file_private;
|
FilePrivate *file_private_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// An abstract base class for handlers that handle DWARF line data
|
// An abstract base class for handlers that handle DWARF line data
|
||||||
|
@ -170,9 +198,17 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||||
// link.
|
// link.
|
||||||
virtual void UnnamedFunction(uint64 offset);
|
virtual void UnnamedFunction(uint64 offset);
|
||||||
|
|
||||||
|
// The DW_FORM_ref_addr at OFFSET to TARGET was not handled because
|
||||||
|
// FilePrivate did not retain the inter-CU specification data.
|
||||||
|
virtual void UnhandledInterCUReference(uint64 offset, uint64 target);
|
||||||
|
|
||||||
|
uint64 cu_offset() const {
|
||||||
|
return cu_offset_;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
string filename_;
|
const string filename_;
|
||||||
uint64 cu_offset_;
|
const uint64 cu_offset_;
|
||||||
string cu_name_;
|
string cu_name_;
|
||||||
bool printed_cu_header_;
|
bool printed_cu_header_;
|
||||||
bool printed_unpaired_header_;
|
bool printed_unpaired_header_;
|
||||||
|
@ -218,13 +254,11 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||||
bool StartRootDIE(uint64 offset, enum DwarfTag tag);
|
bool StartRootDIE(uint64 offset, enum DwarfTag tag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Used internally by the handler. Full definitions are in
|
// Used internally by the handler. Full definitions are in
|
||||||
// dwarf_cu_to_module.cc.
|
// dwarf_cu_to_module.cc.
|
||||||
struct FilePrivate;
|
|
||||||
struct Specification;
|
|
||||||
struct CUContext;
|
struct CUContext;
|
||||||
struct DIEContext;
|
struct DIEContext;
|
||||||
|
struct Specification;
|
||||||
class GenericDIEHandler;
|
class GenericDIEHandler;
|
||||||
class FuncHandler;
|
class FuncHandler;
|
||||||
class NamedScopeHandler;
|
class NamedScopeHandler;
|
||||||
|
|
|
@ -81,6 +81,7 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter {
|
||||||
MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
|
MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
|
||||||
MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
|
MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
|
||||||
MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
|
MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
|
||||||
|
MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target));
|
||||||
};
|
};
|
||||||
|
|
||||||
// A fixture class including all the objects needed to handle a
|
// A fixture class including all the objects needed to handle a
|
||||||
|
@ -88,7 +89,6 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter {
|
||||||
// for doing common kinds of setup and tests.
|
// for doing common kinds of setup and tests.
|
||||||
class CUFixtureBase {
|
class CUFixtureBase {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// If we have:
|
// If we have:
|
||||||
//
|
//
|
||||||
// vector<Module::Line> lines;
|
// vector<Module::Line> lines;
|
||||||
|
@ -108,7 +108,8 @@ class CUFixtureBase {
|
||||||
// in which case calling l2m with some line vector will append lines.
|
// in which case calling l2m with some line vector will append lines.
|
||||||
class AppendLinesFunctor {
|
class AppendLinesFunctor {
|
||||||
public:
|
public:
|
||||||
AppendLinesFunctor(const vector<Module::Line> *lines) : lines_(lines) { }
|
explicit AppendLinesFunctor(
|
||||||
|
const vector<Module::Line> *lines) : lines_(lines) { }
|
||||||
void operator()(const char *program, uint64 length,
|
void operator()(const char *program, uint64 length,
|
||||||
Module *module, vector<Module::Line> *lines) {
|
Module *module, vector<Module::Line> *lines) {
|
||||||
lines->insert(lines->end(), lines_->begin(), lines_->end());
|
lines->insert(lines->end(), lines_->begin(), lines_->end());
|
||||||
|
@ -119,7 +120,7 @@ class CUFixtureBase {
|
||||||
|
|
||||||
CUFixtureBase()
|
CUFixtureBase()
|
||||||
: module_("module-name", "module-os", "module-arch", "module-id"),
|
: module_("module-name", "module-os", "module-arch", "module-id"),
|
||||||
file_context_("dwarf-filename", &module_),
|
file_context_("dwarf-filename", &module_, true),
|
||||||
language_(dwarf2reader::DW_LANG_none),
|
language_(dwarf2reader::DW_LANG_none),
|
||||||
language_signed_(false),
|
language_signed_(false),
|
||||||
appender_(&lines_),
|
appender_(&lines_),
|
||||||
|
@ -137,6 +138,7 @@ class CUFixtureBase {
|
||||||
EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0);
|
EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0);
|
||||||
EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0);
|
EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0);
|
||||||
EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(0);
|
EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(0);
|
||||||
|
EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(0);
|
||||||
|
|
||||||
// By default, expect the line program reader not to be invoked. We
|
// By default, expect the line program reader not to be invoked. We
|
||||||
// may override this in StartCU.
|
// may override this in StartCU.
|
||||||
|
@ -145,7 +147,8 @@ class CUFixtureBase {
|
||||||
|
|
||||||
// The handler will consult this section map to decide what to
|
// The handler will consult this section map to decide what to
|
||||||
// pass to our line reader.
|
// pass to our line reader.
|
||||||
file_context_.section_map[".debug_line"] = make_pair(dummy_line_program_,
|
file_context_.AddSectionToSectionMap(".debug_line",
|
||||||
|
dummy_line_program_,
|
||||||
dummy_line_size_);
|
dummy_line_size_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,7 +711,7 @@ TEST_F(SimpleCU, IrrelevantNamedScopeChildren) {
|
||||||
// Verify that FileContexts can safely be deleted unused.
|
// Verify that FileContexts can safely be deleted unused.
|
||||||
TEST_F(SimpleCU, UnusedFileContext) {
|
TEST_F(SimpleCU, UnusedFileContext) {
|
||||||
Module m("module-name", "module-os", "module-arch", "module-id");
|
Module m("module-name", "module-os", "module-arch", "module-id");
|
||||||
DwarfCUToModule::FileContext fc("dwarf-filename", &m);
|
DwarfCUToModule::FileContext fc("dwarf-filename", &m, true);
|
||||||
|
|
||||||
// Kludge: satisfy reporter_'s expectation.
|
// Kludge: satisfy reporter_'s expectation.
|
||||||
reporter_.SetCUName("compilation-unit-name");
|
reporter_.SetCUName("compilation-unit-name");
|
||||||
|
@ -891,7 +894,6 @@ TEST_P(FuncLinePairing, Pairing) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FuncLinePairing, EmptyCU) {
|
TEST_F(FuncLinePairing, EmptyCU) {
|
||||||
|
|
||||||
StartCU();
|
StartCU();
|
||||||
root_handler_.Finish();
|
root_handler_.Finish();
|
||||||
|
|
||||||
|
@ -1127,8 +1129,8 @@ const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = {
|
||||||
{ dwarf2reader::DW_LANG_Mips_Assembler, NULL }
|
{ dwarf2reader::DW_LANG_Mips_Assembler, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
class QualifiedForLanguage:
|
class QualifiedForLanguage
|
||||||
public CUFixtureBase,
|
: public CUFixtureBase,
|
||||||
public TestWithParam<LanguageAndQualifiedName> { };
|
public TestWithParam<LanguageAndQualifiedName> { };
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage,
|
INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage,
|
||||||
|
@ -1429,7 +1431,7 @@ TEST_F(Specifications, LongChain) {
|
||||||
|
|
||||||
TEST_F(Specifications, InterCU) {
|
TEST_F(Specifications, InterCU) {
|
||||||
Module m("module-name", "module-os", "module-arch", "module-id");
|
Module m("module-name", "module-os", "module-arch", "module-id");
|
||||||
DwarfCUToModule::FileContext fc("dwarf-filename", &m);
|
DwarfCUToModule::FileContext fc("dwarf-filename", &m, true);
|
||||||
EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
|
EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
|
||||||
MockLineToModuleHandler lr;
|
MockLineToModuleHandler lr;
|
||||||
EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0);
|
EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0);
|
||||||
|
@ -1486,6 +1488,63 @@ TEST_F(Specifications, InterCU) {
|
||||||
EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str());
|
EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(Specifications, UnhandledInterCU) {
|
||||||
|
Module m("module-name", "module-os", "module-arch", "module-id");
|
||||||
|
DwarfCUToModule::FileContext fc("dwarf-filename", &m, false);
|
||||||
|
EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
|
||||||
|
MockLineToModuleHandler lr;
|
||||||
|
EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0);
|
||||||
|
|
||||||
|
// Kludge: satisfy reporter_'s expectation.
|
||||||
|
reporter_.SetCUName("compilation-unit-name");
|
||||||
|
|
||||||
|
// First CU. Declares class_A.
|
||||||
|
{
|
||||||
|
DwarfCUToModule root1_handler(&fc, &lr, &reporter_);
|
||||||
|
ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
|
||||||
|
ASSERT_TRUE(root1_handler.StartRootDIE(1,
|
||||||
|
dwarf2reader::DW_TAG_compile_unit));
|
||||||
|
ProcessStrangeAttributes(&root1_handler);
|
||||||
|
ASSERT_TRUE(root1_handler.EndAttributes());
|
||||||
|
DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL,
|
||||||
|
dwarf2reader::DW_TAG_class_type, "class_A", "");
|
||||||
|
root1_handler.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second CU. Defines class_A, declares member_func_B.
|
||||||
|
{
|
||||||
|
DwarfCUToModule root2_handler(&fc, &lr, &reporter_);
|
||||||
|
ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
|
||||||
|
ASSERT_TRUE(root2_handler.StartRootDIE(1,
|
||||||
|
dwarf2reader::DW_TAG_compile_unit));
|
||||||
|
ASSERT_TRUE(root2_handler.EndAttributes());
|
||||||
|
EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1);
|
||||||
|
DIEHandler *class_A_handler
|
||||||
|
= StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type,
|
||||||
|
0xb8fbfdd5f0b26fceULL);
|
||||||
|
DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL,
|
||||||
|
dwarf2reader::DW_TAG_subprogram, "member_func_B", "");
|
||||||
|
class_A_handler->Finish();
|
||||||
|
delete class_A_handler;
|
||||||
|
root2_handler.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third CU. Defines member_func_B.
|
||||||
|
{
|
||||||
|
DwarfCUToModule root3_handler(&fc, &lr, &reporter_);
|
||||||
|
ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
|
||||||
|
ASSERT_TRUE(root3_handler.StartRootDIE(1,
|
||||||
|
dwarf2reader::DW_TAG_compile_unit));
|
||||||
|
ASSERT_TRUE(root3_handler.EndAttributes());
|
||||||
|
EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1);
|
||||||
|
EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(1);
|
||||||
|
DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram,
|
||||||
|
0xb01fef8b380bd1a2ULL, "",
|
||||||
|
0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL);
|
||||||
|
root3_handler.Finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(Specifications, BadOffset) {
|
TEST_F(Specifications, BadOffset) {
|
||||||
PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272);
|
PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272);
|
||||||
EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL))
|
EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL))
|
||||||
|
@ -1554,8 +1613,9 @@ TEST_F(Specifications, PreferSpecificationParents) {
|
||||||
|
|
||||||
StartCU();
|
StartCU();
|
||||||
{
|
{
|
||||||
dwarf2reader::DIEHandler *declaration_class_handler
|
dwarf2reader::DIEHandler *declaration_class_handler =
|
||||||
= StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "declaration-class");
|
StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
|
||||||
|
"declaration-class");
|
||||||
DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL,
|
DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL,
|
||||||
dwarf2reader::DW_TAG_subprogram, "function-declaration",
|
dwarf2reader::DW_TAG_subprogram, "function-declaration",
|
||||||
"");
|
"");
|
||||||
|
@ -1603,7 +1663,7 @@ TEST_F(CUErrors, NoLineSection) {
|
||||||
EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1);
|
EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1);
|
||||||
PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290);
|
PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290);
|
||||||
// Delete the entry for .debug_line added by the fixture class's constructor.
|
// Delete the entry for .debug_line added by the fixture class's constructor.
|
||||||
file_context_.section_map.clear();
|
file_context_.ClearSectionMapForTest();
|
||||||
|
|
||||||
StartCU();
|
StartCU();
|
||||||
root_handler_.Finish();
|
root_handler_.Finish();
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
// This namespace contains helper functions.
|
// This namespace contains helper functions.
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using google_breakpad::DumpOptions;
|
||||||
using google_breakpad::DwarfCFIToModule;
|
using google_breakpad::DwarfCFIToModule;
|
||||||
using google_breakpad::DwarfCUToModule;
|
using google_breakpad::DwarfCUToModule;
|
||||||
using google_breakpad::DwarfLineToModule;
|
using google_breakpad::DwarfLineToModule;
|
||||||
|
@ -216,6 +217,7 @@ template<typename ElfClass>
|
||||||
bool LoadDwarf(const string& dwarf_filename,
|
bool LoadDwarf(const string& dwarf_filename,
|
||||||
const typename ElfClass::Ehdr* elf_header,
|
const typename ElfClass::Ehdr* elf_header,
|
||||||
const bool big_endian,
|
const bool big_endian,
|
||||||
|
bool handle_inter_cu_refs,
|
||||||
Module* module) {
|
Module* module) {
|
||||||
typedef typename ElfClass::Shdr Shdr;
|
typedef typename ElfClass::Shdr Shdr;
|
||||||
|
|
||||||
|
@ -224,7 +226,9 @@ bool LoadDwarf(const string& dwarf_filename,
|
||||||
dwarf2reader::ByteReader byte_reader(endianness);
|
dwarf2reader::ByteReader byte_reader(endianness);
|
||||||
|
|
||||||
// Construct a context for this file.
|
// Construct a context for this file.
|
||||||
DwarfCUToModule::FileContext file_context(dwarf_filename, module);
|
DwarfCUToModule::FileContext file_context(dwarf_filename,
|
||||||
|
module,
|
||||||
|
handle_inter_cu_refs);
|
||||||
|
|
||||||
// Build a map of the ELF file's sections.
|
// Build a map of the ELF file's sections.
|
||||||
const Shdr* sections =
|
const Shdr* sections =
|
||||||
|
@ -238,14 +242,16 @@ bool LoadDwarf(const string& dwarf_filename,
|
||||||
section->sh_name;
|
section->sh_name;
|
||||||
const char* contents = GetOffset<ElfClass, char>(elf_header,
|
const char* contents = GetOffset<ElfClass, char>(elf_header,
|
||||||
section->sh_offset);
|
section->sh_offset);
|
||||||
uint64 length = section->sh_size;
|
file_context.AddSectionToSectionMap(name, contents, section->sh_size);
|
||||||
file_context.section_map[name] = std::make_pair(contents, length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse all the compilation units in the .debug_info section.
|
// Parse all the compilation units in the .debug_info section.
|
||||||
DumperLineToModule line_to_module(&byte_reader);
|
DumperLineToModule line_to_module(&byte_reader);
|
||||||
std::pair<const char *, uint64> debug_info_section
|
dwarf2reader::SectionMap::const_iterator debug_info_entry =
|
||||||
= file_context.section_map[".debug_info"];
|
file_context.section_map().find(".debug_info");
|
||||||
|
assert(debug_info_entry != file_context.section_map().end());
|
||||||
|
const std::pair<const char*, uint64>& debug_info_section =
|
||||||
|
debug_info_entry->second;
|
||||||
// This should never have been called if the file doesn't have a
|
// This should never have been called if the file doesn't have a
|
||||||
// .debug_info section.
|
// .debug_info section.
|
||||||
assert(debug_info_section.first);
|
assert(debug_info_section.first);
|
||||||
|
@ -258,7 +264,7 @@ bool LoadDwarf(const string& dwarf_filename,
|
||||||
// Make a Dwarf2Handler that drives the DIEHandler.
|
// Make a Dwarf2Handler that drives the DIEHandler.
|
||||||
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
|
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
|
||||||
// Make a DWARF parser for the compilation unit at OFFSET.
|
// Make a DWARF parser for the compilation unit at OFFSET.
|
||||||
dwarf2reader::CompilationUnit reader(file_context.section_map,
|
dwarf2reader::CompilationUnit reader(file_context.section_map(),
|
||||||
offset,
|
offset,
|
||||||
&byte_reader,
|
&byte_reader,
|
||||||
&die_dispatcher);
|
&die_dispatcher);
|
||||||
|
@ -521,7 +527,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,
|
const DumpOptions& options,
|
||||||
Module* module) {
|
Module* module) {
|
||||||
typedef typename ElfClass::Addr Addr;
|
typedef typename ElfClass::Addr Addr;
|
||||||
typedef typename ElfClass::Phdr Phdr;
|
typedef typename ElfClass::Phdr Phdr;
|
||||||
|
@ -542,7 +548,7 @@ 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;
|
||||||
|
|
||||||
if (symbol_data != ONLY_CFI) {
|
if (options.symbol_data != ONLY_CFI) {
|
||||||
#ifndef NO_STABS_SUPPORT
|
#ifndef NO_STABS_SUPPORT
|
||||||
// Look for STABS debugging information, and load it if present.
|
// Look for STABS debugging information, and load it if present.
|
||||||
const Shdr* stab_section =
|
const Shdr* stab_section =
|
||||||
|
@ -573,13 +579,15 @@ bool LoadSymbols(const string& obj_file,
|
||||||
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,
|
||||||
|
options.handle_inter_cu_refs, 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (symbol_data != NO_CFI) {
|
if (options.symbol_data != NO_CFI) {
|
||||||
// Dwarf Call Frame Information (CFI) is actually independent from
|
// Dwarf Call Frame Information (CFI) is actually independent from
|
||||||
// the other DWARF debugging information, and can be used alone.
|
// the other DWARF debugging information, and can be used alone.
|
||||||
const Shdr* dwarf_cfi_section =
|
const Shdr* dwarf_cfi_section =
|
||||||
|
@ -655,7 +663,7 @@ bool LoadSymbols(const string& obj_file,
|
||||||
obj_file.c_str());
|
obj_file.c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (symbol_data != ONLY_CFI) {
|
if (options.symbol_data != ONLY_CFI) {
|
||||||
// The caller doesn't want to consult .gnu_debuglink.
|
// The caller doesn't want to consult .gnu_debuglink.
|
||||||
// See if there are export symbols available.
|
// See if there are export symbols available.
|
||||||
const Shdr* dynsym_section =
|
const Shdr* dynsym_section =
|
||||||
|
@ -753,7 +761,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,
|
||||||
SymbolData symbol_data,
|
const DumpOptions& options,
|
||||||
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;
|
||||||
|
@ -788,7 +796,7 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||||
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,
|
!debug_dirs.empty(), &info,
|
||||||
symbol_data, module.get())) {
|
options, 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;
|
||||||
|
@ -827,7 +835,7 @@ 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,
|
debug_elf_header, false, &info,
|
||||||
symbol_data, module.get())) {
|
options, module.get())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -844,9 +852,8 @@ 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,
|
||||||
SymbolData symbol_data,
|
const DumpOptions& options,
|
||||||
Module** module) {
|
Module** module) {
|
||||||
|
|
||||||
if (!IsValidElf(obj_file)) {
|
if (!IsValidElf(obj_file)) {
|
||||||
fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str());
|
fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str());
|
||||||
return false;
|
return false;
|
||||||
|
@ -856,12 +863,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,
|
||||||
symbol_data, module);
|
options, 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,
|
||||||
symbol_data, module);
|
options, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -869,20 +876,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,
|
||||||
SymbolData symbol_data,
|
const DumpOptions& options,
|
||||||
std::ostream &sym_stream) {
|
std::ostream &sym_stream) {
|
||||||
Module* module;
|
Module* module;
|
||||||
if (!ReadSymbolData(obj_file, debug_dirs, symbol_data, &module))
|
if (!ReadSymbolData(obj_file, debug_dirs, options, &module))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool result = module->Write(sym_stream, symbol_data);
|
bool result = module->Write(sym_stream, options.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,
|
||||||
SymbolData symbol_data,
|
const DumpOptions& options,
|
||||||
Module** module) {
|
Module** module) {
|
||||||
MmapWrapper map_wrapper;
|
MmapWrapper map_wrapper;
|
||||||
void* elf_header = NULL;
|
void* elf_header = NULL;
|
||||||
|
@ -890,7 +897,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, symbol_data, module);
|
obj_file, debug_dirs, options, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -46,6 +46,16 @@ namespace google_breakpad {
|
||||||
|
|
||||||
class Module;
|
class Module;
|
||||||
|
|
||||||
|
struct DumpOptions {
|
||||||
|
DumpOptions(SymbolData symbol_data, bool handle_inter_cu_refs)
|
||||||
|
: symbol_data(symbol_data),
|
||||||
|
handle_inter_cu_refs(handle_inter_cu_refs) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolData symbol_data;
|
||||||
|
bool handle_inter_cu_refs;
|
||||||
|
};
|
||||||
|
|
||||||
// Find all the debugging information in OBJ_FILE, an ELF executable
|
// Find all the debugging information in OBJ_FILE, an ELF executable
|
||||||
// or shared library, and write it to SYM_STREAM in the Breakpad symbol
|
// or shared library, and write it to SYM_STREAM in the Breakpad symbol
|
||||||
// file format.
|
// file format.
|
||||||
|
@ -54,7 +64,7 @@ class Module;
|
||||||
// SYMBOL_DATA allows limiting the type of symbol data written.
|
// 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,
|
||||||
SymbolData symbol_data,
|
const DumpOptions& options,
|
||||||
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
|
||||||
|
@ -62,7 +72,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,
|
||||||
SymbolData symbol_data,
|
const DumpOptions& options,
|
||||||
Module** module);
|
Module** module);
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -40,25 +40,24 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "breakpad_googletest_includes.h"
|
#include "breakpad_googletest_includes.h"
|
||||||
|
#include "common/linux/dump_symbols.h"
|
||||||
#include "common/linux/synth_elf.h"
|
#include "common/linux/synth_elf.h"
|
||||||
#include "common/module.h"
|
#include "common/module.h"
|
||||||
#include "common/using_std_string.h"
|
#include "common/using_std_string.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
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,
|
||||||
SymbolData symbol_data,
|
const DumpOptions& options,
|
||||||
Module** module);
|
Module** module);
|
||||||
}
|
|
||||||
|
|
||||||
using google_breakpad::synth_elf::ELF;
|
using google_breakpad::synth_elf::ELF;
|
||||||
using google_breakpad::synth_elf::StringTable;
|
using google_breakpad::synth_elf::StringTable;
|
||||||
using google_breakpad::synth_elf::SymbolTable;
|
using google_breakpad::synth_elf::SymbolTable;
|
||||||
using google_breakpad::test_assembler::kLittleEndian;
|
using google_breakpad::test_assembler::kLittleEndian;
|
||||||
using google_breakpad::test_assembler::Section;
|
using google_breakpad::test_assembler::Section;
|
||||||
using google_breakpad::Module;
|
|
||||||
using google_breakpad::ReadSymbolDataInternal;
|
|
||||||
using std::stringstream;
|
using std::stringstream;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using ::testing::Test;
|
using ::testing::Test;
|
||||||
|
@ -83,10 +82,11 @@ TEST_F(DumpSymbols, Invalid) {
|
||||||
Elf32_Ehdr header;
|
Elf32_Ehdr header;
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
Module* module;
|
Module* module;
|
||||||
|
DumpOptions options(ALL_SYMBOL_DATA, true);
|
||||||
EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
|
EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
|
||||||
"foo",
|
"foo",
|
||||||
vector<string>(),
|
vector<string>(),
|
||||||
ALL_SYMBOL_DATA,
|
options,
|
||||||
&module));
|
&module));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,10 +115,11 @@ TEST_F(DumpSymbols, SimplePublic32) {
|
||||||
GetElfContents(elf);
|
GetElfContents(elf);
|
||||||
|
|
||||||
Module* module;
|
Module* module;
|
||||||
|
DumpOptions options(ALL_SYMBOL_DATA, true);
|
||||||
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
||||||
"foo",
|
"foo",
|
||||||
vector<string>(),
|
vector<string>(),
|
||||||
ALL_SYMBOL_DATA,
|
options,
|
||||||
&module));
|
&module));
|
||||||
|
|
||||||
stringstream s;
|
stringstream s;
|
||||||
|
@ -154,10 +155,11 @@ TEST_F(DumpSymbols, SimplePublic64) {
|
||||||
GetElfContents(elf);
|
GetElfContents(elf);
|
||||||
|
|
||||||
Module* module;
|
Module* module;
|
||||||
|
DumpOptions options(ALL_SYMBOL_DATA, true);
|
||||||
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
||||||
"foo",
|
"foo",
|
||||||
vector<string>(),
|
vector<string>(),
|
||||||
ALL_SYMBOL_DATA,
|
options,
|
||||||
&module));
|
&module));
|
||||||
|
|
||||||
stringstream s;
|
stringstream s;
|
||||||
|
@ -166,3 +168,5 @@ TEST_F(DumpSymbols, SimplePublic64) {
|
||||||
"PUBLIC 1000 0 superfunc\n",
|
"PUBLIC 1000 0 superfunc\n",
|
||||||
s.str());
|
s.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -43,33 +43,43 @@ int usage(const char* self) {
|
||||||
"[directories-for-debug-file]\n\n", self);
|
"[directories-for-debug-file]\n\n", self);
|
||||||
fprintf(stderr, "Options:\n");
|
fprintf(stderr, "Options:\n");
|
||||||
fprintf(stderr, " -c Do not generate CFI section\n");
|
fprintf(stderr, " -c Do not generate CFI section\n");
|
||||||
|
fprintf(stderr, " -r Do not handle inter-compilation unit references\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
if (argc < 2 || argc > 4)
|
if (argc < 2)
|
||||||
return usage(argv[0]);
|
return usage(argv[0]);
|
||||||
|
|
||||||
bool cfi = true;
|
bool cfi = true;
|
||||||
int binary_index = 1;
|
bool handle_inter_cu_refs = true;
|
||||||
if (strcmp("-c", argv[1]) == 0) {
|
int arg_index = 1;
|
||||||
|
while (arg_index < argc && strlen(argv[arg_index]) > 0 &&
|
||||||
|
argv[arg_index][0] == '-') {
|
||||||
|
if (strcmp("-c", argv[arg_index]) == 0) {
|
||||||
cfi = false;
|
cfi = false;
|
||||||
++binary_index;
|
} else if (strcmp("-r", argv[arg_index]) == 0) {
|
||||||
|
handle_inter_cu_refs = false;
|
||||||
|
} else {
|
||||||
|
return usage(argv[0]);
|
||||||
}
|
}
|
||||||
if (!cfi && argc == 2)
|
++arg_index;
|
||||||
|
}
|
||||||
|
if (arg_index == argc)
|
||||||
return usage(argv[0]);
|
return usage(argv[0]);
|
||||||
|
|
||||||
const char* binary;
|
const char* binary;
|
||||||
std::vector<string> debug_dirs;
|
std::vector<string> debug_dirs;
|
||||||
binary = argv[binary_index];
|
binary = argv[arg_index];
|
||||||
for (int debug_dir_index = binary_index + 1;
|
for (int debug_dir_index = arg_index + 1;
|
||||||
debug_dir_index < argc;
|
debug_dir_index < argc;
|
||||||
++debug_dir_index) {
|
++debug_dir_index) {
|
||||||
debug_dirs.push_back(argv[debug_dir_index]);
|
debug_dirs.push_back(argv[debug_dir_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolData symbol_data = cfi ? ALL_SYMBOL_DATA : NO_CFI;
|
SymbolData symbol_data = cfi ? ALL_SYMBOL_DATA : NO_CFI;
|
||||||
if (!WriteSymbolFile(binary, debug_dirs, symbol_data, std::cout)) {
|
google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs);
|
||||||
|
if (!WriteSymbolFile(binary, debug_dirs, options, std::cout)) {
|
||||||
fprintf(stderr, "Failed to write symbol file.\n");
|
fprintf(stderr, "Failed to write symbol file.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue