From fe78287585df806d7024804e4918428ae2642159 Mon Sep 17 00:00:00 2001 From: Frederic Riss Date: Fri, 6 Mar 2015 23:22:53 +0000 Subject: [PATCH] [dsymutil] Support cloning DIE reference attributes. Reference attributes are mainly handled by just creating DIEEntry attributes for them. There is a special case for DW_FORM_ref_addr attributes though, because the DIEEntry code needs a DwarfDebug code to emit them (and we don't have one as we do no CodeGen). In that case, just use DIEInteger attributes with the right form. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231531 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../tools/dsymutil/X86/basic-linking-x86.test | 16 +++ .../dsymutil/X86/basic-lto-linking-x86.test | 19 ++++ tools/dsymutil/DwarfLinker.cpp | 106 ++++++++++++++++-- 3 files changed, 131 insertions(+), 10 deletions(-) diff --git a/test/tools/dsymutil/X86/basic-linking-x86.test b/test/tools/dsymutil/X86/basic-linking-x86.test index 6a9352fb6b6..e220ea64054 100644 --- a/test/tools/dsymutil/X86/basic-linking-x86.test +++ b/test/tools/dsymutil/X86/basic-linking-x86.test @@ -21,17 +21,20 @@ CHECK: DW_TAG_subprogram [2] * CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000051] = "main") CHECK: DW_AT_decl_line [DW_FORM_data1] (23) CHECK: DW_AT_prototyped [DW_FORM_flag] (0x01) +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_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000056] = "argc") CHECK: DW_AT_decl_line [DW_FORM_data1] (23) +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0063 => {0x00000063}) CHECK: DW_AT_location [DW_FORM_block1] (<0x02> 91 78 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000005b] = "argv") CHECK: DW_AT_decl_file [DW_FORM_data1] (0x01) CHECK: DW_AT_decl_line [DW_FORM_data1] (23) +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x006a => {0x0000006a}) CHECK: DW_AT_location [DW_FORM_block1] (<0x02> 91 70 ) CHECK: NULL CHECK: DW_TAG_base_type [4] @@ -39,8 +42,11 @@ CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000060] = "int") CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed) CHECK: DW_AT_byte_size [DW_FORM_data1] (0x04) CHECK: DW_TAG_pointer_type [5] +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x006f => {0x0000006f}) CHECK: DW_TAG_pointer_type [5] +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0074 => {0x00000074}) CHECK: DW_TAG_const_type [6] +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0079 => {0x00000079}) CHECK: DW_TAG_base_type [4] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000064] = "char") CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed_char) @@ -57,17 +63,22 @@ CHECK: DW_TAG_base_type [4] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000060] = "int") CHECK: DW_TAG_variable [7] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000072] = "private_int") +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0026 => {0x000000a7}) CHECK: DW_TAG_variable [7] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000007e] = "baz") +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0026 => {0x000000a7}) 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_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg") +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0026 => {0x000000a7}) CHECK: DW_AT_location [DW_FORM_block1] (<0x02> 91 7c ) CHECK: NULL 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_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: NULL @@ -79,18 +90,23 @@ CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008e] = "basic3.c") CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000049] = "/Inputs") CHECK: DW_TAG_variable [9] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000097] = "val") +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x003c => {0x00000162}) CHECK: DW_TAG_volatile_type [10] +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0041 => {0x00000167}) CHECK: DW_TAG_base_type [4] CHACK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000060] = "int") 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_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg") +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0041 => {0x00000167}) CHECK: DW_AT_location [DW_FORM_block1] (<0x02> 91 78 ) CHECK: NULL 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_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 80da767870e..07b067cef5e 100644 --- a/test/tools/dsymutil/X86/basic-lto-linking-x86.test +++ b/test/tools/dsymutil/X86/basic-lto-linking-x86.test @@ -15,14 +15,17 @@ CHECK: DW_TAG_subprogram [2] * CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000051] = "main") CHECK: DW_AT_decl_line [DW_FORM_data1] (23) CHECK: DW_AT_prototyped [DW_FORM_flag] (0x01) +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_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000056] = "argc") +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0063 => {0x00000063}) CHECK: DW_AT_location [DW_FORM_block1] (<0x03> 55 93 04 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000005b] = "argv") +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x006a => {0x0000006a}) CHECK: DW_AT_location [DW_FORM_block1] (<0x01> 54 ) CHECK: NULL CHECK: DW_TAG_base_type [4] @@ -30,8 +33,11 @@ CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000060] = "int") CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed) CHECK: DW_AT_byte_size [DW_FORM_data1] (0x04) CHECK: DW_TAG_pointer_type [5] +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x006f => {0x0000006f}) CHECK: DW_TAG_pointer_type [5] +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0074 => {0x00000074}) CHECK: DW_TAG_const_type [6] +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0079 => {0x00000079}) CHECK: DW_TAG_base_type [4] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000064] = "char") CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed_char) @@ -46,18 +52,24 @@ CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000069] = "basic2.c") CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000049] = "/Inputs") CHECK: DW_TAG_variable [7] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000072] = "private_int") +CHECK: DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063) CHECK: DW_TAG_variable [7] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000007e] = "baz") +CHECK: DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063) 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_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_call_line [DW_FORM_data1] (20) CHECK: NULL CHECK: DW_TAG_subprogram [11] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008a] = "inc") +CHECK: DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063) CHECK: DW_AT_inline [DW_FORM_data1] (DW_INL_inlined) CHECK: NULL @@ -69,16 +81,23 @@ CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008e] = "basic3.c") CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000049] = "/Inputs") CHECK: DW_TAG_variable [12] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000097] = "val") +CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x003c => {0x00000176}) CHECK: DW_TAG_volatile_type [13] +CHECK: DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063) 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_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_TAG_inlined_subroutine [15] +CHECK: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x009a => {0x000001d4} "inc") + CHECK: NULL CHECK: NULL CHECK: DW_TAG_subprogram [11] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008a] = "inc") +CHECK: DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063) CHECK: NULL diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp index 40d3fb0b546..f71d83b31d4 100644 --- a/tools/dsymutil/DwarfLinker.cpp +++ b/tools/dsymutil/DwarfLinker.cpp @@ -55,6 +55,7 @@ public: /// \brief Information gathered about a DIE in the object file. struct DIEInfo { uint64_t Address; ///< Linked address of 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? bool InDebugMap; ///< Was this DIE's entity found in the map? @@ -89,6 +90,14 @@ public: /// debug_info section size). uint64_t computeNextUnitOffset(); + /// \brief Keep track of a forward reference to DIE \p Die by + /// \p Attr. The attribute should be fixed up later to point to the + /// absolute offset of \p Die in the debug_info section. + void noteForwardReference(DIE *Die, DIEInteger *Attr); + + /// \brief Apply all fixups recored by noteForwardReference(). + void fixupForwardReferences(); + private: DWARFUnit &OrigUnit; std::vector Info; ///< DIE info indexed by DIE index. @@ -96,6 +105,14 @@ private: uint64_t StartOffset; uint64_t NextUnitOffset; + + /// \brief A list of attributes to fixup with the absolute offset of + /// a DIE in the debug_info section. + /// + /// The offsets for the attributes in this array couldn't be set while + /// cloning because for forward refences the target DIE's offset isn't + /// known you emit the reference attribute. + std::vector> ForwardDIEReferences; }; uint64_t CompileUnit::computeNextUnitOffset() { @@ -108,6 +125,17 @@ uint64_t CompileUnit::computeNextUnitOffset() { return NextUnitOffset; } +/// \brief Keep track of a forward reference to \p Die. +void CompileUnit::noteForwardReference(DIE *Die, DIEInteger *Attr) { + ForwardDIEReferences.emplace_back(Die, Attr); +} + +/// \brief Apply all fixups recorded by noteForwardReference(). +void CompileUnit::fixupForwardReferences() { + for (const auto &Ref : ForwardDIEReferences) + Ref.second->setValue(Ref.first->getOffset() + getStartOffset()); +} + /// \brief A string table that doesn't need relocations. /// /// We are doing a final link, no need for a string table that @@ -518,8 +546,11 @@ private: const DWARFFormValue &Val, const DWARFUnit &U); /// \brief Helper for cloneDIE. - unsigned cloneDieReferenceAttribute(DIE &Die, AttributeSpec AttrSpec, - unsigned AttrSize); + unsigned + cloneDieReferenceAttribute(DIE &Die, + const DWARFDebugInfoEntryMinimal &InputDIE, + AttributeSpec AttrSpec, unsigned AttrSize, + const DWARFFormValue &Val, const DWARFUnit &U); /// \brief Helper for cloneDIE. unsigned cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec, @@ -1059,12 +1090,60 @@ unsigned DwarfLinker::cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec, /// \brief Clone an attribute referencing another DIE and add /// it to \p Die. /// \returns the size of the new attribute. -unsigned DwarfLinker::cloneDieReferenceAttribute(DIE &Die, - AttributeSpec AttrSpec, - unsigned AttrSize) { - // FIXME: Handle DIE references. +unsigned DwarfLinker::cloneDieReferenceAttribute( + DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, + AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val, + const DWARFUnit &U) { + uint32_t Ref = *Val.getAsReference(&U); + DIE *NewRefDie = nullptr; + CompileUnit *RefUnit = nullptr; + const DWARFDebugInfoEntryMinimal *RefDie = nullptr; + + if (!(RefUnit = getUnitForOffset(Ref)) || + !(RefDie = RefUnit->getOrigUnit().getDIEForOffset(Ref))) { + const char *AttributeString = dwarf::AttributeString(AttrSpec.Attr); + if (!AttributeString) + AttributeString = "DW_AT_???"; + reportWarning(Twine("Missing DIE for ref in attribute ") + AttributeString + + ". Dropping.", + &U, &InputDIE); + return 0; + } + + unsigned Idx = RefUnit->getOrigUnit().getDIEIndex(RefDie); + CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(Idx); + if (!RefInfo.Clone) { + assert(Ref > InputDIE.getOffset()); + // We haven't cloned this DIE yet. Just create an empty one and + // store it. It'll get really cloned when we process it. + RefInfo.Clone = new DIE(dwarf::Tag(RefDie->getTag())); + } + NewRefDie = RefInfo.Clone; + + if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) { + // We cannot currently rely on a DIEEntry to emit ref_addr + // references, because the implementation calls back to DwarfDebug + // to find the unit offset. (We don't have a DwarfDebug) + // FIXME: we should be able to design DIEEntry reliance on + // DwarfDebug away. + DIEInteger *Attr; + if (Ref < InputDIE.getOffset()) { + // We must have already cloned that DIE. + uint32_t NewRefOffset = + RefUnit->getStartOffset() + NewRefDie->getOffset(); + Attr = new (DIEAlloc) DIEInteger(NewRefOffset); + } else { + // A forward reference. Note and fixup later. + Attr = new (DIEAlloc) DIEInteger(0xBADDEF); + RefUnit->noteForwardReference(NewRefDie, Attr); + } + Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_ref_addr, + Attr); + return AttrSize; + } + Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form), - new (DIEAlloc) DIEInteger(0)); + new (DIEAlloc) DIEEntry(*NewRefDie)); return AttrSize; } @@ -1150,7 +1229,8 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die, case dwarf::DW_FORM_ref2: case dwarf::DW_FORM_ref4: case dwarf::DW_FORM_ref8: - return cloneDieReferenceAttribute(Die, AttrSpec, AttrSize); + return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val, + U); case dwarf::DW_FORM_block: case dwarf::DW_FORM_block1: case dwarf::DW_FORM_block2: @@ -1187,14 +1267,19 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &Unit, uint32_t OutOffset) { DWARFUnit &U = Unit.getOrigUnit(); unsigned Idx = U.getDIEIndex(&InputDIE); + CompileUnit::DIEInfo &Info = Unit.getInfo(Idx); // Should the DIE appear in the output? if (!Unit.getInfo(Idx).Keep) return nullptr; uint32_t Offset = InputDIE.getOffset(); - - DIE *Die = new DIE(static_cast(InputDIE.getTag())); + // The DIE might have been already created by a forward reference + // (see cloneDieReferenceAttribute()). + DIE *Die = Info.Clone; + if (!Die) + Die = Info.Clone = new DIE(dwarf::Tag(InputDIE.getTag())); + assert(Die->getTag() == InputDIE.getTag()); Die->setOffset(OutOffset); // Extract and clone every attribute. @@ -1317,6 +1402,7 @@ bool DwarfLinker::link(const DebugMap &Map) { // Emit all the compile unit's debug information. if (!ValidRelocs.empty() && !Options.NoOutput) for (auto &CurrentUnit : Units) { + CurrentUnit.fixupForwardReferences(); Streamer->emitCompileUnitHeader(CurrentUnit); if (!CurrentUnit.getOutputUnitDIE()) continue; -- 2.34.1