1 //===- DWARFLinkerTypeUnit.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 "DWARFLinkerTypeUnit.h"
10 #include "DIEGenerator.h"
11 #include "DWARFEmitterImpl.h"
12 #include "llvm/Support/LEB128.h"
15 using namespace dwarf_linker
;
16 using namespace dwarf_linker::parallel
;
18 TypeUnit::TypeUnit(LinkingGlobalData
&GlobalData
, unsigned ID
,
19 std::optional
<uint16_t> Language
, dwarf::FormParams Format
,
21 : DwarfUnit(GlobalData
, ID
, ""), Language(Language
),
22 AcceleratorRecords(&GlobalData
.getAllocator()) {
24 UnitName
= "__artificial_type_unit";
26 setOutputFormat(Format
, Endianess
);
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,
39 getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo
);
42 void TypeUnit::createDIETree(BumpPtrAllocator
&Allocator
) {
43 prepareDataForTreeCreation();
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
;
49 SectionDescriptor
&DebugInfoSection
=
50 getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo
);
51 SectionDescriptor
&DebugLineSection
=
52 getOrCreateSectionDescriptor(DebugSectionKind::DebugLine
);
54 DIEGenerator
DIETreeGenerator(Allocator
, *this);
55 OffsetsPtrVector PatchesOffsets
;
57 // Create a Die for artificial compilation unit for types.
58 DIE
*UnitDIE
= DIETreeGenerator
.createDIE(dwarf::DW_TAG_compile_unit
, 0);
59 uint64_t OutOffset
= getDebugInfoHeaderSize();
60 UnitDIE
->setOffset(OutOffset
);
62 SmallString
<200> ProducerString
;
63 ProducerString
+= "llvm DWARFLinkerParallel library version ";
64 DebugInfoSection
.notePatchWithOffsetUpdate(
67 GlobalData
.getStringPool().insert(ProducerString
.str()).first
},
69 OutOffset
+= DIETreeGenerator
70 .addStringPlaceholderAttribute(dwarf::DW_AT_producer
,
75 OutOffset
+= DIETreeGenerator
76 .addScalarAttribute(dwarf::DW_AT_language
,
77 dwarf::DW_FORM_data2
, *Language
)
81 DebugInfoSection
.notePatchWithOffsetUpdate(
82 DebugStrPatch
{{OutOffset
},
83 GlobalData
.getStringPool().insert(getUnitName()).first
},
85 OutOffset
+= DIETreeGenerator
86 .addStringPlaceholderAttribute(dwarf::DW_AT_name
,
90 if (!LineTable
.Prologue
.FileNames
.empty()) {
91 DebugInfoSection
.notePatchWithOffsetUpdate(
92 DebugOffsetPatch
{OutOffset
, &DebugLineSection
}, PatchesOffsets
);
94 OutOffset
+= DIETreeGenerator
95 .addScalarAttribute(dwarf::DW_AT_stmt_list
,
96 dwarf::DW_FORM_sec_offset
, 0xbaddef)
100 DebugInfoSection
.notePatchWithOffsetUpdate(
101 DebugStrPatch
{{OutOffset
}, GlobalData
.getStringPool().insert("").first
},
103 OutOffset
+= DIETreeGenerator
104 .addStringPlaceholderAttribute(dwarf::DW_AT_comp_dir
,
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
112 OutOffset
+= DIETreeGenerator
113 .addScalarAttribute(dwarf::DW_AT_str_offsets_base
,
114 dwarf::DW_FORM_sec_offset
,
115 getDebugStrOffsetsHeaderSize())
119 UnitDIE
->setSize(OutOffset
- UnitDIE
->getOffset() + 1);
121 finalizeTypeEntryRec(UnitDIE
->getOffset(), UnitDIE
, Types
.getRoot());
123 // Update patch offsets.
124 for (uint64_t *OffsetPtr
: PatchesOffsets
)
125 *OffsetPtr
+= getULEB128Size(UnitDIE
->getAbbrevNumber());
127 setOutUnitDIE(UnitDIE
);
131 void TypeUnit::prepareDataForTreeCreation() {
132 SectionDescriptor
&DebugInfoSection
=
133 getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo
);
135 // Type unit data created parallelly. So the order of data is not
136 // deterministic. Order data here if we need deterministic output.
138 llvm::parallel::TaskGroup TG
;
140 if (!GlobalData
.getOptions().AllowNonDeterministicOutput
) {
142 // Sort types to have a deterministic output.
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());
158 // Sort patches to have a deterministic output.
159 DebugInfoSection
.ListDebugTypeDeclFilePatch
.sort(PatchesComparator
);
162 // Update DW_AT_decl_file attribute
163 dwarf::Form DeclFileForm
=
164 getScalarFormForValue(
165 DebugInfoSection
.ListDebugTypeDeclFilePatch
.size())
168 DebugInfoSection
.ListDebugTypeDeclFilePatch
.forEach(
169 [&](DebugTypeDeclFilePatch
&Patch
) {
170 TypeEntryBody
*TypeEntry
= Patch
.TypeName
->getValue().load();
172 formatv("No data for type {0}", Patch
.TypeName
->getKey())
175 if (&TypeEntry
->getFinalDie() != Patch
.Die
)
179 addFileNameIntoLinetable(Patch
.Directory
, Patch
.FilePath
);
181 unsigned DIESize
= Patch
.Die
->getSize();
182 DIEGenerator
DIEGen(Patch
.Die
, Types
.getThreadLocalAllocator(),
186 .addScalarAttribute(dwarf::DW_AT_decl_file
,
187 DeclFileForm
, FileIdx
)
189 Patch
.Die
->setSize(DIESize
);
193 if (!GlobalData
.getOptions().AllowNonDeterministicOutput
) {
194 // Sort patches to have a deterministic output.
196 forEach([&](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();
202 OutSection
.ListDebugStrPatch
.sort(StrPatchesComparator
);
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();
210 OutSection
.ListDebugTypeStrPatch
.sort(TypeStrPatchesComparator
);
215 if (!GlobalData
.getOptions().AllowNonDeterministicOutput
) {
216 // Sort patches to have a deterministic output.
218 forEach([&](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();
225 OutSection
.ListDebugLineStrPatch
.sort(LineStrPatchesComparator
);
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();
234 OutSection
.ListDebugTypeLineStrPatch
.sort(TypeLineStrPatchesComparator
);
240 uint64_t TypeUnit::finalizeTypeEntryRec(uint64_t OutOffset
, DIE
*OutDIE
,
242 bool HasChildren
= !Entry
->getValue().load()->Children
.empty();
243 DIEGenerator
DIEGen(OutDIE
, Types
.getThreadLocalAllocator(), *this);
244 OutOffset
+= DIEGen
.finalizeAbbreviations(HasChildren
, nullptr);
245 OutOffset
+= OutDIE
->getSize() - 1;
248 Entry
->getValue().load()->Children
.forEach([&](TypeEntry
*ChildEntry
) {
249 DIE
*ChildDIE
= &ChildEntry
->getValue().load()->getFinalDie();
250 DIEGen
.addChild(ChildDIE
);
252 ChildDIE
->setOffset(OutOffset
);
254 OutOffset
= finalizeTypeEntryRec(OutOffset
, ChildDIE
, ChildEntry
);
257 // End of children marker.
258 OutOffset
+= sizeof(int8_t);
261 OutDIE
->setSize(OutOffset
- OutDIE
->getOffset());
265 uint32_t TypeUnit::addFileNameIntoLinetable(StringEntry
*Dir
,
266 StringEntry
*FileName
) {
269 if (Dir
->first() == "") {
272 DirectoriesMapTy::iterator DirEntry
= DirectoriesMap
.find(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({Dir
, DirIdx
});
278 LineTable
.Prologue
.IncludeDirectories
.push_back(
279 DWARFFormValue::createFromPValue(dwarf::DW_FORM_string
,
282 DirIdx
= DirEntry
->second
;
285 if (getVersion() < 5)
289 uint32_t FileIdx
= 0;
290 FilenamesMapTy::iterator FileEntry
= FileNamesMap
.find({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({{FileName
, DirIdx
}, FileIdx
});
296 LineTable
.Prologue
.FileNames
.push_back(DWARFDebugLine::FileNameEntry());
297 LineTable
.Prologue
.FileNames
.back().Name
= DWARFFormValue::createFromPValue(
298 dwarf::DW_FORM_string
, FileName
->getKeyData());
299 LineTable
.Prologue
.FileNames
.back().DirIdx
= DirIdx
;
301 FileIdx
= FileEntry
->second
;
304 return getVersion() < 5 ? FileIdx
+ 1 : FileIdx
;
307 std::pair
<dwarf::Form
, uint8_t>
308 TypeUnit::getScalarFormForValue(uint64_t Value
) const {
309 if (Value
> 0xFFFFFFFF)
310 return std::make_pair(dwarf::DW_FORM_data8
, 8);
313 return std::make_pair(dwarf::DW_FORM_data4
, 4);
316 return std::make_pair(dwarf::DW_FORM_data2
, 2);
318 return std::make_pair(dwarf::DW_FORM_data1
, 1);
321 uint8_t TypeUnit::getSizeByAttrForm(dwarf::Form Form
) const {
322 if (Form
== dwarf::DW_FORM_data1
)
325 if (Form
== dwarf::DW_FORM_data2
)
328 if (Form
== dwarf::DW_FORM_data4
)
331 if (Form
== dwarf::DW_FORM_data8
)
334 if (Form
== dwarf::DW_FORM_data16
)
337 llvm_unreachable("Unsupported Attr Form");
340 Error
TypeUnit::finishCloningAndEmit(const Triple
&TargetTriple
) {
341 BumpPtrAllocator Allocator
;
342 createDIETree(Allocator
);
344 if (getOutUnitDIE() == nullptr)
345 return Error::success();
347 // Create sections ahead so that they should not be created asynchronously
349 getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo
);
350 getOrCreateSectionDescriptor(DebugSectionKind::DebugLine
);
351 getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets
);
352 getOrCreateSectionDescriptor(DebugSectionKind::DebugAbbrev
);
353 if (llvm::is_contained(GlobalData
.getOptions().AccelTables
,
354 DWARFLinker::AccelTableKind::Pub
)) {
355 getOrCreateSectionDescriptor(DebugSectionKind::DebugPubNames
);
356 getOrCreateSectionDescriptor(DebugSectionKind::DebugPubTypes
);
359 SmallVector
<std::function
<Error(void)>> Tasks
;
361 // Add task for emitting .debug_line section.
362 if (!LineTable
.Prologue
.FileNames
.empty()) {
364 [&]() -> Error
{ return emitDebugLine(TargetTriple
, LineTable
); });
367 // Add task for emitting .debug_info section.
368 Tasks
.push_back([&]() -> Error
{ return emitDebugInfo(TargetTriple
); });
370 // Add task for emitting Pub accelerator sections.
371 if (llvm::is_contained(GlobalData
.getOptions().AccelTables
,
372 DWARFLinker::AccelTableKind::Pub
)) {
373 Tasks
.push_back([&]() -> Error
{
374 emitPubAccelerators();
375 return Error::success();
379 // Add task for emitting .debug_str_offsets section.
380 Tasks
.push_back([&]() -> Error
{ return emitDebugStringOffsetSection(); });
382 // Add task for emitting .debug_abbr section.
383 Tasks
.push_back([&]() -> Error
{ return emitAbbreviations(); });
385 if (auto Err
= parallelForEachError(
386 Tasks
, [&](std::function
<Error(void)> F
) { return F(); }))
389 return Error::success();