diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DIEAttributeCloner.cpp | 653 | 
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; +}  | 
