summaryrefslogtreecommitdiffstats
path: root/breakpad
diff options
context:
space:
mode:
Diffstat (limited to 'breakpad')
-rw-r--r--breakpad/breakpad.gyp8
-rw-r--r--breakpad/pending/src/common/dwarf_cu_to_module.cc1023
-rw-r--r--breakpad/pending/src/common/dwarf_cu_to_module.h279
-rw-r--r--breakpad/pending/src/common/dwarf_cu_to_module_unittest.cc1763
-rw-r--r--breakpad/pending/src/common/module.cc294
5 files changed, 2 insertions, 3365 deletions
diff --git a/breakpad/breakpad.gyp b/breakpad/breakpad.gyp
index 8ef5e9a..ea137cc 100644
--- a/breakpad/breakpad.gyp
+++ b/breakpad/breakpad.gyp
@@ -206,18 +206,13 @@
{
'target_name': 'dump_syms',
'type': 'executable',
- 'include_dirs++': [
- # ++ ensures this comes before src brought in from target_defaults.
- 'pending/src',
- ],
'include_dirs': [
'src/common/mac',
],
'sources': [
- 'pending/src/common/dwarf_cu_to_module.cc',
- 'pending/src/common/module.cc',
'src/common/dwarf/bytereader.cc',
'src/common/dwarf_cfi_to_module.cc',
+ 'src/common/dwarf_cu_to_module.cc',
'src/common/dwarf/dwarf2diehandler.cc',
'src/common/dwarf/dwarf2reader.cc',
'src/common/dwarf_line_to_module.cc',
@@ -231,6 +226,7 @@
'src/common/mac/macho_utilities.cc',
'src/common/mac/macho_walker.cc',
'src/common/md5.cc',
+ 'src/common/module.cc',
'src/common/stabs_reader.cc',
'src/common/stabs_to_module.cc',
'src/tools/mac/dump_syms/dump_syms_tool.mm',
diff --git a/breakpad/pending/src/common/dwarf_cu_to_module.cc b/breakpad/pending/src/common/dwarf_cu_to_module.cc
deleted file mode 100644
index 54f27bd..0000000
--- a/breakpad/pending/src/common/dwarf_cu_to_module.cc
+++ /dev/null
@@ -1,1023 +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.
-
-// For <inttypes.h> PRI* macros, before anything else might #include it.
-#ifndef __STDC_FORMAT_MACROS
-#define __STDC_FORMAT_MACROS
-#endif /* __STDC_FORMAT_MACROS */
-
-#include "common/dwarf_cu_to_module.h"
-
-#include <assert.h>
-#include <inttypes.h>
-#include <stdio.h>
-
-#include <algorithm>
-#include <set>
-#include <utility>
-
-#include "common/dwarf_line_to_module.h"
-
-namespace google_breakpad {
-
-using std::map;
-using std::pair;
-using std::set;
-using std::vector;
-
-// This Function extends the base definition of Function to defer computation
-// of a function's name until the entire compilation unit has been processed.
-// specification_offset and abstract_origin_offset, if not 0, refer to an
-// offset key in the DwarfCUToModule::FilePrivate::specifications map.
-struct DwarfCUToModule::Function : public Module::Function {
- Function()
- : Module::Function(),
- specification_offset(0),
- abstract_origin_offset(0) {
- }
-
- uint64_t specification_offset;
- uint64_t abstract_origin_offset;
-};
-
-// 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 {
- // Compute qualified_name if it has not yet been computed, and return it.
- // cu_context is used to provide access to the specifications map for
- // further lookups on specification_offset and
- // enclosing_name_specification_offset, as well as access to the
- // WarningReporter. The offset argument is the offset at which the DIE that
- // resulted in this object's creation was located, and is only used for
- // warning reporting.
- string QualifiedName(DwarfCUToModule::CUContext* cu_context, uint64 offset);
-
- // These fields contain values set by the DIE that resulted in the creation
- // of this object.
- string unqualified_name;
- uint64 specification_offset;
- bool declaration;
- uint64 enclosing_name_specification_offset;
- const Language* language;
-
- // The qualified name, empty until computed by QualifiedName.
- string qualified_name;
-};
-
-// Data global to the DWARF-bearing file that is private to the
-// DWARF-to-Module process.
-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;
-
- // A map from offsets of DIEs within the .debug_info section to
- // Specifications describing those DIEs. Specification references can
- // cross compilation unit boundaries. Pointers added to this map are owned
- // by the FileContext that owns this FilePrivate.
- SpecificationByOffset specifications;
-};
-
-DwarfCUToModule::FileContext::FileContext(const string &filename_arg,
- Module *module_arg)
- : filename(filename_arg), module(module_arg) {
- file_private = new FilePrivate();
-}
-
-DwarfCUToModule::FileContext::~FileContext() {
- for (SpecificationByOffset::iterator iterator =
- file_private->specifications.begin();
- iterator != file_private->specifications.end();
- ++iterator) {
- delete iterator->second;
- }
-
- 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.
- //
- // This actually stores google_breakpad::DwarfCUToModule::Function*, a
- // type derived from google_breakpad::Module::Function*.
- vector<Module::Function *> functions;
-};
-
-string DwarfCUToModule::Specification::QualifiedName(
- DwarfCUToModule::CUContext* cu_context, uint64 offset) {
- SpecificationByOffset* specifications =
- &cu_context->file_context->file_private->specifications;
-
- if (!qualified_name.empty()) {
- return qualified_name;
- }
-
- // Avoid infinite recursion in the presence of evil data.
- qualified_name.assign("<in process>");
-
- Specification* other = NULL;
- if (specification_offset) {
- SpecificationByOffset::iterator iterator =
- specifications->find(specification_offset);
- if (iterator != specifications->end()) {
- other = iterator->second;
- if (!other->declaration) {
- other = NULL;
- }
- }
- if (!other) {
- cu_context->reporter->UnknownSpecification(offset, specification_offset);
- }
- }
-
- if (other) {
- other->QualifiedName(cu_context, specification_offset);
- }
-
- if (unqualified_name.empty() && other) {
- unqualified_name = other->unqualified_name;
- }
-
- if (other) {
- enclosing_name_specification_offset =
- other->enclosing_name_specification_offset;
- }
-
- std::string enclosing_name;
- Specification* enclosing = NULL;
- if (enclosing_name_specification_offset) {
- SpecificationByOffset::iterator iterator =
- specifications->find(enclosing_name_specification_offset);
- if (iterator != specifications->end()) {
- enclosing = iterator->second;
- } else {
- cu_context->reporter->UnknownSpecification(
- offset, enclosing_name_specification_offset);
- }
- }
- if (enclosing) {
- enclosing_name =
- enclosing->QualifiedName(cu_context,
- enclosing_name_specification_offset);
- if (enclosing_name.empty() && language == Language::CPlusPlus) {
- enclosing_name.assign("(anonymous namespace)");
- }
- }
-
- qualified_name =
- language->MakeQualifiedName(enclosing_name, unqualified_name);
-
- return qualified_name;
-}
-
-// 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 {
- DIEContext()
- : name_specification_offset(0) {
- }
-
- // 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 "".
- uint64 name_specification_offset;
-};
-
-// 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_offset_(0) { }
-
- // 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:
- // Create and store a Specification for later use. Once all Specifications
- // have been read, they can be used to determine the fully-qualified name
- // of this DIE. Specifications may reference those that come later in the
- // file, so these are all stored in a map and name computation is deferred
- // until they've all been read.
- //
- // Use this from EndAttributes member functions, not ProcessAttribute*
- // functions; only the former can be sure that all the DIE's attributes
- // have been seen.
- void RememberSpecification();
-
- 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
- // offset that it refers to, which can ultimately be looked up in
- // DwarfCUToModule::FilePrivate::specifications. Otherwise, this is 0.
- uint64 specification_offset_;
-
- // 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: {
- specification_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: {
- // 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;
- break;
- }
- default: break;
- }
-}
-
-void DwarfCUToModule::GenericDIEHandler::RememberSpecification() {
- Specification* specification = new Specification();
-
- specification->unqualified_name = name_attribute_;
- specification->specification_offset = specification_offset_;
- specification->declaration = declaration_;
- specification->enclosing_name_specification_offset =
- parent_context_->name_specification_offset;
- specification->language = cu_context_->language;
-
- FileContext *file_context = cu_context_->file_context;
-
- // Make sure it isn't there yet.
- assert(file_context->file_private->specifications.find(offset_) ==
- file_context->file_private->specifications.end());
-
- file_context->file_private->specifications[offset_] = specification;
-}
-
-// 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_offset_(0),
- 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
- uint64 abstract_origin_offset_;
- 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: {
- abstract_origin_offset_ = data;
- break;
- }
- default:
- GenericDIEHandler::ProcessAttributeReference(attr, form, data);
- break;
- }
-}
-
-bool DwarfCUToModule::FuncHandler::EndAttributes() {
- RememberSpecification();
- 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.
- Function *func = new Function;
- func->address = low_pc_;
- func->size = high_pc_ - low_pc_;
- func->parameter_size = 0;
- func->specification_offset = offset_;
- func->abstract_origin_offset = abstract_origin_offset_;
- cu_context_->functions.push_back(func);
- }
-}
-
-// 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);
-
- private:
- DIEContext child_context_; // A context for our children.
-};
-
-bool DwarfCUToModule::NamedScopeHandler::EndAttributes() {
- child_context_.name_specification_offset = offset_;
- RememberSpecification();
- return true;
-}
-
-dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler(
- uint64 offset,
- enum DwarfTag tag) {
- 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%" PRIx64 "\n",
- (line.size == 0 ? " (zero-length)" : ""),
- line.file->name.c_str(), line.number, line.address);
-}
-
-void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
- CUHeading();
- fprintf(stderr, "%s: warning: function at offset 0x%" PRIx64 " has no name\n",
- filename_.c_str(), offset);
-}
-
-DwarfCUToModule::DwarfCUToModule(FileContext *file_context,
- 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();
-}
-
-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) {
- 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 &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 "__"
- // instead of ".".
- if (map_entry == section_map.end())
- 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_->ReadProgram(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(),
- 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()
- && next_transition >= (*func_it)->address
- && !within(**func_it, next_transition))
- func_it++;
- func = (func_it != functions->end()) ? *func_it : NULL;
- while (line_it != lines_.end()
- && next_transition >= 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;
-
- for (vector<Module::Function*>::iterator iterator = functions->begin();
- iterator != functions->end();
- ++iterator) {
- Function* function = static_cast<Function*>(*iterator);
-
- if (function->specification_offset) {
- SpecificationByOffset::iterator specification_iterator =
- cu_context_->file_context->file_private->specifications.find(
- function->specification_offset);
- if (specification_iterator !=
- cu_context_->file_context->file_private->specifications.end()) {
- Specification* specification = specification_iterator->second;
- function->name = specification->QualifiedName(
- cu_context_, function->specification_offset);
- } else {
- cu_context_->reporter->UnknownSpecification(
- 0, function->specification_offset);
- }
- }
-
- if (function->name.empty()) {
- if (function->abstract_origin_offset) {
- SpecificationByOffset::iterator abstract_origin_iterator =
- cu_context_->file_context->file_private->specifications.find(
- function->abstract_origin_offset);
- if (abstract_origin_iterator !=
- cu_context_->file_context->file_private->specifications.end()) {
- Specification* abstract_origin = abstract_origin_iterator->second;
- function->name = abstract_origin->QualifiedName(
- cu_context_, function->abstract_origin_offset);
- } else {
- cu_context_->reporter->UnknownAbstractOrigin(
- 0, function->abstract_origin_offset);
- }
- }
- }
-
- if (function->name.empty()) {
- function->name.assign("<name omitted>");
- cu_context_->reporter->UnnamedFunction(function->specification_offset);
- }
- }
-
- // 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) {
- // 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
diff --git a/breakpad/pending/src/common/dwarf_cu_to_module.h b/breakpad/pending/src/common/dwarf_cu_to_module.h
deleted file mode 100644
index f5ca555..0000000
--- a/breakpad/pending/src/common/dwarf_cu_to_module.h
+++ /dev/null
@@ -1,279 +0,0 @@
-// -*- mode: c++ -*-
-
-// 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>
-
-// Add DWARF debugging information to a Breakpad symbol file. This
-// file defines the DwarfCUToModule class, which accepts parsed DWARF
-// data and populates a google_breakpad::Module with the results; the
-// Module can then write its contents as a Breakpad symbol file.
-
-#ifndef COMMON_LINUX_DWARF_CU_TO_MODULE_H__
-#define COMMON_LINUX_DWARF_CU_TO_MODULE_H__
-
-#include <string>
-
-#include "common/language.h"
-#include "common/module.h"
-#include "common/dwarf/bytereader.h"
-#include "common/dwarf/dwarf2diehandler.h"
-#include "common/dwarf/dwarf2reader.h"
-
-namespace google_breakpad {
-
-using dwarf2reader::DwarfAttribute;
-using dwarf2reader::DwarfForm;
-using dwarf2reader::DwarfLanguage;
-using dwarf2reader::DwarfTag;
-
-// Populate a google_breakpad::Module with DWARF debugging information.
-//
-// An instance of this class can be provided as a handler to a
-// dwarf2reader::CompilationUnit DWARF parser. The handler uses the
-// results of parsing to populate a google_breakpad::Module with
-// source file, function, and source line information.
-class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
- struct FilePrivate;
- public:
-
- // Information global to the DWARF-bearing file we are processing,
- // for use by DwarfCUToModule. Each DwarfCUToModule instance deals
- // with a single compilation unit within the file, but information
- // global to the whole file is held here. The client is responsible
- // for filling it in appropriately (except for the 'file_private'
- // field, which the constructor and destructor take care of), and
- // then providing it to the DwarfCUToModule instance for each
- // compilation unit we process in that file.
- struct FileContext {
- FileContext(const string &filename_arg, Module *module_arg);
- ~FileContext();
-
- // The name of this file, for use in error messages.
- string filename;
-
- // A map of this file's sections, used for finding other DWARF
- // sections that the .debug_info section may refer to.
- dwarf2reader::SectionMap section_map;
-
- // The Module to which we're contributing definitions.
- Module *module;
-
- // Inter-compilation unit data used internally by the handlers.
- FilePrivate *file_private;
- };
-
- // An abstract base class for handlers that handle DWARF line data
- // for DwarfCUToModule. DwarfCUToModule could certainly just use
- // dwarf2reader::LineInfo itself directly, but decoupling things
- // this way makes unit testing a little easier.
- class LineToModuleHandler {
- public:
- LineToModuleHandler() { }
- virtual ~LineToModuleHandler() { }
-
- // Called at the beginning of a new compilation unit, prior to calling
- // ReadProgram(). compilation_dir will indicate the path that the
- // current compilation unit was compiled in, consistent with the
- // DW_AT_comp_dir DIE.
- virtual void StartCompilationUnit(const string& compilation_dir) = 0;
-
- // Populate MODULE and LINES with source file names and code/line
- // mappings, given a pointer to some DWARF line number data
- // PROGRAM, and an overestimate of its size. Add no zero-length
- // lines to LINES.
- virtual void ReadProgram(const char *program, uint64 length,
- Module *module, vector<Module::Line> *lines) = 0;
- };
-
- // The interface DwarfCUToModule uses to report warnings. The member
- // function definitions for this class write messages to stderr, but
- // you can override them if you'd like to detect or report these
- // conditions yourself.
- class WarningReporter {
- public:
- // Warn about problems in the DWARF file FILENAME, in the
- // compilation unit at OFFSET.
- WarningReporter(const string &filename, uint64 cu_offset)
- : filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false),
- printed_unpaired_header_(false),
- uncovered_warnings_enabled_(false) { }
- virtual ~WarningReporter() { }
-
- // Set the name of the compilation unit we're processing to NAME.
- virtual void SetCUName(const string &name) { cu_name_ = name; }
-
- // Accessor and setter for uncovered_warnings_enabled_.
- // UncoveredFunction and UncoveredLine only report a problem if that is
- // true. By default, these warnings are disabled, because those
- // conditions occur occasionally in healthy code.
- virtual bool uncovered_warnings_enabled() const {
- return uncovered_warnings_enabled_;
- }
- virtual void set_uncovered_warnings_enabled(bool value) {
- uncovered_warnings_enabled_ = value;
- }
-
- // A DW_AT_specification in the DIE at OFFSET refers to a DIE we
- // haven't processed yet, or that wasn't marked as a declaration,
- // at TARGET.
- virtual void UnknownSpecification(uint64 offset, uint64 target);
-
- // A DW_AT_abstract_origin in the DIE at OFFSET refers to a DIE we
- // haven't processed yet, or that wasn't marked as inline, at TARGET.
- virtual void UnknownAbstractOrigin(uint64 offset, uint64 target);
-
- // We were unable to find the DWARF section named SECTION_NAME.
- virtual void MissingSection(const string &section_name);
-
- // The CU's DW_AT_stmt_list offset OFFSET is bogus.
- virtual void BadLineInfoOffset(uint64 offset);
-
- // FUNCTION includes code covered by no line number data.
- virtual void UncoveredFunction(const Module::Function &function);
-
- // Line number NUMBER in LINE_FILE, of length LENGTH, includes code
- // covered by no function.
- virtual void UncoveredLine(const Module::Line &line);
-
- // The DW_TAG_subprogram DIE at OFFSET has no name specified directly
- // in the DIE, nor via a DW_AT_specification or DW_AT_abstract_origin
- // link.
- virtual void UnnamedFunction(uint64 offset);
-
- protected:
- string filename_;
- uint64 cu_offset_;
- string cu_name_;
- bool printed_cu_header_;
- bool printed_unpaired_header_;
- bool uncovered_warnings_enabled_;
-
- private:
- // Print a per-CU heading, once.
- void CUHeading();
- // Print an unpaired function/line heading, once.
- void UncoveredHeading();
- };
-
- // Create a DWARF debugging info handler for a compilation unit
- // within FILE_CONTEXT. This uses information received from the
- // dwarf2reader::CompilationUnit DWARF parser to populate
- // FILE_CONTEXT->module. Use LINE_READER to handle the compilation
- // unit's line number data. Use REPORTER to report problems with the
- // data we find.
- DwarfCUToModule(FileContext *file_context,
- LineToModuleHandler *line_reader,
- WarningReporter *reporter);
- ~DwarfCUToModule();
-
- void ProcessAttributeSigned(enum DwarfAttribute attr,
- enum DwarfForm form,
- int64 data);
- void ProcessAttributeUnsigned(enum DwarfAttribute attr,
- enum DwarfForm form,
- uint64 data);
- void ProcessAttributeString(enum DwarfAttribute attr,
- enum DwarfForm form,
- const string &data);
- bool EndAttributes();
- DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag);
-
- // Assign all our source Lines to the Functions that cover their
- // addresses, and then add them to module_.
- void Finish();
-
- bool StartCompilationUnit(uint64 offset, uint8 address_size,
- uint8 offset_size, uint64 cu_length,
- uint8 dwarf_version);
- bool StartRootDIE(uint64 offset, enum DwarfTag tag);
-
- private:
-
- // Used internally by the handler. Full definitions are in
- // dwarf_cu_to_module.cc.
- struct FilePrivate;
- struct Specification;
- struct CUContext;
- struct DIEContext;
- struct Function;
- class GenericDIEHandler;
- class FuncHandler;
- class NamedScopeHandler;
-
- // A map from section offsets to specifications.
- typedef map<uint64, Specification*> SpecificationByOffset;
-
- // Set this compilation unit's source language to LANGUAGE.
- void SetLanguage(DwarfLanguage language);
-
- // Read source line information at OFFSET in the .debug_line
- // section. Record source files in module_, but record source lines
- // in lines_; we apportion them to functions in
- // AssignLinesToFunctions.
- void ReadSourceLines(uint64 offset);
-
- // Assign the lines in lines_ to the individual line lists of the
- // functions in functions_. (DWARF line information maps an entire
- // compilation unit at a time, and gives no indication of which
- // lines belong to which functions, beyond their addresses.)
- void AssignLinesToFunctions();
-
- // The only reason cu_context_ and child_context_ are pointers is
- // that we want to keep their definitions private to
- // dwarf_cu_to_module.cc, instead of listing them all here. They are
- // owned by this DwarfCUToModule: the constructor sets them, and the
- // destructor deletes them.
-
- // The functor to use to handle line number data.
- LineToModuleHandler *line_reader_;
-
- // This compilation unit's context.
- CUContext *cu_context_;
-
- // A context for our children.
- DIEContext *child_context_;
-
- // True if this compilation unit has source line information.
- bool has_source_line_info_;
-
- // The offset of this compilation unit's line number information in
- // the .debug_line section.
- uint64 source_line_offset_;
-
- // The line numbers we have seen thus far. We accumulate these here
- // during parsing. Then, in Finish, we call AssignLinesToFunctions
- // to dole them out to the appropriate functions.
- vector<Module::Line> lines_;
-};
-
-} // namespace google_breakpad
-
-#endif // COMMON_LINUX_DWARF_CU_TO_MODULE_H__
diff --git a/breakpad/pending/src/common/dwarf_cu_to_module_unittest.cc b/breakpad/pending/src/common/dwarf_cu_to_module_unittest.cc
deleted file mode 100644
index 34fd728..0000000
--- a/breakpad/pending/src/common/dwarf_cu_to_module_unittest.cc
+++ /dev/null
@@ -1,1763 +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>
-
-// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule.
-
-#include <vector>
-
-#include "breakpad_googletest_includes.h"
-#include "common/dwarf_cu_to_module.h"
-
-using std::vector;
-
-using dwarf2reader::DIEHandler;
-using dwarf2reader::DwarfTag;
-using dwarf2reader::DwarfAttribute;
-using dwarf2reader::DwarfForm;
-using dwarf2reader::DwarfInline;
-using dwarf2reader::RootDIEHandler;
-using google_breakpad::DwarfCUToModule;
-using google_breakpad::Module;
-
-using ::testing::_;
-using ::testing::AtMost;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::Test;
-using ::testing::TestWithParam;
-using ::testing::Values;
-using ::testing::ValuesIn;
-
-// Mock classes.
-
-class MockLineToModuleFunctor: public DwarfCUToModule::LineToModuleFunctor {
- public:
- MOCK_METHOD4(mock_apply, void(const char *program, uint64 length,
- Module *module, vector<Module::Line> *lines));
- void operator()(const char *program, uint64 length,
- Module *module, vector<Module::Line> *lines) {
- mock_apply(program, length, module, lines);
- }
-};
-
-class MockWarningReporter: public DwarfCUToModule::WarningReporter {
- public:
- MockWarningReporter(const string &filename, uint64 cu_offset)
- : DwarfCUToModule::WarningReporter(filename, cu_offset) { }
- MOCK_METHOD1(SetCUName, void(const string &name));
- MOCK_METHOD2(UnknownSpecification, void(uint64 offset, uint64 target));
- MOCK_METHOD2(UnknownAbstractOrigin, void(uint64 offset, uint64 target));
- MOCK_METHOD1(MissingSection, void(const string &section_name));
- MOCK_METHOD1(BadLineInfoOffset, void(uint64 offset));
- MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
- MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
- MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
-};
-
-// A fixture class including all the objects needed to handle a
-// compilation unit, and their entourage. It includes member functions
-// for doing common kinds of setup and tests.
-class CUFixtureBase {
- public:
-
- // If we have:
- //
- // vector<Module::Line> lines;
- // AppendLinesFunctor appender(lines);
- //
- // then doing:
- //
- // appender(line_program, length, module, line_vector);
- //
- // will append lines to the end of line_vector. We can use this with
- // MockLineToModuleFunctor like this:
- //
- // MockLineToModuleFunctor l2m;
- // EXPECT_CALL(l2m, mock_apply(_,_,_,_))
- // .WillOnce(DoAll(Invoke(appender), Return()));
- //
- // in which case calling l2m with some line vector will append lines.
- class AppendLinesFunctor {
- public:
- AppendLinesFunctor(const vector<Module::Line> *lines) : lines_(lines) { }
- void operator()(const char *program, uint64 length,
- Module *module, vector<Module::Line> *lines) {
- lines->insert(lines->end(), lines_->begin(), lines_->end());
- }
- private:
- const vector<Module::Line> *lines_;
- };
-
- CUFixtureBase()
- : module_("module-name", "module-os", "module-arch", "module-id"),
- file_context_("dwarf-filename", &module_),
- language_(dwarf2reader::DW_LANG_none),
- language_signed_(false),
- appender_(&lines_),
- reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL),
- root_handler_(&file_context_, &line_reader_, &reporter_),
- functions_filled_(false),
- incrementing_offset_(0x0000000000100000ULL) {
- // By default, expect no warnings to be reported, and expect the
- // compilation unit's name to be provided. The test can override
- // these expectations.
- EXPECT_CALL(reporter_, SetCUName("compilation-unit-name")).Times(1);
- EXPECT_CALL(reporter_, UnknownSpecification(_, _)).Times(0);
- EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, _)).Times(0);
- EXPECT_CALL(reporter_, MissingSection(_)).Times(0);
- EXPECT_CALL(reporter_, BadLineInfoOffset(_)).Times(0);
- EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0);
- EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0);
- EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(0);
-
- // By default, expect the line program reader not to be invoked. We
- // may override this in StartCU.
- EXPECT_CALL(line_reader_, mock_apply(_,_,_,_)).Times(0);
-
- // The handler will consult this section map to decide what to
- // pass to our line reader.
- file_context_.section_map[".debug_line"] = std::make_pair(dummy_line_program_,
- dummy_line_size_);
- }
-
- // Add a line with the given address, size, filename, and line
- // number to the end of the statement list the handler will receive
- // when it invokes its LineToModuleFunctor. Call this before calling
- // StartCU.
- void PushLine(Module::Address address, Module::Address size,
- const string &filename, int line_number);
-
- // Use LANGUAGE for the compilation unit. More precisely, arrange
- // for StartCU to pass the compilation unit's root DIE a
- // DW_AT_language attribute whose value is LANGUAGE.
- void SetLanguage(dwarf2reader::DwarfLanguage language) {
- language_ = language;
- }
-
- // If SIGNED true, have StartCU report DW_AT_language as a signed
- // attribute; if false, have it report it as unsigned.
- void SetLanguageSigned(bool is_signed) { language_signed_ = is_signed; }
-
- // Call the handler this.root_handler_'s StartCompilationUnit and
- // StartRootDIE member functions, passing it appropriate attributes as
- // determined by prior calls to PushLine and SetLanguage. Leave
- // this.root_handler_ ready to hear about children: call
- // this.root_handler_.EndAttributes, but not this.root_handler_.Finish.
- void StartCU();
-
- // Have HANDLER process some strange attribute/form/value triples.
- void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler);
-
- // Start a child DIE of PARENT with the given tag and name. Leave
- // the handler ready to hear about children: call EndAttributes, but
- // not Finish.
- DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag,
- const string &name);
-
- // Start a child DIE of PARENT with the given tag and a
- // DW_AT_specification attribute whose value is SPECIFICATION. Leave
- // the handler ready to hear about children: call EndAttributes, but
- // not Finish. If NAME is non-zero, use it as the DW_AT_name
- // attribute.
- DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag,
- uint64 offset, const char *name = NULL);
-
- // Define a function as a child of PARENT with the given name,
- // address, and size. Call EndAttributes and Finish; one cannot
- // define children of the defined function's DIE.
- void DefineFunction(DIEHandler *parent, const string &name,
- Module::Address address, Module::Address size);
-
- // Create a declaration DIE as a child of PARENT with the given
- // offset, tag and name. If NAME is the empty string, don't provide
- // a DW_AT_name attribute. Call EndAttributes and Finish.
- void DeclarationDIE(DIEHandler *parent, uint64 offset,
- DwarfTag tag, const string &name);
-
- // Create a definition DIE as a child of PARENT with the given tag
- // that refers to the declaration DIE at offset SPECIFICATION as its
- // specification. If NAME is non-empty, pass it as the DW_AT_name
- // attribute. If SIZE is non-zero, record ADDRESS and SIZE as
- // low_pc/high_pc attributes.
- void DefinitionDIE(DIEHandler *parent, DwarfTag tag,
- uint64 specification, const string &name,
- Module::Address address = 0, Module::Address size = 0);
-
- // Create an inline DW_TAG_subprogram DIE as a child of PARENT. If
- // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at
- // offset SPECIFICATION as its specification. If Name is non-empty, pass it
- // as the DW_AT_name attribute.
- void AbstractInstanceDIE(DIEHandler *parent, uint64 offset,
- DwarfInline type, uint64 specification,
- const string &name,
- DwarfForm form = dwarf2reader::DW_FORM_data1);
-
- // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to
- // ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty
- // string, don't provide a DW_AT_name attribute.
- void DefineInlineInstanceDIE(DIEHandler *parent, const string &name,
- uint64 origin, Module::Address address,
- Module::Address size);
-
- // The following Test* functions should be called after calling
- // this.root_handler_.Finish. After that point, no further calls
- // should be made on the handler.
-
- // Test that the number of functions defined in the module this.module_ is
- // equal to EXPECTED.
- void TestFunctionCount(size_t expected);
-
- // Test that the I'th function (ordered by address) in the module
- // this.module_ has the given name, address, and size, and that its
- // parameter size is zero.
- void TestFunction(int i, const string &name,
- Module::Address address, Module::Address size);
-
- // Test that the number of source lines owned by the I'th function
- // in the module this.module_ is equal to EXPECTED.
- void TestLineCount(int i, size_t expected);
-
- // Test that the J'th line (ordered by address) of the I'th function
- // (again, by address) has the given address, size, filename, and
- // line number.
- void TestLine(int i, int j, Module::Address address, Module::Address size,
- const string &filename, int number);
-
- // Actual objects under test.
- Module module_;
- DwarfCUToModule::FileContext file_context_;
-
- // If this is not DW_LANG_none, we'll pass it as a DW_AT_language
- // attribute to the compilation unit. This defaults to DW_LANG_none.
- dwarf2reader::DwarfLanguage language_;
-
- // If this is true, report DW_AT_language as a signed value; if false,
- // report it as an unsigned value.
- bool language_signed_;
-
- // If this is not empty, we'll give the CU a DW_AT_stmt_list
- // attribute that, when passed to line_reader_, adds these lines to the
- // provided lines array.
- vector<Module::Line> lines_;
-
- // Mock line program reader.
- MockLineToModuleFunctor line_reader_;
- AppendLinesFunctor appender_;
- static const char dummy_line_program_[];
- static const size_t dummy_line_size_;
-
- MockWarningReporter reporter_;
- DwarfCUToModule root_handler_;
-
- private:
- // Fill functions_, if we haven't already.
- void FillFunctions();
-
- // If functions_filled_ is true, this is a table of functions we've
- // extracted from module_, sorted by address.
- vector<Module::Function *> functions_;
- // True if we have filled the above vector with this.module_'s function list.
- bool functions_filled_;
-
- // When a unique offset value is needed, grab one from here and increment
- // it.
- uint64 incrementing_offset_;
-};
-
-const char CUFixtureBase::dummy_line_program_[] = "lots of fun data";
-const size_t CUFixtureBase::dummy_line_size_ =
- sizeof (CUFixtureBase::dummy_line_program_);
-
-void CUFixtureBase::PushLine(Module::Address address, Module::Address size,
- const string &filename, int line_number) {
- Module::Line l;
- l.address = address;
- l.size = size;
- l.file = module_.FindFile(filename);
- l.number = line_number;
- lines_.push_back(l);
-}
-
-void CUFixtureBase::StartCU() {
- // If we have lines, make the line reader expect to be invoked at
- // most once. (Hey, if the handler can pass its tests without
- // bothering to read the line number data, that's great.)
- // Have it add the lines passed to PushLine. Otherwise, leave the
- // initial expectation (no calls) in force.
- if (!lines_.empty())
- EXPECT_CALL(line_reader_,
- mock_apply(&dummy_line_program_[0], dummy_line_size_,
- &module_, _))
- .Times(AtMost(1))
- .WillOnce(DoAll(Invoke(appender_), Return()));
-
- ASSERT_TRUE(root_handler_
- .StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44,
- 0x4241b4f33720dd5cULL, 3));
- {
- ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL,
- dwarf2reader::DW_TAG_compile_unit));
- }
- root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
- "compilation-unit-name");
- if (!lines_.empty())
- root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list,
- dwarf2reader::DW_FORM_ref4,
- 0);
- if (language_ != dwarf2reader::DW_LANG_none) {
- if (language_signed_)
- root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language,
- dwarf2reader::DW_FORM_sdata,
- language_);
- else
- root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language,
- dwarf2reader::DW_FORM_udata,
- language_);
- }
- ASSERT_TRUE(root_handler_.EndAttributes());
-}
-
-void CUFixtureBase::ProcessStrangeAttributes(
- dwarf2reader::DIEHandler *handler) {
- handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead,
- (DwarfForm) 0x4106e4db,
- 0xa592571997facda1ULL);
- handler->ProcessAttributeSigned((DwarfAttribute) 0x85380095,
- (DwarfForm) 0x0f16fe87,
- 0x12602a4e3bf1f446LL);
- handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f,
- (DwarfForm) 0x829e038a,
- 0x50fddef44734fdecULL);
- static const char buffer[10] = "frobynode";
- handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51,
- (DwarfForm) 0x2f43b041,
- buffer, sizeof(buffer));
- handler->ProcessAttributeString((DwarfAttribute) 0x2f43b041,
- (DwarfForm) 0x895ffa23,
- "strange string");
-}
-
-DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent,
- DwarfTag tag,
- const string &name) {
- dwarf2reader::DIEHandler *handler
- = parent->FindChildHandler(incrementing_offset_++, tag);
- if (!handler)
- return NULL;
- handler->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
- name);
- ProcessStrangeAttributes(handler);
- if (!handler->EndAttributes()) {
- handler->Finish();
- delete handler;
- return NULL;
- }
-
- return handler;
-}
-
-DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent,
- DwarfTag tag,
- uint64 specification,
- const char *name) {
- dwarf2reader::DIEHandler *handler
- = parent->FindChildHandler(incrementing_offset_++, tag);
- if (!handler)
- return NULL;
- if (name)
- handler->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
- name);
- handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
- dwarf2reader::DW_FORM_ref4,
- specification);
- if (!handler->EndAttributes()) {
- handler->Finish();
- delete handler;
- return NULL;
- }
-
- return handler;
-}
-
-void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent,
- const string &name, Module::Address address,
- Module::Address size) {
- dwarf2reader::DIEHandler *func
- = parent->FindChildHandler(incrementing_offset_++,
- dwarf2reader::DW_TAG_subprogram);
- ASSERT_TRUE(func != NULL);
- func->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
- name);
- func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
- dwarf2reader::DW_FORM_addr,
- address);
- func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
- dwarf2reader::DW_FORM_addr,
- address + size);
- ProcessStrangeAttributes(func);
- EXPECT_TRUE(func->EndAttributes());
- func->Finish();
- delete func;
-}
-
-void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset,
- DwarfTag tag,
- const string &name) {
- dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag);
- ASSERT_TRUE(die != NULL);
- if (!name.empty())
- die->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
- name);
- die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration,
- dwarf2reader::DW_FORM_flag,
- 1);
- EXPECT_TRUE(die->EndAttributes());
- die->Finish();
- delete die;
-}
-
-void CUFixtureBase::DefinitionDIE(DIEHandler *parent,
- DwarfTag tag,
- uint64 specification,
- const string &name,
- Module::Address address,
- Module::Address size) {
- dwarf2reader::DIEHandler *die
- = parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag);
- ASSERT_TRUE(die != NULL);
- die->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
- dwarf2reader::DW_FORM_ref4,
- specification);
- if (!name.empty())
- die->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
- name);
- if (size) {
- die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
- dwarf2reader::DW_FORM_addr,
- address);
- die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
- dwarf2reader::DW_FORM_addr,
- address + size);
- }
- EXPECT_TRUE(die->EndAttributes());
- die->Finish();
- delete die;
-}
-
-void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent,
- uint64 offset,
- DwarfInline type,
- uint64 specification,
- const string &name,
- DwarfForm form) {
- dwarf2reader::DIEHandler *die
- = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram);
- ASSERT_TRUE(die != NULL);
- if (specification != 0ULL)
- die->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
- dwarf2reader::DW_FORM_ref4,
- specification);
- if (form == dwarf2reader::DW_FORM_sdata) {
- die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type);
- } else {
- die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type);
- }
- if (!name.empty())
- die->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
- name);
-
- EXPECT_TRUE(die->EndAttributes());
- die->Finish();
- delete die;
-}
-
-void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent,
- const string &name,
- uint64 origin,
- Module::Address address,
- Module::Address size) {
- dwarf2reader::DIEHandler *func
- = parent->FindChildHandler(0x11c70f94c6e87ccdLL,
- dwarf2reader::DW_TAG_subprogram);
- ASSERT_TRUE(func != NULL);
- if (!name.empty()) {
- func->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
- name);
- }
- func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
- dwarf2reader::DW_FORM_addr,
- address);
- func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
- dwarf2reader::DW_FORM_addr,
- address + size);
- func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin,
- dwarf2reader::DW_FORM_ref4,
- origin);
- ProcessStrangeAttributes(func);
- EXPECT_TRUE(func->EndAttributes());
- func->Finish();
- delete func;
-}
-
-void CUFixtureBase::FillFunctions() {
- if (functions_filled_)
- return;
- module_.GetFunctions(&functions_, functions_.end());
- sort(functions_.begin(), functions_.end(),
- Module::Function::CompareByAddress);
- functions_filled_ = true;
-}
-
-void CUFixtureBase::TestFunctionCount(size_t expected) {
- FillFunctions();
- ASSERT_EQ(expected, functions_.size());
-}
-
-void CUFixtureBase::TestFunction(int i, const string &name,
- Module::Address address,
- Module::Address size) {
- FillFunctions();
- ASSERT_LT((size_t) i, functions_.size());
-
- Module::Function *function = functions_[i];
- EXPECT_EQ(name, function->name);
- EXPECT_EQ(address, function->address);
- EXPECT_EQ(size, function->size);
- EXPECT_EQ(0U, function->parameter_size);
-}
-
-void CUFixtureBase::TestLineCount(int i, size_t expected) {
- FillFunctions();
- ASSERT_LT((size_t) i, functions_.size());
-
- ASSERT_EQ(expected, functions_[i]->lines.size());
-}
-
-void CUFixtureBase::TestLine(int i, int j,
- Module::Address address, Module::Address size,
- const string &filename, int number) {
- FillFunctions();
- ASSERT_LT((size_t) i, functions_.size());
- ASSERT_LT((size_t) j, functions_[i]->lines.size());
-
- Module::Line *line = &functions_[i]->lines[j];
- EXPECT_EQ(address, line->address);
- EXPECT_EQ(size, line->size);
- EXPECT_EQ(filename, line->file->name.c_str());
- EXPECT_EQ(number, line->number);
-}
-
-// Include caller locations for our test subroutines.
-#define TRACE(call) do { SCOPED_TRACE("called from here"); call; } while (0)
-#define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d)))
-#define SetLanguage(a) TRACE(SetLanguage(a))
-#define StartCU() TRACE(StartCU())
-#define DefineFunction(a,b,c,d) TRACE(DefineFunction((a),(b),(c),(d)))
-#define DeclarationDIE(a,b,c,d) TRACE(DeclarationDIE((a),(b),(c),(d)))
-#define DefinitionDIE(a,b,c,d,e,f) TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f)))
-#define TestFunctionCount(a) TRACE(TestFunctionCount(a))
-#define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d)))
-#define TestLineCount(a,b) TRACE(TestLineCount((a),(b)))
-#define TestLine(a,b,c,d,e,f) TRACE(TestLine((a),(b),(c),(d),(e),(f)))
-
-class SimpleCU: public CUFixtureBase, public Test {
-};
-
-TEST_F(SimpleCU, OneFunc) {
- PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772);
-
- StartCU();
- DefineFunction(&root_handler_, "function1",
- 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
- TestLineCount(0, 1);
- TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file",
- 246571772);
-}
-
-TEST_F(SimpleCU, IrrelevantRootChildren) {
- StartCU();
- EXPECT_FALSE(root_handler_
- .FindChildHandler(0x7db32bff4e2dcfb1ULL,
- dwarf2reader::DW_TAG_lexical_block));
-}
-
-TEST_F(SimpleCU, IrrelevantNamedScopeChildren) {
- StartCU();
- DIEHandler *class_A_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
- EXPECT_TRUE(class_A_handler != NULL);
- EXPECT_FALSE(class_A_handler
- ->FindChildHandler(0x02e55999b865e4e9ULL,
- dwarf2reader::DW_TAG_lexical_block));
- delete class_A_handler;
-}
-
-// Verify that FileContexts can safely be deleted unused.
-TEST_F(SimpleCU, UnusedFileContext) {
- Module m("module-name", "module-os", "module-arch", "module-id");
- DwarfCUToModule::FileContext fc("dwarf-filename", &m);
-
- // Kludge: satisfy reporter_'s expectation.
- reporter_.SetCUName("compilation-unit-name");
-}
-
-TEST_F(SimpleCU, InlineFunction) {
- PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
-
- StartCU();
- AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
- dwarf2reader::DW_INL_inlined, 0, "inline-name");
- DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
- 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "inline-name",
- 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
-}
-
-TEST_F(SimpleCU, InlineFunctionSignedAttribute) {
- PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
-
- StartCU();
- AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
- dwarf2reader::DW_INL_inlined, 0, "inline-name",
- dwarf2reader::DW_FORM_sdata);
- DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
- 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "inline-name",
- 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
-}
-
-// Any DIE with an DW_AT_inline attribute can be cited by
-// DW_AT_abstract_origin attributes --- even if the value of the
-// DW_AT_inline attribute is DW_INL_not_inlined.
-TEST_F(SimpleCU, AbstractOriginNotInlined) {
- PushLine(0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL, "line-file", 6111581);
-
- StartCU();
- AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL,
- dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance");
- DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL,
- 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "abstract-instance",
- 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL);
-}
-
-TEST_F(SimpleCU, UnknownAbstractOrigin) {
- EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return());
- EXPECT_CALL(reporter_, UnnamedFunction(0x11c70f94c6e87ccdLL))
- .WillOnce(Return());
- PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
-
- StartCU();
- AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
- dwarf2reader::DW_INL_inlined, 0, "inline-name");
- DefineInlineInstanceDIE(&root_handler_, "", 1ULL,
- 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "<name omitted>",
- 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
-}
-
-TEST_F(SimpleCU, UnnamedFunction) {
- EXPECT_CALL(reporter_, UnnamedFunction(_)).WillOnce(Return());
- PushLine(0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, "line-file", 14044850);
-
- StartCU();
- DefineFunction(&root_handler_, "",
- 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "<name omitted>",
- 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL);
-}
-
-// An address range.
-struct Range {
- Module::Address start, end;
-};
-
-// Test data for pairing functions and lines.
-struct Situation {
- // Two function intervals, and two line intervals.
- Range functions[2], lines[2];
-
- // The number of lines we expect to be assigned to each of the
- // functions, and the address ranges.
- int paired_count[2];
- Range paired[2][2];
-
- // The number of functions that are not entirely covered by lines,
- // and vice versa.
- int uncovered_functions, uncovered_lines;
-};
-
-#define PAIRING(func1_start, func1_end, func2_start, func2_end, \
- line1_start, line1_end, line2_start, line2_end, \
- func1_num_lines, func2_num_lines, \
- func1_line1_start, func1_line1_end, \
- func1_line2_start, func1_line2_end, \
- func2_line1_start, func2_line1_end, \
- func2_line2_start, func2_line2_end, \
- uncovered_functions, uncovered_lines) \
- { { { func1_start, func1_end }, { func2_start, func2_end } }, \
- { { line1_start, line1_end }, { line2_start, line2_end } }, \
- { func1_num_lines, func2_num_lines }, \
- { { { func1_line1_start, func1_line1_end }, \
- { func1_line2_start, func1_line2_end } }, \
- { { func2_line1_start, func2_line1_end }, \
- { func2_line2_start, func2_line2_end } } }, \
- uncovered_functions, uncovered_lines },
-
-Situation situations[] = {
-#include "common/testdata/func-line-pairing.h"
-};
-
-#undef PAIRING
-
-class FuncLinePairing: public CUFixtureBase,
- public TestWithParam<Situation> { };
-
-INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing,
- ValuesIn(situations));
-
-TEST_P(FuncLinePairing, Pairing) {
- const Situation &s = GetParam();
- PushLine(s.lines[0].start,
- s.lines[0].end - s.lines[0].start,
- "line-file", 67636963);
- PushLine(s.lines[1].start,
- s.lines[1].end - s.lines[1].start,
- "line-file", 67636963);
- if (s.uncovered_functions)
- EXPECT_CALL(reporter_, UncoveredFunction(_))
- .Times(s.uncovered_functions)
- .WillRepeatedly(Return());
- if (s.uncovered_lines)
- EXPECT_CALL(reporter_, UncoveredLine(_))
- .Times(s.uncovered_lines)
- .WillRepeatedly(Return());
-
- StartCU();
- DefineFunction(&root_handler_, "function1",
- s.functions[0].start,
- s.functions[0].end - s.functions[0].start);
- DefineFunction(&root_handler_, "function2",
- s.functions[1].start,
- s.functions[1].end - s.functions[1].start);
- root_handler_.Finish();
-
- TestFunctionCount(2);
- TestFunction(0, "function1",
- s.functions[0].start,
- s.functions[0].end - s.functions[0].start);
- TestLineCount(0, s.paired_count[0]);
- for (int i = 0; i < s.paired_count[0]; i++)
- TestLine(0, i, s.paired[0][i].start,
- s.paired[0][i].end - s.paired[0][i].start,
- "line-file", 67636963);
- TestFunction(1, "function2",
- s.functions[1].start,
- s.functions[1].end - s.functions[1].start);
- TestLineCount(1, s.paired_count[1]);
- for (int i = 0; i < s.paired_count[1]; i++)
- TestLine(1, i, s.paired[1][i].start,
- s.paired[1][i].end - s.paired[1][i].start,
- "line-file", 67636963);
-}
-
-TEST_F(FuncLinePairing, EmptyCU) {
-
- StartCU();
- root_handler_.Finish();
-
- TestFunctionCount(0);
-}
-
-TEST_F(FuncLinePairing, LinesNoFuncs) {
- PushLine(40, 2, "line-file", 82485646);
- EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
-
- StartCU();
- root_handler_.Finish();
-
- TestFunctionCount(0);
-}
-
-TEST_F(FuncLinePairing, FuncsNoLines) {
- EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
-
- StartCU();
- DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "function1", 0x127da12ffcf5c51fULL, 0x1000U);
-}
-
-TEST_F(FuncLinePairing, GapThenFunction) {
- PushLine(20, 2, "line-file-2", 174314698);
- PushLine(10, 2, "line-file-1", 263008005);
-
- StartCU();
- DefineFunction(&root_handler_, "function1", 10, 2);
- DefineFunction(&root_handler_, "function2", 20, 2);
- root_handler_.Finish();
-
- TestFunctionCount(2);
- TestFunction(0, "function1", 10, 2);
- TestLineCount(0, 1);
- TestLine(0, 0, 10, 2, "line-file-1", 263008005);
- TestFunction(1, "function2", 20, 2);
- TestLineCount(1, 1);
- TestLine(1, 0, 20, 2, "line-file-2", 174314698);
-}
-
-// 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, then assume this is what happened, and
-// don't warn.
-TEST_F(FuncLinePairing, GCCAlignmentStretch) {
- PushLine(10, 10, "line-file", 63351048);
- PushLine(20, 10, "line-file", 61661044);
-
- StartCU();
- DefineFunction(&root_handler_, "function1", 10, 5);
- // five-byte gap between functions, covered by line 63351048.
- // This should not elicit a warning.
- DefineFunction(&root_handler_, "function2", 20, 10);
- root_handler_.Finish();
-
- TestFunctionCount(2);
- TestFunction(0, "function1", 10, 5);
- TestLineCount(0, 1);
- TestLine(0, 0, 10, 5, "line-file", 63351048);
- TestFunction(1, "function2", 20, 10);
- TestLineCount(1, 1);
- TestLine(1, 0, 20, 10, "line-file", 61661044);
-}
-
-// Unfortunately, neither the DWARF parser's handler interface nor the
-// DIEHandler interface is capable of expressing a function that abuts
-// the end of the address space: the high_pc value looks like zero.
-
-TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) {
- PushLine(0xfffffffffffffff0ULL, 16, "line-file", 63351048);
- EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
-
- StartCU();
- DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6);
- DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5);
- root_handler_.Finish();
-
- TestFunctionCount(2);
- TestFunction(0, "function1", 0xfffffffffffffff0ULL, 6);
- TestLineCount(0, 1);
- TestLine(0, 0, 0xfffffffffffffff0ULL, 6, "line-file", 63351048);
- TestFunction(1, "function2", 0xfffffffffffffffaULL, 5);
- TestLineCount(1, 1);
- TestLine(1, 0, 0xfffffffffffffffaULL, 5, "line-file", 63351048);
-}
-
-// A function with more than one uncovered area should only be warned
-// about once.
-TEST_F(FuncLinePairing, WarnOnceFunc) {
- PushLine(20, 1, "line-file-2", 262951329);
- PushLine(11, 1, "line-file-1", 219964021);
- EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
-
- StartCU();
- DefineFunction(&root_handler_, "function", 10, 11);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "function", 10, 11);
- TestLineCount(0, 2);
- TestLine(0, 0, 11, 1, "line-file-1", 219964021);
- TestLine(0, 1, 20, 1, "line-file-2", 262951329);
-}
-
-// A line with more than one uncovered area should only be warned
-// about once.
-TEST_F(FuncLinePairing, WarnOnceLine) {
- PushLine(10, 20, "filename1", 118581871);
- EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
-
- StartCU();
- DefineFunction(&root_handler_, "function1", 11, 1);
- DefineFunction(&root_handler_, "function2", 13, 1);
- root_handler_.Finish();
-
- TestFunctionCount(2);
- TestFunction(0, "function1", 11, 1);
- TestLineCount(0, 1);
- TestLine(0, 0, 11, 1, "filename1", 118581871);
- TestFunction(1, "function2", 13, 1);
- TestLineCount(1, 1);
- TestLine(1, 0, 13, 1, "filename1", 118581871);
-}
-
-class CXXQualifiedNames: public CUFixtureBase,
- public TestWithParam<DwarfTag> { };
-
-INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames,
- Values(dwarf2reader::DW_TAG_class_type,
- dwarf2reader::DW_TAG_structure_type,
- dwarf2reader::DW_TAG_union_type,
- dwarf2reader::DW_TAG_namespace));
-
-TEST_P(CXXQualifiedNames, TwoFunctions) {
- DwarfTag tag = GetParam();
-
- SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
- PushLine(10, 1, "filename1", 69819327);
- PushLine(20, 1, "filename2", 95115701);
-
- StartCU();
- DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag,
- "Enclosure");
- EXPECT_TRUE(enclosure_handler != NULL);
- DefineFunction(enclosure_handler, "func_B", 10, 1);
- DefineFunction(enclosure_handler, "func_C", 20, 1);
- enclosure_handler->Finish();
- delete enclosure_handler;
- root_handler_.Finish();
-
- TestFunctionCount(2);
- TestFunction(0, "Enclosure::func_B", 10, 1);
- TestFunction(1, "Enclosure::func_C", 20, 1);
-}
-
-TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) {
- DwarfTag tag = GetParam();
-
- SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
- PushLine(10, 1, "line-file", 69819327);
-
- StartCU();
- DIEHandler *namespace_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
- "Namespace");
- EXPECT_TRUE(namespace_handler != NULL);
- DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag,
- "Enclosure");
- EXPECT_TRUE(enclosure_handler != NULL);
- DefineFunction(enclosure_handler, "function", 10, 1);
- enclosure_handler->Finish();
- delete enclosure_handler;
- namespace_handler->Finish();
- delete namespace_handler;
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "Namespace::Enclosure::function", 10, 1);
-}
-
-TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) {
- SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
- PushLine(10, 1, "filename1", 69819327);
-
- StartCU();
- DIEHandler *namespace_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
- "namespace_A");
- EXPECT_TRUE(namespace_handler != NULL);
- DIEHandler *struct_handler
- = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type,
- "struct_B");
- EXPECT_TRUE(struct_handler != NULL);
- DIEHandler *class_handler
- = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type,
- "class_C");
- DefineFunction(class_handler, "function_D", 10, 1);
- class_handler->Finish();
- delete class_handler;
- struct_handler->Finish();
- delete struct_handler;
- namespace_handler->Finish();
- delete namespace_handler;
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "namespace_A::struct_B::class_C::function_D", 10, 1);
-}
-
-struct LanguageAndQualifiedName {
- dwarf2reader::DwarfLanguage language;
- const char *name;
-};
-
-const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = {
- { dwarf2reader::DW_LANG_none, "class_A::function_B" },
- { dwarf2reader::DW_LANG_C, "class_A::function_B" },
- { dwarf2reader::DW_LANG_C89, "class_A::function_B" },
- { dwarf2reader::DW_LANG_C99, "class_A::function_B" },
- { dwarf2reader::DW_LANG_C_plus_plus, "class_A::function_B" },
- { dwarf2reader::DW_LANG_Java, "class_A.function_B" },
- { dwarf2reader::DW_LANG_Cobol74, "class_A::function_B" },
- { dwarf2reader::DW_LANG_Mips_Assembler, NULL }
-};
-
-class QualifiedForLanguage:
- public CUFixtureBase,
- public TestWithParam<LanguageAndQualifiedName> { };
-
-INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage,
- ValuesIn(LanguageAndQualifiedNameCases));
-
-TEST_P(QualifiedForLanguage, MemberFunction) {
- const LanguageAndQualifiedName &param = GetParam();
-
- PushLine(10, 1, "line-file", 212966758);
- SetLanguage(param.language);
-
- StartCU();
- DIEHandler *class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
- "class_A");
- DefineFunction(class_handler, "function_B", 10, 1);
- class_handler->Finish();
- delete class_handler;
- root_handler_.Finish();
-
- if (param.name) {
- TestFunctionCount(1);
- TestFunction(0, param.name, 10, 1);
- } else {
- TestFunctionCount(0);
- }
-}
-
-TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) {
- const LanguageAndQualifiedName &param = GetParam();
-
- PushLine(10, 1, "line-file", 212966758);
- SetLanguage(param.language);
- SetLanguageSigned(true);
-
- StartCU();
- DIEHandler *class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
- "class_A");
- DefineFunction(class_handler, "function_B", 10, 1);
- class_handler->Finish();
- delete class_handler;
- root_handler_.Finish();
-
- if (param.name) {
- TestFunctionCount(1);
- TestFunction(0, param.name, 10, 1);
- } else {
- TestFunctionCount(0);
- }
-}
-
-class Specifications: public CUFixtureBase, public Test { };
-
-TEST_F(Specifications, Function) {
- PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
-
- StartCU();
- DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name");
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
- 0xcd3c51b946fb1eeeLL, "",
- 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "declaration-name",
- 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
-}
-
-TEST_F(Specifications, MemberFunction) {
- PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691);
-
- StartCU();
- DIEHandler *class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
- DeclarationDIE(class_handler, 0x7d83028c431406e8ULL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name");
- class_handler->Finish();
- delete class_handler;
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
- 0x7d83028c431406e8ULL, "",
- 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "class_A::declaration-name",
- 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL);
-}
-
-// Specifications.MemberFunction, with DIEs in reverse order.
-TEST_F(Specifications, MemberFunctionForwardReference) {
- PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691);
-
- StartCU();
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
- 0x7d83028c431406e8ULL, "",
- 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL);
- DIEHandler *class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
- DeclarationDIE(class_handler, 0x7d83028c431406e8ULL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name");
- class_handler->Finish();
- delete class_handler;
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "class_A::declaration-name",
- 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL);
-}
-
-// This case should gather the name from both the definition and the
-// declaration's parent.
-TEST_F(Specifications, FunctionDeclarationParent) {
- PushLine(0x463c9ddf405be227ULL, 0x6a47774af5049680ULL, "line-file", 70254922);
-
- StartCU();
- {
- DIEHandler *class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
- "class_A");
- ASSERT_TRUE(class_handler != NULL);
- DeclarationDIE(class_handler, 0x0e0e877c8404544aULL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name");
- class_handler->Finish();
- delete class_handler;
- }
-
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
- 0x0e0e877c8404544aULL, "definition-name",
- 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL);
-
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "class_A::definition-name",
- 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL);
-}
-
-// Named scopes should also gather enclosing name components from
-// their declarations.
-TEST_F(Specifications, NamedScopeDeclarationParent) {
- PushLine(0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, "line-file", 77392604);
-
- StartCU();
- {
- DIEHandler *space_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
- "space_A");
- ASSERT_TRUE(space_handler != NULL);
- DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL,
- dwarf2reader::DW_TAG_class_type, "class-declaration-name");
- space_handler->Finish();
- delete space_handler;
- }
-
- {
- DIEHandler *class_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
- 0x419bb1d12f9a73a2ULL, "class-definition-name");
- ASSERT_TRUE(class_handler != NULL);
- DefineFunction(class_handler, "function",
- 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL);
- class_handler->Finish();
- delete class_handler;
- }
-
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "space_A::class-definition-name::function",
- 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL);
-}
-
-TEST_F(Specifications, UnnamedScopeDeclarationParent) {
- PushLine(0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, "line-file", 77392604);
-
- StartCU();
- {
- DIEHandler *space_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
- "");
- ASSERT_TRUE(space_handler != NULL);
- DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL,
- dwarf2reader::DW_TAG_class_type, "class-declaration-name");
- space_handler->Finish();
- delete space_handler;
- }
-
- {
- DIEHandler *class_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
- 0x419bb1d12f9a73a2ULL, "class-definition-name");
- ASSERT_TRUE(class_handler != NULL);
- DefineFunction(class_handler, "function",
- 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL);
- class_handler->Finish();
- delete class_handler;
- }
-
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "(anonymous namespace)::class-definition-name::function",
- 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL);
-}
-
-// This test recreates bug 364.
-TEST_F(Specifications, InlineFunction) {
- PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
-
- StartCU();
- DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
- dwarf2reader::DW_TAG_subprogram, "inline-name");
- AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
- dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, "");
- DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
- 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "inline-name",
- 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
-}
-
-// Check name construction for a long chain containing each combination of:
-// - struct, union, class, namespace
-// - direct and definition
-TEST_F(Specifications, LongChain) {
- PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926);
- SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
-
- StartCU();
- // The structure we're building here is:
- // space_A full definition
- // space_B declaration
- // space_B definition
- // struct_C full definition
- // struct_D declaration
- // struct_D definition
- // union_E full definition
- // union_F declaration
- // union_F definition
- // class_G full definition
- // class_H declaration
- // class_H definition
- // func_I declaration
- // func_I definition
- //
- // So:
- // - space_A, struct_C, union_E, and class_G don't use specifications;
- // - space_B, struct_D, union_F, and class_H do.
- // - func_I uses a specification.
- //
- // The full name for func_I is thus:
- //
- // space_A::space_B::struct_C::struct_D::union_E::union_F::
- // class_G::class_H::func_I
- {
- DIEHandler *space_A_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
- "space_A");
- DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL,
- dwarf2reader::DW_TAG_namespace, "space_B");
- space_A_handler->Finish();
- delete space_A_handler;
- }
-
- {
- DIEHandler *space_B_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
- 0x2e111126496596e2ULL);
- DIEHandler *struct_C_handler
- = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type,
- "struct_C");
- DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL,
- dwarf2reader::DW_TAG_structure_type, "struct_D");
- struct_C_handler->Finish();
- delete struct_C_handler;
- space_B_handler->Finish();
- delete space_B_handler;
- }
-
- {
- DIEHandler *struct_D_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type,
- 0x20cd423bf2a25a4cULL);
- DIEHandler *union_E_handler
- = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type,
- "union_E");
- DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL,
- dwarf2reader::DW_TAG_union_type, "union_F");
- union_E_handler->Finish();
- delete union_E_handler;
- struct_D_handler->Finish();
- delete struct_D_handler;
- }
-
- {
- DIEHandler *union_F_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type,
- 0xe25c84805aa58c32ULL);
- DIEHandler *class_G_handler
- = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type,
- "class_G");
- DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL,
- dwarf2reader::DW_TAG_class_type, "class_H");
- class_G_handler->Finish();
- delete class_G_handler;
- union_F_handler->Finish();
- delete union_F_handler;
- }
-
- {
- DIEHandler *class_H_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
- 0xb70d960dcc173b6eULL);
- DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL,
- dwarf2reader::DW_TAG_subprogram, "func_I");
- class_H_handler->Finish();
- delete class_H_handler;
- }
-
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
- 0x27ff829e3bf69f37ULL, "",
- 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "space_A::space_B::struct_C::struct_D::union_E::union_F"
- "::class_G::class_H::func_I",
- 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL);
-}
-
-// Specifications.LongChain with DIEs in reverse order.
-TEST_F(Specifications, LongChainForwardReference) {
- PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926);
- SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
-
- StartCU();
-
- {
- DIEHandler *class_H_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
- 0xb70d960dcc173b6eULL);
- DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL,
- dwarf2reader::DW_TAG_subprogram, "func_I");
- class_H_handler->Finish();
- delete class_H_handler;
- }
-
- {
- DIEHandler *union_F_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type,
- 0xe25c84805aa58c32ULL);
- DIEHandler *class_G_handler
- = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type,
- "class_G");
- DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL,
- dwarf2reader::DW_TAG_class_type, "class_H");
- class_G_handler->Finish();
- delete class_G_handler;
- union_F_handler->Finish();
- delete union_F_handler;
- }
-
- {
- DIEHandler *struct_D_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type,
- 0x20cd423bf2a25a4cULL);
- DIEHandler *union_E_handler
- = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type,
- "union_E");
- DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL,
- dwarf2reader::DW_TAG_union_type, "union_F");
- union_E_handler->Finish();
- delete union_E_handler;
- struct_D_handler->Finish();
- delete struct_D_handler;
- }
-
- {
- DIEHandler *space_B_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
- 0x2e111126496596e2ULL);
- DIEHandler *struct_C_handler
- = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type,
- "struct_C");
- DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL,
- dwarf2reader::DW_TAG_structure_type, "struct_D");
- struct_C_handler->Finish();
- delete struct_C_handler;
- space_B_handler->Finish();
- delete space_B_handler;
- }
-
- {
- DIEHandler *space_A_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
- "space_A");
- DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL,
- dwarf2reader::DW_TAG_namespace, "space_B");
- space_A_handler->Finish();
- delete space_A_handler;
- }
-
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
- 0x27ff829e3bf69f37ULL, "",
- 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "space_A::space_B::struct_C::struct_D::union_E::union_F"
- "::class_G::class_H::func_I",
- 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL);
-}
-
-TEST_F(Specifications, InterCU) {
- Module m("module-name", "module-os", "module-arch", "module-id");
- DwarfCUToModule::FileContext fc("dwarf-filename", &m);
- EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
- MockLineToModuleFunctor lr;
- EXPECT_CALL(lr, mock_apply(_,_,_,_)).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());
- 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());
- DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram,
- 0xb01fef8b380bd1a2ULL, "",
- 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL);
- root3_handler.Finish();
- }
-
- vector<Module::Function *> functions;
- m.GetFunctions(&functions, functions.end());
- EXPECT_EQ(1U, functions.size());
- EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str());
-}
-
-TEST_F(Specifications, BadOffset) {
- PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272);
- EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL))
- .WillOnce(Return());
-
- StartCU();
- DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL,
- dwarf2reader::DW_TAG_subprogram, "");
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
- 0x2be953efa6f9a996ULL, "function",
- 0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL);
- root_handler_.Finish();
-}
-
-TEST_F(Specifications, FunctionDefinitionHasOwnName) {
- PushLine(0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL, "line-file", 56792403);
-
- StartCU();
- DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name");
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
- 0xc34ff4786cae78bdULL, "definition-name",
- 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL);
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "definition-name",
- 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL);
-}
-
-TEST_F(Specifications, ClassDefinitionHasOwnName) {
- PushLine(0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL, "line-file", 57119241);
-
- StartCU();
- DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL,
- dwarf2reader::DW_TAG_class_type, "class-declaration-name");
-
- dwarf2reader::DIEHandler *class_definition
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
- 0xd0fe467ec2f1a58cULL, "class-definition-name");
- ASSERT_TRUE(class_definition);
- DeclarationDIE(class_definition, 0x6d028229c15623dbULL,
- dwarf2reader::DW_TAG_subprogram,
- "function-declaration-name");
- class_definition->Finish();
- delete class_definition;
-
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
- 0x6d028229c15623dbULL, "function-definition-name",
- 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL);
-
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "class-definition-name::function-definition-name",
- 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL);
-}
-
-// DIEs that cite a specification should prefer the specification's
-// parents over their own when choosing qualified names. In this test,
-// we take the name from our definition but the enclosing scope name
-// from our declaration. I don't see why they'd ever be different, but
-// we want to verify what DwarfCUToModule is looking at.
-TEST_F(Specifications, PreferSpecificationParents) {
- PushLine(0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL, "line-file", 79488694);
-
- StartCU();
- {
- dwarf2reader::DIEHandler *declaration_class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "declaration-class");
- DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL,
- dwarf2reader::DW_TAG_subprogram, "function-declaration");
- declaration_class_handler->Finish();
- delete declaration_class_handler;
- }
- {
- dwarf2reader::DIEHandler *definition_class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
- "definition-class");
- DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram,
- 0x9ddb35517455ef7aULL, "function-definition",
- 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL);
- definition_class_handler->Finish();
- delete definition_class_handler;
- }
- root_handler_.Finish();
-
- TestFunctionCount(1);
- TestFunction(0, "declaration-class::function-definition",
- 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL);
-}
-
-class CUErrors: public CUFixtureBase, public Test { };
-
-TEST_F(CUErrors, BadStmtList) {
- EXPECT_CALL(reporter_, BadLineInfoOffset(dummy_line_size_ + 10)).Times(1);
-
- ASSERT_TRUE(root_handler_
- .StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd,
- 0x2d7d19546cf6590cULL, 3));
- ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL,
- dwarf2reader::DW_TAG_compile_unit));
- root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
- "compilation-unit-name");
- root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list,
- dwarf2reader::DW_FORM_ref4,
- dummy_line_size_ + 10);
- root_handler_.EndAttributes();
- root_handler_.Finish();
-}
-
-TEST_F(CUErrors, NoLineSection) {
- EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1);
- PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290);
- // Delete the entry for .debug_line added by the fixture class's constructor.
- file_context_.section_map.clear();
-
- StartCU();
- root_handler_.Finish();
-}
-
-TEST_F(CUErrors, BadDwarfVersion1) {
- // Kludge: satisfy reporter_'s expectation.
- reporter_.SetCUName("compilation-unit-name");
-
- ASSERT_FALSE(root_handler_
- .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
- 0xc9de224ccb99ac3eULL, 1));
-}
-
-TEST_F(CUErrors, GoodDwarfVersion2) {
- // Kludge: satisfy reporter_'s expectation.
- reporter_.SetCUName("compilation-unit-name");
-
- ASSERT_TRUE(root_handler_
- .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
- 0xc9de224ccb99ac3eULL, 2));
-}
-
-TEST_F(CUErrors, GoodDwarfVersion3) {
- // Kludge: satisfy reporter_'s expectation.
- reporter_.SetCUName("compilation-unit-name");
-
- ASSERT_TRUE(root_handler_
- .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
- 0xc9de224ccb99ac3eULL, 3));
-}
-
-TEST_F(CUErrors, BadCURootDIETag) {
- // Kludge: satisfy reporter_'s expectation.
- reporter_.SetCUName("compilation-unit-name");
-
- ASSERT_TRUE(root_handler_
- .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
- 0xc9de224ccb99ac3eULL, 3));
-
- ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL,
- dwarf2reader::DW_TAG_subprogram));
-}
-
-// Tests for DwarfCUToModule::Reporter. These just produce (or fail to
-// produce) output, so their results need to be checked by hand.
-struct Reporter: public Test {
- Reporter()
- : reporter("filename", 0x123456789abcdef0ULL) {
- reporter.SetCUName("compilation-unit-name");
-
- function.name = "function name";
- function.address = 0x19c45c30770c1eb0ULL;
- function.size = 0x89808a5bdfa0a6a3ULL;
- function.parameter_size = 0x6a329f18683dcd51ULL;
-
- file.name = "source file name";
-
- line.address = 0x3606ac6267aebeccULL;
- line.size = 0x5de482229f32556aULL;
- line.file = &file;
- line.number = 93400201;
- }
-
- DwarfCUToModule::WarningReporter reporter;
- Module::Function function;
- Module::File file;
- Module::Line line;
-};
-
-TEST_F(Reporter, UnknownSpecification) {
- reporter.UnknownSpecification(0x123456789abcdef1ULL, 0x323456789abcdef2ULL);
-}
-
-TEST_F(Reporter, UnknownAbstractOrigin) {
- reporter.UnknownAbstractOrigin(0x123456789abcdef1ULL, 0x323456789abcdef2ULL);
-}
-
-TEST_F(Reporter, MissingSection) {
- reporter.MissingSection("section name");
-}
-
-TEST_F(Reporter, BadLineInfoOffset) {
- reporter.BadLineInfoOffset(0x123456789abcdef1ULL);
-}
-
-TEST_F(Reporter, UncoveredFunctionDisabled) {
- reporter.UncoveredFunction(function);
- EXPECT_FALSE(reporter.uncovered_warnings_enabled());
-}
-
-TEST_F(Reporter, UncoveredFunctionEnabled) {
- reporter.set_uncovered_warnings_enabled(true);
- reporter.UncoveredFunction(function);
- EXPECT_TRUE(reporter.uncovered_warnings_enabled());
-}
-
-TEST_F(Reporter, UncoveredLineDisabled) {
- reporter.UncoveredLine(line);
- EXPECT_FALSE(reporter.uncovered_warnings_enabled());
-}
-
-TEST_F(Reporter, UncoveredLineEnabled) {
- reporter.set_uncovered_warnings_enabled(true);
- reporter.UncoveredLine(line);
- EXPECT_TRUE(reporter.uncovered_warnings_enabled());
-}
-
-TEST_F(Reporter, UnnamedFunction) {
- reporter.UnnamedFunction(0x90c0baff9dedb2d9ULL);
-}
-
-// Would be nice to also test:
-// - overlapping lines, functions
diff --git a/breakpad/pending/src/common/module.cc b/breakpad/pending/src/common/module.cc
deleted file mode 100644
index cb4847c..0000000
--- a/breakpad/pending/src/common/module.cc
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright (c) 2011 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>
-
-// module.cc: Implement google_breakpad::Module. See module.h.
-
-#include "common/module.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <iostream>
-#include <utility>
-
-namespace google_breakpad {
-
-using std::dec;
-using std::endl;
-using std::hex;
-
-
-Module::Module(const string &name, const string &os,
- const string &architecture, const string &id) :
- name_(name),
- os_(os),
- architecture_(architecture),
- id_(id),
- load_address_(0) { }
-
-Module::~Module() {
- for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
- delete it->second;
- for (FunctionSet::iterator it = functions_.begin();
- it != functions_.end(); ++it) {
- delete *it;
- }
- for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
- it != stack_frame_entries_.end(); ++it) {
- delete *it;
- }
- for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
- delete *it;
-}
-
-void Module::SetLoadAddress(Address address) {
- load_address_ = address;
-}
-
-void Module::AddFunction(Function *function) {
- std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
- if (!ret.second) {
- // Free the duplicate that was not inserted because this Module
- // now owns it.
- delete function;
- }
-}
-
-void Module::AddFunctions(vector<Function *>::iterator begin,
- vector<Function *>::iterator end) {
- for (vector<Function *>::iterator it = begin; it != end; ++it)
- AddFunction(*it);
-}
-
-void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) {
- stack_frame_entries_.push_back(stack_frame_entry);
-}
-
-void Module::AddExtern(Extern *ext) {
- std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
- if (!ret.second) {
- // Free the duplicate that was not inserted because this Module
- // now owns it.
- delete ext;
- }
-}
-
-void Module::GetFunctions(vector<Function *> *vec,
- vector<Function *>::iterator i) {
- vec->insert(i, functions_.begin(), functions_.end());
-}
-
-void Module::GetExterns(vector<Extern *> *vec,
- vector<Extern *>::iterator i) {
- vec->insert(i, externs_.begin(), externs_.end());
-}
-
-Module::File *Module::FindFile(const string &name) {
- // A tricky bit here. The key of each map entry needs to be a
- // pointer to the entry's File's name string. This means that we
- // can't do the initial lookup with any operation that would create
- // an empty entry for us if the name isn't found (like, say,
- // operator[] or insert do), because such a created entry's key will
- // be a pointer the string passed as our argument. Since the key of
- // a map's value type is const, we can't fix it up once we've
- // created our file. lower_bound does the lookup without doing an
- // insertion, and returns a good hint iterator to pass to insert.
- // Our "destiny" is where we belong, whether we're there or not now.
- FileByNameMap::iterator destiny = files_.lower_bound(&name);
- if (destiny == files_.end()
- || *destiny->first != name) { // Repeated string comparison, boo hoo.
- File *file = new File;
- file->name = name;
- file->source_id = -1;
- destiny = files_.insert(destiny,
- FileByNameMap::value_type(&file->name, file));
- }
- return destiny->second;
-}
-
-Module::File *Module::FindFile(const char *name) {
- string name_string = name;
- return FindFile(name_string);
-}
-
-Module::File *Module::FindExistingFile(const string &name) {
- FileByNameMap::iterator it = files_.find(&name);
- return (it == files_.end()) ? NULL : it->second;
-}
-
-void Module::GetFiles(vector<File *> *vec) {
- vec->clear();
- for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
- vec->push_back(it->second);
-}
-
-void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) {
- *vec = stack_frame_entries_;
-}
-
-void Module::AssignSourceIds() {
- // First, give every source file an id of -1.
- for (FileByNameMap::iterator file_it = files_.begin();
- file_it != files_.end(); ++file_it) {
- file_it->second->source_id = -1;
- }
-
- // Next, mark all files actually cited by our functions' line number
- // info, by setting each one's source id to zero.
- for (FunctionSet::const_iterator func_it = functions_.begin();
- func_it != functions_.end(); ++func_it) {
- Function *func = *func_it;
- for (vector<Line>::iterator line_it = func->lines.begin();
- line_it != func->lines.end(); ++line_it)
- line_it->file->source_id = 0;
- }
-
- // Finally, assign source ids to those files that have been marked.
- // We could have just assigned source id numbers while traversing
- // the line numbers, but doing it this way numbers the files in
- // lexicographical order by name, which is neat.
- int next_source_id = 0;
- for (FileByNameMap::iterator file_it = files_.begin();
- file_it != files_.end(); ++file_it) {
- if (!file_it->second->source_id)
- file_it->second->source_id = next_source_id++;
- }
-}
-
-bool Module::ReportError() {
- fprintf(stderr, "error writing symbol file: %s\n",
- strerror(errno));
- return false;
-}
-
-bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
- for (RuleMap::const_iterator it = rule_map.begin();
- it != rule_map.end(); ++it) {
- if (it != rule_map.begin())
- stream << ' ';
- stream << it->first << ": " << it->second;
- }
- return stream.good();
-}
-
-bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
- stream << "MODULE " << os_ << " " << architecture_ << " "
- << id_ << " " << name_ << endl;
- if (!stream.good())
- return ReportError();
-
- if (symbol_data != ONLY_CFI) {
- AssignSourceIds();
-
- // Write out files.
- for (FileByNameMap::iterator file_it = files_.begin();
- file_it != files_.end(); ++file_it) {
- File *file = file_it->second;
- if (file->source_id >= 0) {
- stream << "FILE " << file->source_id << " " << file->name << endl;
- if (!stream.good())
- return ReportError();
- }
- }
-
- // Write out functions and their lines.
- for (FunctionSet::const_iterator func_it = functions_.begin();
- func_it != functions_.end(); ++func_it) {
- Function *func = *func_it;
- assert(!func->name.empty());
- stream << "FUNC " << hex
- << (func->address - load_address_) << " "
- << func->size << " "
- << func->parameter_size << " "
- << func->name << dec << endl;
-
- if (!stream.good())
- return ReportError();
- for (vector<Line>::iterator line_it = func->lines.begin();
- line_it != func->lines.end(); ++line_it) {
- stream << hex
- << (line_it->address - load_address_) << " "
- << line_it->size << " "
- << dec
- << line_it->number << " "
- << line_it->file->source_id << endl;
- if (!stream.good())
- return ReportError();
- }
- }
-
- // Write out 'PUBLIC' records.
- for (ExternSet::const_iterator extern_it = externs_.begin();
- extern_it != externs_.end(); ++extern_it) {
- Extern *ext = *extern_it;
- stream << "PUBLIC " << hex
- << (ext->address - load_address_) << " 0 "
- << ext->name << dec << endl;
- if (!stream.good())
- return ReportError();
- }
- }
-
- if (symbol_data != NO_CFI) {
- // Write out 'STACK CFI INIT' and 'STACK CFI' records.
- vector<StackFrameEntry *>::const_iterator frame_it;
- for (frame_it = stack_frame_entries_.begin();
- frame_it != stack_frame_entries_.end(); ++frame_it) {
- StackFrameEntry *entry = *frame_it;
- stream << "STACK CFI INIT " << hex
- << (entry->address - load_address_) << " "
- << entry->size << " " << dec;
- if (!stream.good()
- || !WriteRuleMap(entry->initial_rules, stream))
- return ReportError();
-
- stream << endl;
-
- // Write out this entry's delta rules as 'STACK CFI' records.
- for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
- delta_it != entry->rule_changes.end(); ++delta_it) {
- stream << "STACK CFI " << hex
- << (delta_it->first - load_address_) << " " << dec;
- if (!stream.good()
- || !WriteRuleMap(delta_it->second, stream))
- return ReportError();
-
- stream << endl;
- }
- }
- }
-
- return true;
-}
-
-} // namespace google_breakpad