Index: obsolete/breakpad/common/dwarf_cu_to_module.cc |
diff --git a/obsolete/breakpad/common/dwarf_cu_to_module.cc b/obsolete/breakpad/common/dwarf_cu_to_module.cc |
deleted file mode 100644 |
index 25178f90c0fb680305633d5a8b670ac811eabb8c..0000000000000000000000000000000000000000 |
--- a/obsolete/breakpad/common/dwarf_cu_to_module.cc |
+++ /dev/null |
@@ -1,882 +0,0 @@ |
-// Copyright (c) 2010 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. |
- |
-// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
- |
-// Implement the DwarfCUToModule class; see dwarf_cu_to_module.h. |
- |
-#include <algorithm> |
-#include <cassert> |
- |
-#include "common/dwarf_cu_to_module.h" |
-#include "common/dwarf_line_to_module.h" |
- |
- |
-namespace google_breakpad { |
- |
-using std::map; |
-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 |
-// example, it's common for a function's address range to appear only in |
-// its definition DIE, but its name to appear only in its declaration |
-// DIE. |
-// |
-// The dumper needs to be able to follow DW_AT_specification links to |
-// bring all this information together in a FUNC record. Conveniently, |
-// DIEs that are the target of such links have a DW_AT_declaration flag |
-// set, so we can identify them when we first see them, and record their |
-// contents for later reference. |
-// |
-// 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 name of the enclosing scope, or the empty string if there is none. |
- string enclosing_name; |
- |
- // The name for the specification DIE itself, without any enclosing |
- // name components. |
- 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 { |
- // A map from offsets of DIEs within the .debug_info section to |
- // Specifications describing those DIEs. Specification references can |
- // cross compilation unit boundaries. |
- SpecificationByOffset specifications; |
- |
- AbstractOriginByOffset origins; |
-}; |
- |
-DwarfCUToModule::FileContext::FileContext(const string &filename_arg, |
- Module *module_arg) |
- : filename(filename_arg), module(module_arg) { |
- file_private = new DwarfCUToModule::FilePrivate(); |
-} |
- |
-DwarfCUToModule::FileContext::~FileContext() { |
- delete file_private; |
-} |
- |
-// Information global to the particular compilation unit we're |
-// parsing. This is for data shared across the CU's entire DIE tree, |
-// and parameters from the code invoking the CU parser. |
-struct DwarfCUToModule::CUContext { |
- CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg) |
- : file_context(file_context_arg), |
- reporter(reporter_arg), |
- language(Language::CPlusPlus) { } |
- ~CUContext() { |
- for (vector<Module::Function *>::iterator it = functions.begin(); |
- it != functions.end(); it++) |
- delete *it; |
- }; |
- |
- // The DWARF-bearing file into which this CU was incorporated. |
- FileContext *file_context; |
- |
- // For printing error messages. |
- WarningReporter *reporter; |
- |
- // The source language of this compilation unit. |
- const Language *language; |
- |
- // The functions defined in this compilation unit. We accumulate |
- // them here during parsing. Then, in DwarfCUToModule::Finish, we |
- // assign them lines and add them to file_context->module. |
- // |
- // Destroying this destroys all the functions this vector points to. |
- vector<Module::Function *> functions; |
-}; |
- |
-// Information about the context of a particular DIE. This is for |
-// information that changes as we descend the tree towards the leaves: |
-// the containing classes/namespaces, etc. |
-struct DwarfCUToModule::DIEContext { |
- // The fully-qualified name of the context. For example, for a |
- // tree like: |
- // |
- // DW_TAG_namespace Foo |
- // DW_TAG_class Bar |
- // DW_TAG_subprogram Baz |
- // |
- // in a C++ compilation unit, the DIEContext's name for the |
- // DW_TAG_subprogram DIE would be "Foo::Bar". The DIEContext's |
- // name for the DW_TAG_namespace DIE would be "". |
- string name; |
-}; |
- |
-// An abstract base class for all the dumper's DIE handlers. |
-class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { |
- public: |
- // Create a handler for the DIE at OFFSET whose compilation unit is |
- // described by CU_CONTEXT, and whose immediate context is described |
- // by PARENT_CONTEXT. |
- GenericDIEHandler(CUContext *cu_context, DIEContext *parent_context, |
- uint64 offset) |
- : cu_context_(cu_context), |
- parent_context_(parent_context), |
- offset_(offset), |
- declaration_(false), |
- specification_(NULL) { } |
- |
- // Derived classes' ProcessAttributeUnsigned can defer to this to |
- // handle DW_AT_declaration, or simply not override it. |
- void ProcessAttributeUnsigned(enum DwarfAttribute attr, |
- enum DwarfForm form, |
- uint64 data); |
- |
- // Derived classes' ProcessAttributeReference can defer to this to |
- // handle DW_AT_specification, or simply not override it. |
- void ProcessAttributeReference(enum DwarfAttribute attr, |
- enum DwarfForm form, |
- uint64 data); |
- |
- // Derived classes' ProcessAttributeReference can defer to this to |
- // handle DW_AT_specification, or simply not override it. |
- void ProcessAttributeString(enum DwarfAttribute attr, |
- enum DwarfForm form, |
- const string &data); |
- |
- protected: |
- // Compute and return the fully-qualified name of the DIE. If this |
- // DIE is a declaration DIE, to be cited by other DIEs' |
- // DW_AT_specification attributes, record its enclosing name and |
- // unqualified name in the specification table. |
- // |
- // Use this from EndAttributes member functions, not ProcessAttribute* |
- // functions; only the former can be sure that all the DIE's attributes |
- // have been seen. |
- string ComputeQualifiedName(); |
- |
- CUContext *cu_context_; |
- DIEContext *parent_context_; |
- uint64 offset_; |
- |
- // 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_; |
- |
- // If this DIE has a DW_AT_specification attribute, this is the |
- // Specification structure for the DIE the attribute refers to. |
- // Otherwise, this is NULL. |
- Specification *specification_; |
- |
- // The value of the DW_AT_name attribute, or the empty string if the |
- // DIE has no such attribute. |
- string name_attribute_; |
-}; |
- |
-void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned( |
- enum DwarfAttribute attr, |
- enum DwarfForm form, |
- uint64 data) { |
- switch (attr) { |
- case dwarf2reader::DW_AT_declaration: declaration_ = (data != 0); break; |
- default: break; |
- } |
-} |
- |
-void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( |
- enum DwarfAttribute attr, |
- enum DwarfForm form, |
- uint64 data) { |
- switch (attr) { |
- case dwarf2reader::DW_AT_specification: { |
- // 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::iterator spec = specifications->find(data); |
- if (spec != specifications->end()) { |
- specification_ = &spec->second; |
- } else { |
- // Technically, there's no reason a DW_AT_specification |
- // couldn't be a forward reference, but supporting that would |
- // be a lot of work (changing to a two-pass structure), and I |
- // don't think any producers we care about ever emit such |
- // things. |
- cu_context_->reporter->UnknownSpecification(offset_, data); |
- } |
- break; |
- } |
- default: break; |
- } |
-} |
- |
-void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( |
- enum DwarfAttribute attr, |
- enum DwarfForm form, |
- const string &data) { |
- switch (attr) { |
- case dwarf2reader::DW_AT_name: name_attribute_ = data; break; |
- default: break; |
- } |
-} |
- |
-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. |
- const string *enclosing_name; |
- if (specification_) |
- enclosing_name = &specification_->enclosing_name; |
- else |
- enclosing_name = &parent_context_->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; |
- Specification spec; |
- spec.enclosing_name = *enclosing_name; |
- spec.unqualified_name = *unqualified_name; |
- 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); |
-} |
- |
-// A handler class for DW_TAG_subprogram DIEs. |
-class DwarfCUToModule::FuncHandler: public GenericDIEHandler { |
- public: |
- 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) { } |
- 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(); |
- |
- private: |
- // The fully-qualified name, as derived from name_attribute_, |
- // 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( |
- enum DwarfAttribute attr, |
- enum DwarfForm form, |
- uint64 data) { |
- switch (attr) { |
- // If this attribute is present at all --- even if its value is |
- // DW_INL_not_inlined --- then GCC may cite it as someone else's |
- // DW_AT_abstract_origin attribute. |
- 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; |
- default: |
- GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); |
- break; |
- } |
-} |
- |
-void DwarfCUToModule::FuncHandler::ProcessAttributeSigned( |
- enum DwarfAttribute attr, |
- enum DwarfForm form, |
- int64 data) { |
- switch (attr) { |
- // If this attribute is present at all --- even if its value is |
- // DW_INL_not_inlined --- then GCC may cite it as someone else's |
- // DW_AT_abstract_origin attribute. |
- case dwarf2reader::DW_AT_inline: inline_ = true; 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; |
-} |
- |
-void DwarfCUToModule::FuncHandler::Finish() { |
- // 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; |
- func->name = name_; |
- func->address = low_pc_; |
- 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; |
- } |
-} |
- |
-// A handler for DIEs that contain functions and contribute a |
-// component to their names: namespaces, classes, etc. |
-class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler { |
- public: |
- NamedScopeHandler(CUContext *cu_context, DIEContext *parent_context, |
- uint64 offset) |
- : GenericDIEHandler(cu_context, parent_context, offset) { } |
- bool EndAttributes(); |
- DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag, |
- const AttributeList &attrs); |
- |
- private: |
- DIEContext child_context_; // A context for our children. |
-}; |
- |
-bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { |
- child_context_.name = ComputeQualifiedName(); |
- return true; |
-} |
- |
-dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler( |
- uint64 offset, |
- enum DwarfTag tag, |
- const AttributeList &attrs) { |
- switch (tag) { |
- case dwarf2reader::DW_TAG_subprogram: |
- return new FuncHandler(cu_context_, &child_context_, 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); |
- default: |
- return NULL; |
- } |
-}; |
- |
-void DwarfCUToModule::WarningReporter::CUHeading() { |
- if (printed_cu_header_) |
- return; |
- fprintf(stderr, "%s: in compilation unit '%s' (offset 0x%llx):\n", |
- filename_.c_str(), cu_name_.c_str(), cu_offset_); |
- printed_cu_header_ = true; |
-} |
- |
-void DwarfCUToModule::WarningReporter::UnknownSpecification(uint64 offset, |
- uint64 target) { |
- CUHeading(); |
- fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_specification" |
- " attribute referring to the die at offset 0x%llx, which either" |
- " was not marked as a declaration, or comes later in the file\n", |
- 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\n", |
- filename_.c_str(), offset, target); |
-} |
- |
-void DwarfCUToModule::WarningReporter::MissingSection(const string &name) { |
- CUHeading(); |
- fprintf(stderr, "%s: warning: couldn't find DWARF '%s' section\n", |
- filename_.c_str(), name.c_str()); |
-} |
- |
-void DwarfCUToModule::WarningReporter::BadLineInfoOffset(uint64 offset) { |
- CUHeading(); |
- fprintf(stderr, "%s: warning: line number data offset beyond end" |
- " of '.debug_line' section\n", |
- filename_.c_str()); |
-} |
- |
-void DwarfCUToModule::WarningReporter::UncoveredHeading() { |
- if (printed_unpaired_header_) |
- return; |
- CUHeading(); |
- fprintf(stderr, "%s: warning: skipping unpaired lines/functions:\n", |
- filename_.c_str()); |
- printed_unpaired_header_ = true; |
-} |
- |
-void DwarfCUToModule::WarningReporter::UncoveredFunction( |
- const Module::Function &function) { |
- if (!uncovered_warnings_enabled_) |
- return; |
- UncoveredHeading(); |
- fprintf(stderr, " function%s: %s\n", |
- function.size == 0 ? " (zero-length)" : "", |
- function.name.c_str()); |
-} |
- |
-void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) { |
- if (!uncovered_warnings_enabled_) |
- return; |
- UncoveredHeading(); |
- fprintf(stderr, " line%s: %s:%d at 0x%llx\n", |
- (line.size == 0 ? " (zero-length)" : ""), |
- line.file->name.c_str(), line.number, line.address); |
-} |
- |
-DwarfCUToModule::DwarfCUToModule(FileContext *file_context, |
- LineToModuleFunctor *line_reader, |
- WarningReporter *reporter) |
- : line_reader_(line_reader), has_source_line_info_(false) { |
- cu_context_ = new CUContext(file_context, reporter); |
- child_context_ = new DIEContext(); |
-} |
- |
-DwarfCUToModule::~DwarfCUToModule() { |
- delete cu_context_; |
- delete child_context_; |
-} |
- |
-void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr, |
- enum DwarfForm form, |
- int64 data) { |
- switch (attr) { |
- case dwarf2reader::DW_AT_language: // source language of this CU |
- SetLanguage(static_cast<DwarfLanguage>(data)); |
- break; |
- default: |
- break; |
- } |
-} |
- |
-void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, |
- enum DwarfForm form, |
- uint64 data) { |
- switch (attr) { |
- case dwarf2reader::DW_AT_stmt_list: // Line number information. |
- has_source_line_info_ = true; |
- source_line_offset_ = data; |
- break; |
- case dwarf2reader::DW_AT_language: // source language of this CU |
- SetLanguage(static_cast<DwarfLanguage>(data)); |
- break; |
- default: |
- break; |
- } |
-} |
- |
-void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr, |
- enum DwarfForm form, |
- const string &data) { |
- if (attr == dwarf2reader::DW_AT_name) |
- cu_context_->reporter->SetCUName(data); |
-} |
- |
-bool DwarfCUToModule::EndAttributes() { |
- return true; |
-} |
- |
-dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler( |
- uint64 offset, |
- enum DwarfTag tag, |
- const AttributeList &attrs) { |
- switch (tag) { |
- case dwarf2reader::DW_TAG_subprogram: |
- return new FuncHandler(cu_context_, child_context_, 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); |
- default: |
- return NULL; |
- } |
-} |
- |
-void DwarfCUToModule::SetLanguage(DwarfLanguage language) { |
- switch (language) { |
- case dwarf2reader::DW_LANG_Java: |
- cu_context_->language = Language::Java; |
- break; |
- |
- // DWARF has no generic language code for assembly language; this is |
- // what the GNU toolchain uses. |
- case dwarf2reader::DW_LANG_Mips_Assembler: |
- cu_context_->language = Language::Assembler; |
- break; |
- |
- // C++ covers so many cases that it probably has some way to cope |
- // with whatever the other languages throw at us. So make it the |
- // default. |
- // |
- // 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. |
- default: |
- case dwarf2reader::DW_LANG_ObjC: |
- case dwarf2reader::DW_LANG_ObjC_plus_plus: |
- case dwarf2reader::DW_LANG_C: |
- case dwarf2reader::DW_LANG_C89: |
- case dwarf2reader::DW_LANG_C99: |
- case dwarf2reader::DW_LANG_C_plus_plus: |
- cu_context_->language = Language::CPlusPlus; |
- break; |
- } |
-} |
- |
-void DwarfCUToModule::ReadSourceLines(uint64 offset) { |
- const dwarf2reader::SectionMap §ion_map |
- = cu_context_->file_context->section_map; |
- dwarf2reader::SectionMap::const_iterator map_entry |
- = section_map.find(".debug_line"); |
- if (map_entry == section_map.end()) { |
- cu_context_->reporter->MissingSection(".debug_line"); |
- return; |
- } |
- const char *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_); |
-} |
- |
-namespace { |
-// Return true if ADDRESS falls within the range of ITEM. |
-template <class T> |
-inline bool within(const T &item, Module::Address address) { |
- // Because Module::Address is unsigned, and unsigned arithmetic |
- // wraps around, this will be false if ADDRESS falls before the |
- // start of ITEM, or if it falls after ITEM's end. |
- return address - item.address < item.size; |
-} |
-} |
- |
-void DwarfCUToModule::AssignLinesToFunctions() { |
- vector<Module::Function *> *functions = &cu_context_->functions; |
- WarningReporter *reporter = cu_context_->reporter; |
- |
- // This would be simpler if we assumed that source line entries |
- // don't cross function boundaries. However, there's no real reason |
- // to assume that (say) a series of function definitions on the same |
- // line wouldn't get coalesced into one line number entry. The |
- // DWARF spec certainly makes no such promises. |
- // |
- // So treat the functions and lines as peers, and take the trouble |
- // to compute their ranges' intersections precisely. In any case, |
- // the hair here is a constant factor for performance; the |
- // 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); |
- |
- // The last line that we used any piece of. We use this only for |
- // generating warnings. |
- const Module::Line *last_line_used = NULL; |
- |
- // The last function and line we warned about --- so we can avoid |
- // doing so more than once. |
- const Module::Function *last_function_cited = NULL; |
- const Module::Line *last_line_cited = NULL; |
- |
- // Make a single pass through both vectors from lower to higher |
- // addresses, populating each Function's lines vector with lines |
- // from our lines_ vector that fall within the function's address |
- // range. |
- vector<Module::Function *>::iterator func_it = functions->begin(); |
- vector<Module::Line>::const_iterator line_it = lines_.begin(); |
- |
- Module::Address current; |
- |
- // Pointers to the referents of func_it and line_it, or NULL if the |
- // iterator is at the end of the sequence. |
- Module::Function *func; |
- const Module::Line *line; |
- |
- // Start current at the beginning of the first line or function, |
- // whichever is earlier. |
- if (func_it != functions->end() && line_it != lines_.end()) { |
- func = *func_it; |
- line = &*line_it; |
- current = std::min(func->address, line->address); |
- } else if (line_it != lines_.end()) { |
- func = NULL; |
- line = &*line_it; |
- current = line->address; |
- } else if (func_it != functions->end()) { |
- func = *func_it; |
- line = NULL; |
- current = (*func_it)->address; |
- } else { |
- return; |
- } |
- |
- while (func || line) { |
- // This loop has two invariants that hold at the top. |
- // |
- // First, at least one of the iterators is not at the end of its |
- // sequence, and those that are not refer to the earliest |
- // function or line that contains or starts after CURRENT. |
- // |
- // Note that every byte is in one of four states: it is covered |
- // or not covered by a function, and, independently, it is |
- // covered or not covered by a line. |
- // |
- // The second invariant is that CURRENT refers to a byte whose |
- // state is different from its predecessor, or it refers to the |
- // first byte in the address space. In other words, CURRENT is |
- // always the address of a transition. |
- // |
- // Note that, although each iteration advances CURRENT from one |
- // transition address to the next in each iteration, it might |
- // not advance the iterators. Suppose we have a function that |
- // starts with a line, has a gap, and then a second line, and |
- // suppose that we enter an iteration with CURRENT at the end of |
- // the first line. The next transition address is the start of |
- // the second line, after the gap, so the iteration should |
- // advance CURRENT to that point. At the head of that iteration, |
- // the invariants require that the line iterator be pointing at |
- // the second line. But this is also true at the head of the |
- // next. And clearly, the iteration must not change the function |
- // iterator. So neither iterator moves. |
- |
- // Assert the first invariant (see above). |
- assert(!func || current < func->address || within(*func, current)); |
- assert(!line || current < line->address || within(*line, current)); |
- |
- // The next transition after CURRENT. |
- Module::Address next_transition; |
- |
- // Figure out which state we're in, add lines or warn, and compute |
- // the next transition address. |
- if (func && current >= func->address) { |
- if (line && current >= line->address) { |
- // Covered by both a line and a function. |
- Module::Address func_left = func->size - (current - func->address); |
- Module::Address line_left = line->size - (current - line->address); |
- // This may overflow, but things work out. |
- next_transition = current + std::min(func_left, line_left); |
- Module::Line l = *line; |
- l.address = current; |
- l.size = next_transition - current; |
- func->lines.push_back(l); |
- last_line_used = line; |
- } else { |
- // Covered by a function, but no line. |
- if (func != last_function_cited) { |
- reporter->UncoveredFunction(*func); |
- last_function_cited = func; |
- } |
- if (line && within(*func, line->address)) |
- next_transition = line->address; |
- else |
- // If this overflows, we'll catch it below. |
- next_transition = func->address + func->size; |
- } |
- } else { |
- if (line && current >= line->address) { |
- // Covered by a line, but no function. |
- // |
- // If GCC emits padding after one function to align the start |
- // of the next, then it will attribute the padding |
- // instructions to the last source line of function (to reduce |
- // the size of the line number info), but omit it from the |
- // DW_AT_{low,high}_pc range given in .debug_info (since it |
- // costs nothing to be precise there). If we did use at least |
- // some of the line we're about to skip, and it ends at the |
- // start of the next function, then assume this is what |
- // happened, and don't warn. |
- if (line != last_line_cited |
- && !(func |
- && line == last_line_used |
- && func->address - line->address == line->size)) { |
- reporter->UncoveredLine(*line); |
- last_line_cited = line; |
- } |
- if (func && within(*line, func->address)) |
- next_transition = func->address; |
- else |
- // If this overflows, we'll catch it below. |
- next_transition = line->address + line->size; |
- } else { |
- // Covered by neither a function nor a line. By the invariant, |
- // 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); |
- if (func && line) |
- next_transition = std::min(func->address, line->address); |
- else if (func) |
- next_transition = func->address; |
- else |
- next_transition = line->address; |
- } |
- } |
- |
- // If a function or line abuts the end of the address space, then |
- // next_transition may end up being zero, in which case we've completed |
- // our pass. Handle that here, instead of trying to deal with it in |
- // each place we compute next_transition. |
- if (!next_transition) |
- break; |
- |
- // Advance iterators as needed. If lines overlap or functions overlap, |
- // then we could go around more than once. We don't worry too much |
- // about what result we produce in that case, just as long as we don't |
- // hang or crash. |
- while (func_it != functions->end() |
- && current >= (*func_it)->address |
- && !within(**func_it, next_transition)) |
- func_it++; |
- func = (func_it != functions->end()) ? *func_it : NULL; |
- while (line_it != lines_.end() |
- && current >= line_it->address |
- && !within(*line_it, next_transition)) |
- line_it++; |
- line = (line_it != lines_.end()) ? &*line_it : NULL; |
- |
- // We must make progress. |
- assert(next_transition > current); |
- current = next_transition; |
- } |
-} |
- |
-void DwarfCUToModule::Finish() { |
- // Assembly language files have no function data, and that gives us |
- // no place to store our line numbers (even though the GNU toolchain |
- // will happily produce source line info for assembly language |
- // files). To avoid spurious warnings about lines we can't assign |
- // to functions, skip CUs in languages that lack functions. |
- if (!cu_context_->language->HasFunctions()) |
- return; |
- |
- // Read source line info, if we have any. |
- if (has_source_line_info_) |
- ReadSourceLines(source_line_offset_); |
- |
- vector<Module::Function *> *functions = &cu_context_->functions; |
- |
- // Dole out lines to the appropriate functions. |
- AssignLinesToFunctions(); |
- |
- // Add our functions, which now have source lines assigned to them, |
- // to module_. |
- 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(); |
-} |
- |
-bool DwarfCUToModule::StartCompilationUnit(uint64 offset, |
- uint8 address_size, |
- uint8 offset_size, |
- uint64 cu_length, |
- uint8 dwarf_version) { |
- return dwarf_version >= 2; |
-} |
- |
-bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag, |
- const AttributeList& attrs) { |
- // 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; |
-} |
- |
-} // namespace google_breakpad |