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(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 | DWARFDie CU = getOrigUnit().getUnitDIE(); |
52 | Language = dwarf::toUnsigned(V: CU.find(Attr: dwarf::DW_AT_language), Default: 0); |
53 | } |
54 | return Language; |
55 | } |
56 | |
57 | StringRef CompileUnit::getSysRoot() { |
58 | if (SysRoot.empty()) { |
59 | DWARFDie CU = getOrigUnit().getUnitDIE(); |
60 | SysRoot = dwarf::toStringRef(V: CU.find(Attr: 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(Index: 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(Attr: dwarf::DW_AT_location))) { |
83 | if ((Value = DIE.find(Attr: dwarf::DW_AT_const_value)) && |
84 | !inFunctionScope(U&: *this, Idx: I.ParentIdx)) |
85 | I.InDebugMap = true; |
86 | continue; |
87 | } |
88 | |
89 | if (auto ExprLockBlock = Value->getAsBlock()) { |
90 | // Parse 'exprloc' expression. |
91 | DataExtractor Data(toStringRef(Input: *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(args&: Die, args&: RefUnit, args&: Ctxt, args&: 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(args&: RefDie, args&: RefUnit, args&: Ctxt, args&: 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(KV: {LabelLowPc, PcOffset}); |
163 | } |
164 | |
165 | void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, |
166 | int64_t PcOffset) { |
167 | Ranges.insert(Range: {FuncLowPc, FuncHighPc}, Value: PcOffset); |
168 | if (LowPc) |
169 | LowPc = std::min(a: *LowPc, b: FuncLowPc + PcOffset); |
170 | else |
171 | LowPc = FuncLowPc + PcOffset; |
172 | this->HighPc = std::max(a: HighPc, b: 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(Args&: Attr); |
182 | } |
183 | |
184 | void CompileUnit::noteLocationAttribute(PatchLocation Attr) { |
185 | LocationAttributes.emplace_back(Args&: Attr); |
186 | } |
187 | |
188 | void CompileUnit::addNamespaceAccelerator(const DIE *Die, |
189 | DwarfStringPoolEntryRef Name) { |
190 | Namespaces.emplace_back(args&: Name, args&: Die); |
191 | } |
192 | |
193 | void CompileUnit::addObjCAccelerator(const DIE *Die, |
194 | DwarfStringPoolEntryRef Name, |
195 | bool SkipPubSection) { |
196 | ObjC.emplace_back(args&: Name, args&: Die, args&: SkipPubSection); |
197 | } |
198 | |
199 | void CompileUnit::addNameAccelerator(const DIE *Die, |
200 | DwarfStringPoolEntryRef Name, |
201 | bool SkipPubSection) { |
202 | Pubnames.emplace_back(args&: Name, args&: Die, args&: SkipPubSection); |
203 | } |
204 | |
205 | void CompileUnit::addTypeAccelerator(const DIE *Die, |
206 | DwarfStringPoolEntryRef Name, |
207 | bool ObjcClassImplementation, |
208 | uint32_t QualifiedNameHash) { |
209 | Pubtypes.emplace_back(args&: Name, args&: Die, args&: QualifiedNameHash, args&: ObjcClassImplementation); |
210 | } |
211 | |
212 | } // namespace llvm |
213 | |