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