xref: /freebsd/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/OutputSections.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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}), 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 
SectionDescriptorSectionDescriptor155   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 &notePatch(const T &Patch) { return List##T.add(Patch); }                  \
195   ArrayList<T> List##T;
196 
197   ADD_PATCHES_LIST(DebugStrPatch)
ADD_PATCHES_LISTSectionDescriptor198   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(&notePatch(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.
getContentsSectionDescriptor226   StringRef getContents() override {
227     if (SectionOffsetInsideAsmPrinterOutputStart == 0)
228       return Contents;
229 
230     return Contents.slice(SectionOffsetInsideAsmPrinterOutputStart,
231                           SectionOffsetInsideAsmPrinterOutputEnd);
232   }
233 
234   /// Emit unit length into the current section contents.
emitUnitLengthSectionDescriptor235   void emitUnitLength(uint64_t Length) {
236     maybeEmitDwarf64Mark();
237     emitIntVal(Length, getFormParams().getDwarfOffsetByteSize());
238   }
239 
240   /// Emit DWARF64 mark into the current section contents.
maybeEmitDwarf64MarkSectionDescriptor241   void maybeEmitDwarf64Mark() {
242     if (getFormParams().Format != dwarf::DWARF64)
243       return;
244     emitIntVal(dwarf::DW_LENGTH_DWARF64, 4);
245   }
246 
247   /// Emit specified offset value into the current section contents.
emitOffsetSectionDescriptor248   void emitOffset(uint64_t Val) {
249     emitIntVal(Val, 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.
emitInplaceStringSectionDescriptor260   void emitInplaceString(StringRef String) {
261     OS << String;
262     emitIntVal(0, 1);
263   }
264 
265   /// Emit string placeholder into the current section contents.
emitStringPlaceholderSectionDescriptor266   void emitStringPlaceholder() {
267     // emit bad offset which should be updated later.
268     emitOffset(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.
setOutputFormatSectionDescriptor288   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:
OutputSections(LinkingGlobalData & GlobalData)307   OutputSections(LinkingGlobalData &GlobalData) : GlobalData(GlobalData) {}
308 
309   /// Sets output format for all keeping sections.
setOutputFormat(dwarf::FormParams Format,llvm::endianness Endianness)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 &
getSectionDescriptor(DebugSectionKind SectionKind)319   getSectionDescriptor(DebugSectionKind SectionKind) const {
320     SectionsSetTy::const_iterator It = SectionDescriptors.find(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.
getSectionDescriptor(DebugSectionKind SectionKind)334   SectionDescriptor &getSectionDescriptor(DebugSectionKind SectionKind) {
335     SectionsSetTy::iterator It = SectionDescriptors.find(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 *>
tryGetSectionDescriptor(DebugSectionKind SectionKind)351   tryGetSectionDescriptor(DebugSectionKind SectionKind) const {
352     SectionsSetTy::const_iterator It = SectionDescriptors.find(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 *>
tryGetSectionDescriptor(DebugSectionKind SectionKind)363   tryGetSectionDescriptor(DebugSectionKind SectionKind) {
364     SectionsSetTy::iterator It = SectionDescriptors.find(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 &
getOrCreateSectionDescriptor(DebugSectionKind SectionKind)375   getOrCreateSectionDescriptor(DebugSectionKind SectionKind) {
376     auto [It, Inserted] = SectionDescriptors.try_emplace(SectionKind);
377 
378     if (Inserted)
379       It->second = std::make_shared<SectionDescriptor>(SectionKind, GlobalData,
380                                                        Format, Endianness);
381 
382     return *It->second;
383   }
384 
385   /// Erases data of all sections.
eraseSections()386   void eraseSections() {
387     for (auto &Section : SectionDescriptors)
388       Section.second->clearAllSectionData();
389   }
390 
391   /// Enumerate all sections and call \p Handler for each.
forEach(function_ref<void (SectionDescriptor &)> Handler)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.
forEach(function_ref<void (std::shared_ptr<SectionDescriptor> Section)> Handler)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.
assignSectionsOffsetAndAccumulateSize(std::array<uint64_t,SectionKindsNum> & SectionSizesAccumulator)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.
getEndianness()427   llvm::endianness getEndianness() const { return Endianness; }
428 
429   /// Return DWARF version.
getVersion()430   uint16_t getVersion() const { return Format.Version; }
431 
432   /// Return size of header of debug_info table.
getDebugInfoHeaderSize()433   uint16_t getDebugInfoHeaderSize() const {
434     return Format.Version >= 5 ? 12 : 11;
435   }
436 
437   /// Return size of header of debug_ table.
getDebugAddrHeaderSize()438   uint16_t getDebugAddrHeaderSize() 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.
getDebugStrOffsetsHeaderSize()444   uint16_t getDebugStrOffsetsHeaderSize() const {
445     assert(Format.Version >= 5);
446     return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
447   }
448 
449   /// Return size of address.
getFormParams()450   const dwarf::FormParams &getFormParams() const { return Format; }
451 
452 protected:
453   LinkingGlobalData &GlobalData;
454 
455   /// Format for sections.
456   dwarf::FormParams Format = {4, 4, 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