summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc')
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc336
1 files changed, 241 insertions, 95 deletions
diff --git a/3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc b/3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc
index ded5f83..a16bee7 100644
--- a/3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc
+++ b/3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc
@@ -40,23 +40,24 @@
#include <assert.h>
#include <inttypes.h>
+#include <stdint.h>
#include <stdio.h>
#include <algorithm>
-#include <set>
#include <utility>
#include "common/dwarf_line_to_module.h"
+#include "common/unordered.h"
namespace google_breakpad {
using std::map;
using std::pair;
-using std::set;
+using std::sort;
using std::vector;
// Data provided by a DWARF specification DIE.
-//
+//
// In DWARF, the DIE for a definition may contain a DW_AT_specification
// attribute giving the offset of the corresponding declaration DIE, and
// the definition DIE may omit information given in the declaration. For
@@ -73,6 +74,9 @@ using std::vector;
// A Specification holds information gathered from a declaration DIE that
// we may need if we find a DW_AT_specification link pointing to it.
struct DwarfCUToModule::Specification {
+ // The qualified name that can be found by demangling DW_AT_MIPS_linkage_name.
+ string qualified_name;
+
// The name of the enclosing scope, or the empty string if there is none.
string enclosing_name;
@@ -84,7 +88,7 @@ struct DwarfCUToModule::Specification {
// An abstract origin -- base definition of an inline function.
struct AbstractOrigin {
AbstractOrigin() : name() {}
- AbstractOrigin(const string& name) : name(name) {}
+ explicit AbstractOrigin(const string& name) : name(name) {}
string name;
};
@@ -97,13 +101,21 @@ struct DwarfCUToModule::FilePrivate {
// A set of strings used in this CU. Before storing a string in one of
// our data structures, insert it into this set, and then use the string
// from the set.
- //
- // Because std::string uses reference counting internally, simply using
- // strings from this set, even if passed by value, assigned, or held
- // directly in structures and containers (map<string, ...>, for example),
- // causes those strings to share a single instance of each distinct piece
- // of text.
- set<string> common_strings;
+ //
+ // In some STL implementations, strings are reference-counted internally,
+ // meaning that simply using strings from this set, even if passed by
+ // value, assigned, or held directly in structures and containers
+ // (map<string, ...>, for example), causes those strings to share a
+ // single instance of each distinct piece of text. GNU's libstdc++ uses
+ // reference counts, and I believe MSVC did as well, at some point.
+ // However, C++ '11 implementations are moving away from reference
+ // counting.
+ //
+ // In other implementations, string assignments copy the string's text,
+ // so this set will actually hold yet another copy of the string (although
+ // everything will still work). To improve memory consumption portably,
+ // we will probably need to use pointers to strings held in this set.
+ unordered_set<string> common_strings;
// A map from offsets of DIEs within the .debug_info section to
// Specifications describing those DIEs. Specification references can
@@ -113,14 +125,42 @@ struct DwarfCUToModule::FilePrivate {
AbstractOriginByOffset origins;
};
-DwarfCUToModule::FileContext::FileContext(const string &filename_arg,
- Module *module_arg)
- : filename(filename_arg), module(module_arg) {
- file_private = new FilePrivate();
+DwarfCUToModule::FileContext::FileContext(const string &filename,
+ Module *module,
+ bool handle_inter_cu_refs)
+ : filename_(filename),
+ module_(module),
+ handle_inter_cu_refs_(handle_inter_cu_refs),
+ file_private_(new FilePrivate()) {
}
DwarfCUToModule::FileContext::~FileContext() {
- delete file_private;
+}
+
+void DwarfCUToModule::FileContext::AddSectionToSectionMap(
+ const string& name, const uint8_t *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
@@ -130,11 +170,13 @@ struct DwarfCUToModule::CUContext {
CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg)
: file_context(file_context_arg),
reporter(reporter_arg),
- language(Language::CPlusPlus) { }
+ language(Language::CPlusPlus) {}
+
~CUContext() {
for (vector<Module::Function *>::iterator it = functions.begin();
- it != functions.end(); it++)
+ it != functions.end(); ++it) {
delete *it;
+ }
};
// The DWARF-bearing file into which this CU was incorporated.
@@ -218,6 +260,14 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
DIEContext *parent_context_;
uint64 offset_;
+ // Place the name in the global set of strings. Even though this looks
+ // like a copy, all the major string implementations use reference
+ // counting internally, so the effect is to have all the data structures
+ // share copies of strings whenever possible.
+ // FIXME: Should this return something like a string_ref to avoid the
+ // assumption about how strings are implemented?
+ string AddStringToPool(const string &str);
+
// If this DIE has a DW_AT_declaration attribute, this is its value.
// It is false on DIEs with no DW_AT_declaration attribute.
bool declaration_;
@@ -230,6 +280,11 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
// The value of the DW_AT_name attribute, or the empty string if the
// DIE has no such attribute.
string name_attribute_;
+
+ // The demangled value of the DW_AT_MIPS_linkage_name attribute, or the empty
+ // string if the DIE has no such attribute or its content could not be
+ // demangled.
+ string demangled_name_;
};
void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned(
@@ -248,14 +303,19 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
uint64 data) {
switch (attr) {
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
// set specification_ appropriately. We could do more processing
// here, but it's better to leave the real work to our
// EndAttribute member function, at which point we know we have
// seen all the DIE's attributes.
- FileContext *file_context = cu_context_->file_context;
- SpecificationByOffset *specifications
- = &file_context->file_private->specifications;
+ SpecificationByOffset *specifications =
+ &file_context->file_private_->specifications;
SpecificationByOffset::iterator spec = specifications->find(data);
if (spec != specifications->end()) {
specification_ = &spec->second;
@@ -273,20 +333,37 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
}
}
+string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) {
+ pair<unordered_set<string>::iterator, bool> result =
+ cu_context_->file_context->file_private_->common_strings.insert(str);
+ return *result.first;
+}
+
void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
enum DwarfAttribute attr,
enum DwarfForm form,
const string &data) {
switch (attr) {
- case dwarf2reader::DW_AT_name: {
- // Place the name in our global set of strings, and then use the
- // string from the set. Even though the assignment looks like a copy,
- // all the major std::string implementations use reference counting
- // internally, so the effect is to have all our data structures share
- // copies of strings whenever possible.
- pair<set<string>::iterator, bool> result =
- cu_context_->file_context->file_private->common_strings.insert(data);
- name_attribute_ = *result.first;
+ case dwarf2reader::DW_AT_name:
+ name_attribute_ = AddStringToPool(data);
+ break;
+ case dwarf2reader::DW_AT_MIPS_linkage_name:
+ case dwarf2reader::DW_AT_linkage_name: {
+ string demangled;
+ Language::DemangleResult result =
+ cu_context_->language->DemangleName(data, &demangled);
+ switch (result) {
+ case Language::kDemangleSuccess:
+ demangled_name_ = AddStringToPool(demangled);
+ break;
+
+ case Language::kDemangleFailure:
+ cu_context_->reporter->DemangleError(data);
+ // fallthrough
+ case Language::kDontDemangle:
+ demangled_name_.clear();
+ break;
+ }
break;
}
default: break;
@@ -294,37 +371,64 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
}
string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
- // Find our unqualified name. If the DIE has its own DW_AT_name
- // attribute, then use that; otherwise, check our specification.
- const string *unqualified_name;
- if (name_attribute_.empty() && specification_)
- unqualified_name = &specification_->unqualified_name;
- else
- unqualified_name = &name_attribute_;
-
- // Find the name of our enclosing context. If we have a
- // specification, it's the specification's enclosing context that
- // counts; otherwise, use this DIE's context.
+ // Use the demangled name, if one is available. Demangled names are
+ // preferable to those inferred from the DWARF structure because they
+ // include argument types.
+ const string *qualified_name = NULL;
+ if (!demangled_name_.empty()) {
+ // Found it is this DIE.
+ qualified_name = &demangled_name_;
+ } else if (specification_ && !specification_->qualified_name.empty()) {
+ // Found it on the specification.
+ qualified_name = &specification_->qualified_name;
+ }
+
+ const string *unqualified_name = NULL;
const string *enclosing_name;
- if (specification_)
- enclosing_name = &specification_->enclosing_name;
- else
- enclosing_name = &parent_context_->name;
+ if (!qualified_name) {
+ // Find the unqualified name. If the DIE has its own DW_AT_name
+ // attribute, then use that; otherwise, check the specification.
+ if (!name_attribute_.empty())
+ unqualified_name = &name_attribute_;
+ else if (specification_)
+ unqualified_name = &specification_->unqualified_name;
+
+ // Find the name of the enclosing context. If this DIE has a
+ // specification, it's the specification's enclosing context that
+ // counts; otherwise, use this DIE's context.
+ if (specification_)
+ enclosing_name = &specification_->enclosing_name;
+ else
+ enclosing_name = &parent_context_->name;
+ }
+
+ // Prepare the return value before upcoming mutations possibly invalidate the
+ // existing pointers.
+ string return_value;
+ if (qualified_name) {
+ return_value = *qualified_name;
+ } else if (unqualified_name && enclosing_name) {
+ // Combine the enclosing name and unqualified name to produce our
+ // own fully-qualified name.
+ return_value = cu_context_->language->MakeQualifiedName(*enclosing_name,
+ *unqualified_name);
+ }
// If this DIE was marked as a declaration, record its names in the
// specification table.
- if (declaration_) {
- FileContext *file_context = cu_context_->file_context;
+ if ((declaration_ && qualified_name) ||
+ (unqualified_name && enclosing_name)) {
Specification spec;
- spec.enclosing_name = *enclosing_name;
- spec.unqualified_name = *unqualified_name;
- file_context->file_private->specifications[offset_] = spec;
+ if (qualified_name) {
+ spec.qualified_name = *qualified_name;
+ } else {
+ spec.enclosing_name = *enclosing_name;
+ spec.unqualified_name = *unqualified_name;
+ }
+ cu_context_->file_context->file_private_->specifications[offset_] = spec;
}
- // Combine the enclosing name and unqualified name to produce our
- // own fully-qualified name.
- return cu_context_->language->MakeQualifiedName(*enclosing_name,
- *unqualified_name);
+ return return_value;
}
// A handler class for DW_TAG_subprogram DIEs.
@@ -333,7 +437,8 @@ 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), abstract_origin_(NULL), inline_(false) { }
+ low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr),
+ abstract_origin_(NULL), inline_(false) { }
void ProcessAttributeUnsigned(enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data);
@@ -352,6 +457,7 @@ 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
+ DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address.
const AbstractOrigin* abstract_origin_;
bool inline_;
};
@@ -367,7 +473,11 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned(
case dwarf2reader::DW_AT_inline: inline_ = true; break;
case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break;
- case dwarf2reader::DW_AT_high_pc: high_pc_ = data; break;
+ case dwarf2reader::DW_AT_high_pc:
+ high_pc_form_ = form;
+ high_pc_ = data;
+ break;
+
default:
GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data);
break;
@@ -393,10 +503,10 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeReference(
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data) {
- switch(attr) {
+ switch (attr) {
case dwarf2reader::DW_AT_abstract_origin: {
const AbstractOriginByOffset& origins =
- cu_context_->file_context->file_private->origins;
+ cu_context_->file_context->file_private_->origins;
AbstractOriginByOffset::const_iterator origin = origins.find(data);
if (origin != origins.end()) {
abstract_origin_ = &(origin->second);
@@ -421,33 +531,39 @@ bool DwarfCUToModule::FuncHandler::EndAttributes() {
}
void DwarfCUToModule::FuncHandler::Finish() {
+ // Make high_pc_ an address, if it isn't already.
+ if (high_pc_form_ != dwarf2reader::DW_FORM_addr) {
+ high_pc_ += low_pc_;
+ }
+
// Did we collect the information we need? Not all DWARF function
// entries have low and high addresses (for example, inlined
// functions that were never used), but all the ones we're
// interested in cover a non-empty range of bytes.
if (low_pc_ < high_pc_) {
- // Create a Module::Function based on the data we've gathered, and
- // add it to the functions_ list.
- Module::Function *func = new Module::Function;
// Malformed DWARF may omit the name, but all Module::Functions must
// have names.
+ string name;
if (!name_.empty()) {
- func->name = name_;
+ name = name_;
} else {
cu_context_->reporter->UnnamedFunction(offset_);
- func->name = "<name omitted>";
+ name = "<name omitted>";
}
- func->address = low_pc_;
+
+ // Create a Module::Function based on the data we've gathered, and
+ // add it to the functions_ list.
+ scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_));
func->size = high_pc_ - low_pc_;
func->parameter_size = 0;
if (func->address) {
// If the function address is zero this is a sign that this function
// description is just empty debug data and should just be discarded.
- cu_context_->functions.push_back(func);
+ cu_context_->functions.push_back(func.release());
}
} else if (inline_) {
AbstractOrigin origin(name_);
- cu_context_->file_context->file_private->origins[offset_] = origin;
+ cu_context_->file_context->file_private_->origins[offset_] = origin;
}
}
@@ -459,8 +575,7 @@ class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler {
uint64 offset)
: GenericDIEHandler(cu_context, parent_context, offset) { }
bool EndAttributes();
- DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
- const AttributeList &attrs);
+ DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag);
private:
DIEContext child_context_; // A context for our children.
@@ -473,8 +588,7 @@ bool DwarfCUToModule::NamedScopeHandler::EndAttributes() {
dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler(
uint64 offset,
- enum DwarfTag tag,
- const AttributeList &attrs) {
+ enum DwarfTag tag) {
switch (tag) {
case dwarf2reader::DW_TAG_subprogram:
return new FuncHandler(cu_context_, &child_context_, offset);
@@ -561,17 +675,31 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
filename_.c_str(), offset);
}
+void DwarfCUToModule::WarningReporter::DemangleError(const string &input) {
+ CUHeading();
+ fprintf(stderr, "%s: warning: failed to demangle %s\n",
+ filename_.c_str(), input.c_str());
+}
+
+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,
- LineToModuleFunctor *line_reader,
+ LineToModuleHandler *line_reader,
WarningReporter *reporter)
- : line_reader_(line_reader), has_source_line_info_(false) {
- cu_context_ = new CUContext(file_context, reporter);
- child_context_ = new DIEContext();
+ : line_reader_(line_reader),
+ cu_context_(new CUContext(file_context, reporter)),
+ child_context_(new DIEContext()),
+ has_source_line_info_(false) {
}
DwarfCUToModule::~DwarfCUToModule() {
- delete cu_context_;
- delete child_context_;
}
void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr,
@@ -605,8 +733,16 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr,
void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
const string &data) {
- if (attr == dwarf2reader::DW_AT_name)
- cu_context_->reporter->SetCUName(data);
+ switch (attr) {
+ case dwarf2reader::DW_AT_name:
+ cu_context_->reporter->SetCUName(data);
+ break;
+ case dwarf2reader::DW_AT_comp_dir:
+ line_reader_->StartCompilationUnit(data);
+ break;
+ default:
+ break;
+ }
}
bool DwarfCUToModule::EndAttributes() {
@@ -615,16 +751,17 @@ bool DwarfCUToModule::EndAttributes() {
dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler(
uint64 offset,
- enum DwarfTag tag,
- const AttributeList &attrs) {
+ enum DwarfTag tag) {
switch (tag) {
case dwarf2reader::DW_TAG_subprogram:
- return new FuncHandler(cu_context_, child_context_, offset);
+ return new FuncHandler(cu_context_.get(), child_context_.get(), offset);
case dwarf2reader::DW_TAG_namespace:
case dwarf2reader::DW_TAG_class_type:
case dwarf2reader::DW_TAG_structure_type:
case dwarf2reader::DW_TAG_union_type:
- return new NamedScopeHandler(cu_context_, child_context_, offset);
+ case dwarf2reader::DW_TAG_module:
+ return new NamedScopeHandler(cu_context_.get(), child_context_.get(),
+ offset);
default:
return NULL;
}
@@ -636,6 +773,14 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
cu_context_->language = Language::Java;
break;
+ case dwarf2reader::DW_LANG_Swift:
+ cu_context_->language = Language::Swift;
+ break;
+
+ case dwarf2reader::DW_LANG_Rust:
+ cu_context_->language = Language::Rust;
+ break;
+
// DWARF has no generic language code for assembly language; this is
// what the GNU toolchain uses.
case dwarf2reader::DW_LANG_Mips_Assembler:
@@ -649,7 +794,7 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
// Objective C and Objective C++ seem to create entries for
// methods whose DW_AT_name values are already fully-qualified:
// "-[Classname method:]". These appear at the top level.
- //
+ //
// DWARF data for C should never include namespaces or functions
// nested in struct types, but if it ever does, then C++'s
// notation is probably not a bad choice for that.
@@ -667,7 +812,7 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
void DwarfCUToModule::ReadSourceLines(uint64 offset) {
const dwarf2reader::SectionMap &section_map
- = cu_context_->file_context->section_map;
+ = cu_context_->file_context->section_map();
dwarf2reader::SectionMap::const_iterator map_entry
= section_map.find(".debug_line");
// Mac OS X puts DWARF data in sections whose names begin with "__"
@@ -678,14 +823,14 @@ void DwarfCUToModule::ReadSourceLines(uint64 offset) {
cu_context_->reporter->MissingSection(".debug_line");
return;
}
- const char *section_start = map_entry->second.first;
+ const uint8_t *section_start = map_entry->second.first;
uint64 section_length = map_entry->second.second;
if (offset >= section_length) {
cu_context_->reporter->BadLineInfoOffset(offset);
return;
}
- (*line_reader_)(section_start + offset, section_length - offset,
- cu_context_->file_context->module, &lines_);
+ line_reader_->ReadProgram(section_start + offset, section_length - offset,
+ cu_context_->file_context->module_, &lines_);
}
namespace {
@@ -715,9 +860,9 @@ void DwarfCUToModule::AssignLinesToFunctions() {
// complexity from here on out is linear.
// Put both our functions and lines in order by address.
- sort(functions->begin(), functions->end(),
- Module::Function::CompareByAddress);
- sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress);
+ std::sort(functions->begin(), functions->end(),
+ Module::Function::CompareByAddress);
+ std::sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress);
// The last line that we used any piece of. We use this only for
// generating warnings.
@@ -852,7 +997,7 @@ void DwarfCUToModule::AssignLinesToFunctions() {
// both func and line begin after CURRENT. The next transition
// is the start of the next function or next line, whichever
// is earliest.
- assert (func || line);
+ assert(func || line);
if (func && line)
next_transition = std::min(func->address, line->address);
else if (func)
@@ -910,12 +1055,14 @@ void DwarfCUToModule::Finish() {
// Add our functions, which now have source lines assigned to them,
// to module_.
- cu_context_->file_context->module->AddFunctions(functions->begin(),
- functions->end());
+ cu_context_->file_context->module_->AddFunctions(functions->begin(),
+ functions->end());
// Ownership of the function objects has shifted from cu_context to
// the Module.
functions->clear();
+
+ cu_context_->file_context->ClearSpecifications();
}
bool DwarfCUToModule::StartCompilationUnit(uint64 offset,
@@ -926,8 +1073,7 @@ bool DwarfCUToModule::StartCompilationUnit(uint64 offset,
return dwarf_version >= 2;
}
-bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag,
- const AttributeList& attrs) {
+bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag) {
// We don't deal with partial compilation units (the only other tag
// likely to be used for root DIE).
return tag == dwarf2reader::DW_TAG_compile_unit;