Add support for DebugFission to DWARF parser
authorAlexey Samsonov <samsonov@google.com>
Tue, 27 Aug 2013 09:20:22 +0000 (09:20 +0000)
committerAlexey Samsonov <samsonov@google.com>
Tue, 27 Aug 2013 09:20:22 +0000 (09:20 +0000)
Summary:
1) Make llvm-symbolizer properly symbolize
files with split debug info (by using stanalone .dwo files).
2) Make DWARFCompileUnit parse and store corresponding .dwo file,
if necessary.
3) Make bits of DWARF parsing more CompileUnit-oriented.

Reviewers: echristo

Reviewed By: echristo

CC: bkramer, llvm-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D1164

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189329 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo/DWARFFormValue.h
lib/DebugInfo/DWARFCompileUnit.cpp
lib/DebugInfo/DWARFCompileUnit.h
lib/DebugInfo/DWARFDebugAranges.cpp
lib/DebugInfo/DWARFDebugInfoEntry.cpp
lib/DebugInfo/DWARFDebugInfoEntry.h
lib/DebugInfo/DWARFFormValue.cpp

index eaaccfb4f33b3bb7737b843f39df0f57ab629b9d..ad6f71d664e50b113015507634f721c61cd118ac 100644 (file)
@@ -20,7 +20,7 @@ class raw_ostream;
 class DWARFFormValue {
 public:
   struct ValueType {
-    ValueType() : data(NULL) {
+    ValueType() : data(NULL), IsDWOIndex(false) {
       uval = 0;
     }
 
@@ -30,6 +30,7 @@ public:
       const char* cstr;
     };
     const uint8_t* data;
+    bool IsDWOIndex;
   };
 
   enum {
@@ -63,11 +64,8 @@ public:
   bool resolveCompileUnitReferences(const DWARFCompileUnit* cu);
   uint64_t getUnsigned() const { return Value.uval; }
   int64_t getSigned() const { return Value.sval; }
-  const char *getAsCString(const DataExtractor *debug_str_data_ptr) const;
-  const char *getIndirectCString(const DataExtractor *,
-                                 const DataExtractor *) const;
-  uint64_t getIndirectAddress(const DataExtractor *,
-                              const DWARFCompileUnit *) const;
+  const char *getAsCString(const DWARFCompileUnit *CU) const;
+  uint64_t getAsAddress(const DWARFCompileUnit *CU) const;
   bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr,
                  const DWARFCompileUnit *cu) const;
   static bool skipValue(uint16_t form, DataExtractor debug_info_data,
index 93b1622e807611b999ece9eba3e2de97cf153293..4b6aa272f7d30d505b89fcd761d341666d4ff562 100644 (file)
 #include "llvm/DebugInfo/DWARFFormValue.h"
 #include "llvm/Support/Dwarf.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
 using namespace dwarf;
 
-DataExtractor DWARFCompileUnit::getDebugInfoExtractor() const {
-  return DataExtractor(InfoSection, isLittleEndian, AddrSize);
+bool DWARFCompileUnit::getAddrOffsetSectionItem(uint32_t Index,
+                                                uint64_t &Result) const {
+  uint32_t Offset = AddrOffsetSectionBase + Index * AddrSize;
+  if (AddrOffsetSection.size() < Offset + AddrSize)
+    return false;
+  DataExtractor DA(AddrOffsetSection, isLittleEndian, AddrSize);
+  Result = DA.getAddress(&Offset);
+  return true;
+}
+
+bool DWARFCompileUnit::getStringOffsetSectionItem(uint32_t Index,
+                                                  uint32_t &Result) const {
+  // FIXME: string offset section entries are 8-byte for DWARF64.
+  const uint32_t ItemSize = 4;
+  uint32_t Offset = Index * ItemSize;
+  if (StringOffsetSection.size() < Offset + ItemSize)
+    return false;
+  DataExtractor DA(StringOffsetSection, isLittleEndian, 0);
+  Result = DA.getU32(&Offset);
+  return true;
 }
 
 bool DWARFCompileUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) {
@@ -78,7 +97,8 @@ bool DWARFCompileUnit::extractRangeList(uint32_t RangeListOffset,
   // Require that compile unit is extracted.
   assert(DieArray.size() > 0);
   DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize);
-  return RangeList.extract(RangesData, &RangeListOffset);
+  uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
+  return RangeList.extract(RangesData, &ActualRangeListOffset);
 }
 
 void DWARFCompileUnit::clear() {
@@ -88,7 +108,10 @@ void DWARFCompileUnit::clear() {
   Abbrevs = 0;
   AddrSize = 0;
   BaseAddr = 0;
+  RangeSectionBase = 0;
+  AddrOffsetSectionBase = 0;
   clearDIEs(false);
+  DWO.reset();
 }
 
 void DWARFCompileUnit::dump(raw_ostream &OS) {
@@ -112,6 +135,15 @@ const char *DWARFCompileUnit::getCompilationDir() {
   return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0);
 }
 
+uint64_t DWARFCompileUnit::getDWOId() {
+  extractDIEsIfNeeded(true);
+  const uint64_t FailValue = -1ULL;
+  if (DieArray.empty())
+    return FailValue;
+  return DieArray[0]
+      .getAttributeValueAsUnsigned(this, DW_AT_GNU_dwo_id, FailValue);
+}
+
 void DWARFCompileUnit::setDIERelations() {
   if (DieArray.empty())
     return;
@@ -207,21 +239,72 @@ size_t DWARFCompileUnit::extractDIEsIfNeeded(bool CUDieOnly) {
       DieArray.size() > 1)
     return 0; // Already parsed.
 
-  extractDIEsToVector(DieArray.empty(), !CUDieOnly, DieArray);
+  bool HasCUDie = DieArray.size() > 0;
+  extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
 
-  // Set the base address of current compile unit.
-  if (!DieArray.empty()) {
+  if (DieArray.empty())
+    return 0;
+
+  // If CU DIE was just parsed, copy several attribute values from it.
+  if (!HasCUDie) {
     uint64_t BaseAddr =
       DieArray[0].getAttributeValueAsUnsigned(this, DW_AT_low_pc, -1U);
     if (BaseAddr == -1U)
       BaseAddr = DieArray[0].getAttributeValueAsUnsigned(this, DW_AT_entry_pc, 0);
     setBaseAddress(BaseAddr);
+    AddrOffsetSectionBase =
+        DieArray[0].getAttributeValueAsReference(this, DW_AT_GNU_addr_base, 0);
+    RangeSectionBase =
+        DieArray[0].getAttributeValueAsReference(this, DW_AT_GNU_ranges_base, 0);
   }
 
   setDIERelations();
   return DieArray.size();
 }
 
+DWARFCompileUnit::DWOHolder::DWOHolder(object::ObjectFile *DWOFile)
+    : DWOFile(DWOFile),
+      DWOContext(cast<DWARFContext>(DIContext::getDWARFContext(DWOFile))),
+      DWOCU(0) {
+  if (DWOContext->getNumDWOCompileUnits() > 0)
+    DWOCU = DWOContext->getDWOCompileUnitAtIndex(0);
+}
+
+bool DWARFCompileUnit::parseDWO() {
+  if (DWO.get() != 0)
+    return false;
+  extractDIEsIfNeeded(true);
+  if (DieArray.empty())
+    return false;
+  const char *DWOFileName =
+      DieArray[0].getAttributeValueAsString(this, DW_AT_GNU_dwo_name, 0);
+  if (DWOFileName == 0)
+    return false;
+  const char *CompilationDir =
+      DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0);
+  SmallString<16> AbsolutePath;
+  if (sys::path::is_relative(DWOFileName) && CompilationDir != 0) {
+    sys::path::append(AbsolutePath, CompilationDir);
+  }
+  sys::path::append(AbsolutePath, DWOFileName);
+  object::ObjectFile *DWOFile =
+      object::ObjectFile::createObjectFile(AbsolutePath);
+  if (!DWOFile)
+    return false;
+  // Reset DWOHolder.
+  DWO.reset(new DWOHolder(DWOFile));
+  DWARFCompileUnit *DWOCU = DWO->getCU();
+  // Verify that compile unit in .dwo file is valid.
+  if (DWOCU == 0 || DWOCU->getDWOId() != getDWOId()) {
+    DWO.reset();
+    return false;
+  }
+  // Share .debug_addr and .debug_ranges section with compile unit in .dwo
+  DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
+  DWOCU->setRangesSection(RangeSection, RangeSectionBase);
+  return true;
+}
+
 void DWARFCompileUnit::clearDIEs(bool KeepCUDie) {
   if (DieArray.size() > (unsigned)KeepCUDie) {
     // std::vectors never get any smaller when resized to a smaller size,
@@ -241,7 +324,8 @@ void DWARFCompileUnit::clearDIEs(bool KeepCUDie) {
 
 void
 DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
-                                         bool clear_dies_if_already_not_parsed){
+                                         bool clear_dies_if_already_not_parsed,
+                                         uint32_t CUOffsetInAranges) {
   // This function is usually called if there in no .debug_aranges section
   // in order to produce a compile unit level set of address ranges that
   // is accurate. If the DIEs weren't parsed, then we don't want all dies for
@@ -250,7 +334,17 @@ DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
   // down.
   const bool clear_dies = extractDIEsIfNeeded(false) > 1 &&
                           clear_dies_if_already_not_parsed;
-  DieArray[0].buildAddressRangeTable(this, debug_aranges);
+  DieArray[0].buildAddressRangeTable(this, debug_aranges, CUOffsetInAranges);
+  bool DWOCreated = parseDWO();
+  if (DWO.get()) {
+    // If there is a .dwo file for this compile unit, then skeleton CU DIE
+    // doesn't have children, and we should instead build address range table
+    // from DIEs in the .debug_info.dwo section of .dwo file.
+    DWO->getCU()->buildAddressRangeTable(
+        debug_aranges, clear_dies_if_already_not_parsed, CUOffsetInAranges);
+  }
+  if (DWOCreated && clear_dies_if_already_not_parsed)
+    DWO.reset();
 
   // Keep memory down by clearing DIEs if this generate function
   // caused them to be parsed.
@@ -258,21 +352,38 @@ DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
     clearDIEs(true);
 }
 
+const DWARFDebugInfoEntryMinimal *
+DWARFCompileUnit::getSubprogramForAddress(uint64_t Address) {
+  extractDIEsIfNeeded(false);
+  for (size_t i = 0, n = DieArray.size(); i != n; i++)
+    if (DieArray[i].isSubprogramDIE() &&
+        DieArray[i].addressRangeContainsAddress(this, Address)) {
+      return &DieArray[i];
+    }
+  return 0;
+}
+
 DWARFDebugInfoEntryInlinedChain
 DWARFCompileUnit::getInlinedChainForAddress(uint64_t Address) {
   // First, find a subprogram that contains the given address (the root
   // of inlined chain).
-  extractDIEsIfNeeded(false);
-  const DWARFDebugInfoEntryMinimal *SubprogramDIE = 0;
-  for (size_t i = 0, n = DieArray.size(); i != n; i++) {
-    if (DieArray[i].isSubprogramDIE() &&
-        DieArray[i].addressRangeContainsAddress(this, Address)) {
-      SubprogramDIE = &DieArray[i];
-      break;
+  const DWARFCompileUnit *ChainCU = 0;
+  const DWARFDebugInfoEntryMinimal *SubprogramDIE =
+      getSubprogramForAddress(Address);
+  if (SubprogramDIE) {
+    ChainCU = this;
+  } else {
+    // Try to look for subprogram DIEs in the DWO file.
+    parseDWO();
+    if (DWO.get()) {
+      SubprogramDIE = DWO->getCU()->getSubprogramForAddress(Address);
+      if (SubprogramDIE)
+        ChainCU = DWO->getCU();
     }
   }
+
   // Get inlined chain rooted at this subprogram DIE.
   if (!SubprogramDIE)
     return DWARFDebugInfoEntryInlinedChain();
-  return SubprogramDIE->getInlinedChainForAddress(this, Address);
-}
+  return SubprogramDIE->getInlinedChainForAddress(ChainCU, Address);
+ }
index 97f847962e27362a5f2c6b6311af8b788dfa7a3d..09167d128f5f30d2cacfb58fbd106e34290ef7c4 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H
 #define LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H
 
+#include "llvm/ADT/OwningPtr.h"
 #include "DWARFDebugAbbrev.h"
 #include "DWARFDebugInfoEntry.h"
 #include "DWARFDebugRangeList.h"
 
 namespace llvm {
 
+namespace object {
+class ObjectFile;
+}
+
 class DWARFDebugAbbrev;
 class StringRef;
 class raw_ostream;
@@ -30,9 +35,11 @@ class DWARFCompileUnit {
   StringRef InfoSection;
   StringRef AbbrevSection;
   StringRef RangeSection;
+  uint32_t RangeSectionBase;
   StringRef StringSection;
   StringRef StringOffsetSection;
   StringRef AddrOffsetSection;
+  uint32_t AddrOffsetSectionBase;
   const RelocAddrMap *RelocMap;
   bool isLittleEndian;
 
@@ -44,6 +51,17 @@ class DWARFCompileUnit {
   uint64_t BaseAddr;
   // The compile unit debug information entry items.
   std::vector<DWARFDebugInfoEntryMinimal> DieArray;
+
+  class DWOHolder {
+    OwningPtr<object::ObjectFile> DWOFile;
+    OwningPtr<DWARFContext> DWOContext;
+    DWARFCompileUnit *DWOCU;
+  public:
+    DWOHolder(object::ObjectFile *DWOFile);
+    DWARFCompileUnit *getCU() const { return DWOCU; }
+  };
+  OwningPtr<DWOHolder> DWO;
+
 public:
 
   DWARFCompileUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS,
@@ -57,9 +75,27 @@ public:
 
   StringRef getStringSection() const { return StringSection; }
   StringRef getStringOffsetSection() const { return StringOffsetSection; }
-  StringRef getAddrOffsetSection() const { return AddrOffsetSection; }
+  void setAddrOffsetSection(StringRef AOS, uint32_t Base) {
+    AddrOffsetSection = AOS;
+    AddrOffsetSectionBase = Base;
+  }
+  void setRangesSection(StringRef RS, uint32_t Base) {
+    RangeSection = RS;
+    RangeSectionBase = Base;
+  }
+
+  bool getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const;
+  // FIXME: Result should be uint64_t in DWARF64.
+  bool getStringOffsetSectionItem(uint32_t Index, uint32_t &Result) const;
+
+  DataExtractor getDebugInfoExtractor() const {
+    return DataExtractor(InfoSection, isLittleEndian, AddrSize);
+  }
+  DataExtractor getStringExtractor() const {
+    return DataExtractor(StringSection, false, 0);
+  }
+
   const RelocAddrMap *getRelocMap() const { return RelocMap; }
-  DataExtractor getDebugInfoExtractor() const;
 
   bool extract(DataExtractor debug_info, uint32_t* offset_ptr);
   uint32_t extract(uint32_t offset, DataExtractor debug_info_data,
@@ -105,6 +141,7 @@ public:
   }
 
   const char *getCompilationDir();
+  uint64_t getDWOId();
 
   /// setDIERelations - We read in all of the DIE entries into our flat list
   /// of DIE entries and now we need to go back through all of them and set the
@@ -112,7 +149,8 @@ public:
   void setDIERelations();
 
   void buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
-                              bool clear_dies_if_already_not_parsed);
+                              bool clear_dies_if_already_not_parsed,
+                              uint32_t CUOffsetInAranges);
 
   /// getInlinedChainForAddress - fetches inlined chain for a given address.
   /// Returns empty chain if there is no subprogram containing address. The
@@ -125,6 +163,15 @@ private:
                            std::vector<DWARFDebugInfoEntryMinimal> &DIEs) const;
   /// clearDIEs - Clear parsed DIEs to keep memory usage low.
   void clearDIEs(bool KeepCUDie);
+
+  /// parseDWO - Parses .dwo file for current compile unit. Returns true if
+  /// it was actually constructed.
+  bool parseDWO();
+
+  /// getSubprogramForAddress - Returns subprogram DIE with address range
+  /// encompassing the provided address. The pointer is alive as long as parsed
+  /// compile unit DIEs are not cleared.
+  const DWARFDebugInfoEntryMinimal *getSubprogramForAddress(uint64_t Address);
 };
 
 }
index f79862d606f5618baae107a71330d683e7e32773..56de5ea28de7593c6d4b4147e410d33517a558cc 100644 (file)
@@ -95,7 +95,7 @@ bool DWARFDebugAranges::generate(DWARFContext *ctx) {
       if (DWARFCompileUnit *cu = ctx->getCompileUnitAtIndex(cu_idx)) {
         uint32_t CUOffset = cu->getOffset();
         if (ParsedCUOffsets.insert(CUOffset).second)
-          cu->buildAddressRangeTable(this, true);
+          cu->buildAddressRangeTable(this, true, CUOffset);
       }
     }
   }
index 9abf8dd2623b1c641ceb51b8874766355560ddff..775e68fa23f3a4ab91be35aa29ee76e5c1386fd0 100644 (file)
@@ -222,29 +222,30 @@ DWARFDebugInfoEntryMinimal::getAttributeValue(const DWARFCompileUnit *cu,
   return 0;
 }
 
-const char*
-DWARFDebugInfoEntryMinimal::getAttributeValueAsString(
-                                                     const DWARFCompileUnit* cu,
-                                                     const uint16_t attr,
-                                                     const char* fail_value)
-                                                     const {
-  DWARFFormValue form_value;
-  if (getAttributeValue(cu, attr, form_value)) {
-    DataExtractor stringExtractor(cu->getStringSection(), false, 0);
-    return form_value.getAsCString(&stringExtractor);
-  }
-  return fail_value;
+const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString(
+    const DWARFCompileUnit *CU, const uint16_t Attr,
+    const char *FailValue) const {
+  DWARFFormValue FormValue;
+  if (getAttributeValue(CU, Attr, FormValue))
+    return FormValue.getAsCString(CU);
+  return FailValue;
 }
 
-uint64_t
-DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsigned(
-                                                    const DWARFCompileUnit* cu,
-                                                    const uint16_t attr,
-                                                    uint64_t fail_value) const {
-  DWARFFormValue form_value;
-  if (getAttributeValue(cu, attr, form_value))
-      return form_value.getUnsigned();
-  return fail_value;
+uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsAddress(
+    const DWARFCompileUnit *CU, const uint16_t Attr, uint64_t FailValue) const {
+  DWARFFormValue FormValue;
+  if (getAttributeValue(CU, Attr, FormValue))
+    return FormValue.getAsAddress(CU);
+  return FailValue;
+}
+
+uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsigned(
+    const DWARFCompileUnit *CU, const uint16_t Attr, uint64_t FailValue) const {
+  DWARFFormValue FormValue;
+  if (getAttributeValue(CU, Attr, FormValue)) {
+    return FormValue.getUnsigned();
+  }
+  return FailValue;
 }
 
 int64_t
@@ -274,29 +275,29 @@ bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFCompileUnit *CU,
                                                  uint64_t &LowPC,
                                                  uint64_t &HighPC) const {
   HighPC = -1ULL;
-  LowPC = getAttributeValueAsUnsigned(CU, DW_AT_low_pc, -1ULL);
+  LowPC = getAttributeValueAsAddress(CU, DW_AT_low_pc, -1ULL);
   if (LowPC != -1ULL)
-    HighPC = getAttributeValueAsUnsigned(CU, DW_AT_high_pc, -1ULL);
+    HighPC = getAttributeValueAsAddress(CU, DW_AT_high_pc, -1ULL);
   return (HighPC != -1ULL);
 }
 
 void
 DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *CU,
-                                               DWARFDebugAranges *DebugAranges)
+                                               DWARFDebugAranges *DebugAranges,
+                                               uint32_t CUOffsetInAranges)
                                                    const {
   if (AbbrevDecl) {
     if (isSubprogramDIE()) {
       uint64_t LowPC, HighPC;
-      if (getLowAndHighPC(CU, LowPC, HighPC)) {
-        DebugAranges->appendRange(CU->getOffset(), LowPC, HighPC);
-      }
+      if (getLowAndHighPC(CU, LowPC, HighPC))
+        DebugAranges->appendRange(CUOffsetInAranges, LowPC, HighPC);
       // FIXME: try to append ranges from .debug_ranges section.
     }
 
-    const DWARFDebugInfoEntryMinimal *child = getFirstChild();
-    while (child) {
-      child->buildAddressRangeTable(CU, DebugAranges);
-      child = child->getSibling();
+    const DWARFDebugInfoEntryMinimal *Child = getFirstChild();
+    while (Child) {
+      Child->buildAddressRangeTable(CU, DebugAranges, CUOffsetInAranges);
+      Child = Child->getSibling();
     }
   }
 }
index a69911f5618ce7fe437377e72429292f990cb6c1..2feea36b9191bbe730893c58af839b0371989eae 100644 (file)
@@ -128,6 +128,10 @@ public:
                                         const uint16_t attr,
                                         const char *fail_value) const;
 
+  uint64_t getAttributeValueAsAddress(const DWARFCompileUnit *CU,
+                                      const uint16_t Attr,
+                                      uint64_t FailValue) const;
+
   uint64_t getAttributeValueAsUnsigned(const DWARFCompileUnit *cu,
                                        const uint16_t attr,
                                        uint64_t fail_value) const;
@@ -146,7 +150,8 @@ public:
                        uint64_t &LowPC, uint64_t &HighPC) const;
 
   void buildAddressRangeTable(const DWARFCompileUnit *CU,
-                              DWARFDebugAranges *DebugAranges) const;
+                              DWARFDebugAranges *DebugAranges,
+                              uint32_t CUOffsetInAranges) const;
 
   bool addressRangeContainsAddress(const DWARFCompileUnit *CU,
                                    const uint64_t Address) const;
index 1a1cf2452cd1a36aaf896fefd481cee86be01638..48e0d2090803d9ea7472afe47111268585b7a419 100644 (file)
@@ -183,10 +183,9 @@ DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr,
       Value.uval = data.getU64(offset_ptr);
       break;
     case DW_FORM_GNU_addr_index:
-      Value.uval = data.getULEB128(offset_ptr);
-      break;
     case DW_FORM_GNU_str_index:
       Value.uval = data.getULEB128(offset_ptr);
+      Value.IsDWOIndex = true;
       break;
     default:
       return false;
@@ -322,12 +321,11 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const {
   switch (Form) {
   case DW_FORM_addr:      OS << format("0x%016" PRIx64, uvalue); break;
   case DW_FORM_GNU_addr_index: {
-    StringRef AddrOffsetSec = cu->getAddrOffsetSection();
     OS << format(" indexed (%8.8x) address = ", (uint32_t)uvalue);
-    if (AddrOffsetSec.size() != 0) {
-      DataExtractor DA(AddrOffsetSec, true, cu->getAddressByteSize());
-      OS << format("0x%016" PRIx64, getIndirectAddress(&DA, cu));
-    else
+    uint64_t Address;
+    if (cu->getAddrOffsetSectionItem(uvalue, Address))
+      OS << format("0x%016" PRIx64, Address);
+    else
       OS << "<no .debug_addr section>";
     break;
   }
@@ -376,7 +374,7 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const {
   case DW_FORM_udata:     OS << getUnsigned(); break;
   case DW_FORM_strp: {
     OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue);
-    const char* dbg_str = getAsCString(&debug_str_data);
+    const char* dbg_str = getAsCString(cu);
     if (dbg_str) {
       OS << '"';
       OS.write_escaped(dbg_str);
@@ -386,8 +384,7 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const {
   }
   case DW_FORM_GNU_str_index: {
     OS << format(" indexed (%8.8x) string = ", (uint32_t)uvalue);
-    const char *dbg_str = getIndirectCString(&debug_str_data,
-                                             &debug_str_offset_data);
+    const char *dbg_str = getAsCString(cu);
     if (dbg_str) {
       OS << '"';
       OS.write_escaped(dbg_str);
@@ -440,33 +437,33 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFCompileUnit *cu) const {
 }
 
 const char*
-DWARFFormValue::getAsCString(const DataExtractor *debug_str_data_ptr) const {
-  if (isInlinedCStr()) {
+DWARFFormValue::getAsCString(const DWARFCompileUnit *CU) const {
+  if (isInlinedCStr())
     return Value.cstr;
-  } else if (debug_str_data_ptr) {
-    uint32_t offset = Value.uval;
-    return debug_str_data_ptr->getCStr(&offset);
+  if (!CU)
+    return NULL;
+  uint32_t Offset = Value.uval;
+  if (Value.IsDWOIndex) {
+    uint32_t StrOffset;
+    if (!CU->getStringOffsetSectionItem(Offset, StrOffset))
+      return NULL;
+    Offset = StrOffset;
   }
-  return NULL;
-}
-
-const char*
-DWARFFormValue::getIndirectCString(const DataExtractor *DS,
-                                   const DataExtractor *DSO) const {
-  if (!DS || !DSO) return NULL;
-
-  uint32_t offset = Value.uval * 4;
-  uint32_t soffset = DSO->getU32(&offset);
-  return DS->getCStr(&soffset);
+  return CU->getStringExtractor().getCStr(&Offset);
 }
 
 uint64_t
-DWARFFormValue::getIndirectAddress(const DataExtractor *DA,
-                                   const DWARFCompileUnit *cu) const {
-  if (!DA) return 0;
-
-  uint32_t offset = Value.uval * cu->getAddressByteSize();
-  return DA->getAddress(&offset);
+DWARFFormValue::getAsAddress(const DWARFCompileUnit *CU) const {
+  if (!CU)
+    return 0;
+  if (Value.IsDWOIndex) {
+    uint32_t Index = Value.uval;
+    uint64_t Address;
+    if (!CU->getAddrOffsetSectionItem(Index, Address))
+      return 0;
+    return Address;
+  }
+  return Value.uval;
 }
 
 uint64_t DWARFFormValue::getReference(const DWARFCompileUnit *cu) const {