diff options
author | jimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2010-02-10 17:55:24 +0000 |
---|---|---|
committer | jimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2010-02-10 17:55:24 +0000 |
commit | dd5067f391baee2561404f8e2915429b3d638ff7 (patch) | |
tree | 0efae97bac0c1ebb82718de14de38d31b2766229 /src/common/linux/dwarf_cu_to_module.cc | |
parent | Breakpad Linux dumper: Don't be silly about global functions. (diff) | |
download | breakpad-dd5067f391baee2561404f8e2915429b3d638ff7.tar.xz |
Linux DWARF reader: Follow DW_AT_abstract_origin links to find function names.
Without this patch, debugging information like the following will produce
FUNC records with no names, because the dumper (correctly) ignores the
DW_TAG_subprogram DIEs that lack DW_AT_low_pc/DW_AT_high_pc attributes, but
won't follow the DW_AT_abstract_origin link from the DIE that does have
code addresses to find its name.
<1><168>: Abbrev Number: 5 (DW_TAG_class_type)
<169> DW_AT_name : Foo
<2><183>: Abbrev Number: 7 (DW_TAG_subprogram)
<185> DW_AT_name : Foo
<18b> DW_AT_declaration : 1
<1><1b7>: Abbrev Number: 12 (DW_TAG_subprogram)
<1b8> DW_AT_specification: <0x183>
<1bc> DW_AT_inline : 2 (declared as inline but ignored)
<1><1dc>: Abbrev Number: 16 (DW_TAG_subprogram)
<1dd> DW_AT_abstract_origin: <0x1b7>
<1e1> DW_AT_low_pc : 0x8048578
<1e5> DW_AT_high_pc : 0x8048588
a=dmuir, r=jimblandy
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@520 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/common/linux/dwarf_cu_to_module.cc')
-rw-r--r-- | src/common/linux/dwarf_cu_to_module.cc | 92 |
1 files changed, 90 insertions, 2 deletions
diff --git a/src/common/linux/dwarf_cu_to_module.cc b/src/common/linux/dwarf_cu_to_module.cc index 3c339870..88cea940 100644 --- a/src/common/linux/dwarf_cu_to_module.cc +++ b/src/common/linux/dwarf_cu_to_module.cc @@ -68,6 +68,16 @@ struct DwarfCUToModule::Specification { string unqualified_name; }; +// An abstract origin -- base definition of an inline function. +struct AbstractOrigin { + AbstractOrigin() : name() {} + AbstractOrigin(const string& name) : name(name) {} + + string name; +}; + +typedef map<uint64, AbstractOrigin> AbstractOriginByOffset; + // Data global to the DWARF-bearing file that is private to the // DWARF-to-Module process. struct DwarfCUToModule::FilePrivate { @@ -75,6 +85,8 @@ struct DwarfCUToModule::FilePrivate { // Specifications describing those DIEs. Specification references can // cross compilation unit boundaries. SpecificationByOffset specifications; + + AbstractOriginByOffset origins; }; DwarfCUToModule::FileContext::FileContext(const string &filename_arg, @@ -230,7 +242,7 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( // don't think any producers we care about ever emit such // things. cu_context_->reporter->UnknownSpecification(offset_, data); - } + } break; } default: break; @@ -287,10 +299,17 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { FuncHandler(CUContext *cu_context, DIEContext *parent_context, uint64 offset) : GenericDIEHandler(cu_context, parent_context, offset), - low_pc_(0), high_pc_(0) { } + low_pc_(0), high_pc_(0), abstract_origin_(NULL), inline_(false) { } void ProcessAttributeUnsigned(enum DwarfAttribute attr, enum DwarfForm form, uint64 data); + void ProcessAttributeSigned(enum DwarfAttribute attr, + enum DwarfForm form, + int64 data); + void ProcessAttributeReference(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + bool EndAttributes(); void Finish(); @@ -299,6 +318,8 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { // specification_, parent_context_. Computed in EndAttributes. string name_; uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc + const AbstractOrigin* abstract_origin_; + bool inline_; }; void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( @@ -306,6 +327,16 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( enum DwarfForm form, uint64 data) { switch (attr) { + case dwarf2reader::DW_AT_inline: + switch(data) { + case dwarf2reader::DW_INL_inlined: + case dwarf2reader::DW_INL_declared_not_inlined: + case dwarf2reader::DW_INL_declared_inlined: + inline_ = true; break; + default: + break; + } + break; case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break; case dwarf2reader::DW_AT_high_pc: high_pc_ = data; break; default: @@ -314,9 +345,54 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( } } +void DwarfCUToModule::FuncHandler::ProcessAttributeSigned( + enum DwarfAttribute attr, + enum DwarfForm form, + int64 data) { + switch (attr) { + case dwarf2reader::DW_AT_inline: + switch(data) { + case dwarf2reader::DW_INL_inlined: + case dwarf2reader::DW_INL_declared_not_inlined: + case dwarf2reader::DW_INL_declared_inlined: + inline_ = true; break; + default: + break; + } + break; + default: + break; + } +} + +void DwarfCUToModule::FuncHandler::ProcessAttributeReference( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch(attr) { + case dwarf2reader::DW_AT_abstract_origin: { + const AbstractOriginByOffset& origins = + cu_context_->file_context->file_private->origins; + AbstractOriginByOffset::const_iterator origin = origins.find(data); + if (origin != origins.end()) { + abstract_origin_ = &(origin->second); + } else { + cu_context_->reporter->UnknownAbstractOrigin(offset_, data); + } + break; + } + default: + GenericDIEHandler::ProcessAttributeReference(attr, form, data); + break; + } +} + bool DwarfCUToModule::FuncHandler::EndAttributes() { // Compute our name, and record a specification, if appropriate. name_ = ComputeQualifiedName(); + if (name_.empty() && abstract_origin_) { + name_ = abstract_origin_->name; + } return true; } @@ -334,6 +410,9 @@ void DwarfCUToModule::FuncHandler::Finish() { func->size = high_pc_ - low_pc_; func->parameter_size = 0; cu_context_->functions.push_back(func); + } else if (inline_) { + AbstractOrigin origin(name_); + cu_context_->file_context->file_private->origins[offset_] = origin; } } @@ -391,6 +470,15 @@ void DwarfCUToModule::WarningReporter::UnknownSpecification(uint64 offset, filename_.c_str(), offset, target); } +void DwarfCUToModule::WarningReporter::UnknownAbstractOrigin(uint64 offset, + uint64 target) { + CUHeading(); + fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_abstract_origin" + " attribute referring to the die at offset 0x%llx, which either" + " was not marked as an inline, or comes later in the file", + filename_.c_str(), offset, target); +} + void DwarfCUToModule::WarningReporter::MissingSection(const string &name) { CUHeading(); fprintf(stderr, "%s: warning: couldn't find DWARF '%s' section\n", |