Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / lib / DWARFLinkerParallel / OutputSections.h
blobb101ac61935c5cf540a2044bb67f9a8612a2c791
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 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
10 #define LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
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/DWARFLinkerParallel/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>
31 namespace llvm {
32 namespace dwarflinker_parallel {
34 /// List of tracked debug tables.
35 enum class DebugSectionKind : uint8_t {
36 DebugInfo = 0,
37 DebugLine,
38 DebugFrame,
39 DebugRange,
40 DebugRngLists,
41 DebugLoc,
42 DebugLocLists,
43 DebugARanges,
44 DebugAbbrev,
45 DebugMacinfo,
46 DebugMacro,
47 DebugAddr,
48 DebugStr,
49 DebugLineStr,
50 DebugStrOffsets,
51 DebugPubNames,
52 DebugPubTypes,
53 DebugNames,
54 AppleNames,
55 AppleNamespaces,
56 AppleObjC,
57 AppleTypes,
58 NumberOfEnumEntries // must be last
60 constexpr static size_t SectionKindsNum =
61 static_cast<size_t>(DebugSectionKind::NumberOfEnumEntries);
63 /// Recognise the table name and match it with the DebugSectionKind.
64 std::optional<DebugSectionKind> parseDebugTableName(StringRef Name);
66 /// Return the name of the section.
67 const StringLiteral &getSectionName(DebugSectionKind SectionKind);
69 /// There are fields(sizes, offsets) which should be updated after
70 /// sections are generated. To remember offsets and related data
71 /// the descendants of SectionPatch structure should be used.
73 struct SectionPatch {
74 uint64_t PatchOffset = 0;
77 /// This structure is used to update strings offsets into .debug_str.
78 struct DebugStrPatch : SectionPatch {
79 const StringEntry *String = nullptr;
82 /// This structure is used to update strings offsets into .debug_line_str.
83 struct DebugLineStrPatch : SectionPatch {
84 const StringEntry *String = nullptr;
87 /// This structure is used to update range list offset into
88 /// .debug_ranges/.debug_rnglists.
89 struct DebugRangePatch : SectionPatch {
90 /// Indicates patch which points to immediate compile unit's attribute.
91 bool IsCompileUnitRanges = false;
94 /// This structure is used to update location list offset into
95 /// .debug_loc/.debug_loclists.
96 struct DebugLocPatch : SectionPatch {
97 int64_t AddrAdjustmentValue = 0;
100 /// This structure is used to update offset with start of another section.
101 struct SectionDescriptor;
102 struct DebugOffsetPatch : SectionPatch {
103 DebugOffsetPatch(uint64_t PatchOffset, SectionDescriptor *SectionPtr,
104 bool AddLocalValue = false)
105 : SectionPatch({PatchOffset}), SectionPtr(SectionPtr, AddLocalValue) {}
107 PointerIntPair<SectionDescriptor *, 1> SectionPtr;
110 /// This structure is used to update reference to the DIE.
111 struct DebugDieRefPatch : SectionPatch {
112 DebugDieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU, CompileUnit *RefCU,
113 uint32_t RefIdx);
115 PointerIntPair<CompileUnit *, 1> RefCU;
116 uint64_t RefDieIdxOrClonedOffset;
119 /// This structure is used to update reference to the DIE of ULEB128 form.
120 struct DebugULEB128DieRefPatch : SectionPatch {
121 DebugULEB128DieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU,
122 CompileUnit *RefCU, uint32_t RefIdx);
124 PointerIntPair<CompileUnit *, 1> RefCU;
125 uint64_t RefDieIdxOrClonedOffset;
128 /// Type for section data.
129 using OutSectionDataTy = SmallString<0>;
131 /// Type for list of pointers to patches offsets.
132 using OffsetsPtrVector = SmallVector<uint64_t *>;
134 class OutputSections;
136 /// This structure is used to keep data of the concrete section.
137 /// Like data bits, list of patches, format.
138 struct SectionDescriptor {
139 friend OutputSections;
141 SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData,
142 dwarf::FormParams Format, llvm::endianness Endianess)
143 : OS(Contents), GlobalData(GlobalData), SectionKind(SectionKind),
144 Format(Format), Endianess(Endianess) {
145 ListDebugStrPatch.setAllocator(&GlobalData.getAllocator());
146 ListDebugLineStrPatch.setAllocator(&GlobalData.getAllocator());
147 ListDebugRangePatch.setAllocator(&GlobalData.getAllocator());
148 ListDebugLocPatch.setAllocator(&GlobalData.getAllocator());
149 ListDebugDieRefPatch.setAllocator(&GlobalData.getAllocator());
150 ListDebugULEB128DieRefPatch.setAllocator(&GlobalData.getAllocator());
151 ListDebugOffsetPatch.setAllocator(&GlobalData.getAllocator());
154 /// Erase whole section contents(data bits, list of patches).
155 void clearAllSectionData();
157 /// Erase only section output data bits.
158 void clearSectionContent();
160 /// When objects(f.e. compile units) are glued into the single file,
161 /// the debug sections corresponding to the concrete object are assigned
162 /// with offsets inside the whole file. This field keeps offset
163 /// to the debug section, corresponding to this object.
164 uint64_t StartOffset = 0;
166 /// Stream which stores data to the Contents.
167 raw_svector_ostream OS;
169 /// Section patches.
170 #define ADD_PATCHES_LIST(T) \
171 T &notePatch(const T &Patch) { return List##T.add(Patch); } \
172 ArrayList<T> List##T;
174 ADD_PATCHES_LIST(DebugStrPatch)
175 ADD_PATCHES_LIST(DebugLineStrPatch)
176 ADD_PATCHES_LIST(DebugRangePatch)
177 ADD_PATCHES_LIST(DebugLocPatch)
178 ADD_PATCHES_LIST(DebugDieRefPatch)
179 ADD_PATCHES_LIST(DebugULEB128DieRefPatch)
180 ADD_PATCHES_LIST(DebugOffsetPatch)
182 /// Offsets to some fields are not known at the moment of noting patch.
183 /// In that case we remember pointers to patch offset to update them later.
184 template <typename T>
185 void notePatchWithOffsetUpdate(const T &Patch,
186 OffsetsPtrVector &PatchesOffsetsList) {
187 PatchesOffsetsList.emplace_back(&notePatch(Patch).PatchOffset);
190 /// Some sections are emitted using AsmPrinter. In that case "Contents"
191 /// member of SectionDescriptor contains elf file. This method searches
192 /// for section data inside elf file and remember offset to it.
193 void setSizesForSectionCreatedByAsmPrinter();
195 /// Returns section content.
196 StringRef getContents() {
197 if (SectionOffsetInsideAsmPrinterOutputStart == 0)
198 return StringRef(Contents.data(), Contents.size());
200 return Contents.slice(SectionOffsetInsideAsmPrinterOutputStart,
201 SectionOffsetInsideAsmPrinterOutputEnd);
204 /// Emit unit length into the current section contents.
205 void emitUnitLength(uint64_t Length) {
206 maybeEmitDwarf64Mark();
207 emitIntVal(Length, getFormParams().getDwarfOffsetByteSize());
210 /// Emit DWARF64 mark into the current section contents.
211 void maybeEmitDwarf64Mark() {
212 if (getFormParams().Format != dwarf::DWARF64)
213 return;
214 emitIntVal(dwarf::DW_LENGTH_DWARF64, 4);
217 /// Emit specified offset value into the current section contents.
218 void emitOffset(uint64_t Val) {
219 emitIntVal(Val, getFormParams().getDwarfOffsetByteSize());
222 /// Emit specified integer value into the current section contents.
223 void emitIntVal(uint64_t Val, unsigned Size);
225 /// Emit specified string value into the current section contents.
226 void emitString(dwarf::Form StringForm, const char *StringVal);
228 /// Emit specified inplace string value into the current section contents.
229 void emitInplaceString(StringRef String) {
230 OS << GlobalData.translateString(String);
231 emitIntVal(0, 1);
234 /// Emit string placeholder into the current section contents.
235 void emitStringPlaceholder() {
236 // emit bad offset which should be updated later.
237 emitOffset(0xBADDEF);
240 /// Write specified \p Value of \p AttrForm to the \p PatchOffset.
241 void apply(uint64_t PatchOffset, dwarf::Form AttrForm, uint64_t Val);
243 /// Returns section kind.
244 DebugSectionKind getKind() { return SectionKind; }
246 /// Returns section name.
247 const StringLiteral &getName() const { return getSectionName(SectionKind); }
249 /// Returns endianess used by section.
250 llvm::endianness getEndianess() const { return Endianess; }
252 /// Returns FormParams used by section.
253 dwarf::FormParams getFormParams() const { return Format; }
255 /// Returns integer value of \p Size located by specified \p PatchOffset.
256 uint64_t getIntVal(uint64_t PatchOffset, unsigned Size);
258 protected:
259 /// Writes integer value \p Val of \p Size by specified \p PatchOffset.
260 void applyIntVal(uint64_t PatchOffset, uint64_t Val, unsigned Size);
262 /// Writes integer value \p Val of ULEB128 format by specified \p PatchOffset.
263 void applyULEB128(uint64_t PatchOffset, uint64_t Val);
265 /// Writes integer value \p Val of SLEB128 format by specified \p PatchOffset.
266 void applySLEB128(uint64_t PatchOffset, uint64_t Val);
268 /// Sets output format.
269 void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianess) {
270 this->Format = Format;
271 this->Endianess = Endianess;
274 LinkingGlobalData &GlobalData;
276 /// The section kind.
277 DebugSectionKind SectionKind = DebugSectionKind::NumberOfEnumEntries;
279 /// Section data bits.
280 OutSectionDataTy Contents;
282 /// Some sections are generated using AsmPrinter. The real section data
283 /// located inside elf file in that case. Following fields points to the
284 /// real section content inside elf file.
285 size_t SectionOffsetInsideAsmPrinterOutputStart = 0;
286 size_t SectionOffsetInsideAsmPrinterOutputEnd = 0;
288 /// Output format.
289 dwarf::FormParams Format = {4, 4, dwarf::DWARF32};
290 llvm::endianness Endianess = llvm::endianness::little;
293 /// This class keeps contents and offsets to the debug sections. Any objects
294 /// which is supposed to be emitted into the debug sections should use this
295 /// class to track debug sections offsets and keep sections data.
296 class OutputSections {
297 public:
298 OutputSections(LinkingGlobalData &GlobalData) : GlobalData(GlobalData) {}
300 /// Sets output format for all keeping sections.
301 void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianness) {
302 this->Format = Format;
303 this->Endianness = Endianness;
306 /// Returns descriptor for the specified section of \p SectionKind.
307 /// The descriptor should already be created. The llvm_unreachable
308 /// would be raised if it is not.
309 const SectionDescriptor &
310 getSectionDescriptor(DebugSectionKind SectionKind) const {
311 SectionsSetTy::const_iterator It = SectionDescriptors.find(SectionKind);
313 if (It == SectionDescriptors.end())
314 llvm_unreachable(
315 formatv("Section {0} does not exist", getSectionName(SectionKind))
316 .str()
317 .c_str());
319 return It->second;
322 /// Returns descriptor for the specified section of \p SectionKind.
323 /// The descriptor should already be created. The llvm_unreachable
324 /// would be raised if it is not.
325 SectionDescriptor &getSectionDescriptor(DebugSectionKind SectionKind) {
326 SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);
328 if (It == SectionDescriptors.end())
329 llvm_unreachable(
330 formatv("Section {0} does not exist", getSectionName(SectionKind))
331 .str()
332 .c_str());
334 return It->second;
337 /// Returns descriptor for the specified section of \p SectionKind.
338 /// Returns std::nullopt if section descriptor is not created yet.
339 std::optional<const SectionDescriptor *>
340 tryGetSectionDescriptor(DebugSectionKind SectionKind) const {
341 SectionsSetTy::const_iterator It = SectionDescriptors.find(SectionKind);
343 if (It == SectionDescriptors.end())
344 return std::nullopt;
346 return &It->second;
349 /// Returns descriptor for the specified section of \p SectionKind.
350 /// Returns std::nullopt if section descriptor is not created yet.
351 std::optional<SectionDescriptor *>
352 tryGetSectionDescriptor(DebugSectionKind SectionKind) {
353 SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);
355 if (It == SectionDescriptors.end())
356 return std::nullopt;
358 return &It->second;
361 /// Returns descriptor for the specified section of \p SectionKind.
362 /// If descriptor does not exist then creates it.
363 SectionDescriptor &
364 getOrCreateSectionDescriptor(DebugSectionKind SectionKind) {
365 return SectionDescriptors
366 .try_emplace(SectionKind, SectionKind, GlobalData, Format, Endianness)
367 .first->second;
370 /// Erases data of all sections.
371 void eraseSections() {
372 for (auto &Section : SectionDescriptors)
373 Section.second.clearAllSectionData();
376 /// Enumerate all sections and call \p Handler for each.
377 void forEach(function_ref<void(SectionDescriptor &)> Handler) {
378 for (auto &Section : SectionDescriptors)
379 Handler(Section.second);
382 /// Enumerate all sections, for each section set current offset
383 /// (kept by \p SectionSizesAccumulator), update current offset with section
384 /// length.
385 void assignSectionsOffsetAndAccumulateSize(
386 std::array<uint64_t, SectionKindsNum> &SectionSizesAccumulator) {
387 for (auto &Section : SectionDescriptors) {
388 Section.second.StartOffset = SectionSizesAccumulator[static_cast<uint8_t>(
389 Section.second.getKind())];
390 SectionSizesAccumulator[static_cast<uint8_t>(Section.second.getKind())] +=
391 Section.second.getContents().size();
395 /// Enumerate all sections, for each section apply all section patches.
396 void applyPatches(SectionDescriptor &Section,
397 StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
398 StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings);
400 /// Endiannes for the sections.
401 llvm::endianness getEndianness() const { return Endianness; }
403 /// Return DWARF version.
404 uint16_t getVersion() const { return Format.Version; }
406 /// Return size of header of debug_info table.
407 uint16_t getDebugInfoHeaderSize() const {
408 return Format.Version >= 5 ? 12 : 11;
411 /// Return size of header of debug_ table.
412 uint16_t getDebugAddrHeaderSize() const {
413 assert(Format.Version >= 5);
414 return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
417 /// Return size of header of debug_str_offsets table.
418 uint16_t getDebugStrOffsetsHeaderSize() const {
419 assert(Format.Version >= 5);
420 return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
423 /// Return size of address.
424 const dwarf::FormParams &getFormParams() const { return Format; }
426 protected:
427 LinkingGlobalData &GlobalData;
429 /// Format for sections.
430 dwarf::FormParams Format = {4, 4, dwarf::DWARF32};
432 /// Endiannes for sections.
433 llvm::endianness Endianness = llvm::endianness::native;
435 /// All keeping sections.
436 using SectionsSetTy = std::map<DebugSectionKind, SectionDescriptor>;
437 SectionsSetTy SectionDescriptors;
440 } // end of namespace dwarflinker_parallel
441 } // end namespace llvm
443 #endif // LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H