From 23e20e95e9418c346cbe19b4733f22698c6d9e85 Mon Sep 17 00:00:00 2001 From: Frederic Riss Date: Sat, 7 Mar 2015 01:25:09 +0000 Subject: [PATCH] [dsymutil] Apply relocations to DIE data before cloning. Doing this gets function's low_pc and global variable's locations right in the output debug info. It also could get right other attributes that need to be relocated (in linker terms), but I don't know of any other than the address attributes. This doesn't fixup low_pc attributes in compile_unit, lexical_block or inlined subroutine, nor does it get right high_pc attributes for function. This will come in a subsequent commit. llvm-svn: 231544 --- .../test/tools/dsymutil/X86/basic-linking-x86.test | 14 ++++- .../tools/dsymutil/X86/basic-lto-linking-x86.test | 6 ++ llvm/tools/dsymutil/DwarfLinker.cpp | 69 +++++++++++++++++++++- 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/llvm/test/tools/dsymutil/X86/basic-linking-x86.test b/llvm/test/tools/dsymutil/X86/basic-linking-x86.test index e220ea6..de919f9 100644 --- a/llvm/test/tools/dsymutil/X86/basic-linking-x86.test +++ b/llvm/test/tools/dsymutil/X86/basic-linking-x86.test @@ -3,8 +3,8 @@ RUN: llvm-dsymutil -oso-prepend-path=%p/.. %t1 RUN: llvm-dwarfdump %t1.dwarf | FileCheck %s RUN: llvm-dsymutil -o %t2 -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 RUN: llvm-dwarfdump %t2 | FileCheck %s -RUN: llvm-dsymutil -o - -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 | llvm-dwarfdump - | FileCheck %s -RUN: llvm-dsymutil -o - -oso-prepend-path=%p/.. %p/../Inputs/basic-archive.macho.x86_64 | llvm-dwarfdump - | FileCheck %s +RUN: llvm-dsymutil -o - -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 | llvm-dwarfdump - | FileCheck %s --check-prefix=CHECK --check-prefix=BASIC +RUN: llvm-dsymutil -o - -oso-prepend-path=%p/.. %p/../Inputs/basic-archive.macho.x86_64 | llvm-dwarfdump - | FileCheck %s --check-prefix=CHECK --check-prefix=ARCHIVE CHECK: file format Mach-O 64-bit x86-64 @@ -24,6 +24,7 @@ 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_low_pc [DW_FORM_addr] (0x0000000100000ea0) 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") @@ -64,12 +65,16 @@ 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}) +BASIC: DW_AT_location [DW_FORM_block1] (<0x09> 03 08 10 00 00 01 00 00 00 ) +ARCHIVE: DW_AT_location [DW_FORM_block1] (<0x09> 03 04 10 00 00 01 00 00 00 ) 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_AT_location [DW_FORM_block1] (<0x09> 03 00 10 00 00 01 00 00 00 ) 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_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [3] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg") @@ -79,6 +84,7 @@ 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_low_pc [DW_FORM_addr] (0x0000000100000f20) CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: NULL @@ -91,6 +97,8 @@ 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}) +BASIC: DW_AT_location [DW_FORM_block1] (<0x09> 03 04 10 00 00 01 00 00 00 ) +ARCHIVE: DW_AT_location [DW_FORM_block1] (<0x09> 03 08 10 00 00 01 00 00 00 ) CHECK: DW_TAG_volatile_type [10] CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0041 => {0x00000167}) CHECK: DW_TAG_base_type [4] @@ -98,6 +106,7 @@ 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_low_pc [DW_FORM_addr] (0x0000000100000f40) 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") @@ -107,6 +116,7 @@ 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_low_pc [DW_FORM_addr] (0x0000000100000f90) CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: NULL diff --git a/llvm/test/tools/dsymutil/X86/basic-lto-linking-x86.test b/llvm/test/tools/dsymutil/X86/basic-lto-linking-x86.test index 07b067c..fa128de 100644 --- a/llvm/test/tools/dsymutil/X86/basic-lto-linking-x86.test +++ b/llvm/test/tools/dsymutil/X86/basic-lto-linking-x86.test @@ -18,6 +18,7 @@ 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_low_pc [DW_FORM_addr] (0x0000000100000f40) 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") @@ -53,12 +54,15 @@ 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_AT_location [DW_FORM_block1] (<0x09> 03 08 10 00 00 01 00 00 00 ) 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_AT_location [DW_FORM_block1] (<0x09> 03 00 10 00 00 01 00 00 00 ) 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_frame_base [DW_FORM_block1] (<0x01> 56 ) CHECK: DW_TAG_formal_parameter [9] CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg") @@ -82,11 +86,13 @@ 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_AT_location [DW_FORM_block1] (<0x09> 03 04 10 00 00 01 00 00 00 ) 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_low_pc [DW_FORM_addr] (0x0000000100000f90) 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") diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index f71d83b..4d84b98 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -463,7 +463,7 @@ private: /// consider. As we walk the DIEs in acsending file offset and as /// ValidRelocs is sorted by file offset, keeping this index /// uptodate is all we have to do to have a cheap lookup during the - /// root DIE selection. + /// root DIE selection and during DIE cloning. unsigned NextValidReloc; bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj, @@ -562,6 +562,10 @@ private: const DWARFUnit &U, AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize); + /// \brief Helper for cloneDIE. + bool applyValidRelocs(MutableArrayRef Data, uint32_t BaseOffset, + bool isLittleEndian); + /// \brief Assign an abbreviation number to \p Abbrev void AssignAbbrev(DIEAbbrev &Abbrev); @@ -1256,6 +1260,50 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die, return 0; } +/// \brief Apply the valid relocations found by findValidRelocs() to +/// the buffer \p Data, taking into account that Data is at \p BaseOffset +/// in the debug_info section. +/// +/// Like for findValidRelocs(), this function must be called with +/// monotonic \p BaseOffset values. +/// +/// \returns wether any reloc has been applied. +bool DwarfLinker::applyValidRelocs(MutableArrayRef Data, + uint32_t BaseOffset, bool isLittleEndian) { + assert(NextValidReloc == 0 || + BaseOffset > ValidRelocs[NextValidReloc - 1].Offset && + "BaseOffset should only be increasing."); + if (NextValidReloc >= ValidRelocs.size()) + return false; + + // Skip relocs that haven't been applied. + while (NextValidReloc < ValidRelocs.size() && + ValidRelocs[NextValidReloc].Offset < BaseOffset) + ++NextValidReloc; + + bool Applied = false; + uint64_t EndOffset = BaseOffset + Data.size(); + while (NextValidReloc < ValidRelocs.size() && + ValidRelocs[NextValidReloc].Offset >= BaseOffset && + ValidRelocs[NextValidReloc].Offset < EndOffset) { + const auto &ValidReloc = ValidRelocs[NextValidReloc++]; + assert(ValidReloc.Offset - BaseOffset < Data.size()); + assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size()); + char Buf[8]; + uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress; + Value += ValidReloc.Addend; + for (unsigned i = 0; i != ValidReloc.Size; ++i) { + unsigned Index = isLittleEndian ? i : (ValidReloc.Size - i - 1); + Buf[i] = uint8_t(Value >> (Index * 8)); + } + assert(ValidReloc.Size <= sizeof(Buf)); + memcpy(&Data[ValidReloc.Offset - BaseOffset], Buf, ValidReloc.Size); + Applied = true; + } + + return Applied; +} + /// \brief Recursively clone \p InputDIE's subtrees that have been /// selected to appear in the linked output. /// @@ -1284,6 +1332,20 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, // Extract and clone every attribute. DataExtractor Data = U.getDebugInfoExtractor(); + uint32_t NextOffset = U.getDIEAtIndex(Idx + 1)->getOffset(); + + // 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 + // doing the copy unconditionally, and it makes the code simpler. + 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()); + + // Reset the Offset to 0 as we will be working on the local copy of + // the data. + Offset = 0; + const auto *Abbrev = InputDIE.getAbbreviationDeclarationPtr(); Offset += getULEB128Size(Abbrev->getCode()); @@ -1386,6 +1448,11 @@ bool DwarfLinker::link(const DebugMap &Map) { lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getCompileUnitDIE(), *Obj, CurrentUnit, 0); + // The calls to applyValidRelocs inside cloneDIE will walk the + // reloc array again (in the same way findValidRelocsInDebugInfo() + // did). We need to reset the NextValidReloc index to the beginning. + NextValidReloc = 0; + // Construct the output DIE tree by cloning the DIEs we chose to // keep above. If there are no valid relocs, then there's nothing // to clone/emit. -- 2.7.4