aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.cpp653
1 files changed, 653 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.cpp b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.cpp
new file mode 100644
index 000000000000..07ebd55e2c46
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.cpp
@@ -0,0 +1,653 @@
+//=== 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"
+
+using namespace llvm;
+using namespace dwarf_linker;
+using namespace dwarf_linker::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;
+}