[dsymutil] Add support for debug_loc section.
authorFrederic Riss <friss@apple.com>
Sat, 14 Mar 2015 15:49:07 +0000 (15:49 +0000)
committerFrederic Riss <friss@apple.com>
Sat, 14 Mar 2015 15:49:07 +0000 (15:49 +0000)
There is no need to look into the location expressions to transfer them,
the only modification to apply is to patch their base address to reflect
the linked function address.

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

test/tools/dsymutil/X86/basic-linking-x86.test
test/tools/dsymutil/X86/basic-lto-dw4-linking-x86.test
test/tools/dsymutil/X86/basic-lto-linking-x86.test
tools/dsymutil/DwarfLinker.cpp

index 7958d83c7e2ffe020c0b0efc4bc918b4626f5d60..66d4d7f3ce68df6773647504f8f54bfc842c46dd 100644 (file)
@@ -129,6 +129,9 @@ CHECK:      DW_AT_frame_base [DW_FORM_block1]       (<0x01> 56 )
 
 CHECK:    NULL
 
+CHECK: .debug_loc contents
+CHECK-NOT: Location
+
 CHECK:.debug_aranges contents:
 CHECK-NEXT:Address Range Header: length = 0x0000002c, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00
 CHECK-NEXT:[0x0000000100000ea0 - 0x0000000100000ec4)
index 40b578ad865e0f3e443060e3474b6fb4d5cf977f..9c0d3b59bda7daaea4e10b997a9c8d90bdec91e4 100644 (file)
@@ -66,7 +66,8 @@ CHECK:      DW_AT_frame_base [DW_FORM_exprloc]        (<0x1> 56 )
 CHECK:      DW_AT_name [DW_FORM_strp]  ( .debug_str[0x0000005c] = "foo")
 CHECK:      DW_AT_prototyped [DW_FORM_flag_present]    (true)
 CHECK:      DW_AT_type [DW_FORM_ref4]  (cu + 0x002a => {0x000000a1})
-CHECK:      DW_TAG_formal_parameter [11]  
+CHECK:      DW_TAG_formal_parameter [11]
+CHECK:        DW_AT_location [DW_FORM_sec_offset]   (0x00000000)
 CHECK:        DW_AT_name [DW_FORM_strp]        ( .debug_str[0x00000060] = "arg")
 CHECK:        DW_AT_type [DW_FORM_ref4]        (cu + 0x002a => {0x000000a1})
 CHECK:      DW_TAG_inlined_subroutine [12]  
@@ -95,7 +96,8 @@ CHECK:      DW_AT_low_pc [DW_FORM_addr]       (0x0000000100000f90)
 CHECK:      DW_AT_high_pc [DW_FORM_data4]      (0x00000024)
 CHECK:      DW_AT_frame_base [DW_FORM_exprloc] (<0x1> 56 )
 CHECK:      DW_AT_name [DW_FORM_strp]  ( .debug_str[0x00000071] = "bar")
-CHECK:      DW_TAG_formal_parameter [16]  
+CHECK:      DW_TAG_formal_parameter [16]
+CHECK:        DW_AT_location [DW_FORM_sec_offset]   (0x00000025)
 CHECK:        DW_AT_name [DW_FORM_strp]        ( .debug_str[0x00000060] = "arg")
 CHECK:      DW_TAG_inlined_subroutine [17]  
 CHECK:        DW_AT_abstract_origin [DW_FORM_ref4]     (cu + 0x0044 => {0x0000015f} "inc")
@@ -106,6 +108,20 @@ CHECK:           [0x0000000100000f9f - 0x0000000100000fa7))
 CHECK:      NULL
 CHECK:    NULL
 
+
+CHECK: .debug_loc contents:
+CHECK-NEXT: 0x00000000: Beginning address offset: 0x0000000000000000
+CHECK-NEXT:                Ending address offset: 0x000000000000000c
+CHECK-NEXT:                 Location description: 55 93 04
+CHECK-NEXT: {{^$}}
+CHECK-NEXT: 0x00000025: Beginning address offset: 0x0000000000000000
+CHECK-NEXT:                Ending address offset: 0x000000000000000f
+CHECK-NEXT:                 Location description: 55 93 04 
+CHECK-NEXT: {{^$}}
+CHECK-NEXT:             Beginning address offset: 0x0000000000000019
+CHECK-NEXT:                Ending address offset: 0x000000000000001d
+CHECK-NEXT:                 Location description: 55 93 04 
+
 CHECK: .debug_aranges contents:
 CHECK-NEXT: Address Range Header: length = 0x0000002c, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00
 CHECK-NEXT: [0x0000000100000f40 - 0x0000000100000f4b)
index 8db5bc54c6676cf9fee78904cb86e792434d9238..b1c630f6b541833af178b0b6906da5de8094c88c 100644 (file)
@@ -71,6 +71,7 @@ CHECK:      DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 )
 CHECK:      DW_TAG_formal_parameter [9]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x00000086] = "arg")
 CHECK:        DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063)
+CHECK:        DW_AT_location [DW_FORM_data4]        (0x00000000)
 CHECK:      DW_TAG_inlined_subroutine [10]
 CHECK:        DW_AT_abstract_origin [DW_FORM_ref4]  (cu + 0x00a7 => {0x00000128} "inc")
 CHECK:        DW_AT_low_pc [DW_FORM_addr]   (0x0000000100000f63)
@@ -105,6 +106,7 @@ CHECK:      DW_AT_frame_base [DW_FORM_block1]       (<0x01> 56 )
 CHECK:      DW_TAG_formal_parameter [9]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x00000086] = "arg")
 CHECK:        DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063)
+CHECK:        DW_AT_location [DW_FORM_data4]        (0x00000025)
 CHECK:      DW_TAG_lexical_block [14] *
 CHECK:        DW_AT_low_pc [DW_FORM_addr]   (0x0000000100000f94)
 CHECK         DW_AT_high_pc [DW_FORM_addr]  (0x0000000100000fa7)
@@ -120,6 +122,19 @@ CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000008a] = "inc")
 CHECK:      DW_AT_type [DW_FORM_ref_addr]   (0x0000000000000063)
 CHECK:    NULL
 
+CHECK:.debug_loc contents:
+CHECK-NEXT: 0x00000000: Beginning address offset: 0x0000000000000000
+CHECK-NEXT:                Ending address offset: 0x000000000000000e
+CHECK-NEXT:                 Location description: 55 93 04 
+CHECK-NEXT: {{^$}}
+CHECK-NEXT: 0x00000025: Beginning address offset: 0x0000000000000000
+CHECK-NEXT:                Ending address offset: 0x000000000000000f
+CHECK-NEXT:                 Location description: 55 93 04 
+CHECK-NEXT: {{^$}}
+CHECK-NEXT:             Beginning address offset: 0x0000000000000019
+CHECK-NEXT:                Ending address offset: 0x000000000000001d
+CHECK-NEXT:                 Location description: 55 93 04 
+
 CHECK: .debug_aranges contents:
 CHECK-NEXT: Address Range Header: length = 0x0000002c, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00
 CHECK-NEXT: [0x0000000100000f40 - 0x0000000100000f4b)
index 295e6160fd322e8cab225143d92da1de8796f09f..31b7d118e4ec9c5c5580e8ee8af77bd22c48a9f4 100644 (file)
@@ -110,6 +110,11 @@ public:
     return RangeAttributes;
   }
 
+  const std::vector<std::pair<DIEInteger *, int64_t>> &
+  getLocationAttributes() const {
+    return LocationAttributes;
+  }
+
   /// \brief Compute the end offset for this unit. Must be
   /// called after the CU's DIEs have been cloned.
   /// \returns the next unit offset (which is also the current
@@ -133,6 +138,10 @@ public:
   /// patch up later.
   void noteRangeAttribute(const DIE &Die, DIEInteger *Attr);
 
+  /// \brief Keep track of a location attribute pointing to a location
+  /// list in the debug_loc section.
+  void noteLocationAttribute(DIEInteger *Attr, int64_t PcOffset);
+
 private:
   DWARFUnit &OrigUnit;
   unsigned ID;
@@ -166,6 +175,12 @@ private:
   std::vector<DIEInteger *> RangeAttributes;
   DIEInteger *UnitRangeAttribute;
   /// @}
+
+  /// \brief Location attributes that need to be transfered from th
+  /// original debug_loc section to the liked one. They are stored
+  /// along with the PC offset that is to be applied to their
+  /// function's address.
+  std::vector<std::pair<DIEInteger *, int64_t>> LocationAttributes;
 };
 
 uint64_t CompileUnit::computeNextUnitOffset() {
@@ -210,6 +225,10 @@ void CompileUnit::noteRangeAttribute(const DIE &Die, DIEInteger *Attr) {
     UnitRangeAttribute = Attr;
 }
 
+void CompileUnit::noteLocationAttribute(DIEInteger *Attr, int64_t PcOffset) {
+  LocationAttributes.emplace_back(Attr, PcOffset);
+}
+
 /// \brief A string table that doesn't need relocations.
 ///
 /// We are doing a final link, no need for a string table that
@@ -319,6 +338,7 @@ class DwarfStreamer {
   std::unique_ptr<raw_fd_ostream> OutFile;
 
   uint32_t RangesSectionSize;
+  uint32_t LocSectionSize;
 
 public:
   /// \brief Actually create the streamer and the ouptut file.
@@ -367,6 +387,11 @@ public:
   void emitUnitRangesEntries(CompileUnit &Unit, bool DoRangesSection);
 
   uint32_t getRangesSectionSize() const { return RangesSectionSize; }
+
+  /// \brief Emit the debug_loc contribution for \p Unit by copying
+  /// the entries from \p Dwarf and offseting them. Update the
+  /// location attributes to point to the new entries.
+  void emitLocationsForUnit(const CompileUnit &Unit, DWARFContext &Dwarf);
 };
 
 bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
@@ -433,6 +458,7 @@ bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
     return error("no asm printer for target " + TripleName, Context);
 
   RangesSectionSize = 0;
+  LocSectionSize = 0;
 
   return true;
 }
@@ -617,6 +643,57 @@ void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit,
   RangesSectionSize += 2 * AddressSize;
 }
 
+/// \brief Emit location lists for \p Unit and update attribtues to
+/// point to the new entries.
+void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
+                                         DWARFContext &Dwarf) {
+  const std::vector<std::pair<DIEInteger *, int64_t>> &Attributes =
+      Unit.getLocationAttributes();
+
+  if (Attributes.empty())
+    return;
+
+  MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection());
+
+  unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
+  const DWARFSection &InputSec = Dwarf.getLocSection();
+  DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize);
+  DWARFUnit &OrigUnit = Unit.getOrigUnit();
+  const auto *OrigUnitDie = OrigUnit.getCompileUnitDIE(false);
+  int64_t UnitPcOffset = 0;
+  uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
+      &OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
+  if (OrigLowPc != -1ULL)
+    UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc();
+
+  for (const auto &Attr : Attributes) {
+    uint32_t Offset = Attr.first->getValue();
+    Attr.first->setValue(LocSectionSize);
+    // This is the quantity to add to the old location address to get
+    // the correct address for the new one.
+    int64_t LocPcOffset = Attr.second + UnitPcOffset;
+    while (Data.isValidOffset(Offset)) {
+      uint64_t Low = Data.getUnsigned(&Offset, AddressSize);
+      uint64_t High = Data.getUnsigned(&Offset, AddressSize);
+      LocSectionSize += 2 * AddressSize;
+      if (Low == 0 && High == 0) {
+        Asm->OutStreamer.EmitIntValue(0, AddressSize);
+        Asm->OutStreamer.EmitIntValue(0, AddressSize);
+        break;
+      }
+      Asm->OutStreamer.EmitIntValue(Low + LocPcOffset, AddressSize);
+      Asm->OutStreamer.EmitIntValue(High + LocPcOffset, AddressSize);
+      uint64_t Length = Data.getU16(&Offset);
+      Asm->OutStreamer.EmitIntValue(Length, 2);
+      // Just copy the bytes over.
+      Asm->OutStreamer.EmitBytes(
+          StringRef(InputSec.Data.substr(Offset, Length)));
+      Offset += Length;
+      LocSectionSize += Length + 2;
+    }
+  }
+}
+
 /// \brief The core of the Dwarf linking logic.
 ///
 /// The link of the dwarf information from the object files will be
@@ -791,7 +868,8 @@ private:
   unsigned cloneScalarAttribute(DIE &Die,
                                 const DWARFDebugInfoEntryMinimal &InputDIE,
                                 CompileUnit &U, AttributeSpec AttrSpec,
-                                const DWARFFormValue &Val, unsigned AttrSize);
+                                const DWARFFormValue &Val, unsigned AttrSize,
+                                const AttributesInfo &Info);
 
   /// \brief Helper for cloneDIE.
   bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
@@ -1486,7 +1564,8 @@ unsigned DwarfLinker::cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec,
 /// \returns the size of the new attribute.
 unsigned DwarfLinker::cloneScalarAttribute(
     DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &Unit,
-    AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize) {
+    AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize,
+    const AttributesInfo &Info) {
   uint64_t Value;
   if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
       Die.getTag() == dwarf::DW_TAG_compile_unit) {
@@ -1508,6 +1587,13 @@ unsigned DwarfLinker::cloneScalarAttribute(
   DIEInteger *Attr = new (DIEAlloc) DIEInteger(Value);
   if (AttrSpec.Attr == dwarf::DW_AT_ranges)
     Unit.noteRangeAttribute(Die, Attr);
+  // A more generic way to check for location attributes would be
+  // nice, but it's very unlikely that any other attribute needs a
+  // location list.
+  else if (AttrSpec.Attr == dwarf::DW_AT_location ||
+           AttrSpec.Attr == dwarf::DW_AT_frame_base)
+    Unit.noteLocationAttribute(Attr, Info.PCOffset);
+
   Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form),
                Attr);
   return AttrSize;
@@ -1552,7 +1638,8 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die,
   case dwarf::DW_FORM_sec_offset:
   case dwarf::DW_FORM_flag:
   case dwarf::DW_FORM_flag_present:
-    return cloneScalarAttribute(Die, InputDIE, Unit, AttrSpec, Val, AttrSize);
+    return cloneScalarAttribute(Die, InputDIE, Unit, AttrSpec, Val, AttrSize,
+                                Info);
   default:
     reportWarning("Unsupported attribute form in cloneAttribute. Dropping.", &U,
                   &InputDIE);
@@ -1843,6 +1930,7 @@ bool DwarfLinker::link(const DebugMap &Map) {
         if (!OutputDIE || Options.NoOutput)
           continue;
         patchRangesForUnit(CurrentUnit, DwarfContext);
+        Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext);
       }
 
     // Emit all the compile unit's debug information.