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/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(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 DWARFDie CU = getOrigUnit().getUnitDIE(); 52 Language = dwarf::toUnsigned(CU.find(dwarf::DW_AT_language), 0); 53 } 54 return Language; 55 } 56 57 StringRef CompileUnit::getSysRoot() { 58 if (SysRoot.empty()) { 59 DWARFDie CU = getOrigUnit().getUnitDIE(); 60 SysRoot = dwarf::toStringRef(CU.find(dwarf::DW_AT_LLVM_sysroot)).str(); 61 } 62 return SysRoot; 63 } 64 65 void CompileUnit::markEverythingAsKept() { 66 unsigned Idx = 0; 67 68 for (auto &I : Info) { 69 // Mark everything that wasn't explicit marked for pruning. 70 I.Keep = !I.Prune; 71 auto DIE = OrigUnit.getDIEAtIndex(Idx++); 72 DWARFUnit *U = DIE.getDwarfUnit(); 73 74 // Try to guess which DIEs must go to the accelerator tables. We do that 75 // just for variables, because functions will be handled depending on 76 // whether they carry a DW_AT_low_pc attribute or not. 77 if (DIE.getTag() != dwarf::DW_TAG_variable && 78 DIE.getTag() != dwarf::DW_TAG_constant) 79 continue; 80 81 std::optional<DWARFFormValue> Value; 82 if (!(Value = DIE.find(dwarf::DW_AT_location))) { 83 if ((Value = DIE.find(dwarf::DW_AT_const_value)) && 84 !inFunctionScope(*this, I.ParentIdx)) 85 I.InDebugMap = true; 86 continue; 87 } 88 89 if (auto ExprLockBlock = Value->getAsBlock()) { 90 // Parse 'exprloc' expression. 91 DataExtractor Data(toStringRef(*ExprLockBlock), 92 U->getContext().isLittleEndian(), 93 U->getAddressByteSize()); 94 DWARFExpression Expression(Data, U->getAddressByteSize(), 95 U->getFormParams().Format); 96 97 for (DWARFExpression::iterator It = Expression.begin(); 98 (It != Expression.end()) && !I.InDebugMap; ++It) { 99 DWARFExpression::iterator NextIt = It; 100 ++NextIt; 101 102 switch (It->getCode()) { 103 case dwarf::DW_OP_const2u: 104 case dwarf::DW_OP_const4u: 105 case dwarf::DW_OP_const8u: 106 case dwarf::DW_OP_const2s: 107 case dwarf::DW_OP_const4s: 108 case dwarf::DW_OP_const8s: 109 if (NextIt == Expression.end() || 110 NextIt->getCode() != dwarf::DW_OP_form_tls_address) 111 break; 112 [[fallthrough]]; 113 case dwarf::DW_OP_constx: 114 case dwarf::DW_OP_addr: 115 case dwarf::DW_OP_addrx: 116 I.InDebugMap = true; 117 break; 118 default: 119 // Nothing to do. 120 break; 121 } 122 } 123 } 124 } 125 } 126 127 uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) { 128 NextUnitOffset = StartOffset; 129 if (NewUnit) { 130 NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size 131 NextUnitOffset += NewUnit->getUnitDie().getSize(); 132 } 133 return NextUnitOffset; 134 } 135 136 /// Keep track of a forward cross-cu reference from this unit 137 /// to \p Die that lives in \p RefUnit. 138 void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit, 139 DeclContext *Ctxt, PatchLocation Attr) { 140 ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr); 141 } 142 143 void CompileUnit::fixupForwardReferences() { 144 for (const auto &Ref : ForwardDIEReferences) { 145 DIE *RefDie; 146 const CompileUnit *RefUnit; 147 PatchLocation Attr; 148 DeclContext *Ctxt; 149 std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref; 150 if (Ctxt && Ctxt->hasCanonicalDIE()) { 151 assert(Ctxt->getCanonicalDIEOffset() && 152 "Canonical die offset is not set"); 153 Attr.set(Ctxt->getCanonicalDIEOffset()); 154 } else { 155 assert(RefDie->getOffset() && "Referenced die offset is not set"); 156 Attr.set(RefDie->getOffset() + RefUnit->getStartOffset()); 157 } 158 } 159 } 160 161 void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) { 162 Labels.insert({LabelLowPc, PcOffset}); 163 } 164 165 void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, 166 int64_t PcOffset) { 167 Ranges.insert({FuncLowPc, FuncHighPc}, PcOffset); 168 if (LowPc) 169 LowPc = std::min(*LowPc, FuncLowPc + PcOffset); 170 else 171 LowPc = FuncLowPc + PcOffset; 172 this->HighPc = std::max(HighPc, FuncHighPc + PcOffset); 173 } 174 175 void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) { 176 if (Die.getTag() == dwarf::DW_TAG_compile_unit) { 177 UnitRangeAttribute = Attr; 178 return; 179 } 180 181 RangeAttributes.emplace_back(Attr); 182 } 183 184 void CompileUnit::noteLocationAttribute(PatchLocation Attr) { 185 LocationAttributes.emplace_back(Attr); 186 } 187 188 void CompileUnit::addNamespaceAccelerator(const DIE *Die, 189 DwarfStringPoolEntryRef Name) { 190 Namespaces.emplace_back(Name, Die); 191 } 192 193 void CompileUnit::addObjCAccelerator(const DIE *Die, 194 DwarfStringPoolEntryRef Name, 195 bool SkipPubSection) { 196 ObjC.emplace_back(Name, Die, SkipPubSection); 197 } 198 199 void CompileUnit::addNameAccelerator(const DIE *Die, 200 DwarfStringPoolEntryRef Name, 201 bool SkipPubSection) { 202 Pubnames.emplace_back(Name, Die, SkipPubSection); 203 } 204 205 void CompileUnit::addTypeAccelerator(const DIE *Die, 206 DwarfStringPoolEntryRef Name, 207 bool ObjcClassImplementation, 208 uint32_t QualifiedNameHash) { 209 Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation); 210 } 211 212 } // namespace llvm 213