[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
This commit is contained in:
Frederic Riss 2015-03-11 18:45:52 +00:00
parent ca75f1df99
commit 89393bbba6
3 changed files with 85 additions and 14 deletions

View File

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

View File

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

View File

@ -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<dwarf::Attribute>(AttrSpec.Attr),
static_cast<dwarf::Form>(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<char> 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<DIE>(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();
}