[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
This commit is contained in:
Frederic Riss 2015-03-07 01:25:09 +00:00
parent d4dc7d5739
commit 23e20e95e9
3 changed files with 86 additions and 3 deletions

View File

@ -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

View File

@ -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")

View File

@ -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<char> 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<char> 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.