1//===- OutputSections.h -----------------------------------------*- C++ -*-===//
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#ifndef LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H
10#define LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H
11
12#include "ArrayList.h"
13#include "ModulePool.h"
14#include "StringEntryToDwarfStringPoolEntryMap.h"
15#include "llvm/ADT/SmallString.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/BinaryFormat/Dwarf.h"
18#include "llvm/CodeGen/DwarfStringPoolEntry.h"
19#include "llvm/DWARFLinker/StringPool.h"
20#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
21#include "llvm/DebugInfo/DWARF/DWARFObject.h"
22#include "llvm/Object/ObjectFile.h"
23#include "llvm/Support/Endian.h"
24#include "llvm/Support/Error.h"
25#include "llvm/Support/FormatVariadic.h"
26#include "llvm/Support/LEB128.h"
27#include "llvm/Support/MemoryBufferRef.h"
28#include "llvm/Support/raw_ostream.h"
29#include <array>
30#include <cstdint>
31
32namespace llvm {
33namespace dwarf_linker {
34namespace parallel {
35
36class TypeUnit;
37
38/// There are fields(sizes, offsets) which should be updated after
39/// sections are generated. To remember offsets and related data
40/// the descendants of SectionPatch structure should be used.
41
42struct SectionPatch {
43 uint64_t PatchOffset = 0;
44};
45
46/// This structure is used to update strings offsets into .debug_str.
47struct DebugStrPatch : SectionPatch {
48 const StringEntry *String = nullptr;
49};
50
51/// This structure is used to update strings offsets into .debug_line_str.
52struct DebugLineStrPatch : SectionPatch {
53 const StringEntry *String = nullptr;
54};
55
56/// This structure is used to update range list offset into
57/// .debug_ranges/.debug_rnglists.
58struct DebugRangePatch : SectionPatch {
59 /// Indicates patch which points to immediate compile unit's attribute.
60 bool IsCompileUnitRanges = false;
61};
62
63/// This structure is used to update location list offset into
64/// .debug_loc/.debug_loclists.
65struct DebugLocPatch : SectionPatch {
66 int64_t AddrAdjustmentValue = 0;
67};
68
69/// This structure is used to update offset with start of another section.
70struct SectionDescriptor;
71struct DebugOffsetPatch : SectionPatch {
72 DebugOffsetPatch(uint64_t PatchOffset, SectionDescriptor *SectionPtr,
73 bool AddLocalValue = false)
74 : SectionPatch({.PatchOffset: PatchOffset}), SectionPtr(SectionPtr, AddLocalValue) {}
75
76 PointerIntPair<SectionDescriptor *, 1> SectionPtr;
77};
78
79/// This structure is used to update reference to the DIE.
80struct DebugDieRefPatch : SectionPatch {
81 DebugDieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU, CompileUnit *RefCU,
82 uint32_t RefIdx);
83
84 PointerIntPair<CompileUnit *, 1> RefCU;
85 uint64_t RefDieIdxOrClonedOffset = 0;
86};
87
88/// This structure is used to update reference to the DIE of ULEB128 form.
89struct DebugULEB128DieRefPatch : SectionPatch {
90 DebugULEB128DieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU,
91 CompileUnit *RefCU, uint32_t RefIdx);
92
93 PointerIntPair<CompileUnit *, 1> RefCU;
94 uint64_t RefDieIdxOrClonedOffset = 0;
95};
96
97/// This structure is used to update reference to the type DIE.
98struct DebugDieTypeRefPatch : SectionPatch {
99 DebugDieTypeRefPatch(uint64_t PatchOffset, TypeEntry *RefTypeName);
100
101 TypeEntry *RefTypeName = nullptr;
102};
103
104/// This structure is used to update a DW_AT_import reference to a
105/// DW_TAG_module. The reference resolves to the module's anchor once the link
106/// has filled it in, and to the inherited target otherwise. The inherited
107/// target is always resolved as an inter-CU reference, so that the attribute
108/// keeps the width it was emitted with whichever of the two wins.
109struct DebugDieModuleRefPatch : DebugDieRefPatch {
110 DebugDieModuleRefPatch(uint64_t PatchOffset, CompileUnit *RefCU,
111 uint32_t RefIdx, ModuleAnchor *Anchor)
112 : DebugDieRefPatch(PatchOffset, nullptr, RefCU, RefIdx), Anchor(Anchor) {}
113
114 ModuleAnchor *Anchor = nullptr;
115};
116
117/// This structure is used to update reference to the type DIE.
118struct DebugType2TypeDieRefPatch : SectionPatch {
119 DebugType2TypeDieRefPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
120 TypeEntry *RefTypeName);
121
122 DIE *Die = nullptr;
123 TypeEntry *TypeName = nullptr;
124 TypeEntry *RefTypeName = nullptr;
125};
126
127struct DebugTypeStrPatch : SectionPatch {
128 DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
129 StringEntry *String);
130
131 DIE *Die = nullptr;
132 TypeEntry *TypeName = nullptr;
133 StringEntry *String = nullptr;
134};
135
136struct DebugTypeLineStrPatch : SectionPatch {
137 DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
138 StringEntry *String);
139
140 DIE *Die = nullptr;
141 TypeEntry *TypeName = nullptr;
142 StringEntry *String = nullptr;
143};
144
145struct DebugTypeDeclFilePatch {
146 DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName, StringEntry *Directory,
147 StringEntry *FilePath);
148
149 DIE *Die = nullptr;
150 TypeEntry *TypeName = nullptr;
151 StringEntry *Directory = nullptr;
152 StringEntry *FilePath = nullptr;
153 uint32_t FileID = 0;
154};
155
156/// Type for section data.
157using OutSectionDataTy = SmallString<0>;
158
159/// Type for list of pointers to patches offsets.
160using OffsetsPtrVector = SmallVector<uint64_t *>;
161
162class OutputSections;
163
164/// This structure is used to keep data of the concrete section.
165/// Like data bits, list of patches, format.
166struct SectionDescriptor : SectionDescriptorBase {
167 friend OutputSections;
168
169 SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData,
170 dwarf::FormParams Format, llvm::endianness Endianess)
171 : SectionDescriptorBase(SectionKind, Format, Endianess), OS(Contents),
172 ListDebugStrPatch(&GlobalData.getAllocator()),
173 ListDebugLineStrPatch(&GlobalData.getAllocator()),
174 ListDebugRangePatch(&GlobalData.getAllocator()),
175 ListDebugLocPatch(&GlobalData.getAllocator()),
176 ListDebugDieRefPatch(&GlobalData.getAllocator()),
177 ListDebugULEB128DieRefPatch(&GlobalData.getAllocator()),
178 ListDebugOffsetPatch(&GlobalData.getAllocator()),
179 ListDebugDieTypeRefPatch(&GlobalData.getAllocator()),
180 ListDebugDieModuleRefPatch(&GlobalData.getAllocator()),
181 ListDebugType2TypeDieRefPatch(&GlobalData.getAllocator()),
182 ListDebugTypeStrPatch(&GlobalData.getAllocator()),
183 ListDebugTypeLineStrPatch(&GlobalData.getAllocator()),
184 ListDebugTypeDeclFilePatch(&GlobalData.getAllocator()),
185 GlobalData(GlobalData) {}
186
187 /// Erase whole section content(data bits, list of patches).
188 void clearAllSectionData();
189
190 /// Erase only section output data bits.
191 void clearSectionContent();
192
193 /// When objects(f.e. compile units) are glued into the single file,
194 /// the debug sections corresponding to the concrete object are assigned
195 /// with offsets inside the whole file. This field keeps offset
196 /// to the debug section, corresponding to this object.
197 uint64_t StartOffset = 0;
198
199protected:
200 /// Section data bits.
201 OutSectionDataTy Contents;
202
203public:
204 /// Stream which stores data to the Contents.
205 raw_svector_ostream OS;
206
207 /// Section patches.
208#define ADD_PATCHES_LIST(T) \
209 T &notePatch(const T &Patch) { return List##T.add(Patch); } \
210 ArrayList<T> List##T;
211
212 ADD_PATCHES_LIST(DebugStrPatch)
213 ADD_PATCHES_LIST(DebugLineStrPatch)
214 ADD_PATCHES_LIST(DebugRangePatch)
215 ADD_PATCHES_LIST(DebugLocPatch)
216 ADD_PATCHES_LIST(DebugDieRefPatch)
217 ADD_PATCHES_LIST(DebugULEB128DieRefPatch)
218 ADD_PATCHES_LIST(DebugOffsetPatch)
219 ADD_PATCHES_LIST(DebugDieTypeRefPatch)
220 ADD_PATCHES_LIST(DebugDieModuleRefPatch)
221 ADD_PATCHES_LIST(DebugType2TypeDieRefPatch)
222 ADD_PATCHES_LIST(DebugTypeStrPatch)
223 ADD_PATCHES_LIST(DebugTypeLineStrPatch)
224 ADD_PATCHES_LIST(DebugTypeDeclFilePatch)
225
226 /// While creating patches, offsets to attributes may be partially
227 /// unknown(because size of abbreviation number is unknown). In such case we
228 /// remember patch itself and pointer to patch application offset to add size
229 /// of abbreviation number later.
230 template <typename T>
231 void notePatchWithOffsetUpdate(const T &Patch,
232 OffsetsPtrVector &PatchesOffsetsList) {
233 PatchesOffsetsList.emplace_back(&notePatch(Patch).PatchOffset);
234 }
235
236 /// Some sections are emitted using AsmPrinter. In that case "Contents"
237 /// member of SectionDescriptor contains elf file. This method searches
238 /// for section data inside elf file and remember offset to it.
239 void setSizesForSectionCreatedByAsmPrinter();
240
241 /// Returns section content.
242 StringRef getContents() override {
243 if (SectionOffsetInsideAsmPrinterOutputStart == 0)
244 return Contents;
245
246 return Contents.slice(Start: SectionOffsetInsideAsmPrinterOutputStart,
247 End: SectionOffsetInsideAsmPrinterOutputEnd);
248 }
249
250 /// Emit unit length into the current section contents.
251 void emitUnitLength(uint64_t Length) {
252 maybeEmitDwarf64Mark();
253 emitIntVal(Val: Length, Size: getFormParams().getDwarfOffsetByteSize());
254 }
255
256 /// Emit DWARF64 mark into the current section contents.
257 void maybeEmitDwarf64Mark() {
258 if (getFormParams().Format != dwarf::DWARF64)
259 return;
260 emitIntVal(Val: dwarf::DW_LENGTH_DWARF64, Size: 4);
261 }
262
263 /// Emit specified offset value into the current section contents.
264 void emitOffset(uint64_t Val) {
265 emitIntVal(Val, Size: getFormParams().getDwarfOffsetByteSize());
266 }
267
268 /// Emit specified integer value into the current section contents.
269 void emitIntVal(uint64_t Val, unsigned Size);
270
271 void emitString(dwarf::Form StringForm, const char *StringVal);
272
273 void emitBinaryData(llvm::StringRef Data);
274
275 /// Emit specified inplace string value into the current section contents.
276 void emitInplaceString(StringRef String) {
277 OS << String;
278 emitIntVal(Val: 0, Size: 1);
279 }
280
281 /// Emit string placeholder into the current section contents.
282 void emitStringPlaceholder() {
283 // emit bad offset which should be updated later.
284 emitOffset(Val: 0xBADDEF);
285 }
286
287 /// Write specified \p Value of \p AttrForm to the \p PatchOffset.
288 void apply(uint64_t PatchOffset, dwarf::Form AttrForm, uint64_t Val);
289
290 /// Returns integer value of \p Size located by specified \p PatchOffset.
291 uint64_t getIntVal(uint64_t PatchOffset, unsigned Size);
292
293protected:
294 /// Writes integer value \p Val of \p Size by specified \p PatchOffset.
295 void applyIntVal(uint64_t PatchOffset, uint64_t Val, unsigned Size);
296
297 /// Writes integer value \p Val of ULEB128 format by specified \p PatchOffset.
298 void applyULEB128(uint64_t PatchOffset, uint64_t Val);
299
300 /// Writes integer value \p Val of SLEB128 format by specified \p PatchOffset.
301 void applySLEB128(uint64_t PatchOffset, uint64_t Val);
302
303 /// Sets output format.
304 void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianess) {
305 this->Format = Format;
306 this->Endianess = Endianess;
307 }
308
309 LinkingGlobalData &GlobalData;
310
311 /// Some sections are generated using AsmPrinter. The real section data
312 /// located inside elf file in that case. Following fields points to the
313 /// real section content inside elf file.
314 size_t SectionOffsetInsideAsmPrinterOutputStart = 0;
315 size_t SectionOffsetInsideAsmPrinterOutputEnd = 0;
316};
317
318/// This class keeps contents and offsets to the debug sections. Any objects
319/// which is supposed to be emitted into the debug sections should use this
320/// class to track debug sections offsets and keep sections data.
321class OutputSections {
322public:
323 OutputSections(LinkingGlobalData &GlobalData) : GlobalData(GlobalData) {}
324
325 /// Sets output format for all keeping sections.
326 void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianness) {
327 this->Format = Format;
328 this->Endianness = Endianness;
329 }
330
331 /// Returns descriptor for the specified section of \p SectionKind.
332 /// The descriptor should already be created. The llvm_unreachable
333 /// would be raised if it is not.
334 const SectionDescriptor &
335 getSectionDescriptor(DebugSectionKind SectionKind) const {
336 SectionsSetTy::const_iterator It = SectionDescriptors.find(x: SectionKind);
337
338 if (It == SectionDescriptors.end())
339 llvm_unreachable(
340 formatv("Section {0} does not exist", getSectionName(SectionKind))
341 .str()
342 .c_str());
343
344 return *It->second;
345 }
346
347 /// Returns descriptor for the specified section of \p SectionKind.
348 /// The descriptor should already be created. The llvm_unreachable
349 /// would be raised if it is not.
350 SectionDescriptor &getSectionDescriptor(DebugSectionKind SectionKind) {
351 SectionsSetTy::iterator It = SectionDescriptors.find(x: SectionKind);
352
353 if (It == SectionDescriptors.end())
354 llvm_unreachable(
355 formatv("Section {0} does not exist", getSectionName(SectionKind))
356 .str()
357 .c_str());
358
359 assert(It->second.get() != nullptr);
360
361 return *It->second;
362 }
363
364 /// Returns descriptor for the specified section of \p SectionKind.
365 /// Returns std::nullopt if section descriptor is not created yet.
366 std::optional<const SectionDescriptor *>
367 tryGetSectionDescriptor(DebugSectionKind SectionKind) const {
368 SectionsSetTy::const_iterator It = SectionDescriptors.find(x: SectionKind);
369
370 if (It == SectionDescriptors.end())
371 return std::nullopt;
372
373 return It->second.get();
374 }
375
376 /// Returns descriptor for the specified section of \p SectionKind.
377 /// Returns std::nullopt if section descriptor is not created yet.
378 std::optional<SectionDescriptor *>
379 tryGetSectionDescriptor(DebugSectionKind SectionKind) {
380 SectionsSetTy::iterator It = SectionDescriptors.find(x: SectionKind);
381
382 if (It == SectionDescriptors.end())
383 return std::nullopt;
384
385 return It->second.get();
386 }
387
388 /// Returns descriptor for the specified section of \p SectionKind.
389 /// If descriptor does not exist then creates it.
390 SectionDescriptor &
391 getOrCreateSectionDescriptor(DebugSectionKind SectionKind) {
392 auto [It, Inserted] = SectionDescriptors.try_emplace(k: SectionKind);
393
394 if (Inserted)
395 It->second = std::make_shared<SectionDescriptor>(args&: SectionKind, args&: GlobalData,
396 args&: Format, args&: Endianness);
397
398 return *It->second;
399 }
400
401 /// Erases data of all sections.
402 void eraseSections() {
403 for (auto &Section : SectionDescriptors)
404 Section.second->clearAllSectionData();
405 }
406
407 /// Enumerate all sections and call \p Handler for each.
408 void forEach(function_ref<void(SectionDescriptor &)> Handler) {
409 for (auto &Section : SectionDescriptors) {
410 assert(Section.second.get() != nullptr);
411 Handler(*(Section.second));
412 }
413 }
414
415 /// Enumerate all sections and call \p Handler for each.
416 void forEach(
417 function_ref<void(std::shared_ptr<SectionDescriptor> Section)> Handler) {
418 for (auto &Section : SectionDescriptors)
419 Handler(Section.second);
420 }
421
422 /// Enumerate all sections, for each section set current offset
423 /// (kept by \p SectionSizesAccumulator), update current offset with section
424 /// length.
425 void assignSectionsOffsetAndAccumulateSize(
426 std::array<uint64_t, SectionKindsNum> &SectionSizesAccumulator) {
427 for (auto &Section : SectionDescriptors) {
428 Section.second->StartOffset =
429 SectionSizesAccumulator[static_cast<uint8_t>(
430 Section.second->getKind())];
431 SectionSizesAccumulator[static_cast<uint8_t>(
432 Section.second->getKind())] += Section.second->getContents().size();
433 }
434 }
435
436 /// Enumerate all sections, for each section apply all section patches.
437 void applyPatches(SectionDescriptor &Section,
438 StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
439 StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings,
440 TypeUnit *TypeUnitPtr);
441
442 /// Endiannes for the sections.
443 llvm::endianness getEndianness() const { return Endianness; }
444
445 /// Return DWARF version.
446 uint16_t getVersion() const { return Format.Version; }
447
448 /// Return size of header of debug_info table.
449 uint16_t getDebugInfoHeaderSize() const {
450 return Format.Version >= 5 ? 12 : 11;
451 }
452
453 /// Return size of header of debug_ table.
454 uint16_t getDebugAddrHeaderSize() const {
455 assert(Format.Version >= 5);
456 return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
457 }
458
459 /// Return size of header of debug_str_offsets table.
460 uint16_t getDebugStrOffsetsHeaderSize() const {
461 assert(Format.Version >= 5);
462 return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
463 }
464
465 /// Return size of address.
466 const dwarf::FormParams &getFormParams() const { return Format; }
467
468protected:
469 LinkingGlobalData &GlobalData;
470
471 /// Format for sections.
472 dwarf::FormParams Format = {.Version: 4, .AddrSize: 4, .Format: dwarf::DWARF32};
473
474 /// Endiannes for sections.
475 llvm::endianness Endianness = llvm::endianness::native;
476
477 /// All keeping sections.
478 using SectionsSetTy =
479 std::map<DebugSectionKind, std::shared_ptr<SectionDescriptor>>;
480 SectionsSetTy SectionDescriptors;
481};
482
483} // end of namespace parallel
484} // end of namespace dwarf_linker
485} // end of namespace llvm
486
487#endif // LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H
488