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