1 | //===- DWARFLinkerTypeUnit.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 "DWARFLinkerTypeUnit.h" |
10 | #include "DIEGenerator.h" |
11 | #include "DWARFEmitterImpl.h" |
12 | #include "llvm/Support/LEB128.h" |
13 | |
14 | using namespace llvm; |
15 | using namespace dwarf_linker; |
16 | using namespace dwarf_linker::parallel; |
17 | |
18 | TypeUnit::TypeUnit(LinkingGlobalData &GlobalData, unsigned ID, |
19 | std::optional<uint16_t> Language, dwarf::FormParams Format, |
20 | endianness Endianess) |
21 | : DwarfUnit(GlobalData, ID, "" ), Language(Language), |
22 | AcceleratorRecords(&GlobalData.getAllocator()) { |
23 | |
24 | UnitName = "__artificial_type_unit" ; |
25 | |
26 | setOutputFormat(Format, Endianness: Endianess); |
27 | |
28 | // Create line table prologue. |
29 | LineTable.Prologue.FormParams = getFormParams(); |
30 | LineTable.Prologue.MinInstLength = 1; |
31 | LineTable.Prologue.MaxOpsPerInst = 1; |
32 | LineTable.Prologue.DefaultIsStmt = 1; |
33 | LineTable.Prologue.LineBase = -5; |
34 | LineTable.Prologue.LineRange = 14; |
35 | LineTable.Prologue.OpcodeBase = 13; |
36 | LineTable.Prologue.StandardOpcodeLengths = {0, 1, 1, 1, 1, 0, |
37 | 0, 0, 1, 0, 0, 1}; |
38 | |
39 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo); |
40 | } |
41 | |
42 | void TypeUnit::createDIETree(BumpPtrAllocator &Allocator) { |
43 | prepareDataForTreeCreation(); |
44 | |
45 | // TaskGroup is created here as internal code has calls to |
46 | // PerThreadBumpPtrAllocator which should be called from the task group task. |
47 | llvm::parallel::TaskGroup TG; |
48 | TG.spawn(f: [&]() { |
49 | SectionDescriptor &DebugInfoSection = |
50 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo); |
51 | SectionDescriptor &DebugLineSection = |
52 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugLine); |
53 | |
54 | DIEGenerator DIETreeGenerator(Allocator, *this); |
55 | OffsetsPtrVector PatchesOffsets; |
56 | |
57 | // Create a Die for artificial compilation unit for types. |
58 | DIE *UnitDIE = DIETreeGenerator.createDIE(DieTag: dwarf::DW_TAG_compile_unit, OutOffset: 0); |
59 | uint64_t OutOffset = getDebugInfoHeaderSize(); |
60 | UnitDIE->setOffset(OutOffset); |
61 | |
62 | SmallString<200> ProducerString; |
63 | ProducerString += "llvm DWARFLinkerParallel library version " ; |
64 | DebugInfoSection.notePatchWithOffsetUpdate( |
65 | Patch: DebugStrPatch{ |
66 | {.PatchOffset: OutOffset}, |
67 | .String: GlobalData.getStringPool().insert(NewValue: ProducerString.str()).first}, |
68 | PatchesOffsetsList&: PatchesOffsets); |
69 | OutOffset += DIETreeGenerator |
70 | .addStringPlaceholderAttribute(Attr: dwarf::DW_AT_producer, |
71 | AttrForm: dwarf::DW_FORM_strp) |
72 | .second; |
73 | |
74 | if (Language) { |
75 | OutOffset += DIETreeGenerator |
76 | .addScalarAttribute(Attr: dwarf::DW_AT_language, |
77 | AttrForm: dwarf::DW_FORM_data2, Value: *Language) |
78 | .second; |
79 | } |
80 | |
81 | DebugInfoSection.notePatchWithOffsetUpdate( |
82 | Patch: DebugStrPatch{{.PatchOffset: OutOffset}, |
83 | .String: GlobalData.getStringPool().insert(NewValue: getUnitName()).first}, |
84 | PatchesOffsetsList&: PatchesOffsets); |
85 | OutOffset += DIETreeGenerator |
86 | .addStringPlaceholderAttribute(Attr: dwarf::DW_AT_name, |
87 | AttrForm: dwarf::DW_FORM_strp) |
88 | .second; |
89 | |
90 | if (!LineTable.Prologue.FileNames.empty()) { |
91 | DebugInfoSection.notePatchWithOffsetUpdate( |
92 | Patch: DebugOffsetPatch{OutOffset, &DebugLineSection}, PatchesOffsetsList&: PatchesOffsets); |
93 | |
94 | OutOffset += DIETreeGenerator |
95 | .addScalarAttribute(Attr: dwarf::DW_AT_stmt_list, |
96 | AttrForm: dwarf::DW_FORM_sec_offset, Value: 0xbaddef) |
97 | .second; |
98 | } |
99 | |
100 | DebugInfoSection.notePatchWithOffsetUpdate( |
101 | Patch: DebugStrPatch{{.PatchOffset: OutOffset}, .String: GlobalData.getStringPool().insert(NewValue: "" ).first}, |
102 | PatchesOffsetsList&: PatchesOffsets); |
103 | OutOffset += DIETreeGenerator |
104 | .addStringPlaceholderAttribute(Attr: dwarf::DW_AT_comp_dir, |
105 | AttrForm: dwarf::DW_FORM_strp) |
106 | .second; |
107 | |
108 | if (!DebugStringIndexMap.empty()) { |
109 | // Type unit is assumed to be emitted first. Thus we can use direct value |
110 | // for DW_AT_str_offsets_base attribute(No need to fix it up with unit |
111 | // offset value). |
112 | OutOffset += DIETreeGenerator |
113 | .addScalarAttribute(Attr: dwarf::DW_AT_str_offsets_base, |
114 | AttrForm: dwarf::DW_FORM_sec_offset, |
115 | Value: getDebugStrOffsetsHeaderSize()) |
116 | .second; |
117 | } |
118 | |
119 | UnitDIE->setSize(OutOffset - UnitDIE->getOffset() + 1); |
120 | OutOffset = |
121 | finalizeTypeEntryRec(OutOffset: UnitDIE->getOffset(), OutDIE: UnitDIE, Entry: Types.getRoot()); |
122 | |
123 | // Update patch offsets. |
124 | for (uint64_t *OffsetPtr : PatchesOffsets) |
125 | *OffsetPtr += getULEB128Size(Value: UnitDIE->getAbbrevNumber()); |
126 | |
127 | setOutUnitDIE(UnitDIE); |
128 | }); |
129 | } |
130 | |
131 | void TypeUnit::prepareDataForTreeCreation() { |
132 | SectionDescriptor &DebugInfoSection = |
133 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo); |
134 | |
135 | // Type unit data created parallelly. So the order of data is not |
136 | // deterministic. Order data here if we need deterministic output. |
137 | |
138 | llvm::parallel::TaskGroup TG; |
139 | |
140 | if (!GlobalData.getOptions().AllowNonDeterministicOutput) { |
141 | TG.spawn(f: [&]() { |
142 | // Sort types to have a deterministic output. |
143 | Types.sortTypes(); |
144 | }); |
145 | } |
146 | |
147 | TG.spawn(f: [&]() { |
148 | if (!GlobalData.getOptions().AllowNonDeterministicOutput) { |
149 | // Sort decl type patches to have a deterministic output. |
150 | std::function<bool(const DebugTypeDeclFilePatch &LHS, |
151 | const DebugTypeDeclFilePatch &RHS)> |
152 | PatchesComparator = [&](const DebugTypeDeclFilePatch &LHS, |
153 | const DebugTypeDeclFilePatch &RHS) { |
154 | return LHS.Directory->first() < RHS.Directory->first() || |
155 | (!(RHS.Directory->first() < LHS.Directory->first()) && |
156 | LHS.FilePath->first() < RHS.FilePath->first()); |
157 | }; |
158 | // Sort patches to have a deterministic output. |
159 | DebugInfoSection.ListDebugTypeDeclFilePatch.sort(Comparator: PatchesComparator); |
160 | } |
161 | |
162 | // Update DW_AT_decl_file attribute |
163 | dwarf::Form DeclFileForm = |
164 | getScalarFormForValue( |
165 | Value: DebugInfoSection.ListDebugTypeDeclFilePatch.size()) |
166 | .first; |
167 | |
168 | DebugInfoSection.ListDebugTypeDeclFilePatch.forEach( |
169 | Handler: [&](DebugTypeDeclFilePatch &Patch) { |
170 | TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load(); |
171 | assert(TypeEntry && |
172 | formatv("No data for type {0}" , Patch.TypeName->getKey()) |
173 | .str() |
174 | .c_str()); |
175 | if (&TypeEntry->getFinalDie() != Patch.Die) |
176 | return; |
177 | |
178 | uint32_t FileIdx = |
179 | addFileNameIntoLinetable(Dir: Patch.Directory, FileName: Patch.FilePath); |
180 | |
181 | unsigned DIESize = Patch.Die->getSize(); |
182 | DIEGenerator DIEGen(Patch.Die, Types.getThreadLocalAllocator(), |
183 | *this); |
184 | |
185 | DIESize += DIEGen |
186 | .addScalarAttribute(Attr: dwarf::DW_AT_decl_file, |
187 | AttrForm: DeclFileForm, Value: FileIdx) |
188 | .second; |
189 | Patch.Die->setSize(DIESize); |
190 | }); |
191 | }); |
192 | |
193 | if (!GlobalData.getOptions().AllowNonDeterministicOutput) { |
194 | // Sort patches to have a deterministic output. |
195 | TG.spawn(f: [&]() { |
196 | forEach(Handler: [&](SectionDescriptor &OutSection) { |
197 | std::function<bool(const DebugStrPatch &LHS, const DebugStrPatch &RHS)> |
198 | StrPatchesComparator = |
199 | [&](const DebugStrPatch &LHS, const DebugStrPatch &RHS) { |
200 | return LHS.String->getKey() < RHS.String->getKey(); |
201 | }; |
202 | OutSection.ListDebugStrPatch.sort(Comparator: StrPatchesComparator); |
203 | |
204 | std::function<bool(const DebugTypeStrPatch &LHS, |
205 | const DebugTypeStrPatch &RHS)> |
206 | TypeStrPatchesComparator = [&](const DebugTypeStrPatch &LHS, |
207 | const DebugTypeStrPatch &RHS) { |
208 | return LHS.String->getKey() < RHS.String->getKey(); |
209 | }; |
210 | OutSection.ListDebugTypeStrPatch.sort(Comparator: TypeStrPatchesComparator); |
211 | }); |
212 | }); |
213 | } |
214 | |
215 | if (!GlobalData.getOptions().AllowNonDeterministicOutput) { |
216 | // Sort patches to have a deterministic output. |
217 | TG.spawn(f: [&]() { |
218 | forEach(Handler: [&](SectionDescriptor &OutSection) { |
219 | std::function<bool(const DebugLineStrPatch &LHS, |
220 | const DebugLineStrPatch &RHS)> |
221 | LineStrPatchesComparator = [&](const DebugLineStrPatch &LHS, |
222 | const DebugLineStrPatch &RHS) { |
223 | return LHS.String->getKey() < RHS.String->getKey(); |
224 | }; |
225 | OutSection.ListDebugLineStrPatch.sort(Comparator: LineStrPatchesComparator); |
226 | |
227 | std::function<bool(const DebugTypeLineStrPatch &LHS, |
228 | const DebugTypeLineStrPatch &RHS)> |
229 | TypeLineStrPatchesComparator = |
230 | [&](const DebugTypeLineStrPatch &LHS, |
231 | const DebugTypeLineStrPatch &RHS) { |
232 | return LHS.String->getKey() < RHS.String->getKey(); |
233 | }; |
234 | OutSection.ListDebugTypeLineStrPatch.sort(Comparator: TypeLineStrPatchesComparator); |
235 | }); |
236 | }); |
237 | } |
238 | } |
239 | |
240 | uint64_t TypeUnit::finalizeTypeEntryRec(uint64_t OutOffset, DIE *OutDIE, |
241 | TypeEntry *Entry) { |
242 | bool HasChildren = !Entry->getValue().load()->Children.empty(); |
243 | DIEGenerator DIEGen(OutDIE, Types.getThreadLocalAllocator(), *this); |
244 | OutOffset += DIEGen.finalizeAbbreviations(CHILDREN_yes: HasChildren, OffsetsList: nullptr); |
245 | OutOffset += OutDIE->getSize() - 1; |
246 | |
247 | if (HasChildren) { |
248 | Entry->getValue().load()->Children.forEach(Handler: [&](TypeEntry *ChildEntry) { |
249 | DIE *ChildDIE = &ChildEntry->getValue().load()->getFinalDie(); |
250 | DIEGen.addChild(Child: ChildDIE); |
251 | |
252 | ChildDIE->setOffset(OutOffset); |
253 | |
254 | OutOffset = finalizeTypeEntryRec(OutOffset, OutDIE: ChildDIE, Entry: ChildEntry); |
255 | }); |
256 | |
257 | // End of children marker. |
258 | OutOffset += sizeof(int8_t); |
259 | } |
260 | |
261 | OutDIE->setSize(OutOffset - OutDIE->getOffset()); |
262 | return OutOffset; |
263 | } |
264 | |
265 | uint32_t TypeUnit::addFileNameIntoLinetable(StringEntry *Dir, |
266 | StringEntry *FileName) { |
267 | uint32_t DirIdx = 0; |
268 | |
269 | if (Dir->first() == "" ) { |
270 | DirIdx = 0; |
271 | } else { |
272 | DirectoriesMapTy::iterator DirEntry = DirectoriesMap.find(x: Dir); |
273 | if (DirEntry == DirectoriesMap.end()) { |
274 | // We currently do not support more than UINT32_MAX directories. |
275 | assert(LineTable.Prologue.IncludeDirectories.size() < UINT32_MAX); |
276 | DirIdx = LineTable.Prologue.IncludeDirectories.size(); |
277 | DirectoriesMap.insert(x: {Dir, DirIdx}); |
278 | LineTable.Prologue.IncludeDirectories.push_back( |
279 | x: DWARFFormValue::createFromPValue(F: dwarf::DW_FORM_string, |
280 | V: Dir->getKeyData())); |
281 | } else { |
282 | DirIdx = DirEntry->second; |
283 | } |
284 | |
285 | if (getVersion() < 5) |
286 | DirIdx++; |
287 | } |
288 | |
289 | uint32_t FileIdx = 0; |
290 | FilenamesMapTy::iterator FileEntry = FileNamesMap.find(x: {FileName, DirIdx}); |
291 | if (FileEntry == FileNamesMap.end()) { |
292 | // We currently do not support more than UINT32_MAX files. |
293 | assert(LineTable.Prologue.FileNames.size() < UINT32_MAX); |
294 | FileIdx = LineTable.Prologue.FileNames.size(); |
295 | FileNamesMap.insert(x: {{FileName, DirIdx}, FileIdx}); |
296 | LineTable.Prologue.FileNames.push_back(x: DWARFDebugLine::FileNameEntry()); |
297 | LineTable.Prologue.FileNames.back().Name = DWARFFormValue::createFromPValue( |
298 | F: dwarf::DW_FORM_string, V: FileName->getKeyData()); |
299 | LineTable.Prologue.FileNames.back().DirIdx = DirIdx; |
300 | } else { |
301 | FileIdx = FileEntry->second; |
302 | } |
303 | |
304 | return getVersion() < 5 ? FileIdx + 1 : FileIdx; |
305 | } |
306 | |
307 | std::pair<dwarf::Form, uint8_t> |
308 | TypeUnit::getScalarFormForValue(uint64_t Value) const { |
309 | if (Value > 0xFFFFFFFF) |
310 | return std::make_pair(x: dwarf::DW_FORM_data8, y: 8); |
311 | |
312 | if (Value > 0xFFFF) |
313 | return std::make_pair(x: dwarf::DW_FORM_data4, y: 4); |
314 | |
315 | if (Value > 0xFF) |
316 | return std::make_pair(x: dwarf::DW_FORM_data2, y: 2); |
317 | |
318 | return std::make_pair(x: dwarf::DW_FORM_data1, y: 1); |
319 | } |
320 | |
321 | uint8_t TypeUnit::getSizeByAttrForm(dwarf::Form Form) const { |
322 | if (Form == dwarf::DW_FORM_data1) |
323 | return 1; |
324 | |
325 | if (Form == dwarf::DW_FORM_data2) |
326 | return 2; |
327 | |
328 | if (Form == dwarf::DW_FORM_data4) |
329 | return 4; |
330 | |
331 | if (Form == dwarf::DW_FORM_data8) |
332 | return 8; |
333 | |
334 | if (Form == dwarf::DW_FORM_data16) |
335 | return 16; |
336 | |
337 | llvm_unreachable("Unsupported Attr Form" ); |
338 | } |
339 | |
340 | Error TypeUnit::finishCloningAndEmit(const Triple &TargetTriple) { |
341 | BumpPtrAllocator Allocator; |
342 | createDIETree(Allocator); |
343 | |
344 | if (getOutUnitDIE() == nullptr) |
345 | return Error::success(); |
346 | |
347 | // Create sections ahead so that they should not be created asynchronously |
348 | // later. |
349 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo); |
350 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugLine); |
351 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugStrOffsets); |
352 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugAbbrev); |
353 | if (llvm::is_contained(Range: GlobalData.getOptions().AccelTables, |
354 | Element: DWARFLinker::AccelTableKind::Pub)) { |
355 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugPubNames); |
356 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugPubTypes); |
357 | } |
358 | |
359 | SmallVector<std::function<Error(void)>> Tasks; |
360 | |
361 | // Add task for emitting .debug_line section. |
362 | if (!LineTable.Prologue.FileNames.empty()) { |
363 | Tasks.push_back( |
364 | Elt: [&]() -> Error { return emitDebugLine(TargetTriple, OutLineTable: LineTable); }); |
365 | } |
366 | |
367 | // Add task for emitting .debug_info section. |
368 | Tasks.push_back(Elt: [&]() -> Error { return emitDebugInfo(TargetTriple); }); |
369 | |
370 | // Add task for emitting Pub accelerator sections. |
371 | if (llvm::is_contained(Range: GlobalData.getOptions().AccelTables, |
372 | Element: DWARFLinker::AccelTableKind::Pub)) { |
373 | Tasks.push_back(Elt: [&]() -> Error { |
374 | emitPubAccelerators(); |
375 | return Error::success(); |
376 | }); |
377 | } |
378 | |
379 | // Add task for emitting .debug_str_offsets section. |
380 | Tasks.push_back(Elt: [&]() -> Error { return emitDebugStringOffsetSection(); }); |
381 | |
382 | // Add task for emitting .debug_abbr section. |
383 | Tasks.push_back(Elt: [&]() -> Error { return emitAbbreviations(); }); |
384 | |
385 | if (auto Err = parallelForEachError( |
386 | R&: Tasks, Fn: [&](std::function<Error(void)> F) { return F(); })) |
387 | return Err; |
388 | |
389 | return Error::success(); |
390 | } |
391 | |