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/DWARFLinkerCompileUnit.h"
10 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
11 #include "llvm/Support/FormatVariadic.h"
12 
13 namespace llvm {
14 
15 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump()16 LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() {
17   llvm::errs() << "{\n";
18   llvm::errs() << "  AddrAdjust: " << AddrAdjust << '\n';
19   llvm::errs() << "  Ctxt: " << formatv("{0:x}", Ctxt) << '\n';
20   llvm::errs() << "  Clone: " << formatv("{0:x}", Clone) << '\n';
21   llvm::errs() << "  ParentIdx: " << ParentIdx << '\n';
22   llvm::errs() << "  Keep: " << Keep << '\n';
23   llvm::errs() << "  InDebugMap: " << InDebugMap << '\n';
24   llvm::errs() << "  Prune: " << Prune << '\n';
25   llvm::errs() << "  Incomplete: " << Incomplete << '\n';
26   llvm::errs() << "  InModuleScope: " << InModuleScope << '\n';
27   llvm::errs() << "  ODRMarkingDone: " << ODRMarkingDone << '\n';
28   llvm::errs() << "  UnclonedReference: " << UnclonedReference << '\n';
29   llvm::errs() << "}\n";
30 }
31 #endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
32 
33 /// Check if the DIE at \p Idx is in the scope of a function.
inFunctionScope(CompileUnit & U,unsigned Idx)34 static bool inFunctionScope(CompileUnit &U, unsigned Idx) {
35   while (Idx) {
36     if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram)
37       return true;
38     Idx = U.getInfo(Idx).ParentIdx;
39   }
40   return false;
41 }
42 
getLanguage()43 uint16_t CompileUnit::getLanguage() {
44   if (!Language) {
45     DWARFDie CU = getOrigUnit().getUnitDIE();
46     Language = dwarf::toUnsigned(CU.find(dwarf::DW_AT_language), 0);
47   }
48   return Language;
49 }
50 
getSysRoot()51 StringRef CompileUnit::getSysRoot() {
52   if (SysRoot.empty()) {
53     DWARFDie CU = getOrigUnit().getUnitDIE();
54     SysRoot = dwarf::toStringRef(CU.find(dwarf::DW_AT_LLVM_sysroot)).str();
55   }
56   return SysRoot;
57 }
58 
markEverythingAsKept()59 void CompileUnit::markEverythingAsKept() {
60   unsigned Idx = 0;
61 
62   for (auto &I : Info) {
63     // Mark everything that wasn't explicit marked for pruning.
64     I.Keep = !I.Prune;
65     auto DIE = OrigUnit.getDIEAtIndex(Idx++);
66 
67     // Try to guess which DIEs must go to the accelerator tables. We do that
68     // just for variables, because functions will be handled depending on
69     // whether they carry a DW_AT_low_pc attribute or not.
70     if (DIE.getTag() != dwarf::DW_TAG_variable &&
71         DIE.getTag() != dwarf::DW_TAG_constant)
72       continue;
73 
74     std::optional<DWARFFormValue> Value;
75     if (!(Value = DIE.find(dwarf::DW_AT_location))) {
76       if ((Value = DIE.find(dwarf::DW_AT_const_value)) &&
77           !inFunctionScope(*this, I.ParentIdx))
78         I.InDebugMap = true;
79       continue;
80     }
81     if (auto Block = Value->getAsBlock()) {
82       if (Block->size() > OrigUnit.getAddressByteSize() &&
83           (*Block)[0] == dwarf::DW_OP_addr)
84         I.InDebugMap = true;
85     }
86   }
87 }
88 
computeNextUnitOffset(uint16_t DwarfVersion)89 uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) {
90   NextUnitOffset = StartOffset;
91   if (NewUnit) {
92     NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size
93     NextUnitOffset += NewUnit->getUnitDie().getSize();
94   }
95   return NextUnitOffset;
96 }
97 
98 /// Keep track of a forward cross-cu reference from this unit
99 /// to \p Die that lives in \p RefUnit.
noteForwardReference(DIE * Die,const CompileUnit * RefUnit,DeclContext * Ctxt,PatchLocation Attr)100 void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
101                                        DeclContext *Ctxt, PatchLocation Attr) {
102   ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr);
103 }
104 
fixupForwardReferences()105 void CompileUnit::fixupForwardReferences() {
106   for (const auto &Ref : ForwardDIEReferences) {
107     DIE *RefDie;
108     const CompileUnit *RefUnit;
109     PatchLocation Attr;
110     DeclContext *Ctxt;
111     std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref;
112     if (Ctxt && Ctxt->hasCanonicalDIE()) {
113       assert(Ctxt->getCanonicalDIEOffset() &&
114              "Canonical die offset is not set");
115       Attr.set(Ctxt->getCanonicalDIEOffset());
116     } else {
117       assert(RefDie->getOffset() && "Referenced die offset is not set");
118       Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
119     }
120   }
121 }
122 
addLabelLowPc(uint64_t LabelLowPc,int64_t PcOffset)123 void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) {
124   Labels.insert({LabelLowPc, PcOffset});
125 }
126 
addFunctionRange(uint64_t FuncLowPc,uint64_t FuncHighPc,int64_t PcOffset)127 void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
128                                    int64_t PcOffset) {
129   Ranges.insert({FuncLowPc, FuncHighPc}, PcOffset);
130   if (LowPc)
131     LowPc = std::min(*LowPc, FuncLowPc + PcOffset);
132   else
133     LowPc = FuncLowPc + PcOffset;
134   this->HighPc = std::max(HighPc, FuncHighPc + PcOffset);
135 }
136 
noteRangeAttribute(const DIE & Die,PatchLocation Attr)137 void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) {
138   if (Die.getTag() != dwarf::DW_TAG_compile_unit)
139     RangeAttributes.push_back(Attr);
140   else
141     UnitRangeAttribute = Attr;
142 }
143 
noteLocationAttribute(PatchLocation Attr,int64_t PcOffset)144 void CompileUnit::noteLocationAttribute(PatchLocation Attr, int64_t PcOffset) {
145   LocationAttributes.emplace_back(Attr, PcOffset);
146 }
147 
addNamespaceAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name)148 void CompileUnit::addNamespaceAccelerator(const DIE *Die,
149                                           DwarfStringPoolEntryRef Name) {
150   Namespaces.emplace_back(Name, Die);
151 }
152 
addObjCAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name,bool SkipPubSection)153 void CompileUnit::addObjCAccelerator(const DIE *Die,
154                                      DwarfStringPoolEntryRef Name,
155                                      bool SkipPubSection) {
156   ObjC.emplace_back(Name, Die, SkipPubSection);
157 }
158 
addNameAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name,bool SkipPubSection)159 void CompileUnit::addNameAccelerator(const DIE *Die,
160                                      DwarfStringPoolEntryRef Name,
161                                      bool SkipPubSection) {
162   Pubnames.emplace_back(Name, Die, SkipPubSection);
163 }
164 
addTypeAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name,bool ObjcClassImplementation,uint32_t QualifiedNameHash)165 void CompileUnit::addTypeAccelerator(const DIE *Die,
166                                      DwarfStringPoolEntryRef Name,
167                                      bool ObjcClassImplementation,
168                                      uint32_t QualifiedNameHash) {
169   Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation);
170 }
171 
172 } // namespace llvm
173