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]
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")
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)
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)
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)
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)
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
/// 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;
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() {
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
std::unique_ptr<raw_fd_ostream> OutFile;
uint32_t RangesSectionSize;
+ uint32_t LocSectionSize;
public:
/// \brief Actually create the streamer and the ouptut file.
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) {
return error("no asm printer for target " + TripleName, Context);
RangesSectionSize = 0;
+ LocSectionSize = 0;
return true;
}
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
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,
/// \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) {
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;
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);
if (!OutputDIE || Options.NoOutput)
continue;
patchRangesForUnit(CurrentUnit, DwarfContext);
+ Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext);
}
// Emit all the compile unit's debug information.