| 1 | //===- DWARFLinkerCompileUnit.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 "llvm/DWARFLinker/Classic/DWARFLinkerCompileUnit.h" |
| 10 | #include "llvm/ADT/StringExtras.h" |
| 11 | #include "llvm/DWARFLinker/Classic/DWARFLinkerDeclContext.h" |
| 12 | #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
| 13 | #include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h" |
| 14 | #include "llvm/Support/FormatVariadic.h" |
| 15 | |
| 16 | namespace llvm { |
| 17 | |
| 18 | using namespace dwarf_linker; |
| 19 | using namespace dwarf_linker::classic; |
| 20 | |
| 21 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| 22 | LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() { |
| 23 | llvm::errs() << "{\n" ; |
| 24 | llvm::errs() << " AddrAdjust: " << AddrAdjust << '\n'; |
| 25 | llvm::errs() << " Ctxt: " << formatv("{0:x}" , Ctxt) << '\n'; |
| 26 | llvm::errs() << " Clone: " << formatv("{0:x}" , Clone) << '\n'; |
| 27 | llvm::errs() << " ParentIdx: " << ParentIdx << '\n'; |
| 28 | llvm::errs() << " Keep: " << Keep << '\n'; |
| 29 | llvm::errs() << " InDebugMap: " << InDebugMap << '\n'; |
| 30 | llvm::errs() << " Prune: " << Prune << '\n'; |
| 31 | llvm::errs() << " Incomplete: " << Incomplete << '\n'; |
| 32 | llvm::errs() << " InModuleScope: " << InModuleScope << '\n'; |
| 33 | llvm::errs() << " ODRMarkingDone: " << ODRMarkingDone << '\n'; |
| 34 | llvm::errs() << " UnclonedReference: " << UnclonedReference << '\n'; |
| 35 | llvm::errs() << "}\n" ; |
| 36 | } |
| 37 | #endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| 38 | |
| 39 | /// Check if the DIE at \p Idx is in the scope of a function. |
| 40 | static bool inFunctionScope(CompileUnit &U, unsigned Idx) { |
| 41 | while (Idx) { |
| 42 | if (U.getOrigUnit().getDIEAtIndex(Index: Idx).getTag() == dwarf::DW_TAG_subprogram) |
| 43 | return true; |
| 44 | Idx = U.getInfo(Idx).ParentIdx; |
| 45 | } |
| 46 | return false; |
| 47 | } |
| 48 | |
| 49 | uint16_t CompileUnit::getLanguage() { |
| 50 | if (!Language) |
| 51 | Language = getOrigUnit().getUnitDIE().getLanguage().value_or(u: 0); |
| 52 | |
| 53 | return Language; |
| 54 | } |
| 55 | |
| 56 | StringRef CompileUnit::getSysRoot() { |
| 57 | if (SysRoot.empty()) { |
| 58 | DWARFDie CU = getOrigUnit().getUnitDIE(); |
| 59 | SysRoot = dwarf::toStringRef(V: CU.find(Attr: dwarf::DW_AT_LLVM_sysroot)).str(); |
| 60 | } |
| 61 | return SysRoot; |
| 62 | } |
| 63 | |
| 64 | void CompileUnit::markEverythingAsKept() { |
| 65 | unsigned Idx = 0; |
| 66 | |
| 67 | for (auto &I : Info) { |
| 68 | // Mark everything that wasn't explicit marked for pruning. |
| 69 | I.Keep = !I.Prune; |
| 70 | auto DIE = OrigUnit.getDIEAtIndex(Index: Idx++); |
| 71 | DWARFUnit *U = DIE.getDwarfUnit(); |
| 72 | |
| 73 | // Try to guess which DIEs must go to the accelerator tables. We do that |
| 74 | // just for variables, because functions will be handled depending on |
| 75 | // whether they carry a DW_AT_low_pc attribute or not. |
| 76 | if (DIE.getTag() != dwarf::DW_TAG_variable && |
| 77 | DIE.getTag() != dwarf::DW_TAG_constant) |
| 78 | continue; |
| 79 | |
| 80 | std::optional<DWARFFormValue> Value; |
| 81 | if (!(Value = DIE.find(Attr: dwarf::DW_AT_location))) { |
| 82 | if ((Value = DIE.find(Attr: dwarf::DW_AT_const_value)) && |
| 83 | !inFunctionScope(U&: *this, Idx: I.ParentIdx)) |
| 84 | I.InDebugMap = true; |
| 85 | continue; |
| 86 | } |
| 87 | |
| 88 | if (auto ExprLockBlock = Value->getAsBlock()) { |
| 89 | // Parse 'exprloc' expression. |
| 90 | DataExtractor Data(*ExprLockBlock, U->getContext().isLittleEndian()); |
| 91 | DWARFExpression Expression(Data, U->getAddressByteSize(), |
| 92 | U->getFormParams().Format); |
| 93 | |
| 94 | for (DWARFExpression::iterator It = Expression.begin(); |
| 95 | (It != Expression.end()) && !I.InDebugMap; ++It) { |
| 96 | DWARFExpression::iterator NextIt = It; |
| 97 | ++NextIt; |
| 98 | |
| 99 | switch (It->getCode()) { |
| 100 | case dwarf::DW_OP_const2u: |
| 101 | case dwarf::DW_OP_const4u: |
| 102 | case dwarf::DW_OP_const8u: |
| 103 | case dwarf::DW_OP_const2s: |
| 104 | case dwarf::DW_OP_const4s: |
| 105 | case dwarf::DW_OP_const8s: |
| 106 | if (NextIt == Expression.end() || |
| 107 | !dwarf::isTlsAddressOp(O: NextIt->getCode())) |
| 108 | break; |
| 109 | [[fallthrough]]; |
| 110 | case dwarf::DW_OP_constx: |
| 111 | case dwarf::DW_OP_addr: |
| 112 | case dwarf::DW_OP_addrx: |
| 113 | I.InDebugMap = true; |
| 114 | break; |
| 115 | default: |
| 116 | // Nothing to do. |
| 117 | break; |
| 118 | } |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) { |
| 125 | NextUnitOffset = StartOffset; |
| 126 | if (NewUnit) { |
| 127 | NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size |
| 128 | NextUnitOffset += NewUnit->getUnitDie().getSize(); |
| 129 | } |
| 130 | return NextUnitOffset; |
| 131 | } |
| 132 | |
| 133 | /// Keep track of a forward cross-cu reference from this unit |
| 134 | /// to \p Die that lives in \p RefUnit. |
| 135 | void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit, |
| 136 | DeclContext *Ctxt, PatchLocation Attr) { |
| 137 | ForwardDIEReferences.emplace_back(args&: Die, args&: RefUnit, args&: Ctxt, args&: Attr); |
| 138 | } |
| 139 | |
| 140 | void CompileUnit::fixupForwardReferences() { |
| 141 | for (const auto &Ref : ForwardDIEReferences) { |
| 142 | DIE *RefDie; |
| 143 | const CompileUnit *RefUnit; |
| 144 | PatchLocation Attr; |
| 145 | DeclContext *Ctxt; |
| 146 | std::tie(args&: RefDie, args&: RefUnit, args&: Ctxt, args&: Attr) = Ref; |
| 147 | if (Ctxt && Ctxt->hasCanonicalDIE()) { |
| 148 | assert(Ctxt->getCanonicalDIEOffset() && |
| 149 | "Canonical die offset is not set" ); |
| 150 | Attr.set(Ctxt->getCanonicalDIEOffset()); |
| 151 | } else { |
| 152 | assert(RefDie->getOffset() && "Referenced die offset is not set" ); |
| 153 | Attr.set(RefDie->getOffset() + RefUnit->getStartOffset()); |
| 154 | } |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) { |
| 159 | Labels.insert(KV: {LabelLowPc, PcOffset}); |
| 160 | } |
| 161 | |
| 162 | void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, |
| 163 | int64_t PcOffset) { |
| 164 | Ranges.insert(Range: {FuncLowPc, FuncHighPc}, Value: PcOffset); |
| 165 | if (LowPc) |
| 166 | LowPc = std::min(a: *LowPc, b: FuncLowPc + PcOffset); |
| 167 | else |
| 168 | LowPc = FuncLowPc + PcOffset; |
| 169 | this->HighPc = std::max(a: HighPc, b: FuncHighPc + PcOffset); |
| 170 | } |
| 171 | |
| 172 | void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) { |
| 173 | if (Die.getTag() == dwarf::DW_TAG_compile_unit) { |
| 174 | UnitRangeAttribute = Attr; |
| 175 | return; |
| 176 | } |
| 177 | |
| 178 | RangeAttributes.emplace_back(Args&: Attr); |
| 179 | } |
| 180 | |
| 181 | void CompileUnit::noteLocationAttribute(PatchLocation Attr) { |
| 182 | LocationAttributes.emplace_back(Args&: Attr); |
| 183 | } |
| 184 | |
| 185 | void CompileUnit::noteStmtSeqListAttribute(PatchLocation Attr) { |
| 186 | StmtSeqListAttributes.emplace_back(Args&: Attr); |
| 187 | } |
| 188 | |
| 189 | void CompileUnit::addNamespaceAccelerator(const DIE *Die, |
| 190 | DwarfStringPoolEntryRef Name) { |
| 191 | Namespaces.emplace_back(args&: Name, args&: Die); |
| 192 | } |
| 193 | |
| 194 | void CompileUnit::addObjCAccelerator(const DIE *Die, |
| 195 | DwarfStringPoolEntryRef Name, |
| 196 | bool SkipPubSection) { |
| 197 | ObjC.emplace_back(args&: Name, args&: Die, args&: SkipPubSection); |
| 198 | } |
| 199 | |
| 200 | void CompileUnit::addNameAccelerator(const DIE *Die, |
| 201 | DwarfStringPoolEntryRef Name, |
| 202 | bool SkipPubSection) { |
| 203 | Pubnames.emplace_back(args&: Name, args&: Die, args&: SkipPubSection); |
| 204 | } |
| 205 | |
| 206 | void CompileUnit::addTypeAccelerator(const DIE *Die, |
| 207 | DwarfStringPoolEntryRef Name, |
| 208 | bool ObjcClassImplementation, |
| 209 | uint32_t QualifiedNameHash) { |
| 210 | Pubtypes.emplace_back(args&: Name, args&: Die, args&: QualifiedNameHash, args&: ObjcClassImplementation); |
| 211 | } |
| 212 | |
| 213 | } // namespace llvm |
| 214 | |