1*1db9f3b2SDimitry Andric //===- DWARFLinkerCompileUnit.cpp -----------------------------------------===//
2*1db9f3b2SDimitry Andric //
3*1db9f3b2SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*1db9f3b2SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*1db9f3b2SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*1db9f3b2SDimitry Andric //
7*1db9f3b2SDimitry Andric //===----------------------------------------------------------------------===//
8*1db9f3b2SDimitry Andric 
9*1db9f3b2SDimitry Andric #include "llvm/DWARFLinker/Classic/DWARFLinkerCompileUnit.h"
10*1db9f3b2SDimitry Andric #include "llvm/ADT/StringExtras.h"
11*1db9f3b2SDimitry Andric #include "llvm/DWARFLinker/Classic/DWARFLinkerDeclContext.h"
12*1db9f3b2SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
13*1db9f3b2SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
14*1db9f3b2SDimitry Andric #include "llvm/Support/FormatVariadic.h"
15*1db9f3b2SDimitry Andric 
16*1db9f3b2SDimitry Andric namespace llvm {
17*1db9f3b2SDimitry Andric 
18*1db9f3b2SDimitry Andric using namespace dwarf_linker;
19*1db9f3b2SDimitry Andric using namespace dwarf_linker::classic;
20*1db9f3b2SDimitry Andric 
21*1db9f3b2SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump()22*1db9f3b2SDimitry Andric LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() {
23*1db9f3b2SDimitry Andric   llvm::errs() << "{\n";
24*1db9f3b2SDimitry Andric   llvm::errs() << "  AddrAdjust: " << AddrAdjust << '\n';
25*1db9f3b2SDimitry Andric   llvm::errs() << "  Ctxt: " << formatv("{0:x}", Ctxt) << '\n';
26*1db9f3b2SDimitry Andric   llvm::errs() << "  Clone: " << formatv("{0:x}", Clone) << '\n';
27*1db9f3b2SDimitry Andric   llvm::errs() << "  ParentIdx: " << ParentIdx << '\n';
28*1db9f3b2SDimitry Andric   llvm::errs() << "  Keep: " << Keep << '\n';
29*1db9f3b2SDimitry Andric   llvm::errs() << "  InDebugMap: " << InDebugMap << '\n';
30*1db9f3b2SDimitry Andric   llvm::errs() << "  Prune: " << Prune << '\n';
31*1db9f3b2SDimitry Andric   llvm::errs() << "  Incomplete: " << Incomplete << '\n';
32*1db9f3b2SDimitry Andric   llvm::errs() << "  InModuleScope: " << InModuleScope << '\n';
33*1db9f3b2SDimitry Andric   llvm::errs() << "  ODRMarkingDone: " << ODRMarkingDone << '\n';
34*1db9f3b2SDimitry Andric   llvm::errs() << "  UnclonedReference: " << UnclonedReference << '\n';
35*1db9f3b2SDimitry Andric   llvm::errs() << "}\n";
36*1db9f3b2SDimitry Andric }
37*1db9f3b2SDimitry Andric #endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
38*1db9f3b2SDimitry Andric 
39*1db9f3b2SDimitry Andric /// Check if the DIE at \p Idx is in the scope of a function.
inFunctionScope(CompileUnit & U,unsigned Idx)40*1db9f3b2SDimitry Andric static bool inFunctionScope(CompileUnit &U, unsigned Idx) {
41*1db9f3b2SDimitry Andric   while (Idx) {
42*1db9f3b2SDimitry Andric     if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram)
43*1db9f3b2SDimitry Andric       return true;
44*1db9f3b2SDimitry Andric     Idx = U.getInfo(Idx).ParentIdx;
45*1db9f3b2SDimitry Andric   }
46*1db9f3b2SDimitry Andric   return false;
47*1db9f3b2SDimitry Andric }
48*1db9f3b2SDimitry Andric 
getLanguage()49*1db9f3b2SDimitry Andric uint16_t CompileUnit::getLanguage() {
50*1db9f3b2SDimitry Andric   if (!Language) {
51*1db9f3b2SDimitry Andric     DWARFDie CU = getOrigUnit().getUnitDIE();
52*1db9f3b2SDimitry Andric     Language = dwarf::toUnsigned(CU.find(dwarf::DW_AT_language), 0);
53*1db9f3b2SDimitry Andric   }
54*1db9f3b2SDimitry Andric   return Language;
55*1db9f3b2SDimitry Andric }
56*1db9f3b2SDimitry Andric 
getSysRoot()57*1db9f3b2SDimitry Andric StringRef CompileUnit::getSysRoot() {
58*1db9f3b2SDimitry Andric   if (SysRoot.empty()) {
59*1db9f3b2SDimitry Andric     DWARFDie CU = getOrigUnit().getUnitDIE();
60*1db9f3b2SDimitry Andric     SysRoot = dwarf::toStringRef(CU.find(dwarf::DW_AT_LLVM_sysroot)).str();
61*1db9f3b2SDimitry Andric   }
62*1db9f3b2SDimitry Andric   return SysRoot;
63*1db9f3b2SDimitry Andric }
64*1db9f3b2SDimitry Andric 
markEverythingAsKept()65*1db9f3b2SDimitry Andric void CompileUnit::markEverythingAsKept() {
66*1db9f3b2SDimitry Andric   unsigned Idx = 0;
67*1db9f3b2SDimitry Andric 
68*1db9f3b2SDimitry Andric   for (auto &I : Info) {
69*1db9f3b2SDimitry Andric     // Mark everything that wasn't explicit marked for pruning.
70*1db9f3b2SDimitry Andric     I.Keep = !I.Prune;
71*1db9f3b2SDimitry Andric     auto DIE = OrigUnit.getDIEAtIndex(Idx++);
72*1db9f3b2SDimitry Andric     DWARFUnit *U = DIE.getDwarfUnit();
73*1db9f3b2SDimitry Andric 
74*1db9f3b2SDimitry Andric     // Try to guess which DIEs must go to the accelerator tables. We do that
75*1db9f3b2SDimitry Andric     // just for variables, because functions will be handled depending on
76*1db9f3b2SDimitry Andric     // whether they carry a DW_AT_low_pc attribute or not.
77*1db9f3b2SDimitry Andric     if (DIE.getTag() != dwarf::DW_TAG_variable &&
78*1db9f3b2SDimitry Andric         DIE.getTag() != dwarf::DW_TAG_constant)
79*1db9f3b2SDimitry Andric       continue;
80*1db9f3b2SDimitry Andric 
81*1db9f3b2SDimitry Andric     std::optional<DWARFFormValue> Value;
82*1db9f3b2SDimitry Andric     if (!(Value = DIE.find(dwarf::DW_AT_location))) {
83*1db9f3b2SDimitry Andric       if ((Value = DIE.find(dwarf::DW_AT_const_value)) &&
84*1db9f3b2SDimitry Andric           !inFunctionScope(*this, I.ParentIdx))
85*1db9f3b2SDimitry Andric         I.InDebugMap = true;
86*1db9f3b2SDimitry Andric       continue;
87*1db9f3b2SDimitry Andric     }
88*1db9f3b2SDimitry Andric 
89*1db9f3b2SDimitry Andric     if (auto ExprLockBlock = Value->getAsBlock()) {
90*1db9f3b2SDimitry Andric       // Parse 'exprloc' expression.
91*1db9f3b2SDimitry Andric       DataExtractor Data(toStringRef(*ExprLockBlock),
92*1db9f3b2SDimitry Andric                          U->getContext().isLittleEndian(),
93*1db9f3b2SDimitry Andric                          U->getAddressByteSize());
94*1db9f3b2SDimitry Andric       DWARFExpression Expression(Data, U->getAddressByteSize(),
95*1db9f3b2SDimitry Andric                                  U->getFormParams().Format);
96*1db9f3b2SDimitry Andric 
97*1db9f3b2SDimitry Andric       for (DWARFExpression::iterator It = Expression.begin();
98*1db9f3b2SDimitry Andric            (It != Expression.end()) && !I.InDebugMap; ++It) {
99*1db9f3b2SDimitry Andric         DWARFExpression::iterator NextIt = It;
100*1db9f3b2SDimitry Andric         ++NextIt;
101*1db9f3b2SDimitry Andric 
102*1db9f3b2SDimitry Andric         switch (It->getCode()) {
103*1db9f3b2SDimitry Andric         case dwarf::DW_OP_const2u:
104*1db9f3b2SDimitry Andric         case dwarf::DW_OP_const4u:
105*1db9f3b2SDimitry Andric         case dwarf::DW_OP_const8u:
106*1db9f3b2SDimitry Andric         case dwarf::DW_OP_const2s:
107*1db9f3b2SDimitry Andric         case dwarf::DW_OP_const4s:
108*1db9f3b2SDimitry Andric         case dwarf::DW_OP_const8s:
109*1db9f3b2SDimitry Andric           if (NextIt == Expression.end() ||
110*1db9f3b2SDimitry Andric               NextIt->getCode() != dwarf::DW_OP_form_tls_address)
111*1db9f3b2SDimitry Andric             break;
112*1db9f3b2SDimitry Andric           [[fallthrough]];
113*1db9f3b2SDimitry Andric         case dwarf::DW_OP_constx:
114*1db9f3b2SDimitry Andric         case dwarf::DW_OP_addr:
115*1db9f3b2SDimitry Andric         case dwarf::DW_OP_addrx:
116*1db9f3b2SDimitry Andric           I.InDebugMap = true;
117*1db9f3b2SDimitry Andric           break;
118*1db9f3b2SDimitry Andric         default:
119*1db9f3b2SDimitry Andric           // Nothing to do.
120*1db9f3b2SDimitry Andric           break;
121*1db9f3b2SDimitry Andric         }
122*1db9f3b2SDimitry Andric       }
123*1db9f3b2SDimitry Andric     }
124*1db9f3b2SDimitry Andric   }
125*1db9f3b2SDimitry Andric }
126*1db9f3b2SDimitry Andric 
computeNextUnitOffset(uint16_t DwarfVersion)127*1db9f3b2SDimitry Andric uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) {
128*1db9f3b2SDimitry Andric   NextUnitOffset = StartOffset;
129*1db9f3b2SDimitry Andric   if (NewUnit) {
130*1db9f3b2SDimitry Andric     NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size
131*1db9f3b2SDimitry Andric     NextUnitOffset += NewUnit->getUnitDie().getSize();
132*1db9f3b2SDimitry Andric   }
133*1db9f3b2SDimitry Andric   return NextUnitOffset;
134*1db9f3b2SDimitry Andric }
135*1db9f3b2SDimitry Andric 
136*1db9f3b2SDimitry Andric /// Keep track of a forward cross-cu reference from this unit
137*1db9f3b2SDimitry Andric /// to \p Die that lives in \p RefUnit.
noteForwardReference(DIE * Die,const CompileUnit * RefUnit,DeclContext * Ctxt,PatchLocation Attr)138*1db9f3b2SDimitry Andric void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
139*1db9f3b2SDimitry Andric                                        DeclContext *Ctxt, PatchLocation Attr) {
140*1db9f3b2SDimitry Andric   ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr);
141*1db9f3b2SDimitry Andric }
142*1db9f3b2SDimitry Andric 
fixupForwardReferences()143*1db9f3b2SDimitry Andric void CompileUnit::fixupForwardReferences() {
144*1db9f3b2SDimitry Andric   for (const auto &Ref : ForwardDIEReferences) {
145*1db9f3b2SDimitry Andric     DIE *RefDie;
146*1db9f3b2SDimitry Andric     const CompileUnit *RefUnit;
147*1db9f3b2SDimitry Andric     PatchLocation Attr;
148*1db9f3b2SDimitry Andric     DeclContext *Ctxt;
149*1db9f3b2SDimitry Andric     std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref;
150*1db9f3b2SDimitry Andric     if (Ctxt && Ctxt->hasCanonicalDIE()) {
151*1db9f3b2SDimitry Andric       assert(Ctxt->getCanonicalDIEOffset() &&
152*1db9f3b2SDimitry Andric              "Canonical die offset is not set");
153*1db9f3b2SDimitry Andric       Attr.set(Ctxt->getCanonicalDIEOffset());
154*1db9f3b2SDimitry Andric     } else {
155*1db9f3b2SDimitry Andric       assert(RefDie->getOffset() && "Referenced die offset is not set");
156*1db9f3b2SDimitry Andric       Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
157*1db9f3b2SDimitry Andric     }
158*1db9f3b2SDimitry Andric   }
159*1db9f3b2SDimitry Andric }
160*1db9f3b2SDimitry Andric 
addLabelLowPc(uint64_t LabelLowPc,int64_t PcOffset)161*1db9f3b2SDimitry Andric void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) {
162*1db9f3b2SDimitry Andric   Labels.insert({LabelLowPc, PcOffset});
163*1db9f3b2SDimitry Andric }
164*1db9f3b2SDimitry Andric 
addFunctionRange(uint64_t FuncLowPc,uint64_t FuncHighPc,int64_t PcOffset)165*1db9f3b2SDimitry Andric void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
166*1db9f3b2SDimitry Andric                                    int64_t PcOffset) {
167*1db9f3b2SDimitry Andric   Ranges.insert({FuncLowPc, FuncHighPc}, PcOffset);
168*1db9f3b2SDimitry Andric   if (LowPc)
169*1db9f3b2SDimitry Andric     LowPc = std::min(*LowPc, FuncLowPc + PcOffset);
170*1db9f3b2SDimitry Andric   else
171*1db9f3b2SDimitry Andric     LowPc = FuncLowPc + PcOffset;
172*1db9f3b2SDimitry Andric   this->HighPc = std::max(HighPc, FuncHighPc + PcOffset);
173*1db9f3b2SDimitry Andric }
174*1db9f3b2SDimitry Andric 
noteRangeAttribute(const DIE & Die,PatchLocation Attr)175*1db9f3b2SDimitry Andric void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) {
176*1db9f3b2SDimitry Andric   if (Die.getTag() == dwarf::DW_TAG_compile_unit) {
177*1db9f3b2SDimitry Andric     UnitRangeAttribute = Attr;
178*1db9f3b2SDimitry Andric     return;
179*1db9f3b2SDimitry Andric   }
180*1db9f3b2SDimitry Andric 
181*1db9f3b2SDimitry Andric   RangeAttributes.emplace_back(Attr);
182*1db9f3b2SDimitry Andric }
183*1db9f3b2SDimitry Andric 
noteLocationAttribute(PatchLocation Attr)184*1db9f3b2SDimitry Andric void CompileUnit::noteLocationAttribute(PatchLocation Attr) {
185*1db9f3b2SDimitry Andric   LocationAttributes.emplace_back(Attr);
186*1db9f3b2SDimitry Andric }
187*1db9f3b2SDimitry Andric 
addNamespaceAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name)188*1db9f3b2SDimitry Andric void CompileUnit::addNamespaceAccelerator(const DIE *Die,
189*1db9f3b2SDimitry Andric                                           DwarfStringPoolEntryRef Name) {
190*1db9f3b2SDimitry Andric   Namespaces.emplace_back(Name, Die);
191*1db9f3b2SDimitry Andric }
192*1db9f3b2SDimitry Andric 
addObjCAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name,bool SkipPubSection)193*1db9f3b2SDimitry Andric void CompileUnit::addObjCAccelerator(const DIE *Die,
194*1db9f3b2SDimitry Andric                                      DwarfStringPoolEntryRef Name,
195*1db9f3b2SDimitry Andric                                      bool SkipPubSection) {
196*1db9f3b2SDimitry Andric   ObjC.emplace_back(Name, Die, SkipPubSection);
197*1db9f3b2SDimitry Andric }
198*1db9f3b2SDimitry Andric 
addNameAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name,bool SkipPubSection)199*1db9f3b2SDimitry Andric void CompileUnit::addNameAccelerator(const DIE *Die,
200*1db9f3b2SDimitry Andric                                      DwarfStringPoolEntryRef Name,
201*1db9f3b2SDimitry Andric                                      bool SkipPubSection) {
202*1db9f3b2SDimitry Andric   Pubnames.emplace_back(Name, Die, SkipPubSection);
203*1db9f3b2SDimitry Andric }
204*1db9f3b2SDimitry Andric 
addTypeAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name,bool ObjcClassImplementation,uint32_t QualifiedNameHash)205*1db9f3b2SDimitry Andric void CompileUnit::addTypeAccelerator(const DIE *Die,
206*1db9f3b2SDimitry Andric                                      DwarfStringPoolEntryRef Name,
207*1db9f3b2SDimitry Andric                                      bool ObjcClassImplementation,
208*1db9f3b2SDimitry Andric                                      uint32_t QualifiedNameHash) {
209*1db9f3b2SDimitry Andric   Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation);
210*1db9f3b2SDimitry Andric }
211*1db9f3b2SDimitry Andric 
212*1db9f3b2SDimitry Andric } // namespace llvm
213