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