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 | |
31 | namespace llvm { |
32 | namespace dwarf_linker { |
33 | namespace parallel { |
34 | |
35 | class 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 | |
41 | struct SectionPatch { |
42 | uint64_t PatchOffset = 0; |
43 | }; |
44 | |
45 | /// This structure is used to update strings offsets into .debug_str. |
46 | struct DebugStrPatch : SectionPatch { |
47 | const StringEntry *String = nullptr; |
48 | }; |
49 | |
50 | /// This structure is used to update strings offsets into .debug_line_str. |
51 | struct 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. |
57 | struct 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. |
64 | struct DebugLocPatch : SectionPatch { |
65 | int64_t AddrAdjustmentValue = 0; |
66 | }; |
67 | |
68 | /// This structure is used to update offset with start of another section. |
69 | struct SectionDescriptor; |
70 | struct 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. |
79 | struct 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. |
88 | struct 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. |
97 | struct 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. |
104 | struct 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 | |
113 | struct 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 | |
122 | struct 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 | |
131 | struct 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. |
143 | using OutSectionDataTy = SmallString<0>; |
144 | |
145 | /// Type for list of pointers to patches offsets. |
146 | using OffsetsPtrVector = SmallVector<uint64_t *>; |
147 | |
148 | class OutputSections; |
149 | |
150 | /// This structure is used to keep data of the concrete section. |
151 | /// Like data bits, list of patches, format. |
152 | struct 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 | protected: |
185 | /// Section data bits. |
186 | OutSectionDataTy Contents; |
187 | |
188 | public: |
189 | /// Stream which stores data to the Contents. |
190 | raw_svector_ostream OS; |
191 | |
192 | /// Section patches. |
193 | #define ADD_PATCHES_LIST(T) \ |
194 | T ¬ePatch(const T &Patch) { return List##T.add(Patch); } \ |
195 | ArrayList<T> List##T; |
196 | |
197 | ADD_PATCHES_LIST(DebugStrPatch) |
198 | ADD_PATCHES_LIST(DebugLineStrPatch) |
199 | ADD_PATCHES_LIST(DebugRangePatch) |
200 | ADD_PATCHES_LIST(DebugLocPatch) |
201 | ADD_PATCHES_LIST(DebugDieRefPatch) |
202 | ADD_PATCHES_LIST(DebugULEB128DieRefPatch) |
203 | ADD_PATCHES_LIST(DebugOffsetPatch) |
204 | ADD_PATCHES_LIST(DebugDieTypeRefPatch) |
205 | ADD_PATCHES_LIST(DebugType2TypeDieRefPatch) |
206 | ADD_PATCHES_LIST(DebugTypeStrPatch) |
207 | ADD_PATCHES_LIST(DebugTypeLineStrPatch) |
208 | ADD_PATCHES_LIST(DebugTypeDeclFilePatch) |
209 | |
210 | /// While creating patches, offsets to attributes may be partially |
211 | /// unknown(because size of abbreviation number is unknown). In such case we |
212 | /// remember patch itself and pointer to patch application offset to add size |
213 | /// of abbreviation number later. |
214 | template <typename T> |
215 | void notePatchWithOffsetUpdate(const T &Patch, |
216 | OffsetsPtrVector &PatchesOffsetsList) { |
217 | PatchesOffsetsList.emplace_back(¬ePatch(Patch).PatchOffset); |
218 | } |
219 | |
220 | /// Some sections are emitted using AsmPrinter. In that case "Contents" |
221 | /// member of SectionDescriptor contains elf file. This method searches |
222 | /// for section data inside elf file and remember offset to it. |
223 | void setSizesForSectionCreatedByAsmPrinter(); |
224 | |
225 | /// Returns section content. |
226 | StringRef getContents() override { |
227 | if (SectionOffsetInsideAsmPrinterOutputStart == 0) |
228 | return Contents; |
229 | |
230 | return Contents.slice(Start: SectionOffsetInsideAsmPrinterOutputStart, |
231 | End: SectionOffsetInsideAsmPrinterOutputEnd); |
232 | } |
233 | |
234 | /// Emit unit length into the current section contents. |
235 | void emitUnitLength(uint64_t Length) { |
236 | maybeEmitDwarf64Mark(); |
237 | emitIntVal(Val: Length, Size: getFormParams().getDwarfOffsetByteSize()); |
238 | } |
239 | |
240 | /// Emit DWARF64 mark into the current section contents. |
241 | void maybeEmitDwarf64Mark() { |
242 | if (getFormParams().Format != dwarf::DWARF64) |
243 | return; |
244 | emitIntVal(Val: dwarf::DW_LENGTH_DWARF64, Size: 4); |
245 | } |
246 | |
247 | /// Emit specified offset value into the current section contents. |
248 | void emitOffset(uint64_t Val) { |
249 | emitIntVal(Val, Size: getFormParams().getDwarfOffsetByteSize()); |
250 | } |
251 | |
252 | /// Emit specified integer value into the current section contents. |
253 | void emitIntVal(uint64_t Val, unsigned Size); |
254 | |
255 | void emitString(dwarf::Form StringForm, const char *StringVal); |
256 | |
257 | void emitBinaryData(llvm::StringRef Data); |
258 | |
259 | /// Emit specified inplace string value into the current section contents. |
260 | void emitInplaceString(StringRef String) { |
261 | OS << String; |
262 | emitIntVal(Val: 0, Size: 1); |
263 | } |
264 | |
265 | /// Emit string placeholder into the current section contents. |
266 | void emitStringPlaceholder() { |
267 | // emit bad offset which should be updated later. |
268 | emitOffset(Val: 0xBADDEF); |
269 | } |
270 | |
271 | /// Write specified \p Value of \p AttrForm to the \p PatchOffset. |
272 | void apply(uint64_t PatchOffset, dwarf::Form AttrForm, uint64_t Val); |
273 | |
274 | /// Returns integer value of \p Size located by specified \p PatchOffset. |
275 | uint64_t getIntVal(uint64_t PatchOffset, unsigned Size); |
276 | |
277 | protected: |
278 | /// Writes integer value \p Val of \p Size by specified \p PatchOffset. |
279 | void applyIntVal(uint64_t PatchOffset, uint64_t Val, unsigned Size); |
280 | |
281 | /// Writes integer value \p Val of ULEB128 format by specified \p PatchOffset. |
282 | void applyULEB128(uint64_t PatchOffset, uint64_t Val); |
283 | |
284 | /// Writes integer value \p Val of SLEB128 format by specified \p PatchOffset. |
285 | void applySLEB128(uint64_t PatchOffset, uint64_t Val); |
286 | |
287 | /// Sets output format. |
288 | void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianess) { |
289 | this->Format = Format; |
290 | this->Endianess = Endianess; |
291 | } |
292 | |
293 | LinkingGlobalData &GlobalData; |
294 | |
295 | /// Some sections are generated using AsmPrinter. The real section data |
296 | /// located inside elf file in that case. Following fields points to the |
297 | /// real section content inside elf file. |
298 | size_t SectionOffsetInsideAsmPrinterOutputStart = 0; |
299 | size_t SectionOffsetInsideAsmPrinterOutputEnd = 0; |
300 | }; |
301 | |
302 | /// This class keeps contents and offsets to the debug sections. Any objects |
303 | /// which is supposed to be emitted into the debug sections should use this |
304 | /// class to track debug sections offsets and keep sections data. |
305 | class OutputSections { |
306 | public: |
307 | OutputSections(LinkingGlobalData &GlobalData) : GlobalData(GlobalData) {} |
308 | |
309 | /// Sets output format for all keeping sections. |
310 | void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianness) { |
311 | this->Format = Format; |
312 | this->Endianness = Endianness; |
313 | } |
314 | |
315 | /// Returns descriptor for the specified section of \p SectionKind. |
316 | /// The descriptor should already be created. The llvm_unreachable |
317 | /// would be raised if it is not. |
318 | const SectionDescriptor & |
319 | getSectionDescriptor(DebugSectionKind SectionKind) const { |
320 | SectionsSetTy::const_iterator It = SectionDescriptors.find(x: SectionKind); |
321 | |
322 | if (It == SectionDescriptors.end()) |
323 | llvm_unreachable( |
324 | formatv("Section {0} does not exist" , getSectionName(SectionKind)) |
325 | .str() |
326 | .c_str()); |
327 | |
328 | return *It->second; |
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 | SectionDescriptor &getSectionDescriptor(DebugSectionKind SectionKind) { |
335 | SectionsSetTy::iterator It = SectionDescriptors.find(x: SectionKind); |
336 | |
337 | if (It == SectionDescriptors.end()) |
338 | llvm_unreachable( |
339 | formatv("Section {0} does not exist" , getSectionName(SectionKind)) |
340 | .str() |
341 | .c_str()); |
342 | |
343 | assert(It->second.get() != nullptr); |
344 | |
345 | return *It->second; |
346 | } |
347 | |
348 | /// Returns descriptor for the specified section of \p SectionKind. |
349 | /// Returns std::nullopt if section descriptor is not created yet. |
350 | std::optional<const SectionDescriptor *> |
351 | tryGetSectionDescriptor(DebugSectionKind SectionKind) const { |
352 | SectionsSetTy::const_iterator It = SectionDescriptors.find(x: SectionKind); |
353 | |
354 | if (It == SectionDescriptors.end()) |
355 | return std::nullopt; |
356 | |
357 | return It->second.get(); |
358 | } |
359 | |
360 | /// Returns descriptor for the specified section of \p SectionKind. |
361 | /// Returns std::nullopt if section descriptor is not created yet. |
362 | std::optional<SectionDescriptor *> |
363 | tryGetSectionDescriptor(DebugSectionKind SectionKind) { |
364 | SectionsSetTy::iterator It = SectionDescriptors.find(x: SectionKind); |
365 | |
366 | if (It == SectionDescriptors.end()) |
367 | return std::nullopt; |
368 | |
369 | return It->second.get(); |
370 | } |
371 | |
372 | /// Returns descriptor for the specified section of \p SectionKind. |
373 | /// If descriptor does not exist then creates it. |
374 | SectionDescriptor & |
375 | getOrCreateSectionDescriptor(DebugSectionKind SectionKind) { |
376 | auto [It, Inserted] = SectionDescriptors.try_emplace(k: SectionKind); |
377 | |
378 | if (Inserted) |
379 | It->second = std::make_shared<SectionDescriptor>(args&: SectionKind, args&: GlobalData, |
380 | args&: Format, args&: Endianness); |
381 | |
382 | return *It->second; |
383 | } |
384 | |
385 | /// Erases data of all sections. |
386 | void eraseSections() { |
387 | for (auto &Section : SectionDescriptors) |
388 | Section.second->clearAllSectionData(); |
389 | } |
390 | |
391 | /// Enumerate all sections and call \p Handler for each. |
392 | void forEach(function_ref<void(SectionDescriptor &)> Handler) { |
393 | for (auto &Section : SectionDescriptors) { |
394 | assert(Section.second.get() != nullptr); |
395 | Handler(*(Section.second)); |
396 | } |
397 | } |
398 | |
399 | /// Enumerate all sections and call \p Handler for each. |
400 | void forEach( |
401 | function_ref<void(std::shared_ptr<SectionDescriptor> Section)> Handler) { |
402 | for (auto &Section : SectionDescriptors) |
403 | Handler(Section.second); |
404 | } |
405 | |
406 | /// Enumerate all sections, for each section set current offset |
407 | /// (kept by \p SectionSizesAccumulator), update current offset with section |
408 | /// length. |
409 | void assignSectionsOffsetAndAccumulateSize( |
410 | std::array<uint64_t, SectionKindsNum> &SectionSizesAccumulator) { |
411 | for (auto &Section : SectionDescriptors) { |
412 | Section.second->StartOffset = |
413 | SectionSizesAccumulator[static_cast<uint8_t>( |
414 | Section.second->getKind())]; |
415 | SectionSizesAccumulator[static_cast<uint8_t>( |
416 | Section.second->getKind())] += Section.second->getContents().size(); |
417 | } |
418 | } |
419 | |
420 | /// Enumerate all sections, for each section apply all section patches. |
421 | void applyPatches(SectionDescriptor &Section, |
422 | StringEntryToDwarfStringPoolEntryMap &DebugStrStrings, |
423 | StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings, |
424 | TypeUnit *TypeUnitPtr); |
425 | |
426 | /// Endiannes for the sections. |
427 | llvm::endianness getEndianness() const { return Endianness; } |
428 | |
429 | /// Return DWARF version. |
430 | uint16_t getVersion() const { return Format.Version; } |
431 | |
432 | /// Return size of header of debug_info table. |
433 | uint16_t () const { |
434 | return Format.Version >= 5 ? 12 : 11; |
435 | } |
436 | |
437 | /// Return size of header of debug_ table. |
438 | uint16_t () const { |
439 | assert(Format.Version >= 5); |
440 | return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16; |
441 | } |
442 | |
443 | /// Return size of header of debug_str_offsets table. |
444 | uint16_t () const { |
445 | assert(Format.Version >= 5); |
446 | return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16; |
447 | } |
448 | |
449 | /// Return size of address. |
450 | const dwarf::FormParams &getFormParams() const { return Format; } |
451 | |
452 | protected: |
453 | LinkingGlobalData &GlobalData; |
454 | |
455 | /// Format for sections. |
456 | dwarf::FormParams Format = {.Version: 4, .AddrSize: 4, .Format: dwarf::DWARF32}; |
457 | |
458 | /// Endiannes for sections. |
459 | llvm::endianness Endianness = llvm::endianness::native; |
460 | |
461 | /// All keeping sections. |
462 | using SectionsSetTy = |
463 | std::map<DebugSectionKind, std::shared_ptr<SectionDescriptor>>; |
464 | SectionsSetTy SectionDescriptors; |
465 | }; |
466 | |
467 | } // end of namespace parallel |
468 | } // end of namespace dwarf_linker |
469 | } // end of namespace llvm |
470 | |
471 | #endif // LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H |
472 | |