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
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(Index: 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 Language = getOrigUnit().getUnitDIE().getLanguage().value_or(u: 0);
52
53 return Language;
54}
55
56StringRef 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
64void 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
124uint64_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.
135void 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
140void 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
158void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) {
159 Labels.insert(KV: {LabelLowPc, PcOffset});
160}
161
162void 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
172void 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
181void CompileUnit::noteLocationAttribute(PatchLocation Attr) {
182 LocationAttributes.emplace_back(Args&: Attr);
183}
184
185void CompileUnit::noteStmtSeqListAttribute(PatchLocation Attr) {
186 StmtSeqListAttributes.emplace_back(Args&: Attr);
187}
188
189void CompileUnit::addNamespaceAccelerator(const DIE *Die,
190 DwarfStringPoolEntryRef Name) {
191 Namespaces.emplace_back(args&: Name, args&: Die);
192}
193
194void CompileUnit::addObjCAccelerator(const DIE *Die,
195 DwarfStringPoolEntryRef Name,
196 bool SkipPubSection) {
197 ObjC.emplace_back(args&: Name, args&: Die, args&: SkipPubSection);
198}
199
200void CompileUnit::addNameAccelerator(const DIE *Die,
201 DwarfStringPoolEntryRef Name,
202 bool SkipPubSection) {
203 Pubnames.emplace_back(args&: Name, args&: Die, args&: SkipPubSection);
204}
205
206void 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