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 | /// Stream which stores data to the Contents. |
185 | raw_svector_ostream OS; |
186 | |
187 | /// Section patches. |
188 | #define ADD_PATCHES_LIST(T) \ |
189 | T ¬ePatch(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(¬ePatch(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 Contents; |
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 | |
272 | protected: |
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. |
303 | class OutputSections { |
304 | public: |
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 () const { |
437 | return Format.Version >= 5 ? 12 : 11; |
438 | } |
439 | |
440 | /// Return size of header of debug_ table. |
441 | uint16_t () 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 () 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 | |
455 | protected: |
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 | |