From 89393bbba69e0cb600c4fe67ffccd45b5de4e862 Mon Sep 17 00:00:00 2001 From: Frederic Riss Date: Wed, 11 Mar 2015 18:45:52 +0000 Subject: [PATCH] [dsymutil] Correctly clone address attributes. DW_AT_low_pc on functions is taken care of by the relocation processing, but DW_AT_high_pc and DW_AT_low_pc on other lexical scopes need special handling. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231955 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../tools/dsymutil/X86/basic-linking-x86.test | 5 ++ .../dsymutil/X86/basic-lto-linking-x86.test | 7 ++ tools/dsymutil/DwarfLinker.cpp | 87 ++++++++++++++++--- 3 files changed, 85 insertions(+), 14 deletions(-) diff --git a/test/tools/dsymutil/X86/basic-linking-x86.test b/test/tools/dsymutil/X86/basic-linking-x86.test index de919f9bc00..4b47263b7b1 100644 --- a/test/tools/dsymutil/X86/basic-linking-x86.test +++ b/test/tools/dsymutil/X86/basic-linking-x86.test @@ -25,6 +25,7 @@ CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0063 => {0x00000063}) CHECK: DW_AT_external [DW_FORM_flag] (0x01) CHECK: DW_AT_accessibility [DW_FORM_data1] (DW_ACCESS_public) CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000100000ea0) +CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000100000ec4) CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000056] = "argc") @@ -75,6 +76,7 @@ CHECK: DW_TAG_subprogram [2] * CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000082] = "foo") CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0026 => {0x000000a7}) CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000100000ed0) +CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000100000f19) CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg") @@ -85,6 +87,7 @@ CHECK: DW_TAG_subprogram [8] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008a] = "inc") CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0026 => {0x000000a7}) CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000100000f20) +CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000100000f37) CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: NULL @@ -107,6 +110,7 @@ CHECK: DW_TAG_subprogram [2] * CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000009b] = "bar") CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0041 => {0x00000167}) CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000100000f40) +CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000100000f84) CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg") @@ -117,6 +121,7 @@ CHECK: DW_TAG_subprogram [8] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008a] = "inc") CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0041 => {0x00000167}) CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000100000f90) +CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000100000fa9) CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: NULL diff --git a/test/tools/dsymutil/X86/basic-lto-linking-x86.test b/test/tools/dsymutil/X86/basic-lto-linking-x86.test index fa128de767f..0fafb238ae3 100644 --- a/test/tools/dsymutil/X86/basic-lto-linking-x86.test +++ b/test/tools/dsymutil/X86/basic-lto-linking-x86.test @@ -19,6 +19,7 @@ CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0063 => {0x00000063}) CHECK: DW_AT_external [DW_FORM_flag] (0x01) CHECK: DW_AT_accessibility [DW_FORM_data1] (DW_ACCESS_public) CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000100000f40) +CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000100000f4b) CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000056] = "argc") @@ -63,12 +64,15 @@ CHECK: DW_TAG_subprogram [8] * CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000082] = "foo") CHECK: DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063) CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000100000f50) +CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000100000f89) 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_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_AT_high_pc [DW_FORM_addr] (0x0000000100000f72) CHECK: DW_AT_call_line [DW_FORM_data1] (20) CHECK: NULL CHECK: DW_TAG_subprogram [11] @@ -93,11 +97,14 @@ CHECK: DW_TAG_subprogram [8] * CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000009b] = "bar") CHECK: DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063) CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000100000f90) +CHECK: DW_AT_high_pc [DW_FORM_addr] (0x0000000100000fb4) 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_TAG_lexical_block [14] * +CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000100000f94) +CHECK DW_AT_high_pc [DW_FORM_addr] (0x0000000100000fa7) CHECK: DW_TAG_inlined_subroutine [15] CHECK: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x009a => {0x000001d4} "inc") diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp index 264e72aa4d4..74d603486ab 100644 --- a/tools/dsymutil/DwarfLinker.cpp +++ b/tools/dsymutil/DwarfLinker.cpp @@ -54,7 +54,7 @@ class CompileUnit { public: /// \brief Information gathered about a DIE in the object file. struct DIEInfo { - uint64_t Address; ///< Linked address of the described entity. + int64_t AddrAdjust; ///< Address offset to apply to the described entity. DIE *Clone; ///< Cloned version of that DIE. uint32_t ParentIdx; ///< The index of this DIE's parent. bool Keep; ///< Is the DIE part of the linked output? @@ -529,17 +529,29 @@ private: /// /// \param OutOffset is the offset the cloned DIE in the output /// compile unit. + /// \param PCOffset (while cloning a function scope) is the offset + /// applied to the entry point of the function to get the linked address. /// /// \returns the root of the cloned tree. DIE *cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U, - uint32_t OutOffset); + int64_t PCOffset, uint32_t OutOffset); typedef DWARFAbbreviationDeclaration::AttributeSpec AttributeSpec; + /// \brief Information gathered and exchanged between the various + /// clone*Attributes helpers about the attributes of a particular DIE. + struct AttributesInfo { + uint64_t OrigHighPc; ///< Value of AT_high_pc in the input DIE + int64_t PCOffset; ///< Offset to apply to PC addresses inside a function. + + AttributesInfo() : OrigHighPc(0), PCOffset(0) {} + }; + /// \brief Helper for cloneDIE. unsigned cloneAttribute(DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U, const DWARFFormValue &Val, - const AttributeSpec AttrSpec, unsigned AttrSize); + const AttributeSpec AttrSpec, unsigned AttrSize, + AttributesInfo &AttrInfo); /// \brief Helper for cloneDIE. unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec, @@ -556,6 +568,11 @@ private: unsigned cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize); + /// \brief Helper for cloneDIE. + unsigned cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec, + const DWARFFormValue &Val, + const CompileUnit &Unit, AttributesInfo &Info); + /// \brief Helper for cloneDIE. unsigned cloneScalarAttribute(DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, @@ -831,8 +848,9 @@ bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset, ValidReloc.Mapping->getValue().ObjectAddress, ValidReloc.Mapping->getValue().BinaryAddress); - Info.Address = - ValidReloc.Mapping->getValue().BinaryAddress + ValidReloc.Addend; + Info.AddrAdjust = int64_t(ValidReloc.Mapping->getValue().BinaryAddress) + + ValidReloc.Addend - + ValidReloc.Mapping->getValue().ObjectAddress; Info.InDebugMap = true; return true; } @@ -1189,6 +1207,30 @@ unsigned DwarfLinker::cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec, return AttrSize; } +/// \brief Clone an address attribute and add it to \p Die. +/// \returns the size of the new attribute. +unsigned DwarfLinker::cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec, + const DWARFFormValue &Val, + const CompileUnit &Unit, + AttributesInfo &Info) { + int64_t Addr = *Val.getAsAddress(&Unit.getOrigUnit()); + if (AttrSpec.Attr == dwarf::DW_AT_low_pc) { + if (Die.getTag() == dwarf::DW_TAG_inlined_subroutine || + Die.getTag() == dwarf::DW_TAG_lexical_block) + Addr += Info.PCOffset; + } else if (AttrSpec.Attr == dwarf::DW_AT_high_pc) { + // If we have a high_pc recorded for the input DIE, use + // it. Otherwise (when no relocations where applied) just use the + // one we just decoded. + Addr = (Info.OrigHighPc ? Info.OrigHighPc : Addr) + Info.PCOffset; + } + + Die.addValue(static_cast(AttrSpec.Attr), + static_cast(AttrSpec.Form), + new (DIEAlloc) DIEInteger(Addr)); + return Unit.getOrigUnit().getAddressByteSize(); +} + /// \brief Clone a scalar attribute and add it to \p Die. /// \returns the size of the new attribute. unsigned DwarfLinker::cloneScalarAttribute( @@ -1199,8 +1241,6 @@ unsigned DwarfLinker::cloneScalarAttribute( Value = *Val.getAsSectionOffset(); else if (AttrSpec.Form == dwarf::DW_FORM_sdata) Value = *Val.getAsSignedConstant(); - else if (AttrSpec.Form == dwarf::DW_FORM_addr) - Value = *Val.getAsAddress(&U); else if (auto OptionalValue = Val.getAsUnsignedConstant()) Value = *OptionalValue; else { @@ -1221,7 +1261,7 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die, CompileUnit &Unit, const DWARFFormValue &Val, const AttributeSpec AttrSpec, - unsigned AttrSize) { + unsigned AttrSize, AttributesInfo &Info) { const DWARFUnit &U = Unit.getOrigUnit(); switch (AttrSpec.Form) { @@ -1242,6 +1282,7 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die, case dwarf::DW_FORM_exprloc: return cloneBlockAttribute(Die, AttrSpec, Val, AttrSize); case dwarf::DW_FORM_addr: + return cloneAddressAttribute(Die, AttrSpec, Val, Unit, Info); case dwarf::DW_FORM_data1: case dwarf::DW_FORM_data2: case dwarf::DW_FORM_data4: @@ -1312,7 +1353,8 @@ bool DwarfLinker::applyValidRelocs(MutableArrayRef Data, /// /// \returns the cloned DIE object or null if nothing was selected. DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, - CompileUnit &Unit, uint32_t OutOffset) { + CompileUnit &Unit, int64_t PCOffset, + uint32_t OutOffset) { DWARFUnit &U = Unit.getOrigUnit(); unsigned Idx = U.getDIEIndex(&InputDIE); CompileUnit::DIEInfo &Info = Unit.getInfo(Idx); @@ -1333,6 +1375,7 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, // Extract and clone every attribute. DataExtractor Data = U.getDebugInfoExtractor(); uint32_t NextOffset = U.getDIEAtIndex(Idx + 1)->getOffset(); + AttributesInfo AttrInfo; // We could copy the data only if we need to aply a relocation to // it. After testing, it seems there is no performance downside to @@ -1340,7 +1383,17 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset)); Data = DataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize()); // Modify the copy with relocated addresses. - applyValidRelocs(DIECopy, Offset, Data.isLittleEndian()); + if (applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) { + // If we applied relocations, we store the value of high_pc that was + // potentially stored in the input DIE. If high_pc is an address + // (Dwarf version == 2), then it might have been relocated to a + // totally unrelated value (because the end address in the object + // file might be start address of another function which got moved + // independantly by the linker). The computation of the actual + // high_pc value is done in cloneAddressAttribute(). + AttrInfo.OrigHighPc = + InputDIE.getAttributeValueAsAddress(&U, dwarf::DW_AT_high_pc, 0); + } // Reset the Offset to 0 as we will be working on the local copy of // the data. @@ -1349,13 +1402,19 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, const auto *Abbrev = InputDIE.getAbbreviationDeclarationPtr(); Offset += getULEB128Size(Abbrev->getCode()); + // We are entering a subprogram. Get and propagate the PCOffset. + if (Die->getTag() == dwarf::DW_TAG_subprogram) + PCOffset = Info.AddrAdjust; + AttrInfo.PCOffset = PCOffset; + for (const auto &AttrSpec : Abbrev->attributes()) { DWARFFormValue Val(AttrSpec.Form); uint32_t AttrSize = Offset; Val.extractValue(Data, &Offset, &U); AttrSize = Offset - AttrSize; - OutOffset += cloneAttribute(*Die, InputDIE, Unit, Val, AttrSpec, AttrSize); + OutOffset += + cloneAttribute(*Die, InputDIE, Unit, Val, AttrSpec, AttrSize, AttrInfo); } DIEAbbrev &NewAbbrev = Die->getAbbrev(); @@ -1379,7 +1438,7 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, // Recursively clone children. for (auto *Child = InputDIE.getFirstChild(); Child && !Child->isNULL(); Child = Child->getSibling()) { - if (DIE *Clone = cloneDIE(*Child, Unit, OutOffset)) { + if (DIE *Clone = cloneDIE(*Child, Unit, PCOffset, OutOffset)) { Die->addChild(std::unique_ptr(Clone)); OutOffset = Clone->getOffset() + Clone->getSize(); } @@ -1460,8 +1519,8 @@ bool DwarfLinker::link(const DebugMap &Map) { for (auto &CurrentUnit : Units) { const auto *InputDIE = CurrentUnit.getOrigUnit().getCompileUnitDIE(); CurrentUnit.setStartOffset(OutputDebugInfoSize); - DIE *OutputDIE = - cloneDIE(*InputDIE, CurrentUnit, 11 /* Unit Header size */); + DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */, + 11 /* Unit Header size */); CurrentUnit.setOutputUnitDIE(OutputDIE); OutputDebugInfoSize = CurrentUnit.computeNextUnitOffset(); }