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/DWARFLinkerCompileUnit.h"
10 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
14 /// Check if the DIE at \p Idx is in the scope of a function.
15 static bool inFunctionScope(CompileUnit
&U
, unsigned Idx
) {
17 if (U
.getOrigUnit().getDIEAtIndex(Idx
).getTag() == dwarf::DW_TAG_subprogram
)
19 Idx
= U
.getInfo(Idx
).ParentIdx
;
24 uint16_t CompileUnit::getLanguage() {
26 DWARFDie CU
= getOrigUnit().getUnitDIE();
27 Language
= dwarf::toUnsigned(CU
.find(dwarf::DW_AT_language
), 0);
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();
40 void CompileUnit::markEverythingAsKept() {
43 setHasInterestingContent();
45 for (auto &I
: Info
) {
46 // Mark everything that wasn't explicit marked for pruning.
48 auto DIE
= OrigUnit
.getDIEAtIndex(Idx
++);
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
)
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
))
64 if (auto Block
= Value
->getAsBlock()) {
65 if (Block
->size() > OrigUnit
.getAddressByteSize() &&
66 (*Block
)[0] == dwarf::DW_OP_addr
)
72 uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion
) {
73 NextUnitOffset
= StartOffset
;
75 NextUnitOffset
+= (DwarfVersion
>= 5) ? 12 : 11; // Header size
76 NextUnitOffset
+= NewUnit
->getUnitDie().getSize();
78 return NextUnitOffset
;
81 /// Keep track of a forward cross-cu reference from this unit
82 /// to \p Die that lives in \p RefUnit.
83 void CompileUnit::noteForwardReference(DIE
*Die
, const CompileUnit
*RefUnit
,
84 DeclContext
*Ctxt
, PatchLocation Attr
) {
85 ForwardDIEReferences
.emplace_back(Die
, RefUnit
, Ctxt
, Attr
);
88 void CompileUnit::fixupForwardReferences() {
89 for (const auto &Ref
: ForwardDIEReferences
) {
91 const CompileUnit
*RefUnit
;
94 std::tie(RefDie
, RefUnit
, Ctxt
, Attr
) = Ref
;
95 if (Ctxt
&& Ctxt
->getCanonicalDIEOffset())
96 Attr
.set(Ctxt
->getCanonicalDIEOffset());
98 Attr
.set(RefDie
->getOffset() + RefUnit
->getStartOffset());
102 void CompileUnit::addLabelLowPc(uint64_t LabelLowPc
, int64_t PcOffset
) {
103 Labels
.insert({LabelLowPc
, PcOffset
});
106 void CompileUnit::addFunctionRange(uint64_t FuncLowPc
, uint64_t FuncHighPc
,
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
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
);
117 void CompileUnit::noteRangeAttribute(const DIE
&Die
, PatchLocation Attr
) {
118 if (Die
.getTag() != dwarf::DW_TAG_compile_unit
)
119 RangeAttributes
.push_back(Attr
);
121 UnitRangeAttribute
= Attr
;
124 void CompileUnit::noteLocationAttribute(PatchLocation Attr
, int64_t PcOffset
) {
125 LocationAttributes
.emplace_back(Attr
, PcOffset
);
128 void CompileUnit::addNamespaceAccelerator(const DIE
*Die
,
129 DwarfStringPoolEntryRef Name
) {
130 Namespaces
.emplace_back(Name
, Die
);
133 void CompileUnit::addObjCAccelerator(const DIE
*Die
,
134 DwarfStringPoolEntryRef Name
,
135 bool SkipPubSection
) {
136 ObjC
.emplace_back(Name
, Die
, SkipPubSection
);
139 void CompileUnit::addNameAccelerator(const DIE
*Die
,
140 DwarfStringPoolEntryRef Name
,
141 bool SkipPubSection
) {
142 Pubnames
.emplace_back(Name
, Die
, SkipPubSection
);
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
);