forked from OSchip/llvm-project
[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:
parent
d4dc7d5739
commit
23e20e95e9
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue