brintos

brintos / llvm-project-archived public Read only

0
0
Text · 38.7 KiB · 5b628f6 Raw
1052 lines · cpp
1//===- bolt/Core/DIEBuilder.cpp -------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "bolt/Core/DIEBuilder.h"10#include "bolt/Core/BinaryContext.h"11#include "bolt/Core/ParallelUtilities.h"12#include "llvm/ADT/StringRef.h"13#include "llvm/BinaryFormat/Dwarf.h"14#include "llvm/CodeGen/DIE.h"15#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"16#include "llvm/DebugInfo/DWARF/DWARFDie.h"17#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"18#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"19#include "llvm/DebugInfo/DWARF/DWARFUnit.h"20#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"21#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"22#include "llvm/Support/Casting.h"23#include "llvm/Support/Debug.h"24#include "llvm/Support/ErrorHandling.h"25#include "llvm/Support/FileSystem.h"26#include "llvm/Support/LEB128.h"27 28#include <algorithm>29#include <cstdint>30#include <memory>31#include <mutex>32#include <optional>33#include <unordered_map>34#include <utility>35#include <vector>36 37#undef DEBUG_TYPE38#define DEBUG_TYPE "bolt"39namespace opts {40extern cl::opt<unsigned> Verbosity;41}42namespace llvm {43namespace bolt {44 45/// Returns DWO Name to be used to update DW_AT_dwo_name/DW_AT_GNU_dwo_name46/// either in CU or TU unit die. Handles case where user specifies output DWO47/// directory, and there are duplicate names. Assumes DWO ID is unique.48static std::string49getDWOName(llvm::DWARFUnit &CU,50           std::unordered_map<std::string, uint32_t> &NameToIndexMap,51           std::optional<StringRef> &DwarfOutputPath) {52  assert(CU.getDWOId() && "DWO ID not found.");53  std::string DWOName = dwarf::toString(54      CU.getUnitDIE().find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),55      "");56  assert(!DWOName.empty() &&57         "DW_AT_dwo_name/DW_AT_GNU_dwo_name does not exist.");58  if (DwarfOutputPath) {59    DWOName = std::string(sys::path::filename(DWOName));60    uint32_t &Index = NameToIndexMap[DWOName];61    DWOName.append(std::to_string(Index));62    ++Index;63  }64  DWOName.append(".dwo");65  return DWOName;66}67 68/// Adds a \p Str to .debug_str section.69/// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using70/// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets71/// for this contribution of \p Unit.72static void addStringHelper(DebugStrOffsetsWriter &StrOffstsWriter,73                            DebugStrWriter &StrWriter, DIEBuilder &DIEBldr,74                            DIE &Die, const DWARFUnit &Unit,75                            DIEValue &DIEAttrInfo, StringRef Str) {76  uint32_t NewOffset = StrWriter.addString(Str);77  if (Unit.getVersion() >= 5) {78    StrOffstsWriter.updateAddressMap(DIEAttrInfo.getDIEInteger().getValue(),79                                     NewOffset, Unit);80    return;81  }82  DIEBldr.replaceValue(&Die, DIEAttrInfo.getAttribute(), DIEAttrInfo.getForm(),83                       DIEInteger(NewOffset));84}85 86std::string DIEBuilder::updateDWONameCompDir(87    DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,88    DWARFUnit &SkeletonCU, std::optional<StringRef> DwarfOutputPath,89    std::optional<StringRef> DWONameToUse) {90  DIE &UnitDIE = *getUnitDIEbyUnit(SkeletonCU);91  DIEValue DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_dwo_name);92  if (!DWONameAttrInfo)93    DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_GNU_dwo_name);94  if (!DWONameAttrInfo)95    return "";96  std::string ObjectName;97  if (DWONameToUse)98    ObjectName = *DWONameToUse;99  else100    ObjectName = getDWOName(SkeletonCU, NameToIndexMap, DwarfOutputPath);101  addStringHelper(StrOffstsWriter, StrWriter, *this, UnitDIE, SkeletonCU,102                  DWONameAttrInfo, ObjectName);103 104  DIEValue CompDirAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_comp_dir);105  assert(CompDirAttrInfo && "DW_AT_comp_dir is not in Skeleton CU.");106 107  if (DwarfOutputPath) {108    if (!sys::fs::exists(*DwarfOutputPath))109      sys::fs::create_directory(*DwarfOutputPath);110    addStringHelper(StrOffstsWriter, StrWriter, *this, UnitDIE, SkeletonCU,111                    CompDirAttrInfo, *DwarfOutputPath);112  }113  return ObjectName;114}115 116void DIEBuilder::updateDWONameCompDirForTypes(117    DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,118    DWARFUnit &Unit, std::optional<StringRef> DwarfOutputPath,119    const StringRef DWOName) {120  for (DWARFUnit *DU : getState().DWARF5TUVector)121    updateDWONameCompDir(StrOffstsWriter, StrWriter, *DU, DwarfOutputPath,122                         DWOName);123  if (StrOffstsWriter.isStrOffsetsSectionModified())124    StrOffstsWriter.finalizeSection(Unit, *this);125}126 127void DIEBuilder::updateReferences() {128  for (auto &[SrcDIEInfo, ReferenceInfo] : getState().AddrReferences) {129    DIEInfo *DstDIEInfo = ReferenceInfo.Dst;130    DWARFUnitInfo &DstUnitInfo = getUnitInfo(DstDIEInfo->UnitId);131    dwarf::Attribute Attr = ReferenceInfo.AttrSpec.Attr;132    dwarf::Form Form = ReferenceInfo.AttrSpec.Form;133 134    const uint64_t NewAddr =135        DstDIEInfo->Die->getOffset() + DstUnitInfo.UnitOffset;136    SrcDIEInfo->Die->replaceValue(getState().DIEAlloc, Attr, Form,137                                  DIEInteger(NewAddr));138  }139 140  // Handling references in location expressions.141  for (LocWithReference &LocExpr : getState().LocWithReferencesToProcess) {142    SmallVector<uint8_t, 32> Buffer;143    DataExtractor Data(StringRef((const char *)LocExpr.BlockData.data(),144                                 LocExpr.BlockData.size()),145                       LocExpr.U.isLittleEndian(),146                       LocExpr.U.getAddressByteSize());147    DWARFExpression Expr(Data, LocExpr.U.getAddressByteSize(),148                         LocExpr.U.getFormParams().Format);149    cloneExpression(Data, Expr, LocExpr.U, Buffer, CloneExpressionStage::PATCH);150 151    DIEValueList *AttrVal;152    if (LocExpr.Form == dwarf::DW_FORM_exprloc) {153      DIELoc *DL = new (getState().DIEAlloc) DIELoc;154      DL->setSize(Buffer.size());155      AttrVal = static_cast<DIEValueList *>(DL);156    } else {157      DIEBlock *DBL = new (getState().DIEAlloc) DIEBlock;158      DBL->setSize(Buffer.size());159      AttrVal = static_cast<DIEValueList *>(DBL);160    }161    for (auto Byte : Buffer)162      AttrVal->addValue(getState().DIEAlloc, static_cast<dwarf::Attribute>(0),163                        dwarf::DW_FORM_data1, DIEInteger(Byte));164 165    DIEValue Value;166    if (LocExpr.Form == dwarf::DW_FORM_exprloc)167      Value =168          DIEValue(dwarf::Attribute(LocExpr.Attr), dwarf::Form(LocExpr.Form),169                   static_cast<DIELoc *>(AttrVal));170    else171      Value =172          DIEValue(dwarf::Attribute(LocExpr.Attr), dwarf::Form(LocExpr.Form),173                   static_cast<DIEBlock *>(AttrVal));174 175    LocExpr.Die.replaceValue(getState().DIEAlloc, LocExpr.Attr, LocExpr.Form,176                             Value);177  }178}179 180uint32_t DIEBuilder::allocDIE(const DWARFUnit &DU, const DWARFDie &DDie,181                              BumpPtrAllocator &Alloc, const uint32_t UId) {182  DWARFUnitInfo &DWARFUnitInfo = getUnitInfo(UId);183  const uint64_t DDieOffset = DDie.getOffset();184  if (DWARFUnitInfo.DIEIDMap.count(DDieOffset))185    return DWARFUnitInfo.DIEIDMap[DDieOffset];186 187  DIE *Die = DIE::get(Alloc, dwarf::Tag(DDie.getTag()));188  // This handles the case where there is a DIE ref which points to189  // invalid DIE. This prevents assert when IR is written out.190  // Also it makes debugging easier.191  // DIE dump is not very useful.192  // It's nice to know original offset from which this DIE was constructed.193  Die->setOffset(DDie.getOffset());194  if (opts::Verbosity >= 1)195    getState().DWARFDieAddressesParsed.insert(DDie.getOffset());196  const uint32_t DId = DWARFUnitInfo.DieInfoVector.size();197  DWARFUnitInfo.DIEIDMap[DDieOffset] = DId;198  DWARFUnitInfo.DieInfoVector.emplace_back(199      std::make_unique<DIEInfo>(DIEInfo{Die, DId, UId}));200  return DId;201}202 203void DIEBuilder::constructFromUnit(DWARFUnit &DU) {204  std::optional<uint32_t> UnitId = getUnitId(DU);205  if (!UnitId) {206    BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: "207              << "Skip Unit at " << Twine::utohexstr(DU.getOffset()) << "\n";208    return;209  }210 211  const uint32_t UnitHeaderSize = DU.getHeaderSize();212  uint64_t DIEOffset = DU.getOffset() + UnitHeaderSize;213  uint64_t NextCUOffset = DU.getNextUnitOffset();214  DWARFDataExtractor DebugInfoData = DU.getDebugInfoExtractor();215  DWARFDebugInfoEntry DIEEntry;216  std::vector<DIE *> CurParentDIEStack;217  std::vector<uint32_t> Parents;218  uint32_t TUTypeOffset = 0;219 220  if (DWARFTypeUnit *TU = dyn_cast_or_null<DWARFTypeUnit>(&DU))221    TUTypeOffset = TU->getTypeOffset();222 223  assert(DebugInfoData.isValidOffset(NextCUOffset - 1));224  Parents.push_back(UINT32_MAX);225  do {226    const bool IsTypeDIE = (TUTypeOffset == DIEOffset - DU.getOffset());227    if (!DIEEntry.extractFast(DU, &DIEOffset, DebugInfoData, NextCUOffset,228                              Parents.back()))229      break;230 231    if (const DWARFAbbreviationDeclaration *AbbrDecl =232            DIEEntry.getAbbreviationDeclarationPtr()) {233      DWARFDie DDie(&DU, &DIEEntry);234 235      DIE *CurDIE = constructDIEFast(DDie, DU, *UnitId);236      DWARFUnitInfo &UI = getUnitInfo(*UnitId);237      // Can't rely on first element in DieVector due to cross CU forward238      // references.239      if (!UI.UnitDie)240        UI.UnitDie = CurDIE;241      if (IsTypeDIE)242        getState().TypeDIEMap[&DU] = CurDIE;243 244      if (!CurParentDIEStack.empty())245        CurParentDIEStack.back()->addChild(CurDIE);246 247      if (AbbrDecl->hasChildren())248        CurParentDIEStack.push_back(CurDIE);249    } else {250      // NULL DIE: finishes current children scope.251      CurParentDIEStack.pop_back();252    }253  } while (CurParentDIEStack.size() > 0);254 255  getState().CloneUnitCtxMap[*UnitId].IsConstructed = true;256}257 258DIEBuilder::DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext,259                       DWARF5AcceleratorTable &DebugNamesTable,260                       DWARFUnit *SkeletonCU)261    : BC(BC), DwarfContext(DwarfContext), SkeletonCU(SkeletonCU),262      DebugNamesTable(DebugNamesTable) {}263 264static unsigned int getCUNum(DWARFContext *DwarfContext, bool IsDWO) {265  unsigned int CUNum = IsDWO ? DwarfContext->getNumDWOCompileUnits()266                             : DwarfContext->getNumCompileUnits();267  CUNum += IsDWO ? DwarfContext->getNumDWOTypeUnits()268                 : DwarfContext->getNumTypeUnits();269  return CUNum;270}271 272void DIEBuilder::buildTypeUnits(DebugStrOffsetsWriter *StrOffsetWriter,273                                const bool Init) {274  if (Init)275    BuilderState.reset(new State());276 277  const DWARFUnitIndex &TUIndex = DwarfContext->getTUIndex();278  if (!TUIndex.getRows().empty()) {279    for (auto &Row : TUIndex.getRows()) {280      uint64_t Signature = Row.getSignature();281      // manually populate TypeUnit to UnitVector282      DwarfContext->getTypeUnitForHash(Signature, true);283    }284  }285  const unsigned int CUNum = getCUNum(DwarfContext, isDWO());286  getState().CloneUnitCtxMap.resize(CUNum);287  DWARFContext::unit_iterator_range CU4TURanges =288      isDWO() ? DwarfContext->dwo_types_section_units()289              : DwarfContext->types_section_units();290 291  getState().Type = ProcessingType::DWARF4TUs;292  for (std::unique_ptr<DWARFUnit> &DU : CU4TURanges)293    registerUnit(*DU, false);294 295  for (std::unique_ptr<DWARFUnit> &DU : CU4TURanges)296    constructFromUnit(*DU);297 298  DWARFContext::unit_iterator_range CURanges =299      isDWO() ? DwarfContext->dwo_info_section_units()300              : DwarfContext->info_section_units();301 302  // This handles DWARF4 CUs and DWARF5 CU/TUs.303  // Creating a vector so that for reference handling only DWARF5 CU/TUs are304  // used, and not DWARF4 TUs.305  getState().Type = ProcessingType::DWARF5TUs;306  for (std::unique_ptr<DWARFUnit> &DU : CURanges) {307    if (!DU->isTypeUnit())308      continue;309    registerUnit(*DU, false);310  }311 312  for (DWARFUnit *DU : getState().DWARF5TUVector) {313    constructFromUnit(*DU);314    if (StrOffsetWriter)315      StrOffsetWriter->finalizeSection(*DU, *this);316  }317}318 319void DIEBuilder::buildCompileUnits(const bool Init) {320  if (Init)321    BuilderState.reset(new State());322 323  unsigned int CUNum = getCUNum(DwarfContext, isDWO());324  getState().CloneUnitCtxMap.resize(CUNum);325  DWARFContext::unit_iterator_range CURanges =326      isDWO() ? DwarfContext->dwo_info_section_units()327              : DwarfContext->info_section_units();328 329  // This handles DWARF4 CUs and DWARF5 CU/TUs.330  // Creating a vector so that for reference handling only DWARF5 CU/TUs are331  // used, and not DWARF4 TUs.getState().DUList332  getState().Type = ProcessingType::CUs;333  for (std::unique_ptr<DWARFUnit> &DU : CURanges) {334    if (DU->isTypeUnit())335      continue;336    registerUnit(*DU, false);337  }338 339  // Using DULIst since it can be modified by cross CU reference resolution.340  for (DWARFUnit *DU : getState().DUList) {341    if (DU->isTypeUnit())342      continue;343    constructFromUnit(*DU);344  }345}346void DIEBuilder::buildCompileUnits(const std::vector<DWARFUnit *> &CUs) {347  BuilderState.reset(new State());348  // Allocating enough for current batch being processed.349  // In real use cases we either processing a batch of CUs with no cross350  // references, or if they do have them it is due to LTO. With clang they will351  // share the same abbrev table. In either case this vector will not grow.352  getState().CloneUnitCtxMap.resize(CUs.size());353  getState().Type = ProcessingType::CUs;354  for (DWARFUnit *CU : CUs)355    registerUnit(*CU, false);356 357  for (DWARFUnit *DU : getState().DUList)358    constructFromUnit(*DU);359}360 361void DIEBuilder::buildDWOUnit(DWARFUnit &U) {362  BuilderState.release();363  BuilderState = std::make_unique<State>();364  buildTypeUnits(nullptr, false);365  getState().Type = ProcessingType::CUs;366  registerUnit(U, false);367  constructFromUnit(U);368}369 370DIE *DIEBuilder::constructDIEFast(DWARFDie &DDie, DWARFUnit &U,371                                  uint32_t UnitId) {372 373  std::optional<uint32_t> Idx = getAllocDIEId(U, DDie);374  if (Idx) {375    DWARFUnitInfo &DWARFUnitInfo = getUnitInfo(UnitId);376    DIEInfo &DieInfo = getDIEInfo(UnitId, *Idx);377    if (DWARFUnitInfo.IsConstructed && DieInfo.Die)378      return DieInfo.Die;379  } else {380    Idx = allocDIE(U, DDie, getState().DIEAlloc, UnitId);381  }382 383  DIEInfo &DieInfo = getDIEInfo(UnitId, *Idx);384 385  uint64_t Offset = DDie.getOffset();386  uint64_t NextOffset = Offset;387  DWARFDataExtractor Data = U.getDebugInfoExtractor();388  DWARFDebugInfoEntry DDIEntry;389 390  if (DDIEntry.extractFast(U, &NextOffset, Data, U.getNextUnitOffset(), 0))391    assert(NextOffset - U.getOffset() <= Data.getData().size() &&392           "NextOffset OOB");393 394  SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset));395  Data =396      DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());397 398  const DWARFAbbreviationDeclaration *Abbrev =399      DDie.getAbbreviationDeclarationPtr();400  uint64_t AttrOffset = getULEB128Size(Abbrev->getCode());401 402  using AttrSpec = DWARFAbbreviationDeclaration::AttributeSpec;403  for (const AttrSpec &AttrSpec : Abbrev->attributes()) {404    DWARFFormValue Val(AttrSpec.Form);405    Val.extractValue(Data, &AttrOffset, U.getFormParams(), &U);406    cloneAttribute(*DieInfo.Die, DDie, U, Val, AttrSpec);407  }408  return DieInfo.Die;409}410 411static DWARFUnit *412getUnitForOffset(DIEBuilder &Builder, DWARFContext &DWCtx,413                 const uint64_t Offset,414                 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec) {415  auto findUnit = [&](std::vector<DWARFUnit *> &Units) -> DWARFUnit * {416    auto CUIter = llvm::upper_bound(Units, Offset,417                                    [](uint64_t LHS, const DWARFUnit *RHS) {418                                      return LHS < RHS->getNextUnitOffset();419                                    });420    static std::vector<DWARFUnit *> CUOffsets;421    static std::once_flag InitVectorFlag;422    auto initCUVector = [&]() {423      CUOffsets.reserve(DWCtx.getNumCompileUnits());424      for (const std::unique_ptr<DWARFUnit> &CU : DWCtx.compile_units())425        CUOffsets.emplace_back(CU.get());426    };427    DWARFUnit *CU = CUIter != Units.end() ? *CUIter : nullptr;428    // Above algorithm breaks when there is only one CU, and reference is429    // outside of it. Fall through slower path, that searches all the CUs.430    // For example when src and destination of cross CU references have431    // different abbrev section.432    if (!CU ||433        (CU && AttrSpec.Form == dwarf::DW_FORM_ref_addr &&434         !(CU->getOffset() < Offset && CU->getNextUnitOffset() > Offset))) {435      // This is a work around for XCode clang. There is a build error when we436      // pass DWCtx.compile_units() to llvm::upper_bound437      std::call_once(InitVectorFlag, initCUVector);438      auto CUIter = llvm::upper_bound(CUOffsets, Offset,439                                      [](uint64_t LHS, const DWARFUnit *RHS) {440                                        return LHS < RHS->getNextUnitOffset();441                                      });442      CU = CUIter != CUOffsets.end() ? (*CUIter) : nullptr;443    }444    return CU;445  };446 447  switch (Builder.getCurrentProcessingState()) {448  case DIEBuilder::ProcessingType::DWARF4TUs:449    return findUnit(Builder.getDWARF4TUVector());450  case DIEBuilder::ProcessingType::DWARF5TUs:451    return findUnit(Builder.getDWARF5TUVector());452  case DIEBuilder::ProcessingType::CUs:453    return findUnit(Builder.getDWARFCUVector());454  };455 456  return nullptr;457}458 459uint32_t DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die,460                                  uint32_t &CurOffset) {461  getState().DWARFDieAddressesParsed.erase(Die.getOffset());462  uint32_t CurSize = 0;463  Die.setOffset(CurOffset);464  // It is possible that an indexed debugging information entry has a parent465  // that is not indexed (for example, if its parent does not have a name466  // attribute). In such a case, a parent attribute may point to a nameless467  // index entry (that is, one that cannot be reached from any entry in the name468  // table), or it may point to the nearest ancestor that does have an index469  // entry.470  // Skipping entry is not very useful for LLDB. This follows clang where471  // children of forward declaration won't have DW_IDX_parent.472  // https://github.com/llvm/llvm-project/pull/91808473 474  // If Parent is nullopt and NumberParentsInChain is not zero, then forward475  // declaration was encountered in this DF traversal. Propagating nullopt for476  // Parent to children.477  for (DIEValue &Val : Die.values())478    CurSize += Val.sizeOf(CU.getFormParams());479  CurSize += getULEB128Size(Die.getAbbrevNumber());480  CurOffset += CurSize;481 482  for (DIE &Child : Die.children()) {483    uint32_t ChildSize = finalizeDIEs(CU, Child, CurOffset);484    CurSize += ChildSize;485  }486  // for children end mark.487  if (Die.hasChildren()) {488    CurSize += sizeof(uint8_t);489    CurOffset += sizeof(uint8_t);490  }491 492  Die.setSize(CurSize);493  return CurSize;494}495 496void DIEBuilder::finish() {497  auto finalizeCU = [&](DWARFUnit &CU, uint64_t &UnitStartOffset) -> void {498    DIE *UnitDIE = getUnitDIEbyUnit(CU);499    uint32_t HeaderSize = CU.getHeaderSize();500    uint32_t CurOffset = HeaderSize;501    std::vector<std::optional<BOLTDWARF5AccelTableData *>> Parents;502    Parents.push_back(std::nullopt);503    finalizeDIEs(CU, *UnitDIE, CurOffset);504 505    DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(CU);506    CurUnitInfo.UnitOffset = UnitStartOffset;507    CurUnitInfo.UnitLength = HeaderSize + UnitDIE->getSize();508    UnitStartOffset += CurUnitInfo.UnitLength;509  };510  // Computing offsets for .debug_types section.511  // It's processed first when CU is registered so will be at the beginning of512  // the vector.513  uint64_t TypeUnitStartOffset = 0;514  for (DWARFUnit *CU : getState().DUList) {515    // We process DWARF$ types first.516    if (!(CU->getVersion() < 5 && CU->isTypeUnit()))517      break;518    finalizeCU(*CU, TypeUnitStartOffset);519  }520 521  for (DWARFUnit *CU : getState().DUList) {522    // Skipping DWARF4 types.523    if (CU->getVersion() < 5 && CU->isTypeUnit())524      continue;525    finalizeCU(*CU, UnitSize);526  }527  if (opts::Verbosity >= 1) {528    if (!getState().DWARFDieAddressesParsed.empty())529      dbgs() << "Referenced DIE offsets not in .debug_info\n";530    for (const uint64_t Address : getState().DWARFDieAddressesParsed) {531      dbgs() << Twine::utohexstr(Address) << "\n";532    }533  }534}535 536void DIEBuilder::populateDebugNamesTable(537    DWARFUnit &CU, const DIE &Die,538    std::optional<BOLTDWARF5AccelTableData *> Parent,539    uint32_t NumberParentsInChain) {540  std::optional<BOLTDWARF5AccelTableData *> NameEntry =541      DebugNamesTable.addAccelTableEntry(542          CU, Die, SkeletonCU ? SkeletonCU->getDWOId() : std::nullopt,543          NumberParentsInChain, Parent);544  if (!Parent && NumberParentsInChain)545    NameEntry = std::nullopt;546  if (NameEntry)547    ++NumberParentsInChain;548 549  for (const DIE &Child : Die.children())550    populateDebugNamesTable(CU, Child, NameEntry, NumberParentsInChain);551}552 553void DIEBuilder::updateDebugNamesTable() {554  auto finalizeDebugNamesTableForCU = [&](DWARFUnit &CU,555                                          uint64_t &UnitStartOffset) -> void {556    DIE *UnitDIE = getUnitDIEbyUnit(CU);557    DebugNamesTable.setCurrentUnit(CU, UnitStartOffset);558    populateDebugNamesTable(CU, *UnitDIE, std::nullopt, 0);559 560    DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(CU);561    UnitStartOffset += CurUnitInfo.UnitLength;562  };563 564  uint64_t TypeUnitStartOffset = 0;565  for (DWARFUnit *CU : getState().DUList) {566    if (!(CU->getVersion() < 5 && CU->isTypeUnit()))567      break;568    finalizeDebugNamesTableForCU(*CU, TypeUnitStartOffset);569  }570 571  for (DWARFUnit *CU : getState().DUList) {572    if (CU->getVersion() < 5 && CU->isTypeUnit())573      continue;574    finalizeDebugNamesTableForCU(*CU, DebugNamesUnitSize);575  }576  updateReferences();577}578 579DWARFDie DIEBuilder::resolveDIEReference(580    const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,581    const uint64_t RefOffset, DWARFUnit *&RefCU,582    DWARFDebugInfoEntry &DwarfDebugInfoEntry) {583  uint64_t TmpRefOffset = RefOffset;584  if ((RefCU =585           getUnitForOffset(*this, *DwarfContext, TmpRefOffset, AttrSpec))) {586    /// Trying to add to current working set in case it's cross CU reference.587    if (!registerUnit(*RefCU, true))588      return DWARFDie();589    DWARFDataExtractor DebugInfoData = RefCU->getDebugInfoExtractor();590    if (DwarfDebugInfoEntry.extractFast(*RefCU, &TmpRefOffset, DebugInfoData,591                                        RefCU->getNextUnitOffset(), 0)) {592      // In a file with broken references, an attribute might point to a NULL593      // DIE.594      DWARFDie RefDie = DWARFDie(RefCU, &DwarfDebugInfoEntry);595      if (!RefDie.isNULL()) {596        std::optional<uint32_t> UnitId = getUnitId(*RefCU);597 598        // forward reference599        if (UnitId && !getState().CloneUnitCtxMap[*UnitId].IsConstructed &&600            !getAllocDIEId(*RefCU, RefDie))601          allocDIE(*RefCU, RefDie, getState().DIEAlloc, *UnitId);602        return RefDie;603      }604      BC.errs()605          << "BOLT-WARNING: [internal-dwarf-error]: invalid referenced DIE "606             "at offset: "607          << Twine::utohexstr(RefOffset) << ".\n";608 609    } else {610      BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: could not parse "611                   "referenced DIE at offset: "612                << Twine::utohexstr(RefOffset) << ".\n";613    }614  } else {615    BC.errs()616        << "BOLT-WARNING: [internal-dwarf-error]: could not find referenced "617           "CU. Referenced DIE offset: "618        << Twine::utohexstr(RefOffset) << ".\n";619  }620  return DWARFDie();621}622 623void DIEBuilder::cloneDieOffsetReferenceAttribute(624    DIE &Die, DWARFUnit &U, const DWARFDie &InputDIE,625    const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, uint64_t Ref) {626  DIE *NewRefDie = nullptr;627  DWARFUnit *RefUnit = nullptr;628 629  DWARFDebugInfoEntry DDIEntry;630  const DWARFDie RefDie = resolveDIEReference(AttrSpec, Ref, RefUnit, DDIEntry);631 632  if (!RefDie)633    return;634 635  const std::optional<uint32_t> UnitId = getUnitId(*RefUnit);636  const std::optional<uint32_t> IsAllocId = getAllocDIEId(*RefUnit, RefDie);637  assert(IsAllocId.has_value() && "Encountered unexpected unallocated DIE.");638  const uint32_t DIEId = *IsAllocId;639  DIEInfo &DieInfo = getDIEInfo(*UnitId, DIEId);640 641  if (!DieInfo.Die) {642    assert(Ref > InputDIE.getOffset());643    (void)Ref;644    BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: encounter unexpected "645                 "unallocated DIE. Should be alloc!\n";646    // We haven't cloned this DIE yet. Just create an empty one and647    // store it. It'll get really cloned when we process it.648    DieInfo.Die = DIE::get(getState().DIEAlloc, dwarf::Tag(RefDie.getTag()));649  }650  NewRefDie = DieInfo.Die;651 652  if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) {653    // Adding referenced DIE to DebugNames to be used when entries are created654    // that contain cross cu references.655    if (DebugNamesTable.canGenerateEntryWithCrossCUReference(U, Die, AttrSpec))656      DebugNamesTable.addCrossCUDie(&U, DieInfo.Die);657    // no matter forward reference or backward reference, we are supposed658    // to calculate them in `finish` due to the possible modification of659    // the DIE.660    DWARFDie CurDie = const_cast<DWARFDie &>(InputDIE);661    DIEInfo *CurDieInfo = &getDIEInfoByDwarfDie(CurDie);662    getState().AddrReferences.push_back(663        std::make_pair(CurDieInfo, AddrReferenceInfo(&DieInfo, AttrSpec)));664 665    Die.addValue(getState().DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_ref_addr,666                 DIEInteger(DieInfo.Die->getOffset()));667    return;668  }669 670  Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form,671               DIEEntry(*NewRefDie));672}673 674void DIEBuilder::cloneStringAttribute(675    DIE &Die, const DWARFUnit &U,676    const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,677    const DWARFFormValue &Val) {678  if (AttrSpec.Form == dwarf::DW_FORM_string) {679    Expected<const char *> StrAddr = Val.getAsCString();680    if (!StrAddr) {681      consumeError(StrAddr.takeError());682      return;683    }684    Die.addValue(getState().DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_string,685                 new (getState().DIEAlloc)686                     DIEInlineString(StrAddr.get(), getState().DIEAlloc));687  } else {688    std::optional<uint64_t> OffsetIndex = Val.getRawUValue();689    Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form,690                 DIEInteger(*OffsetIndex));691  }692}693 694bool DIEBuilder::cloneExpression(const DataExtractor &Data,695                                 const DWARFExpression &Expression,696                                 DWARFUnit &U,697                                 SmallVectorImpl<uint8_t> &OutputBuffer,698                                 const CloneExpressionStage &Stage) {699  using Encoding = DWARFExpression::Operation::Encoding;700  using Descr = DWARFExpression::Operation::Description;701  uint64_t OpOffset = 0;702  bool DoesContainReference = false;703  for (const DWARFExpression::Operation &Op : Expression) {704    const Descr &Description = Op.getDescription();705    // DW_OP_const_type is variable-length and has 3706    // operands. Thus far we only support 2.707    if ((Description.Op.size() == 2 &&708         Description.Op[0] == Encoding::BaseTypeRef) ||709        (Description.Op.size() == 2 &&710         Description.Op[1] == Encoding::BaseTypeRef &&711         Description.Op[0] != Encoding::Size1))712      BC.outs() << "BOLT-WARNING: [internal-dwarf-error]: unsupported DW_OP "713                   "encoding.\n";714 715    if ((Description.Op.size() == 1 &&716         Description.Op[0] == Encoding::BaseTypeRef) ||717        (Description.Op.size() == 2 &&718         Description.Op[1] == Encoding::BaseTypeRef &&719         Description.Op[0] == Encoding::Size1)) {720      // This code assumes that the other non-typeref operand fits into 1721      // byte.722      assert(OpOffset < Op.getEndOffset());723      const uint32_t ULEBsize = Op.getEndOffset() - OpOffset - 1;724      (void)ULEBsize;725      assert(ULEBsize <= 16);726 727      // Copy over the operation.728      OutputBuffer.push_back(Op.getCode());729      uint64_t RefOffset;730      if (Description.Op.size() == 1) {731        RefOffset = Op.getRawOperand(0);732      } else {733        OutputBuffer.push_back(Op.getRawOperand(0));734        RefOffset = Op.getRawOperand(1);735      }736      uint32_t Offset = 0;737      if (RefOffset > 0 || Op.getCode() != dwarf::DW_OP_convert) {738        DoesContainReference = true;739        std::optional<uint32_t> RefDieID =740            getAllocDIEId(U, U.getOffset() + RefOffset);741        std::optional<uint32_t> RefUnitID = getUnitId(U);742        if (RefDieID.has_value() && RefUnitID.has_value()) {743          DIEInfo &RefDieInfo = getDIEInfo(*RefUnitID, *RefDieID);744          if (DIE *Clone = RefDieInfo.Die)745            Offset = Stage == CloneExpressionStage::INIT ? RefOffset746                                                         : Clone->getOffset();747          else748            BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: base type ref "749                         "doesn't point to "750                         "DW_TAG_base_type.\n";751        }752      }753      uint8_t ULEB[16];754      // Hard coding to max size so size doesn't change when we update the755      // offset.756      encodeULEB128(Offset, ULEB, 4);757      ArrayRef<uint8_t> ULEBbytes(ULEB, 4);758      OutputBuffer.append(ULEBbytes.begin(), ULEBbytes.end());759    } else {760      // Copy over everything else unmodified.761      const StringRef Bytes = Data.getData().slice(OpOffset, Op.getEndOffset());762      OutputBuffer.append(Bytes.begin(), Bytes.end());763    }764    OpOffset = Op.getEndOffset();765  }766  return DoesContainReference;767}768 769void DIEBuilder::cloneBlockAttribute(770    DIE &Die, DWARFUnit &U,771    const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,772    const DWARFFormValue &Val) {773  DIEValueList *Attr;774  DIEValue Value;775  DIELoc *Loc = nullptr;776  DIEBlock *Block = nullptr;777 778  if (AttrSpec.Form == dwarf::DW_FORM_exprloc) {779    Loc = new (getState().DIEAlloc) DIELoc;780  } else if (doesFormBelongToClass(AttrSpec.Form, DWARFFormValue::FC_Block,781                                   U.getVersion())) {782    Block = new (getState().DIEAlloc) DIEBlock;783  } else {784    BC.errs()785        << "BOLT-WARNING: [internal-dwarf-error]: Unexpected Form value in "786           "cloneBlockAttribute\n";787    return;788  }789  Attr = Loc ? static_cast<DIEValueList *>(Loc)790             : static_cast<DIEValueList *>(Block);791 792  SmallVector<uint8_t, 32> Buffer;793  ArrayRef<uint8_t> Bytes = *Val.getAsBlock();794  if (DWARFAttribute::mayHaveLocationExpr(AttrSpec.Attr) &&795      (Val.isFormClass(DWARFFormValue::FC_Block) ||796       Val.isFormClass(DWARFFormValue::FC_Exprloc))) {797    DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()),798                       U.isLittleEndian(), U.getAddressByteSize());799    DWARFExpression Expr(Data, U.getAddressByteSize(),800                         U.getFormParams().Format);801    if (cloneExpression(Data, Expr, U, Buffer, CloneExpressionStage::INIT))802      getState().LocWithReferencesToProcess.emplace_back(803          Bytes.vec(), U, Die, AttrSpec.Form, AttrSpec.Attr);804    Bytes = Buffer;805  }806  for (auto Byte : Bytes)807    Attr->addValue(getState().DIEAlloc, static_cast<dwarf::Attribute>(0),808                   dwarf::DW_FORM_data1, DIEInteger(Byte));809 810  if (Loc)811    Loc->setSize(Bytes.size());812  else813    Block->setSize(Bytes.size());814 815  if (Loc)816    Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),817                     dwarf::Form(AttrSpec.Form), Loc);818  else819    Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),820                     dwarf::Form(AttrSpec.Form), Block);821  Die.addValue(getState().DIEAlloc, Value);822}823 824void DIEBuilder::cloneAddressAttribute(825    DIE &Die, const DWARFUnit &U,826    const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,827    const DWARFFormValue &Val) {828  Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form,829               DIEInteger(Val.getRawUValue()));830}831 832void DIEBuilder::cloneRefsigAttribute(833    DIE &Die, DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,834    const DWARFFormValue &Val) {835  const std::optional<uint64_t> SigVal = Val.getAsSignatureReference();836  Die.addValue(getState().DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_ref_sig8,837               DIEInteger(*SigVal));838}839 840void DIEBuilder::cloneScalarAttribute(841    DIE &Die, const DWARFDie &InputDIE,842    const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,843    const DWARFFormValue &Val) {844  uint64_t Value;845 846  if (auto OptionalValue = Val.getAsUnsignedConstant())847    Value = *OptionalValue;848  else if (auto OptionalValue = Val.getAsSignedConstant())849    Value = *OptionalValue;850  else if (auto OptionalValue = Val.getAsSectionOffset())851    Value = *OptionalValue;852  else {853    BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: Unsupported scalar "854                 "attribute form. Dropping "855                 "attribute.\n";856    return;857  }858 859  Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form,860               DIEInteger(Value));861}862 863void DIEBuilder::cloneLoclistAttrubute(864    DIE &Die, const DWARFDie &InputDIE,865    const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,866    const DWARFFormValue &Val) {867  std::optional<uint64_t> Value = std::nullopt;868 869  if (auto OptionalValue = Val.getAsUnsignedConstant())870    Value = OptionalValue;871  else if (auto OptionalValue = Val.getAsSignedConstant())872    Value = OptionalValue;873  else if (auto OptionalValue = Val.getAsSectionOffset())874    Value = OptionalValue;875  else876    BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: Unsupported scalar "877                 "attribute form. Dropping "878                 "attribute.\n";879 880  if (!Value.has_value())881    return;882 883  Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form,884               DIELocList(*Value));885}886 887void DIEBuilder::cloneAttribute(888    DIE &Die, const DWARFDie &InputDIE, DWARFUnit &U, const DWARFFormValue &Val,889    const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec) {890  switch (AttrSpec.Form) {891  case dwarf::DW_FORM_strp:892  case dwarf::DW_FORM_string:893  case dwarf::DW_FORM_strx:894  case dwarf::DW_FORM_strx1:895  case dwarf::DW_FORM_strx2:896  case dwarf::DW_FORM_strx3:897  case dwarf::DW_FORM_strx4:898  case dwarf::DW_FORM_GNU_str_index:899  case dwarf::DW_FORM_line_strp:900    cloneStringAttribute(Die, U, AttrSpec, Val);901    break;902  case dwarf::DW_FORM_ref_addr:903    cloneDieOffsetReferenceAttribute(Die, U, InputDIE, AttrSpec,904                                     *Val.getAsDebugInfoReference());905    break;906  case dwarf::DW_FORM_ref1:907  case dwarf::DW_FORM_ref2:908  case dwarf::DW_FORM_ref4:909  case dwarf::DW_FORM_ref8:910    cloneDieOffsetReferenceAttribute(Die, U, InputDIE, AttrSpec,911                                     Val.getUnit()->getOffset() +912                                         *Val.getAsRelativeReference());913    break;914  case dwarf::DW_FORM_block:915  case dwarf::DW_FORM_block1:916  case dwarf::DW_FORM_block2:917  case dwarf::DW_FORM_block4:918  case dwarf::DW_FORM_exprloc:919    cloneBlockAttribute(Die, U, AttrSpec, Val);920    break;921  case dwarf::DW_FORM_addr:922  case dwarf::DW_FORM_addrx:923  case dwarf::DW_FORM_GNU_addr_index:924    cloneAddressAttribute(Die, U, AttrSpec, Val);925    break;926  case dwarf::DW_FORM_data1:927  case dwarf::DW_FORM_data2:928  case dwarf::DW_FORM_data4:929  case dwarf::DW_FORM_data8:930  case dwarf::DW_FORM_udata:931  case dwarf::DW_FORM_sdata:932  case dwarf::DW_FORM_sec_offset:933  case dwarf::DW_FORM_rnglistx:934  case dwarf::DW_FORM_flag:935  case dwarf::DW_FORM_flag_present:936  case dwarf::DW_FORM_implicit_const:937    cloneScalarAttribute(Die, InputDIE, AttrSpec, Val);938    break;939  case dwarf::DW_FORM_loclistx:940    cloneLoclistAttrubute(Die, InputDIE, AttrSpec, Val);941    break;942  case dwarf::DW_FORM_ref_sig8:943    cloneRefsigAttribute(Die, AttrSpec, Val);944    break;945  default:946    BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: Unsupported attribute "947                 "form " +948                     dwarf::FormEncodingString(AttrSpec.Form).str() +949                     " in cloneAttribute. Dropping.";950  }951}952void DIEBuilder::assignAbbrev(DIEAbbrev &Abbrev) {953  // Check the set for priors.954  FoldingSetNodeID ID;955  Abbrev.Profile(ID);956  void *InsertToken;957  DIEAbbrev *InSet = AbbreviationsSet.FindNodeOrInsertPos(ID, InsertToken);958 959  // If it's newly added.960  if (InSet) {961    // Assign existing abbreviation number.962    Abbrev.setNumber(InSet->getNumber());963  } else {964    // Add to abbreviation list.965    Abbreviations.push_back(966        std::make_unique<DIEAbbrev>(Abbrev.getTag(), Abbrev.hasChildren()));967    for (const auto &Attr : Abbrev.getData())968      Abbreviations.back()->AddAttribute(Attr.getAttribute(), Attr.getForm());969    AbbreviationsSet.InsertNode(Abbreviations.back().get(), InsertToken);970    // Assign the unique abbreviation number.971    Abbrev.setNumber(Abbreviations.size());972    Abbreviations.back()->setNumber(Abbreviations.size());973  }974}975 976void DIEBuilder::generateAbbrevs() {977  if (isEmpty())978    return;979 980  for (DWARFUnit *DU : getState().DUList) {981    DIE *UnitDIE = getUnitDIEbyUnit(*DU);982    generateUnitAbbrevs(UnitDIE);983  }984}985 986void DIEBuilder::generateUnitAbbrevs(DIE *Die) {987  DIEAbbrev NewAbbrev = Die->generateAbbrev();988 989  if (Die->hasChildren())990    NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);991  assignAbbrev(NewAbbrev);992  Die->setAbbrevNumber(NewAbbrev.getNumber());993 994  for (auto &Child : Die->children()) {995    generateUnitAbbrevs(&Child);996  }997}998 999static uint64_t getHash(const DWARFUnit &DU) {1000  // Before DWARF5 TU units are in their own section, so at least one offset,1001  // first one, will be the same as CUs in .debug_info.dwo section1002  if (DU.getVersion() < 5 && DU.isTypeUnit()) {1003    const uint64_t TypeUnitHash =1004        cast_or_null<DWARFTypeUnit>(&DU)->getTypeHash();1005    const uint64_t Offset = DU.getOffset();1006    return llvm::hash_combine(llvm::hash_value(TypeUnitHash),1007                              llvm::hash_value(Offset));1008  }1009  return DU.getOffset();1010}1011 1012bool DIEBuilder::registerUnit(DWARFUnit &DU, bool NeedSort) {1013  if (!BC.isValidDwarfUnit(DU))1014    return false;1015  auto IterGlobal = AllProcessed.insert(getHash(DU));1016  // If DU is already in a current working set or was already processed we can1017  // skip it.1018  if (!IterGlobal.second)1019    return true;1020  if (getState().Type == ProcessingType::DWARF4TUs) {1021    getState().DWARF4TUVector.push_back(&DU);1022  } else if (getState().Type == ProcessingType::DWARF5TUs) {1023    getState().DWARF5TUVector.push_back(&DU);1024  } else {1025    getState().DWARFCUVector.push_back(&DU);1026    /// Sorting for cross CU reference resolution.1027    if (NeedSort)1028      std::sort(getState().DWARFCUVector.begin(),1029                getState().DWARFCUVector.end(),1030                [](const DWARFUnit *A, const DWARFUnit *B) {1031                  return A->getOffset() < B->getOffset();1032                });1033  }1034  getState().UnitIDMap[getHash(DU)] = getState().DUList.size();1035  // This handles the case where we do have cross cu references, but CUs do not1036  // share the same abbrev table.1037  if (getState().DUList.size() == getState().CloneUnitCtxMap.size())1038    getState().CloneUnitCtxMap.emplace_back();1039  getState().DUList.push_back(&DU);1040  return true;1041}1042 1043std::optional<uint32_t> DIEBuilder::getUnitId(const DWARFUnit &DU) {1044  auto Iter = getState().UnitIDMap.find(getHash(DU));1045  if (Iter != getState().UnitIDMap.end())1046    return Iter->second;1047  return std::nullopt;1048}1049 1050} // namespace bolt1051} // namespace llvm1052