217 lines · cpp
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-exception6//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 16namespace llvm {17 18using namespace dwarf_linker;19using namespace dwarf_linker::classic;20 21#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)22LLVM_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.40static 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 49uint16_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 57StringRef 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 65void 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 that75 // just for variables, because functions will be handled depending on76 // 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 127uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) {128 NextUnitOffset = StartOffset;129 if (NewUnit) {130 NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size131 NextUnitOffset += NewUnit->getUnitDie().getSize();132 }133 return NextUnitOffset;134}135 136/// Keep track of a forward cross-cu reference from this unit137/// to \p Die that lives in \p RefUnit.138void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit,139 DeclContext *Ctxt, PatchLocation Attr) {140 ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr);141}142 143void 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 161void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) {162 Labels.insert({LabelLowPc, PcOffset});163}164 165void 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 else171 LowPc = FuncLowPc + PcOffset;172 this->HighPc = std::max(HighPc, FuncHighPc + PcOffset);173}174 175void 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 184void CompileUnit::noteLocationAttribute(PatchLocation Attr) {185 LocationAttributes.emplace_back(Attr);186}187 188void CompileUnit::noteStmtSeqListAttribute(PatchLocation Attr) {189 StmtSeqListAttributes.emplace_back(Attr);190}191 192void CompileUnit::addNamespaceAccelerator(const DIE *Die,193 DwarfStringPoolEntryRef Name) {194 Namespaces.emplace_back(Name, Die);195}196 197void CompileUnit::addObjCAccelerator(const DIE *Die,198 DwarfStringPoolEntryRef Name,199 bool SkipPubSection) {200 ObjC.emplace_back(Name, Die, SkipPubSection);201}202 203void CompileUnit::addNameAccelerator(const DIE *Die,204 DwarfStringPoolEntryRef Name,205 bool SkipPubSection) {206 Pubnames.emplace_back(Name, Die, SkipPubSection);207}208 209void CompileUnit::addTypeAccelerator(const DIE *Die,210 DwarfStringPoolEntryRef Name,211 bool ObjcClassImplementation,212 uint32_t QualifiedNameHash) {213 Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation);214}215 216} // namespace llvm217