LLVM 23.0.0git
DWARFLinkerTypeUnit.cpp
Go to the documentation of this file.
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
10#include "DIEGenerator.h"
11#include "llvm/Support/LEB128.h"
12
13using namespace llvm;
14using namespace dwarf_linker;
15using namespace dwarf_linker::parallel;
16
18 std::optional<uint16_t> Language, dwarf::FormParams Format,
19 endianness Endianess)
20 : DwarfUnit(GlobalData, ID, ""), Language(Language),
21 AcceleratorRecords(&GlobalData.getAllocator()) {
22
23 UnitName = "__artificial_type_unit";
24
25 setOutputFormat(Format, Endianess);
26
27 // Create line table prologue.
28 LineTable.Prologue.FormParams = getFormParams();
29 LineTable.Prologue.MinInstLength = 1;
30 LineTable.Prologue.MaxOpsPerInst = 1;
31 LineTable.Prologue.DefaultIsStmt = 1;
32 LineTable.Prologue.LineBase = -5;
33 LineTable.Prologue.LineRange = 14;
34 LineTable.Prologue.OpcodeBase = 13;
35 LineTable.Prologue.StandardOpcodeLengths = {0, 1, 1, 1, 1, 0,
36 0, 0, 1, 0, 0, 1};
37
39}
40
42 prepareDataForTreeCreation();
43
44 // TaskGroup is created here as internal code has calls to
45 // PerThreadBumpPtrAllocator which should be called from the task group task.
47 TG.spawn([&]() {
48 SectionDescriptor &DebugInfoSection =
50 SectionDescriptor &DebugLineSection =
52
53 DIEGenerator DIETreeGenerator(Allocator, *this);
54 OffsetsPtrVector PatchesOffsets;
55
56 // Create a Die for artificial compilation unit for types.
57 DIE *UnitDIE = DIETreeGenerator.createDIE(dwarf::DW_TAG_compile_unit, 0);
58 uint64_t OutOffset = getDebugInfoHeaderSize();
59 UnitDIE->setOffset(OutOffset);
60
61 const char *ProducerString =
62 "llvm DWARFLinkerParallel library version " LLVM_VERSION_STRING;
63 DebugInfoSection.notePatchWithOffsetUpdate(
64 DebugStrPatch{{OutOffset},
65 GlobalData.getStringPool().insert(ProducerString).first},
66 PatchesOffsets);
67 OutOffset += DIETreeGenerator
68 .addStringPlaceholderAttribute(dwarf::DW_AT_producer,
69 dwarf::DW_FORM_strp)
70 .second;
71
72 if (Language) {
73 OutOffset += DIETreeGenerator
74 .addScalarAttribute(dwarf::DW_AT_language,
75 dwarf::DW_FORM_data2, *Language)
76 .second;
77 }
78
79 DebugInfoSection.notePatchWithOffsetUpdate(
80 DebugStrPatch{{OutOffset},
81 GlobalData.getStringPool().insert(getUnitName()).first},
82 PatchesOffsets);
83 OutOffset += DIETreeGenerator
84 .addStringPlaceholderAttribute(dwarf::DW_AT_name,
85 dwarf::DW_FORM_strp)
86 .second;
87
88 if (!LineTable.Prologue.FileNames.empty()) {
89 DebugInfoSection.notePatchWithOffsetUpdate(
90 DebugOffsetPatch{OutOffset, &DebugLineSection}, PatchesOffsets);
91
92 OutOffset += DIETreeGenerator
93 .addScalarAttribute(dwarf::DW_AT_stmt_list,
94 dwarf::DW_FORM_sec_offset, 0xbaddef)
95 .second;
96 }
97
98 DebugInfoSection.notePatchWithOffsetUpdate(
99 DebugStrPatch{{OutOffset}, GlobalData.getStringPool().insert("").first},
100 PatchesOffsets);
101 OutOffset += DIETreeGenerator
102 .addStringPlaceholderAttribute(dwarf::DW_AT_comp_dir,
103 dwarf::DW_FORM_strp)
104 .second;
105
106 if (!DebugStringIndexMap.empty()) {
107 // Type unit is assumed to be emitted first. Thus we can use direct value
108 // for DW_AT_str_offsets_base attribute(No need to fix it up with unit
109 // offset value).
110 OutOffset += DIETreeGenerator
111 .addScalarAttribute(dwarf::DW_AT_str_offsets_base,
112 dwarf::DW_FORM_sec_offset,
114 .second;
115 }
116
117 UnitDIE->setSize(OutOffset - UnitDIE->getOffset() + 1);
118 OutOffset =
119 finalizeTypeEntryRec(UnitDIE->getOffset(), UnitDIE, Types.getRoot());
120
121 // Update patch offsets.
122 for (uint64_t *OffsetPtr : PatchesOffsets)
123 *OffsetPtr += getULEB128Size(UnitDIE->getAbbrevNumber());
124
125 setOutUnitDIE(UnitDIE);
126 });
127}
128
129void TypeUnit::prepareDataForTreeCreation() {
130 SectionDescriptor &DebugInfoSection =
132
133 // Type unit data created parallelly. So the order of data is not
134 // deterministic. Sort data here to produce deterministic output.
135
137
138 TG.spawn([&]() {
139 // Sort types to have a deterministic output.
140 Types.sortTypes();
141 });
142
143 TG.spawn([&]() {
144 // Sort decl type patches to have a deterministic output.
145 std::function<bool(const DebugTypeDeclFilePatch &LHS,
146 const DebugTypeDeclFilePatch &RHS)>
147 PatchesComparator = [&](const DebugTypeDeclFilePatch &LHS,
148 const DebugTypeDeclFilePatch &RHS) {
149 return LHS.Directory->first() < RHS.Directory->first() ||
150 (!(RHS.Directory->first() < LHS.Directory->first()) &&
151 LHS.FilePath->first() < RHS.FilePath->first());
152 };
153 DebugInfoSection.ListDebugTypeDeclFilePatch.sort(PatchesComparator);
154
155 // Update DW_AT_decl_file attribute
156 dwarf::Form DeclFileForm =
157 getScalarFormForValue(
158 DebugInfoSection.ListDebugTypeDeclFilePatch.size())
159 .first;
160
161 DebugInfoSection.ListDebugTypeDeclFilePatch.forEach(
162 [&](DebugTypeDeclFilePatch &Patch) {
163 TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
165 formatv("No data for type {0}", Patch.TypeName->getKey())
166 .str()
167 .c_str());
168 if (&TypeEntry->getFinalDie() != Patch.Die)
169 return;
170
171 uint32_t FileIdx =
172 addFileNameIntoLinetable(Patch.Directory, Patch.FilePath);
173
174 unsigned DIESize = Patch.Die->getSize();
175 DIEGenerator DIEGen(Patch.Die, Types.getThreadLocalAllocator(),
176 *this);
177
178 DIESize += DIEGen
179 .addScalarAttribute(dwarf::DW_AT_decl_file,
180 DeclFileForm, FileIdx)
181 .second;
182 Patch.Die->setSize(DIESize);
183 });
184 });
185
186 // Sort patches to have a deterministic output.
187 TG.spawn([&]() {
188 forEach([&](SectionDescriptor &OutSection) {
189 std::function<bool(const DebugStrPatch &LHS, const DebugStrPatch &RHS)>
190 StrPatchesComparator =
191 [&](const DebugStrPatch &LHS, const DebugStrPatch &RHS) {
192 return LHS.String->getKey() < RHS.String->getKey();
193 };
194 OutSection.ListDebugStrPatch.sort(StrPatchesComparator);
195
196 std::function<bool(const DebugTypeStrPatch &LHS,
197 const DebugTypeStrPatch &RHS)>
198 TypeStrPatchesComparator =
199 [&](const DebugTypeStrPatch &LHS, const DebugTypeStrPatch &RHS) {
200 return LHS.String->getKey() < RHS.String->getKey();
201 };
202 OutSection.ListDebugTypeStrPatch.sort(TypeStrPatchesComparator);
203 });
204 });
205
206 // Sort patches to have a deterministic output.
207 TG.spawn([&]() {
208 forEach([&](SectionDescriptor &OutSection) {
209 std::function<bool(const DebugLineStrPatch &LHS,
210 const DebugLineStrPatch &RHS)>
211 LineStrPatchesComparator =
212 [&](const DebugLineStrPatch &LHS, const DebugLineStrPatch &RHS) {
213 return LHS.String->getKey() < RHS.String->getKey();
214 };
215 OutSection.ListDebugLineStrPatch.sort(LineStrPatchesComparator);
216
217 std::function<bool(const DebugTypeLineStrPatch &LHS,
218 const DebugTypeLineStrPatch &RHS)>
219 TypeLineStrPatchesComparator = [&](const DebugTypeLineStrPatch &LHS,
220 const DebugTypeLineStrPatch &RHS) {
221 return LHS.String->getKey() < RHS.String->getKey();
222 };
223 OutSection.ListDebugTypeLineStrPatch.sort(TypeLineStrPatchesComparator);
224 });
225 });
226}
227
228uint64_t TypeUnit::finalizeTypeEntryRec(uint64_t OutOffset, DIE *OutDIE,
229 TypeEntry *Entry) {
230 bool HasChildren = !Entry->getValue().load()->Children.empty();
231 DIEGenerator DIEGen(OutDIE, Types.getThreadLocalAllocator(), *this);
232 OutOffset += DIEGen.finalizeAbbreviations(HasChildren, nullptr);
233 OutOffset += OutDIE->getSize() - 1;
234
235 if (HasChildren) {
236 Entry->getValue().load()->Children.forEach([&](TypeEntry *ChildEntry) {
237 DIE *ChildDIE = &ChildEntry->getValue().load()->getFinalDie();
238 DIEGen.addChild(ChildDIE);
239
240 ChildDIE->setOffset(OutOffset);
241
242 OutOffset = finalizeTypeEntryRec(OutOffset, ChildDIE, ChildEntry);
243 });
244
245 // End of children marker.
246 OutOffset += sizeof(int8_t);
247 }
248
249 OutDIE->setSize(OutOffset - OutDIE->getOffset());
250 return OutOffset;
251}
252
253uint32_t TypeUnit::addFileNameIntoLinetable(StringEntry *Dir,
254 StringEntry *FileName) {
255 uint32_t DirIdx = 0;
256
257 if (Dir->first() == "") {
258 DirIdx = 0;
259 } else {
260 DirectoriesMapTy::iterator DirEntry = DirectoriesMap.find(Dir);
261 if (DirEntry == DirectoriesMap.end()) {
262 // We currently do not support more than UINT32_MAX directories.
263 assert(LineTable.Prologue.IncludeDirectories.size() < UINT32_MAX);
264 DirIdx = LineTable.Prologue.IncludeDirectories.size();
265 DirectoriesMap.insert({Dir, DirIdx});
266 LineTable.Prologue.IncludeDirectories.push_back(
267 DWARFFormValue::createFromPValue(dwarf::DW_FORM_string,
268 Dir->getKeyData()));
269 } else {
270 DirIdx = DirEntry->second;
271 }
272
273 if (getVersion() < 5)
274 DirIdx++;
275 }
276
277 auto [FileEntry, Inserted] = FileNamesMap.try_emplace(
278 {FileName, DirIdx}, LineTable.Prologue.FileNames.size());
279 if (Inserted) {
280 // We currently do not support more than UINT32_MAX files.
281 assert(LineTable.Prologue.FileNames.size() < UINT32_MAX);
282 LineTable.Prologue.FileNames.push_back(DWARFDebugLine::FileNameEntry());
283 LineTable.Prologue.FileNames.back().Name = DWARFFormValue::createFromPValue(
284 dwarf::DW_FORM_string, FileName->getKeyData());
285 LineTable.Prologue.FileNames.back().DirIdx = DirIdx;
286 }
287
288 uint32_t FileIdx = FileEntry->second;
289 return getVersion() < 5 ? FileIdx + 1 : FileIdx;
290}
291
292std::pair<dwarf::Form, uint8_t>
293TypeUnit::getScalarFormForValue(uint64_t Value) const {
294 if (Value > 0xFFFFFFFF)
295 return std::make_pair(dwarf::DW_FORM_data8, 8);
296
297 if (Value > 0xFFFF)
298 return std::make_pair(dwarf::DW_FORM_data4, 4);
299
300 if (Value > 0xFF)
301 return std::make_pair(dwarf::DW_FORM_data2, 2);
302
303 return std::make_pair(dwarf::DW_FORM_data1, 1);
304}
305
306uint8_t TypeUnit::getSizeByAttrForm(dwarf::Form Form) const {
307 if (Form == dwarf::DW_FORM_data1)
308 return 1;
309
310 if (Form == dwarf::DW_FORM_data2)
311 return 2;
312
313 if (Form == dwarf::DW_FORM_data4)
314 return 4;
315
316 if (Form == dwarf::DW_FORM_data8)
317 return 8;
318
319 if (Form == dwarf::DW_FORM_data16)
320 return 16;
321
322 llvm_unreachable("Unsupported Attr Form");
323}
324
326 BumpPtrAllocator Allocator;
327 createDIETree(Allocator);
328
329 if (getOutUnitDIE() == nullptr)
330 return Error::success();
331
332 // Create sections ahead so that they should not be created asynchronously
333 // later.
338 if (llvm::is_contained(GlobalData.getOptions().AccelTables,
342 }
343
344 SmallVector<std::function<Error(void)>> Tasks;
345
346 // Add task for emitting .debug_line section.
347 if (!LineTable.Prologue.FileNames.empty()) {
348 Tasks.push_back(
349 [&]() -> Error { return emitDebugLine(TargetTriple, LineTable); });
350 }
351
352 // Add task for emitting .debug_info section.
353 Tasks.push_back([&]() -> Error { return emitDebugInfo(TargetTriple); });
354
355 // Add task for emitting Pub accelerator sections.
356 if (llvm::is_contained(GlobalData.getOptions().AccelTables,
358 Tasks.push_back([&]() -> Error {
360 return Error::success();
361 });
362 }
363
364 // Add task for emitting .debug_str_offsets section.
365 Tasks.push_back([&]() -> Error { return emitDebugStringOffsetSection(); });
366
367 // Add task for emitting .debug_abbr section.
368 Tasks.push_back([&]() -> Error { return emitAbbreviations(); });
369
370 if (auto Err = parallelForEachError(
371 Tasks, [&](std::function<Error(void)> F) { return F(); }))
372 return Err;
373
374 return Error::success();
375}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define F(x, y, z)
Definition MD5.cpp:54
Value * RHS
Value * LHS
A structured debug information entry.
Definition DIE.h:828
unsigned getAbbrevNumber() const
Definition DIE.h:863
unsigned getSize() const
Definition DIE.h:871
void setSize(unsigned S)
Definition DIE.h:941
unsigned getOffset() const
Get the compile/type unit relative offset of this DIE.
Definition DIE.h:866
void setOffset(unsigned O)
Definition DIE.h:940
static LLVM_ABI DWARFFormValue createFromPValue(dwarf::Form F, const char *V)
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
const ValueTy & getValue() const
StringRef getKey() const
StringRef first() const
const char * getKeyData() const
getKeyData - Return the start of the string data that is the key for this value.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
This class is a helper to create output DIE tree.
std::pair< DIEValue &, size_t > addStringPlaceholderAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm)
Adds string attribute with dummy offset to the current DIE.
DIE * createDIE(dwarf::Tag DieTag, uint32_t OutOffset)
Creates a DIE of specified tag DieTag and OutOffset.
std::pair< DIEValue &, size_t > addScalarAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm, uint64_t Value)
Adds specified scalar attribute to the current DIE.
std::string UnitName
The name of this unit.
IndexedValuesMap< const StringEntry * > DebugStringIndexMap
Maps a string into the index inside .debug_str_offsets section.
unsigned ID
Unique ID for the unit.
StringRef getUnitName() const
Returns this unit name.
void setOutUnitDIE(DIE *UnitDie)
Set output unit DIE.
DwarfUnit(LinkingGlobalData &GlobalData, unsigned ID, StringRef ClangModuleName)
DIE * getOutUnitDIE()
Returns output unit DIE.
This class keeps data and services common for the whole linking process.
uint16_t getDebugStrOffsetsHeaderSize() const
Return size of header of debug_str_offsets table.
dwarf::FormParams Format
Format for sections.
const dwarf::FormParams & getFormParams() const
Return size of address.
void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianness)
Sets output format for all keeping sections.
uint16_t getVersion() const
Return DWARF version.
uint16_t getDebugInfoHeaderSize() const
Return size of header of debug_info table.
void forEach(function_ref< void(SectionDescriptor &)> Handler)
Enumerate all sections and call Handler for each.
SectionDescriptor & getOrCreateSectionDescriptor(DebugSectionKind SectionKind)
Returns descriptor for the specified section of SectionKind.
Keeps cloned data for the type DIE.
Definition TypePool.h:31
Error finishCloningAndEmit(const Triple &TargetTriple)
Emits resulting dwarf based on information from DIE tree.
void createDIETree(BumpPtrAllocator &Allocator)
Generates DIE tree based on information from TypesMap.
TypeUnit(LinkingGlobalData &GlobalData, unsigned ID, std::optional< uint16_t > Language, dwarf::FormParams Format, llvm::endianness Endianess)
LLVM_ABI void spawn(std::function< void()> f)
Definition Parallel.cpp:250
Error emitDebugInfo(const Triple &TargetTriple)
Emit .debug_info section for unit DIEs.
Error emitDebugLine(const Triple &TargetTriple, const DWARFDebugLine::LineTable &OutLineTable, ArrayRef< uint64_t > OrigRowIndices={}, DenseMap< uint64_t, uint64_t > *RowIndexToSeqStartOffset=nullptr)
Emit .debug_line section.
Error emitDebugStringOffsetSection()
Emit the .debug_str_offsets section for current unit.
void emitPubAccelerators()
Emit .debug_pubnames and .debug_pubtypes for Unit.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Entry
Definition COFF.h:862
SmallVector< uint64_t * > OffsetsPtrVector
Type for list of pointers to patches offsets.
StringMapEntry< std::atomic< TypeEntryBody * > > TypeEntry
Definition TypePool.h:28
StringMapEntry< EmptyStringSetTag > StringEntry
StringEntry keeps data of the string: the length, external offset and a string body which is placed r...
Definition StringPool.h:23
This is an optimization pass for GlobalISel generic memory operations.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ABI unsigned getULEB128Size(uint64_t Value)
Utility function to get the size of the ULEB128-encoded value.
Definition LEB128.cpp:19
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:390
endianness
Definition bit.h:71
Error parallelForEachError(RangeTy &&R, FuncTy Fn)
Definition Parallel.h:272
A helper struct providing information about the byte size of DW_FORM values that vary in size dependi...
Definition Dwarf.h:1122
This structure is used to update strings offsets into .debug_str.
This structure is used to keep data of the concrete section.
void notePatchWithOffsetUpdate(const T &Patch, OffsetsPtrVector &PatchesOffsetsList)
While creating patches, offsets to attributes may be partially unknown(because size of abbreviation n...