1 //===- DWARFLinkerCompileUnit.cpp -----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
18 using namespace dwarf_linker
;
19 using namespace dwarf_linker::classic
;
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";
37 #endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
39 /// Check if the DIE at \p Idx is in the scope of a function.
40 static bool inFunctionScope(CompileUnit
&U
, unsigned Idx
) {
42 if (U
.getOrigUnit().getDIEAtIndex(Idx
).getTag() == dwarf::DW_TAG_subprogram
)
44 Idx
= U
.getInfo(Idx
).ParentIdx
;
49 uint16_t CompileUnit::getLanguage() {
51 DWARFDie CU
= getOrigUnit().getUnitDIE();
52 Language
= dwarf::toUnsigned(CU
.find(dwarf::DW_AT_language
), 0);
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();
65 void CompileUnit::markEverythingAsKept() {
68 for (auto &I
: Info
) {
69 // Mark everything that wasn't explicit marked for pruning.
71 auto DIE
= OrigUnit
.getDIEAtIndex(Idx
++);
72 DWARFUnit
*U
= DIE
.getDwarfUnit();
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
)
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
))
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
);
97 for (DWARFExpression::iterator It
= Expression
.begin();
98 (It
!= Expression
.end()) && !I
.InDebugMap
; ++It
) {
99 DWARFExpression::iterator NextIt
= It
;
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
)
113 case dwarf::DW_OP_constx
:
114 case dwarf::DW_OP_addr
:
115 case dwarf::DW_OP_addrx
:
127 uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion
) {
128 NextUnitOffset
= StartOffset
;
130 NextUnitOffset
+= (DwarfVersion
>= 5) ? 12 : 11; // Header size
131 NextUnitOffset
+= NewUnit
->getUnitDie().getSize();
133 return NextUnitOffset
;
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
);
143 void CompileUnit::fixupForwardReferences() {
144 for (const auto &Ref
: ForwardDIEReferences
) {
146 const CompileUnit
*RefUnit
;
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());
155 assert(RefDie
->getOffset() && "Referenced die offset is not set");
156 Attr
.set(RefDie
->getOffset() + RefUnit
->getStartOffset());
161 void CompileUnit::addLabelLowPc(uint64_t LabelLowPc
, int64_t PcOffset
) {
162 Labels
.insert({LabelLowPc
, PcOffset
});
165 void CompileUnit::addFunctionRange(uint64_t FuncLowPc
, uint64_t FuncHighPc
,
167 Ranges
.insert({FuncLowPc
, FuncHighPc
}, PcOffset
);
169 LowPc
= std::min(*LowPc
, FuncLowPc
+ PcOffset
);
171 LowPc
= FuncLowPc
+ PcOffset
;
172 this->HighPc
= std::max(HighPc
, FuncHighPc
+ PcOffset
);
175 void CompileUnit::noteRangeAttribute(const DIE
&Die
, PatchLocation Attr
) {
176 if (Die
.getTag() == dwarf::DW_TAG_compile_unit
) {
177 UnitRangeAttribute
= Attr
;
181 RangeAttributes
.emplace_back(Attr
);
184 void CompileUnit::noteLocationAttribute(PatchLocation Attr
) {
185 LocationAttributes
.emplace_back(Attr
);
188 void CompileUnit::addNamespaceAccelerator(const DIE
*Die
,
189 DwarfStringPoolEntryRef Name
) {
190 Namespaces
.emplace_back(Name
, Die
);
193 void CompileUnit::addObjCAccelerator(const DIE
*Die
,
194 DwarfStringPoolEntryRef Name
,
195 bool SkipPubSection
) {
196 ObjC
.emplace_back(Name
, Die
, SkipPubSection
);
199 void CompileUnit::addNameAccelerator(const DIE
*Die
,
200 DwarfStringPoolEntryRef Name
,
201 bool SkipPubSection
) {
202 Pubnames
.emplace_back(Name
, Die
, SkipPubSection
);
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
);