|  | //===- DWARFLinkerCompileUnit.cpp -----------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" | 
|  | #include "llvm/ADT/StringExtras.h" | 
|  | #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" | 
|  | #include "llvm/DebugInfo/DWARF/DWARFContext.h" | 
|  | #include "llvm/DebugInfo/DWARF/DWARFExpression.h" | 
|  | #include "llvm/Support/FormatVariadic.h" | 
|  |  | 
|  | namespace llvm { | 
|  |  | 
|  | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | 
|  | LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() { | 
|  | llvm::errs() << "{\n"; | 
|  | llvm::errs() << "  AddrAdjust: " << AddrAdjust << '\n'; | 
|  | llvm::errs() << "  Ctxt: " << formatv("{0:x}", Ctxt) << '\n'; | 
|  | llvm::errs() << "  Clone: " << formatv("{0:x}", Clone) << '\n'; | 
|  | llvm::errs() << "  ParentIdx: " << ParentIdx << '\n'; | 
|  | llvm::errs() << "  Keep: " << Keep << '\n'; | 
|  | llvm::errs() << "  InDebugMap: " << InDebugMap << '\n'; | 
|  | llvm::errs() << "  Prune: " << Prune << '\n'; | 
|  | llvm::errs() << "  Incomplete: " << Incomplete << '\n'; | 
|  | llvm::errs() << "  InModuleScope: " << InModuleScope << '\n'; | 
|  | llvm::errs() << "  ODRMarkingDone: " << ODRMarkingDone << '\n'; | 
|  | llvm::errs() << "  UnclonedReference: " << UnclonedReference << '\n'; | 
|  | llvm::errs() << "}\n"; | 
|  | } | 
|  | #endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | 
|  |  | 
|  | /// Check if the DIE at \p Idx is in the scope of a function. | 
|  | static bool inFunctionScope(CompileUnit &U, unsigned Idx) { | 
|  | while (Idx) { | 
|  | if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram) | 
|  | return true; | 
|  | Idx = U.getInfo(Idx).ParentIdx; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint16_t CompileUnit::getLanguage() { | 
|  | if (!Language) { | 
|  | DWARFDie CU = getOrigUnit().getUnitDIE(); | 
|  | Language = dwarf::toUnsigned(CU.find(dwarf::DW_AT_language), 0); | 
|  | } | 
|  | return Language; | 
|  | } | 
|  |  | 
|  | StringRef CompileUnit::getSysRoot() { | 
|  | if (SysRoot.empty()) { | 
|  | DWARFDie CU = getOrigUnit().getUnitDIE(); | 
|  | SysRoot = dwarf::toStringRef(CU.find(dwarf::DW_AT_LLVM_sysroot)).str(); | 
|  | } | 
|  | return SysRoot; | 
|  | } | 
|  |  | 
|  | void CompileUnit::markEverythingAsKept() { | 
|  | unsigned Idx = 0; | 
|  |  | 
|  | for (auto &I : Info) { | 
|  | // Mark everything that wasn't explicit marked for pruning. | 
|  | I.Keep = !I.Prune; | 
|  | auto DIE = OrigUnit.getDIEAtIndex(Idx++); | 
|  | DWARFUnit *U = DIE.getDwarfUnit(); | 
|  |  | 
|  | // Try to guess which DIEs must go to the accelerator tables. We do that | 
|  | // just for variables, because functions will be handled depending on | 
|  | // whether they carry a DW_AT_low_pc attribute or not. | 
|  | if (DIE.getTag() != dwarf::DW_TAG_variable && | 
|  | DIE.getTag() != dwarf::DW_TAG_constant) | 
|  | continue; | 
|  |  | 
|  | std::optional<DWARFFormValue> Value; | 
|  | if (!(Value = DIE.find(dwarf::DW_AT_location))) { | 
|  | if ((Value = DIE.find(dwarf::DW_AT_const_value)) && | 
|  | !inFunctionScope(*this, I.ParentIdx)) | 
|  | I.InDebugMap = true; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (auto ExprLockBlock = Value->getAsBlock()) { | 
|  | // Parse 'exprloc' expression. | 
|  | DataExtractor Data(toStringRef(*ExprLockBlock), | 
|  | U->getContext().isLittleEndian(), | 
|  | U->getAddressByteSize()); | 
|  | DWARFExpression Expression(Data, U->getAddressByteSize(), | 
|  | U->getFormParams().Format); | 
|  |  | 
|  | for (DWARFExpression::iterator It = Expression.begin(); | 
|  | (It != Expression.end()) && !I.InDebugMap; ++It) { | 
|  | DWARFExpression::iterator NextIt = It; | 
|  | ++NextIt; | 
|  |  | 
|  | switch (It->getCode()) { | 
|  | case dwarf::DW_OP_const4u: | 
|  | case dwarf::DW_OP_const8u: | 
|  | case dwarf::DW_OP_const4s: | 
|  | case dwarf::DW_OP_const8s: | 
|  | if (NextIt == Expression.end() || | 
|  | NextIt->getCode() != dwarf::DW_OP_form_tls_address) | 
|  | break; | 
|  | [[fallthrough]]; | 
|  | case dwarf::DW_OP_constx: | 
|  | case dwarf::DW_OP_addr: | 
|  | case dwarf::DW_OP_addrx: | 
|  | I.InDebugMap = true; | 
|  | break; | 
|  | default: | 
|  | // Nothing to do. | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) { | 
|  | NextUnitOffset = StartOffset; | 
|  | if (NewUnit) { | 
|  | NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size | 
|  | NextUnitOffset += NewUnit->getUnitDie().getSize(); | 
|  | } | 
|  | return NextUnitOffset; | 
|  | } | 
|  |  | 
|  | /// Keep track of a forward cross-cu reference from this unit | 
|  | /// to \p Die that lives in \p RefUnit. | 
|  | void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit, | 
|  | DeclContext *Ctxt, PatchLocation Attr) { | 
|  | ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr); | 
|  | } | 
|  |  | 
|  | void CompileUnit::fixupForwardReferences() { | 
|  | for (const auto &Ref : ForwardDIEReferences) { | 
|  | DIE *RefDie; | 
|  | const CompileUnit *RefUnit; | 
|  | PatchLocation Attr; | 
|  | DeclContext *Ctxt; | 
|  | std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref; | 
|  | if (Ctxt && Ctxt->hasCanonicalDIE()) { | 
|  | assert(Ctxt->getCanonicalDIEOffset() && | 
|  | "Canonical die offset is not set"); | 
|  | Attr.set(Ctxt->getCanonicalDIEOffset()); | 
|  | } else { | 
|  | assert(RefDie->getOffset() && "Referenced die offset is not set"); | 
|  | Attr.set(RefDie->getOffset() + RefUnit->getStartOffset()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) { | 
|  | Labels.insert({LabelLowPc, PcOffset}); | 
|  | } | 
|  |  | 
|  | void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, | 
|  | int64_t PcOffset) { | 
|  | Ranges.insert({FuncLowPc, FuncHighPc}, PcOffset); | 
|  | if (LowPc) | 
|  | LowPc = std::min(*LowPc, FuncLowPc + PcOffset); | 
|  | else | 
|  | LowPc = FuncLowPc + PcOffset; | 
|  | this->HighPc = std::max(HighPc, FuncHighPc + PcOffset); | 
|  | } | 
|  |  | 
|  | void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) { | 
|  | if (Die.getTag() == dwarf::DW_TAG_compile_unit) { | 
|  | UnitRangeAttribute = Attr; | 
|  | return; | 
|  | } | 
|  |  | 
|  | RangeAttributes.emplace_back(Attr); | 
|  | } | 
|  |  | 
|  | void CompileUnit::noteLocationAttribute(PatchLocation Attr) { | 
|  | LocationAttributes.emplace_back(Attr); | 
|  | } | 
|  |  | 
|  | void CompileUnit::addNamespaceAccelerator(const DIE *Die, | 
|  | DwarfStringPoolEntryRef Name) { | 
|  | Namespaces.emplace_back(Name, Die); | 
|  | } | 
|  |  | 
|  | void CompileUnit::addObjCAccelerator(const DIE *Die, | 
|  | DwarfStringPoolEntryRef Name, | 
|  | bool SkipPubSection) { | 
|  | ObjC.emplace_back(Name, Die, SkipPubSection); | 
|  | } | 
|  |  | 
|  | void CompileUnit::addNameAccelerator(const DIE *Die, | 
|  | DwarfStringPoolEntryRef Name, | 
|  | bool SkipPubSection) { | 
|  | Pubnames.emplace_back(Name, Die, SkipPubSection); | 
|  | } | 
|  |  | 
|  | void CompileUnit::addTypeAccelerator(const DIE *Die, | 
|  | DwarfStringPoolEntryRef Name, | 
|  | bool ObjcClassImplementation, | 
|  | uint32_t QualifiedNameHash) { | 
|  | Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation); | 
|  | } | 
|  |  | 
|  | } // namespace llvm |