diff options
Diffstat (limited to 'llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp')
| -rw-r--r-- | llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp | 655 |
1 files changed, 655 insertions, 0 deletions
diff --git a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp new file mode 100644 index 000000000000..81fc57f7cabb --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp @@ -0,0 +1,655 @@ +//=== DIEAttributeCloner.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DIEAttributeCloner.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" + +namespace llvm { +namespace dwarflinker_parallel { + +void DIEAttributeCloner::clone() { + // Extract and clone every attribute. + DWARFDataExtractor Data = InUnit.getOrigUnit().getDebugInfoExtractor(); + + uint64_t Offset = InputDieEntry->getOffset(); + // Point to the next DIE (generally there is always at least a NULL + // entry after the current one). If this is a lone + // DW_TAG_compile_unit without any children, point to the next unit. + uint64_t NextOffset = (InputDIEIdx + 1 < InUnit.getOrigUnit().getNumDIEs()) + ? InUnit.getDIEAtIndex(InputDIEIdx + 1).getOffset() + : InUnit.getOrigUnit().getNextUnitOffset(); + + // We could copy the data only if we need to apply 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 = + DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize()); + + // Modify the copy with relocated addresses. + InUnit.getContaingFile().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 = InputDieEntry->getAbbreviationDeclarationPtr(); + Offset += getULEB128Size(Abbrev->getCode()); + + // Set current output offset. + AttrOutOffset = OutUnit.isCompileUnit() ? OutDIE->getOffset() : 0; + for (const auto &AttrSpec : Abbrev->attributes()) { + // Check whether current attribute should be skipped. + if (shouldSkipAttribute(AttrSpec)) { + DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, + InUnit.getFormParams()); + continue; + } + + DWARFFormValue Val = AttrSpec.getFormValue(); + Val.extractValue(Data, &Offset, InUnit.getFormParams(), + &InUnit.getOrigUnit()); + + // Clone current attribute. + switch (AttrSpec.Form) { + case dwarf::DW_FORM_strp: + case dwarf::DW_FORM_line_strp: + case dwarf::DW_FORM_string: + case dwarf::DW_FORM_strx: + case dwarf::DW_FORM_strx1: + case dwarf::DW_FORM_strx2: + case dwarf::DW_FORM_strx3: + case dwarf::DW_FORM_strx4: + AttrOutOffset += cloneStringAttr(Val, AttrSpec); + break; + case dwarf::DW_FORM_ref_addr: + case dwarf::DW_FORM_ref1: + case dwarf::DW_FORM_ref2: + case dwarf::DW_FORM_ref4: + case dwarf::DW_FORM_ref8: + case dwarf::DW_FORM_ref_udata: + AttrOutOffset += cloneDieRefAttr(Val, AttrSpec); + break; + case dwarf::DW_FORM_data1: + case dwarf::DW_FORM_data2: + case dwarf::DW_FORM_data4: + case dwarf::DW_FORM_data8: + case dwarf::DW_FORM_udata: + case dwarf::DW_FORM_sdata: + case dwarf::DW_FORM_sec_offset: + case dwarf::DW_FORM_flag: + case dwarf::DW_FORM_flag_present: + case dwarf::DW_FORM_rnglistx: + case dwarf::DW_FORM_loclistx: + case dwarf::DW_FORM_implicit_const: + AttrOutOffset += cloneScalarAttr(Val, AttrSpec); + break; + case dwarf::DW_FORM_block: + case dwarf::DW_FORM_block1: + case dwarf::DW_FORM_block2: + case dwarf::DW_FORM_block4: + case dwarf::DW_FORM_exprloc: + AttrOutOffset += cloneBlockAttr(Val, AttrSpec); + break; + case dwarf::DW_FORM_addr: + case dwarf::DW_FORM_addrx: + case dwarf::DW_FORM_addrx1: + case dwarf::DW_FORM_addrx2: + case dwarf::DW_FORM_addrx3: + case dwarf::DW_FORM_addrx4: + AttrOutOffset += cloneAddressAttr(Val, AttrSpec); + break; + default: + InUnit.warn("unsupported attribute form " + + dwarf::FormEncodingString(AttrSpec.Form) + + " in DieAttributeCloner::clone(). Dropping.", + InputDieEntry); + } + } + + // We convert source strings into the indexed form for DWARFv5. + // Check if original compile unit already has DW_AT_str_offsets_base + // attribute. + if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit && + InUnit.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugOffsetPatch{AttrOutOffset, + &OutUnit->getOrCreateSectionDescriptor( + DebugSectionKind::DebugStrOffsets), + true}, + PatchesOffsets); + + AttrOutOffset += + Generator + .addScalarAttribute(dwarf::DW_AT_str_offsets_base, + dwarf::DW_FORM_sec_offset, + OutUnit->getDebugStrOffsetsHeaderSize()) + .second; + } +} + +bool DIEAttributeCloner::shouldSkipAttribute( + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec) { + switch (AttrSpec.Attr) { + default: + return false; + case dwarf::DW_AT_low_pc: + case dwarf::DW_AT_high_pc: + case dwarf::DW_AT_ranges: + if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) + return false; + + // Skip address attribute if we are in function scope and function does not + // reference live address. + return InUnit.getDIEInfo(InputDIEIdx).getIsInFunctionScope() && + !FuncAddressAdjustment.has_value(); + case dwarf::DW_AT_rnglists_base: + // In case !Update the .debug_addr table is not generated/preserved. + // Thus instead of DW_FORM_rnglistx the DW_FORM_sec_offset is used. + // Since DW_AT_rnglists_base is used for only DW_FORM_rnglistx the + // DW_AT_rnglists_base is removed. + return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly; + case dwarf::DW_AT_loclists_base: + // In case !Update the .debug_addr table is not generated/preserved. + // Thus instead of DW_FORM_loclistx the DW_FORM_sec_offset is used. + // Since DW_AT_loclists_base is used for only DW_FORM_loclistx the + // DW_AT_loclists_base is removed. + return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly; + case dwarf::DW_AT_location: + case dwarf::DW_AT_frame_base: + if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) + return false; + + // When location expression contains an address: skip this attribute + // if it does not reference live address. + if (HasLocationExpressionAddress) + return !VarAddressAdjustment.has_value(); + + // Skip location attribute if we are in function scope and function does not + // reference live address. + return InUnit.getDIEInfo(InputDIEIdx).getIsInFunctionScope() && + !FuncAddressAdjustment.has_value(); + } +} + +size_t DIEAttributeCloner::cloneStringAttr( + const DWARFFormValue &Val, + const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) { + std::optional<const char *> String = dwarf::toString(Val); + if (!String) { + InUnit.warn("cann't read string attribute."); + return 0; + } + + StringEntry *StringInPool = + InUnit.getGlobalData().getStringPool().insert(*String).first; + + // Update attributes info. + if (AttrSpec.Attr == dwarf::DW_AT_name) + AttrInfo.Name = StringInPool; + else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name || + AttrSpec.Attr == dwarf::DW_AT_linkage_name) + AttrInfo.MangledName = StringInPool; + + if (AttrSpec.Form == dwarf::DW_FORM_line_strp) { + if (OutUnit.isTypeUnit()) { + DebugInfoOutputSection.notePatch(DebugTypeLineStrPatch{ + AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(InputDIEIdx), + StringInPool}); + } else { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugLineStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets); + } + return Generator + .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_line_strp) + .second; + } + + if (Use_DW_FORM_strp) { + if (OutUnit.isTypeUnit()) { + DebugInfoOutputSection.notePatch( + DebugTypeStrPatch{AttrOutOffset, OutDIE, + InUnit.getDieTypeEntry(InputDIEIdx), StringInPool}); + } else { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets); + } + + return Generator + .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_strp) + .second; + } + + return Generator + .addIndexedStringAttribute(AttrSpec.Attr, dwarf::DW_FORM_strx, + OutUnit->getDebugStrIndex(StringInPool)) + .second; +} + +size_t DIEAttributeCloner::cloneDieRefAttr( + const DWARFFormValue &Val, + const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) { + if (AttrSpec.Attr == dwarf::DW_AT_sibling) + return 0; + + std::optional<UnitEntryPairTy> RefDiePair = + InUnit.resolveDIEReference(Val, ResolveInterCUReferencesMode::Resolve); + if (!RefDiePair || !RefDiePair->DieEntry) { + // If the referenced DIE is not found, drop the attribute. + InUnit.warn("cann't find referenced DIE.", InputDieEntry); + return 0; + } + + TypeEntry *RefTypeName = nullptr; + const CompileUnit::DIEInfo &RefDIEInfo = + RefDiePair->CU->getDIEInfo(RefDiePair->DieEntry); + if (RefDIEInfo.needToPlaceInTypeTable()) + RefTypeName = RefDiePair->CU->getDieTypeEntry(RefDiePair->DieEntry); + + if (OutUnit.isTypeUnit()) { + assert(RefTypeName && "Type name for referenced DIE is not set"); + assert(InUnit.getDieTypeEntry(InputDIEIdx) && + "Type name for DIE is not set"); + + DebugInfoOutputSection.notePatch(DebugType2TypeDieRefPatch{ + AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(InputDIEIdx), + RefTypeName}); + + return Generator + .addScalarAttribute(AttrSpec.Attr, dwarf::DW_FORM_ref4, 0xBADDEF) + .second; + } + + if (RefTypeName) { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugDieTypeRefPatch{AttrOutOffset, RefTypeName}, PatchesOffsets); + + return Generator + .addScalarAttribute(AttrSpec.Attr, dwarf::DW_FORM_ref_addr, 0xBADDEF) + .second; + } + + // Get output offset for referenced DIE. + uint64_t OutDieOffset = RefDiePair->CU->getDieOutOffset(RefDiePair->DieEntry); + + // Examine whether referenced DIE is in current compile unit. + bool IsLocal = OutUnit->getUniqueID() == RefDiePair->CU->getUniqueID(); + + // Set attribute form basing on the kind of referenced DIE(local or not?). + dwarf::Form NewForm = IsLocal ? dwarf::DW_FORM_ref4 : dwarf::DW_FORM_ref_addr; + + // Check whether current attribute references already cloned DIE inside + // the same compilation unit. If true - write the already known offset value. + if (IsLocal && (OutDieOffset != 0)) + return Generator.addScalarAttribute(AttrSpec.Attr, NewForm, OutDieOffset) + .second; + + // If offset value is not known at this point then create patch for the + // reference value and write dummy value into the attribute. + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugDieRefPatch{AttrOutOffset, OutUnit.getAsCompileUnit(), + RefDiePair->CU, + RefDiePair->CU->getDIEIndex(RefDiePair->DieEntry)}, + PatchesOffsets); + return Generator.addScalarAttribute(AttrSpec.Attr, NewForm, 0xBADDEF).second; +} + +size_t DIEAttributeCloner::cloneScalarAttr( + const DWARFFormValue &Val, + const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) { + + // Create patches for attribute referencing other non invariant section. + // Invariant section could not be updated here as this section and + // reference to it do not change value in case --update. + switch (AttrSpec.Attr) { + case dwarf::DW_AT_macro_info: { + if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) { + const DWARFDebugMacro *Macro = + InUnit.getContaingFile().Dwarf->getDebugMacinfo(); + if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset)) + return 0; + + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugOffsetPatch{AttrOutOffset, + &OutUnit->getOrCreateSectionDescriptor( + DebugSectionKind::DebugMacinfo)}, + PatchesOffsets); + } + } break; + case dwarf::DW_AT_macros: { + if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) { + const DWARFDebugMacro *Macro = + InUnit.getContaingFile().Dwarf->getDebugMacro(); + if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset)) + return 0; + + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugOffsetPatch{AttrOutOffset, + &OutUnit->getOrCreateSectionDescriptor( + DebugSectionKind::DebugMacro)}, + PatchesOffsets); + } + } break; + case dwarf::DW_AT_stmt_list: { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugOffsetPatch{AttrOutOffset, &OutUnit->getOrCreateSectionDescriptor( + DebugSectionKind::DebugLine)}, + PatchesOffsets); + } break; + case dwarf::DW_AT_str_offsets_base: { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugOffsetPatch{AttrOutOffset, + &OutUnit->getOrCreateSectionDescriptor( + DebugSectionKind::DebugStrOffsets), + true}, + PatchesOffsets); + + // Use size of .debug_str_offsets header as attribute value. The offset + // to .debug_str_offsets would be added later while patching. + AttrInfo.HasStringOffsetBaseAttr = true; + return Generator + .addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, + OutUnit->getDebugStrOffsetsHeaderSize()) + .second; + } break; + case dwarf::DW_AT_decl_file: { + // Value of DW_AT_decl_file may exceed original form. Longer + // form can affect offsets to the following attributes. To not + // update offsets of the following attributes we always remove + // original DW_AT_decl_file and attach it to the last position + // later. + if (OutUnit.isTypeUnit()) { + if (std::optional<std::pair<StringRef, StringRef>> DirAndFilename = + InUnit.getDirAndFilenameFromLineTable(Val)) + DebugInfoOutputSection.notePatch(DebugTypeDeclFilePatch{ + OutDIE, + InUnit.getDieTypeEntry(InputDIEIdx), + OutUnit->getGlobalData() + .getStringPool() + .insert(DirAndFilename->first) + .first, + OutUnit->getGlobalData() + .getStringPool() + .insert(DirAndFilename->second) + .first, + }); + return 0; + } + } break; + default: { + } break; + }; + + uint64_t Value; + if (AttrSpec.Attr == dwarf::DW_AT_const_value && + (InputDieEntry->getTag() == dwarf::DW_TAG_variable || + InputDieEntry->getTag() == dwarf::DW_TAG_constant)) + AttrInfo.HasLiveAddress = true; + + if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) { + if (auto OptionalValue = Val.getAsUnsignedConstant()) + Value = *OptionalValue; + else if (auto OptionalValue = Val.getAsSignedConstant()) + Value = *OptionalValue; + else if (auto OptionalValue = Val.getAsSectionOffset()) + Value = *OptionalValue; + else { + InUnit.warn("unsupported scalar attribute form. Dropping attribute.", + InputDieEntry); + return 0; + } + + if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value) + AttrInfo.IsDeclaration = true; + + if (AttrSpec.Form == dwarf::DW_FORM_loclistx) + return Generator.addLocListAttribute(AttrSpec.Attr, AttrSpec.Form, Value) + .second; + + return Generator.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, Value) + .second; + } + + dwarf::Form ResultingForm = AttrSpec.Form; + if (AttrSpec.Form == dwarf::DW_FORM_rnglistx) { + // DWARFLinker does not generate .debug_addr table. Thus we need to change + // all "addrx" related forms to "addr" version. Change DW_FORM_rnglistx + // to DW_FORM_sec_offset here. + std::optional<uint64_t> Index = Val.getAsSectionOffset(); + if (!Index) { + InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry); + return 0; + } + std::optional<uint64_t> Offset = + InUnit.getOrigUnit().getRnglistOffset(*Index); + if (!Offset) { + InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry); + return 0; + } + + Value = *Offset; + ResultingForm = dwarf::DW_FORM_sec_offset; + } else if (AttrSpec.Form == dwarf::DW_FORM_loclistx) { + // DWARFLinker does not generate .debug_addr table. Thus we need to change + // all "addrx" related forms to "addr" version. Change DW_FORM_loclistx + // to DW_FORM_sec_offset here. + std::optional<uint64_t> Index = Val.getAsSectionOffset(); + if (!Index) { + InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry); + return 0; + } + std::optional<uint64_t> Offset = + InUnit.getOrigUnit().getLoclistOffset(*Index); + if (!Offset) { + InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry); + return 0; + } + + Value = *Offset; + ResultingForm = dwarf::DW_FORM_sec_offset; + } else if (AttrSpec.Attr == dwarf::DW_AT_high_pc && + InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) { + if (!OutUnit.isCompileUnit()) + return 0; + + std::optional<uint64_t> LowPC = OutUnit.getAsCompileUnit()->getLowPc(); + if (!LowPC) + return 0; + // Dwarf >= 4 high_pc is an size, not an address. + Value = OutUnit.getAsCompileUnit()->getHighPc() - *LowPC; + } else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset) + Value = *Val.getAsSectionOffset(); + else if (AttrSpec.Form == dwarf::DW_FORM_sdata) + Value = *Val.getAsSignedConstant(); + else if (auto OptionalValue = Val.getAsUnsignedConstant()) + Value = *OptionalValue; + else { + InUnit.warn("unsupported scalar attribute form. Dropping attribute.", + InputDieEntry); + return 0; + } + + if (AttrSpec.Attr == dwarf::DW_AT_ranges || + AttrSpec.Attr == dwarf::DW_AT_start_scope) { + // Create patch for the range offset value. + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugRangePatch{{AttrOutOffset}, + InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit}, + PatchesOffsets); + AttrInfo.HasRanges = true; + } else if (DWARFAttribute::mayHaveLocationList(AttrSpec.Attr) && + dwarf::doesFormBelongToClass(AttrSpec.Form, + DWARFFormValue::FC_SectionOffset, + InUnit.getOrigUnit().getVersion())) { + int64_t AddrAdjustmentValue = 0; + if (VarAddressAdjustment) + AddrAdjustmentValue = *VarAddressAdjustment; + else if (FuncAddressAdjustment) + AddrAdjustmentValue = *FuncAddressAdjustment; + + // Create patch for the location offset value. + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugLocPatch{{AttrOutOffset}, AddrAdjustmentValue}, PatchesOffsets); + } else if (AttrSpec.Attr == dwarf::DW_AT_addr_base) { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugOffsetPatch{ + AttrOutOffset, + &OutUnit->getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr), + true}, + PatchesOffsets); + + // Use size of .debug_addr header as attribute value. The offset to + // .debug_addr would be added later while patching. + return Generator + .addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, + OutUnit->getDebugAddrHeaderSize()) + .second; + } else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value) + AttrInfo.IsDeclaration = true; + + return Generator.addScalarAttribute(AttrSpec.Attr, ResultingForm, Value) + .second; +} + +size_t DIEAttributeCloner::cloneBlockAttr( + const DWARFFormValue &Val, + const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) { + + if (OutUnit.isTypeUnit()) + return 0; + + size_t NumberOfPatchesAtStart = PatchesOffsets.size(); + + // If the block is a DWARF Expression, clone it into the temporary + // buffer using cloneExpression(), otherwise copy the data directly. + SmallVector<uint8_t, 32> Buffer; + ArrayRef<uint8_t> Bytes = *Val.getAsBlock(); + if (DWARFAttribute::mayHaveLocationExpr(AttrSpec.Attr) && + (Val.isFormClass(DWARFFormValue::FC_Block) || + Val.isFormClass(DWARFFormValue::FC_Exprloc))) { + DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()), + InUnit.getOrigUnit().isLittleEndian(), + InUnit.getOrigUnit().getAddressByteSize()); + DWARFExpression Expr(Data, InUnit.getOrigUnit().getAddressByteSize(), + InUnit.getFormParams().Format); + + InUnit.cloneDieAttrExpression(Expr, Buffer, DebugInfoOutputSection, + VarAddressAdjustment, PatchesOffsets); + Bytes = Buffer; + } + + // The expression location data might be updated and exceed the original size. + // Check whether the new data fits into the original form. + dwarf::Form ResultForm = AttrSpec.Form; + if ((ResultForm == dwarf::DW_FORM_block1 && Bytes.size() > UINT8_MAX) || + (ResultForm == dwarf::DW_FORM_block2 && Bytes.size() > UINT16_MAX) || + (ResultForm == dwarf::DW_FORM_block4 && Bytes.size() > UINT32_MAX)) + ResultForm = dwarf::DW_FORM_block; + + size_t FinalAttributeSize; + if (AttrSpec.Form == dwarf::DW_FORM_exprloc) + FinalAttributeSize = + Generator.addLocationAttribute(AttrSpec.Attr, ResultForm, Bytes).second; + else + FinalAttributeSize = + Generator.addBlockAttribute(AttrSpec.Attr, ResultForm, Bytes).second; + + // Update patches offsets with the size of length field for Bytes. + for (size_t Idx = NumberOfPatchesAtStart; Idx < PatchesOffsets.size(); + Idx++) { + assert(FinalAttributeSize > Bytes.size()); + *PatchesOffsets[Idx] += + (AttrOutOffset + (FinalAttributeSize - Bytes.size())); + } + + if (HasLocationExpressionAddress) + AttrInfo.HasLiveAddress = + VarAddressAdjustment.has_value() || + InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly; + + return FinalAttributeSize; +} + +size_t DIEAttributeCloner::cloneAddressAttr( + const DWARFFormValue &Val, + const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) { + if (AttrSpec.Attr == dwarf::DW_AT_low_pc) + AttrInfo.HasLiveAddress = true; + + if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) + return Generator + .addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, Val.getRawUValue()) + .second; + + if (OutUnit.isTypeUnit()) + return 0; + + // Cloned Die may have address attributes relocated to a + // totally unrelated value. This can happen: + // - 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 + // independently by the linker). + // - If address relocated in an inline_subprogram that happens at the + // beginning of its inlining function. + // To avoid above cases and to not apply relocation twice (in + // applyValidRelocs and here), read address attribute from InputDIE and apply + // Info.PCOffset here. + + std::optional<DWARFFormValue> AddrAttribute = + InUnit.find(InputDieEntry, AttrSpec.Attr); + if (!AddrAttribute) + llvm_unreachable("Cann't find attribute"); + + std::optional<uint64_t> Addr = AddrAttribute->getAsAddress(); + if (!Addr) { + InUnit.warn("cann't read address attribute value."); + return 0; + } + + if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit && + AttrSpec.Attr == dwarf::DW_AT_low_pc) { + if (std::optional<uint64_t> LowPC = OutUnit.getAsCompileUnit()->getLowPc()) + Addr = *LowPC; + else + return 0; + } else if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit && + AttrSpec.Attr == dwarf::DW_AT_high_pc) { + if (uint64_t HighPc = OutUnit.getAsCompileUnit()->getHighPc()) + Addr = HighPc; + else + return 0; + } else { + if (VarAddressAdjustment) + *Addr += *VarAddressAdjustment; + else if (FuncAddressAdjustment) + *Addr += *FuncAddressAdjustment; + } + + if (AttrSpec.Form == dwarf::DW_FORM_addr) { + return Generator.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, *Addr) + .second; + } + + return Generator + .addScalarAttribute(AttrSpec.Attr, dwarf::Form::DW_FORM_addrx, + OutUnit.getAsCompileUnit()->getDebugAddrIndex(*Addr)) + .second; +} + +unsigned DIEAttributeCloner::finalizeAbbreviations(bool HasChildrenToClone) { + // Add the size of the abbreviation number to the output offset. + AttrOutOffset += + Generator.finalizeAbbreviations(HasChildrenToClone, &PatchesOffsets); + + return AttrOutOffset; +} + +} // end of namespace dwarflinker_parallel +} // namespace llvm |
