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