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

source code of llvm/lib/DWARFLinker/Parallel/OutputSections.h