1 //=== AcceleratorRecordsSaver.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 "AcceleratorRecordsSaver.h"
10 #include "llvm/DWARFLinker/Utils.h"
11 #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
12 #include "llvm/Support/DJB.h"
15 using namespace dwarf_linker
;
16 using namespace dwarf_linker::parallel
;
18 static uint32_t hashFullyQualifiedName(CompileUnit
&InputCU
, DWARFDie
&InputDIE
,
19 int ChildRecurseDepth
= 0) {
20 const char *Name
= nullptr;
21 CompileUnit
*CU
= &InputCU
;
22 std::optional
<DWARFFormValue
> RefVal
;
24 if (Error Err
= finiteLoop([&]() -> Expected
<bool> {
25 if (const char *CurrentName
= InputDIE
.getName(DINameKind::ShortName
))
28 if (!(RefVal
= InputDIE
.find(dwarf::DW_AT_specification
)) &&
29 !(RefVal
= InputDIE
.find(dwarf::DW_AT_abstract_origin
)))
32 if (!RefVal
->isFormClass(DWARFFormValue::FC_Reference
))
35 std::optional
<UnitEntryPairTy
> RefDie
= CU
->resolveDIEReference(
36 *RefVal
, ResolveInterCUReferencesMode::Resolve
);
40 if (!RefDie
->DieEntry
)
44 InputDIE
= RefDie
->CU
->getDIE(RefDie
->DieEntry
);
47 consumeError(std::move(Err
));
50 if (!Name
&& InputDIE
.getTag() == dwarf::DW_TAG_namespace
)
51 Name
= "(anonymous namespace)";
53 DWARFDie ParentDie
= InputDIE
.getParent();
54 if (!ParentDie
.isValid() || ParentDie
.getTag() == dwarf::DW_TAG_compile_unit
)
55 return djbHash(Name
? Name
: "", djbHash(ChildRecurseDepth
? "" : "::"));
59 djbHash((Name
? "::" : ""),
60 hashFullyQualifiedName(*CU
, ParentDie
, ++ChildRecurseDepth
)));
63 void AcceleratorRecordsSaver::save(const DWARFDebugInfoEntry
*InputDieEntry
,
64 DIE
*OutDIE
, AttributesInfo
&AttrInfo
,
65 TypeEntry
*TypeEntry
) {
66 if (GlobalData
.getOptions().AccelTables
.empty())
69 DWARFDie InputDIE
= InUnit
.getDIE(InputDieEntry
);
71 // Look for short name recursively if short name is not known yet.
72 if (AttrInfo
.Name
== nullptr)
73 if (const char *ShortName
= InputDIE
.getShortName())
74 AttrInfo
.Name
= GlobalData
.getStringPool().insert(ShortName
).first
;
76 switch (InputDieEntry
->getTag()) {
77 case dwarf::DW_TAG_array_type
:
78 case dwarf::DW_TAG_class_type
:
79 case dwarf::DW_TAG_enumeration_type
:
80 case dwarf::DW_TAG_pointer_type
:
81 case dwarf::DW_TAG_reference_type
:
82 case dwarf::DW_TAG_string_type
:
83 case dwarf::DW_TAG_structure_type
:
84 case dwarf::DW_TAG_subroutine_type
:
85 case dwarf::DW_TAG_typedef
:
86 case dwarf::DW_TAG_union_type
:
87 case dwarf::DW_TAG_ptr_to_member_type
:
88 case dwarf::DW_TAG_set_type
:
89 case dwarf::DW_TAG_subrange_type
:
90 case dwarf::DW_TAG_base_type
:
91 case dwarf::DW_TAG_const_type
:
92 case dwarf::DW_TAG_constant
:
93 case dwarf::DW_TAG_file_type
:
94 case dwarf::DW_TAG_namelist
:
95 case dwarf::DW_TAG_packed_type
:
96 case dwarf::DW_TAG_volatile_type
:
97 case dwarf::DW_TAG_restrict_type
:
98 case dwarf::DW_TAG_atomic_type
:
99 case dwarf::DW_TAG_interface_type
:
100 case dwarf::DW_TAG_unspecified_type
:
101 case dwarf::DW_TAG_shared_type
:
102 case dwarf::DW_TAG_immutable_type
:
103 case dwarf::DW_TAG_rvalue_reference_type
: {
104 if (!AttrInfo
.IsDeclaration
&& AttrInfo
.Name
!= nullptr &&
105 !AttrInfo
.Name
->getKey().empty()) {
106 uint32_t Hash
= hashFullyQualifiedName(InUnit
, InputDIE
);
108 uint64_t RuntimeLang
=
109 dwarf::toUnsigned(InputDIE
.find(dwarf::DW_AT_APPLE_runtime_class
))
112 bool ObjCClassIsImplementation
=
113 (RuntimeLang
== dwarf::DW_LANG_ObjC
||
114 RuntimeLang
== dwarf::DW_LANG_ObjC_plus_plus
) &&
116 InputDIE
.find(dwarf::DW_AT_APPLE_objc_complete_type
))
119 saveTypeRecord(AttrInfo
.Name
, OutDIE
, InputDieEntry
->getTag(), Hash
,
120 ObjCClassIsImplementation
, TypeEntry
);
123 case dwarf::DW_TAG_namespace
: {
124 if (AttrInfo
.Name
== nullptr)
126 GlobalData
.getStringPool().insert("(anonymous namespace)").first
;
128 saveNamespaceRecord(AttrInfo
.Name
, OutDIE
, InputDieEntry
->getTag(),
131 case dwarf::DW_TAG_imported_declaration
: {
132 if (AttrInfo
.Name
!= nullptr)
133 saveNamespaceRecord(AttrInfo
.Name
, OutDIE
, InputDieEntry
->getTag(),
136 case dwarf::DW_TAG_compile_unit
:
137 case dwarf::DW_TAG_lexical_block
: {
142 // Do not store this kind of accelerator entries for type entries.
145 if (AttrInfo
.HasLiveAddress
|| AttrInfo
.HasRanges
) {
147 saveNameRecord(AttrInfo
.Name
, OutDIE
, InputDieEntry
->getTag(),
148 InputDieEntry
->getTag() ==
149 dwarf::DW_TAG_inlined_subroutine
);
151 // Look for mangled name recursively if mangled name is not known yet.
152 if (!AttrInfo
.MangledName
)
153 if (const char *LinkageName
= InputDIE
.getLinkageName())
154 AttrInfo
.MangledName
=
155 GlobalData
.getStringPool().insert(LinkageName
).first
;
157 if (AttrInfo
.MangledName
&& AttrInfo
.MangledName
!= AttrInfo
.Name
)
158 saveNameRecord(AttrInfo
.MangledName
, OutDIE
, InputDieEntry
->getTag(),
159 InputDieEntry
->getTag() ==
160 dwarf::DW_TAG_inlined_subroutine
);
162 // Strip template parameters from the short name.
163 if (AttrInfo
.Name
&& AttrInfo
.MangledName
!= AttrInfo
.Name
&&
164 (InputDieEntry
->getTag() != dwarf::DW_TAG_inlined_subroutine
)) {
165 if (std::optional
<StringRef
> Name
=
166 StripTemplateParameters(AttrInfo
.Name
->getKey())) {
167 StringEntry
*NameWithoutTemplateParams
=
168 GlobalData
.getStringPool().insert(*Name
).first
;
170 saveNameRecord(NameWithoutTemplateParams
, OutDIE
,
171 InputDieEntry
->getTag(), true);
176 saveObjC(InputDieEntry
, OutDIE
, AttrInfo
);
182 void AcceleratorRecordsSaver::saveObjC(const DWARFDebugInfoEntry
*InputDieEntry
,
183 DIE
*OutDIE
, AttributesInfo
&AttrInfo
) {
184 std::optional
<ObjCSelectorNames
> Names
=
185 getObjCNamesIfSelector(AttrInfo
.Name
->getKey());
189 StringEntry
*Selector
=
190 GlobalData
.getStringPool().insert(Names
->Selector
).first
;
191 saveNameRecord(Selector
, OutDIE
, InputDieEntry
->getTag(), true);
192 StringEntry
*ClassName
=
193 GlobalData
.getStringPool().insert(Names
->ClassName
).first
;
194 saveObjCNameRecord(ClassName
, OutDIE
, InputDieEntry
->getTag());
195 if (Names
->ClassNameNoCategory
) {
196 StringEntry
*ClassNameNoCategory
=
197 GlobalData
.getStringPool().insert(*Names
->ClassNameNoCategory
).first
;
198 saveObjCNameRecord(ClassNameNoCategory
, OutDIE
, InputDieEntry
->getTag());
200 if (Names
->MethodNameNoCategory
) {
201 StringEntry
*MethodNameNoCategory
=
202 GlobalData
.getStringPool().insert(*Names
->MethodNameNoCategory
).first
;
203 saveNameRecord(MethodNameNoCategory
, OutDIE
, InputDieEntry
->getTag(), true);
207 void AcceleratorRecordsSaver::saveNameRecord(StringEntry
*Name
, DIE
*OutDIE
,
209 bool AvoidForPubSections
) {
210 DwarfUnit::AccelInfo Info
;
212 Info
.Type
= DwarfUnit::AccelType::Name
;
214 Info
.OutOffset
= OutDIE
->getOffset();
216 Info
.AvoidForPubSections
= AvoidForPubSections
;
218 OutUnit
.getAsCompileUnit()->saveAcceleratorInfo(Info
);
220 void AcceleratorRecordsSaver::saveNamespaceRecord(StringEntry
*Name
,
221 DIE
*OutDIE
, dwarf::Tag Tag
,
222 TypeEntry
*TypeEntry
) {
223 if (OutUnit
.isCompileUnit()) {
224 assert(TypeEntry
== nullptr);
225 DwarfUnit::AccelInfo Info
;
227 Info
.Type
= DwarfUnit::AccelType::Namespace
;
229 Info
.OutOffset
= OutDIE
->getOffset();
232 OutUnit
.getAsCompileUnit()->saveAcceleratorInfo(Info
);
236 assert(TypeEntry
!= nullptr);
237 TypeUnit::TypeUnitAccelInfo Info
;
238 Info
.Type
= DwarfUnit::AccelType::Namespace
;
240 Info
.OutOffset
= 0xbaddef;
242 Info
.OutDIE
= OutDIE
;
243 Info
.TypeEntryBodyPtr
= TypeEntry
->getValue().load();
245 OutUnit
.getAsTypeUnit()->saveAcceleratorInfo(Info
);
248 void AcceleratorRecordsSaver::saveObjCNameRecord(StringEntry
*Name
, DIE
*OutDIE
,
250 DwarfUnit::AccelInfo Info
;
252 Info
.Type
= DwarfUnit::AccelType::ObjC
;
254 Info
.OutOffset
= OutDIE
->getOffset();
256 Info
.AvoidForPubSections
= true;
258 OutUnit
.getAsCompileUnit()->saveAcceleratorInfo(Info
);
261 void AcceleratorRecordsSaver::saveTypeRecord(StringEntry
*Name
, DIE
*OutDIE
,
263 uint32_t QualifiedNameHash
,
264 bool ObjcClassImplementation
,
265 TypeEntry
*TypeEntry
) {
266 if (OutUnit
.isCompileUnit()) {
267 assert(TypeEntry
== nullptr);
268 DwarfUnit::AccelInfo Info
;
270 Info
.Type
= DwarfUnit::AccelType::Type
;
272 Info
.OutOffset
= OutDIE
->getOffset();
274 Info
.QualifiedNameHash
= QualifiedNameHash
;
275 Info
.ObjcClassImplementation
= ObjcClassImplementation
;
277 OutUnit
.getAsCompileUnit()->saveAcceleratorInfo(Info
);
281 assert(TypeEntry
!= nullptr);
282 TypeUnit::TypeUnitAccelInfo Info
;
284 Info
.Type
= DwarfUnit::AccelType::Type
;
286 Info
.OutOffset
= 0xbaddef;
288 Info
.QualifiedNameHash
= QualifiedNameHash
;
289 Info
.ObjcClassImplementation
= ObjcClassImplementation
;
290 Info
.OutDIE
= OutDIE
;
291 Info
.TypeEntryBodyPtr
= TypeEntry
->getValue().load();
292 OutUnit
.getAsTypeUnit()->saveAcceleratorInfo(Info
);