1//=== AcceleratorRecordsSaver.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 "AcceleratorRecordsSaver.h"
10#include "llvm/DWARFLinker/Utils.h"
11#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
12#include "llvm/Support/DJB.h"
13
14using namespace llvm;
15using namespace dwarf_linker;
16using namespace dwarf_linker::parallel;
17
18static 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;
23
24 if (Error Err = finiteLoop(Iteration: [&]() -> Expected<bool> {
25 if (const char *CurrentName = InputDIE.getName(Kind: DINameKind::ShortName))
26 Name = CurrentName;
27
28 if (!(RefVal = InputDIE.find(Attr: dwarf::DW_AT_specification)) &&
29 !(RefVal = InputDIE.find(Attr: dwarf::DW_AT_abstract_origin)))
30 return false;
31
32 if (!RefVal->isFormClass(FC: DWARFFormValue::FC_Reference))
33 return false;
34
35 std::optional<UnitEntryPairTy> RefDie = CU->resolveDIEReference(
36 RefValue: *RefVal, CanResolveInterCUReferences: ResolveInterCUReferencesMode::Resolve);
37 if (!RefDie)
38 return false;
39
40 if (!RefDie->DieEntry)
41 return false;
42
43 CU = RefDie->CU;
44 InputDIE = RefDie->CU->getDIE(Die: RefDie->DieEntry);
45 return true;
46 })) {
47 consumeError(Err: std::move(Err));
48 }
49
50 if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace)
51 Name = "(anonymous namespace)";
52
53 DWARFDie ParentDie = InputDIE.getParent();
54 if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit)
55 return djbHash(Buffer: Name ? Name : "", H: djbHash(Buffer: ChildRecurseDepth ? "" : "::"));
56
57 return djbHash(
58 Buffer: (Name ? Name : ""),
59 H: djbHash(Buffer: (Name ? "::" : ""),
60 H: hashFullyQualifiedName(InputCU&: *CU, InputDIE&: ParentDie, ChildRecurseDepth: ++ChildRecurseDepth)));
61}
62
63void AcceleratorRecordsSaver::save(const DWARFDebugInfoEntry *InputDieEntry,
64 DIE *OutDIE, AttributesInfo &AttrInfo,
65 TypeEntry *TypeEntry) {
66 if (GlobalData.getOptions().AccelTables.empty())
67 return;
68
69 DWARFDie InputDIE = InUnit.getDIE(Die: InputDieEntry);
70
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(NewValue: ShortName).first;
75
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(InputCU&: InUnit, InputDIE);
107
108 uint64_t RuntimeLang =
109 dwarf::toUnsigned(V: InputDIE.find(Attr: dwarf::DW_AT_APPLE_runtime_class))
110 .value_or(u: 0);
111
112 bool ObjCClassIsImplementation =
113 (RuntimeLang == dwarf::DW_LANG_ObjC ||
114 RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
115 dwarf::toUnsigned(
116 V: InputDIE.find(Attr: dwarf::DW_AT_APPLE_objc_complete_type))
117 .value_or(u: 0);
118
119 saveTypeRecord(Name: AttrInfo.Name, OutDIE, Tag: InputDieEntry->getTag(), QualifiedNameHash: Hash,
120 ObjcClassImplementation: ObjCClassIsImplementation, TypeEntry);
121 }
122 } break;
123 case dwarf::DW_TAG_namespace: {
124 if (AttrInfo.Name == nullptr)
125 AttrInfo.Name =
126 GlobalData.getStringPool().insert(NewValue: "(anonymous namespace)").first;
127
128 saveNamespaceRecord(Name: AttrInfo.Name, OutDIE, Tag: InputDieEntry->getTag(),
129 TypeEntry);
130 } break;
131 case dwarf::DW_TAG_imported_declaration: {
132 if (AttrInfo.Name != nullptr)
133 saveNamespaceRecord(Name: AttrInfo.Name, OutDIE, Tag: InputDieEntry->getTag(),
134 TypeEntry);
135 } break;
136 case dwarf::DW_TAG_compile_unit:
137 case dwarf::DW_TAG_lexical_block: {
138 // Nothing to do.
139 } break;
140 default:
141 if (TypeEntry)
142 // Do not store this kind of accelerator entries for type entries.
143 return;
144
145 if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) {
146 if (AttrInfo.Name)
147 saveNameRecord(Name: AttrInfo.Name, OutDIE, Tag: InputDieEntry->getTag(),
148 AvoidForPubSections: InputDieEntry->getTag() ==
149 dwarf::DW_TAG_inlined_subroutine);
150
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(NewValue: LinkageName).first;
156
157 if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
158 saveNameRecord(Name: AttrInfo.MangledName, OutDIE, Tag: InputDieEntry->getTag(),
159 AvoidForPubSections: InputDieEntry->getTag() ==
160 dwarf::DW_TAG_inlined_subroutine);
161
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(Name: AttrInfo.Name->getKey())) {
167 StringEntry *NameWithoutTemplateParams =
168 GlobalData.getStringPool().insert(NewValue: *Name).first;
169
170 saveNameRecord(Name: NameWithoutTemplateParams, OutDIE,
171 Tag: InputDieEntry->getTag(), AvoidForPubSections: true);
172 }
173 }
174
175 if (AttrInfo.Name)
176 saveObjC(InputDieEntry, OutDIE, AttrInfo);
177 }
178 break;
179 }
180}
181
182void AcceleratorRecordsSaver::saveObjC(const DWARFDebugInfoEntry *InputDieEntry,
183 DIE *OutDIE, AttributesInfo &AttrInfo) {
184 std::optional<ObjCSelectorNames> Names =
185 getObjCNamesIfSelector(Name: AttrInfo.Name->getKey());
186 if (!Names)
187 return;
188
189 StringEntry *Selector =
190 GlobalData.getStringPool().insert(NewValue: Names->Selector).first;
191 saveNameRecord(Name: Selector, OutDIE, Tag: InputDieEntry->getTag(), AvoidForPubSections: true);
192 StringEntry *ClassName =
193 GlobalData.getStringPool().insert(NewValue: Names->ClassName).first;
194 saveObjCNameRecord(Name: ClassName, OutDIE, Tag: InputDieEntry->getTag());
195 if (Names->ClassNameNoCategory) {
196 StringEntry *ClassNameNoCategory =
197 GlobalData.getStringPool().insert(NewValue: *Names->ClassNameNoCategory).first;
198 saveObjCNameRecord(Name: ClassNameNoCategory, OutDIE, Tag: InputDieEntry->getTag());
199 }
200 if (Names->MethodNameNoCategory) {
201 StringEntry *MethodNameNoCategory =
202 GlobalData.getStringPool().insert(NewValue: *Names->MethodNameNoCategory).first;
203 saveNameRecord(Name: MethodNameNoCategory, OutDIE, Tag: InputDieEntry->getTag(), AvoidForPubSections: true);
204 }
205}
206
207void AcceleratorRecordsSaver::saveNameRecord(StringEntry *Name, DIE *OutDIE,
208 dwarf::Tag Tag,
209 bool AvoidForPubSections) {
210 DwarfUnit::AccelInfo Info;
211
212 Info.Type = DwarfUnit::AccelType::Name;
213 Info.String = Name;
214 Info.OutOffset = OutDIE->getOffset();
215 Info.Tag = Tag;
216 Info.AvoidForPubSections = AvoidForPubSections;
217
218 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
219}
220void 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;
226
227 Info.Type = DwarfUnit::AccelType::Namespace;
228 Info.String = Name;
229 Info.OutOffset = OutDIE->getOffset();
230 Info.Tag = Tag;
231
232 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
233 return;
234 }
235
236 assert(TypeEntry != nullptr);
237 TypeUnit::TypeUnitAccelInfo Info;
238 Info.Type = DwarfUnit::AccelType::Namespace;
239 Info.String = Name;
240 Info.OutOffset = 0xbaddef;
241 Info.Tag = Tag;
242 Info.OutDIE = OutDIE;
243 Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
244
245 OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
246}
247
248void AcceleratorRecordsSaver::saveObjCNameRecord(StringEntry *Name, DIE *OutDIE,
249 dwarf::Tag Tag) {
250 DwarfUnit::AccelInfo Info;
251
252 Info.Type = DwarfUnit::AccelType::ObjC;
253 Info.String = Name;
254 Info.OutOffset = OutDIE->getOffset();
255 Info.Tag = Tag;
256 Info.AvoidForPubSections = true;
257
258 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
259}
260
261void AcceleratorRecordsSaver::saveTypeRecord(StringEntry *Name, DIE *OutDIE,
262 dwarf::Tag Tag,
263 uint32_t QualifiedNameHash,
264 bool ObjcClassImplementation,
265 TypeEntry *TypeEntry) {
266 if (OutUnit.isCompileUnit()) {
267 assert(TypeEntry == nullptr);
268 DwarfUnit::AccelInfo Info;
269
270 Info.Type = DwarfUnit::AccelType::Type;
271 Info.String = Name;
272 Info.OutOffset = OutDIE->getOffset();
273 Info.Tag = Tag;
274 Info.QualifiedNameHash = QualifiedNameHash;
275 Info.ObjcClassImplementation = ObjcClassImplementation;
276
277 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
278 return;
279 }
280
281 assert(TypeEntry != nullptr);
282 TypeUnit::TypeUnitAccelInfo Info;
283
284 Info.Type = DwarfUnit::AccelType::Type;
285 Info.String = Name;
286 Info.OutOffset = 0xbaddef;
287 Info.Tag = Tag;
288 Info.QualifiedNameHash = QualifiedNameHash;
289 Info.ObjcClassImplementation = ObjcClassImplementation;
290 Info.OutDIE = OutDIE;
291 Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
292 OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
293}
294