Bug 524410 - part 2 - parse DW_TAG_inlined_subroutine DIEs; r=gsvelto
authorNathan Froyd <froydnj@mozilla.com>
Fri, 05 Apr 2019 16:35:09 +0000
changeset 468620 589e276c75fadc2f261f3edb1c8d7f59d2008d55
parent 468619 578c94538897c59349de77ee3c2da4252198a371
child 468621 b3e5b74ed19fcf6c6f44457accccf4bb59eebcb3
push id35843
push usernbeleuzu@mozilla.com
push dateTue, 09 Apr 2019 22:08:13 +0000
treeherdermozilla-central@a31032a16330 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgsvelto
bugs524410
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 524410 - part 2 - parse DW_TAG_inlined_subroutine DIEs; r=gsvelto We record the file and line that these subroutines were inlined from. We'll use that information to provide more coarse-grained line information in the next patch. Depends on D25469 Differential Revision: https://phabricator.services.mozilla.com/D25470
toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc
toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h
--- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc
+++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc
@@ -120,16 +120,30 @@ struct DwarfCUToModule::FilePrivate {
   unordered_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.
   SpecificationByOffset specifications;
 
   AbstractOriginByOffset origins;
+
+  struct InlinedSubroutineRange {
+    InlinedSubroutineRange(Module::Range range, uint64 call_file,
+                           uint64 call_line)
+      : range_(range), call_file_(call_file), call_line_(call_line) {}
+
+    Module::Range range_;
+    uint64 call_file_, call_line_;
+  };
+
+  // A collection of address ranges with the file and line that they
+  // correspond to. We'll use this information to replace the precise line
+  // information gathered from .debug_line.
+  vector<InlinedSubroutineRange> inlined_ranges;
 };
 
 DwarfCUToModule::FileContext::FileContext(const string &filename,
                                           Module *module,
                                           bool handle_inter_cu_refs)
     : filename_(filename),
       module_(module),
       handle_inter_cu_refs_(handle_inter_cu_refs),
@@ -450,16 +464,114 @@ string DwarfCUToModule::GenericDIEHandle
       spec.unqualified_name = *unqualified_name;
     }
     cu_context_->file_context->file_private_->specifications[offset_] = spec;
   }
 
   return return_value;
 }
 
+// A handler class for DW_TAG_inlined_subroutine DIEs.
+class DwarfCUToModule::InlinedSubroutineHandler: public GenericDIEHandler {
+ public:
+  InlinedSubroutineHandler(CUContext *cu_context, DIEContext *parent_context,
+                           uint64 offset)
+    : GenericDIEHandler(cu_context, parent_context, offset),
+      low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr),
+      ranges_(0), call_file_(0), call_file_set_(false), call_line_(0),
+      call_line_set_(false) {}
+
+  void ProcessAttributeUnsigned(enum DwarfAttribute attr,
+                                enum DwarfForm form,
+                                uint64 data);
+
+  bool EndAttributes();
+
+ private:
+  uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc
+  DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address.
+  uint64 ranges_; // DW_AT_ranges
+  uint64 call_file_; // DW_AT_call_file
+  bool call_file_set_;
+  uint64 call_line_; // DW_AT_call_line
+  bool call_line_set_;
+};
+
+void DwarfCUToModule::InlinedSubroutineHandler::ProcessAttributeUnsigned(
+    enum DwarfAttribute attr,
+    enum DwarfForm form,
+    uint64 data) {
+  switch (attr) {
+    case dwarf2reader::DW_AT_low_pc:      low_pc_  = data; break;
+    case dwarf2reader::DW_AT_high_pc:
+      high_pc_form_ = form;
+      high_pc_ = data;
+      break;
+    case dwarf2reader::DW_AT_ranges:
+      ranges_ = data;
+      break;
+    case dwarf2reader::DW_AT_call_file:
+      call_file_ = data;
+      call_file_set_ = true;
+      break;
+    case dwarf2reader::DW_AT_call_line:
+      call_line_ = data;
+      call_line_set_ = true;
+      break;
+
+    default:
+      GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data);
+      break;
+  }
+}
+
+bool DwarfCUToModule::InlinedSubroutineHandler::EndAttributes() {
+  // DW_TAG_inlined_subroutine child DIEs are only information about formal
+  // parameters and any subroutines that were further inlined, which we're
+  // not particularly concerned about.
+  const bool ignore_children = false;
+
+  // If we didn't find complete information about what file and line we were
+  // inlined from, then there's no point in computing anything.
+  if (!call_file_set_ || !call_line_set_) {
+    return ignore_children;
+  }
+
+  vector<Module::Range> ranges;
+
+  if (!ranges_) {
+    // Make high_pc_ an address, if it isn't already.
+    if (high_pc_form_ != dwarf2reader::DW_FORM_addr &&
+        high_pc_form_ != dwarf2reader::DW_FORM_GNU_addr_index) {
+      high_pc_ += low_pc_;
+    }
+
+    Module::Range range(low_pc_, high_pc_ - low_pc_);
+    ranges.push_back(range);
+  } else {
+    RangesHandler *ranges_handler = cu_context_->ranges_handler;
+
+    if (ranges_handler) {
+      if (!ranges_handler->ReadRanges(ranges_, cu_context_->low_pc, &ranges)) {
+        ranges.clear();
+        cu_context_->reporter->MalformedRangeList(ranges_);
+      }
+    } else {
+      cu_context_->reporter->MissingRanges();
+    }
+  }
+
+  for (const auto& range : ranges) {
+    FilePrivate::InlinedSubroutineRange inline_range(range, call_file_, call_line_);
+    cu_context_->file_context->file_private_->inlined_ranges.push_back(inline_range);
+  }
+
+  return ignore_children;
+}
+
 // 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), high_pc_form_(dwarf2reader::DW_FORM_addr),
         ranges_(0), abstract_origin_(NULL), inline_(false) { }
@@ -471,16 +583,18 @@ class DwarfCUToModule::FuncHandler: publ
                               int64 data);
   void ProcessAttributeReference(enum DwarfAttribute attr,
                                  enum DwarfForm form,
                                  uint64 data);
 
   bool EndAttributes();
   void Finish();
 
+  DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag);
+
  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
   DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address.
   uint64 ranges_; // DW_AT_ranges
   const AbstractOrigin* abstract_origin_;
@@ -621,16 +735,28 @@ void DwarfCUToModule::FuncHandler::Finis
        cu_context_->functions.push_back(func.release());
      }
   } else if (inline_) {
     AbstractOrigin origin(name_);
     cu_context_->file_context->file_private_->origins[offset_] = origin;
   }
 }
 
+dwarf2reader::DIEHandler *DwarfCUToModule::FuncHandler::FindChildHandler(
+    uint64 offset,
+    enum DwarfTag tag) {
+  switch (tag) {
+    case dwarf2reader::DW_TAG_inlined_subroutine:
+      return new InlinedSubroutineHandler(cu_context_, parent_context_, offset);
+
+    default:
+      return NULL;
+  }
+}
+
 // 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();
--- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h
+++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h
@@ -291,16 +291,17 @@ class DwarfCUToModule: public dwarf2read
  private:
   // Used internally by the handler. Full definitions are in
   // dwarf_cu_to_module.cc.
   struct CUContext;
   struct DIEContext;
   struct Specification;
   class GenericDIEHandler;
   class FuncHandler;
+  class InlinedSubroutineHandler;
   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);