aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/DWARFLinker/Parallel/OutputSections.h
blob: 5043e918013e46662352ba4afc0385b30e44510f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
//===- OutputSections.h -----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H
#define LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H

#include "ArrayList.h"
#include "StringEntryToDwarfStringPoolEntryMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
#include "llvm/DWARFLinker/StringPool.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFObject.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/raw_ostream.h"
#include <array>
#include <cstdint>

namespace llvm {
namespace dwarf_linker {
namespace parallel {

class TypeUnit;

/// There are fields(sizes, offsets) which should be updated after
/// sections are generated. To remember offsets and related data
/// the descendants of SectionPatch structure should be used.

struct SectionPatch {
  uint64_t PatchOffset = 0;
};

/// This structure is used to update strings offsets into .debug_str.
struct DebugStrPatch : SectionPatch {
  const StringEntry *String = nullptr;
};

/// This structure is used to update strings offsets into .debug_line_str.
struct DebugLineStrPatch : SectionPatch {
  const StringEntry *String = nullptr;
};

/// This structure is used to update range list offset into
/// .debug_ranges/.debug_rnglists.
struct DebugRangePatch : SectionPatch {
  /// Indicates patch which points to immediate compile unit's attribute.
  bool IsCompileUnitRanges = false;
};

/// This structure is used to update location list offset into
/// .debug_loc/.debug_loclists.
struct DebugLocPatch : SectionPatch {
  int64_t AddrAdjustmentValue = 0;
};

/// This structure is used to update offset with start of another section.
struct SectionDescriptor;
struct DebugOffsetPatch : SectionPatch {
  DebugOffsetPatch(uint64_t PatchOffset, SectionDescriptor *SectionPtr,
                   bool AddLocalValue = false)
      : SectionPatch({PatchOffset}), SectionPtr(SectionPtr, AddLocalValue) {}

  PointerIntPair<SectionDescriptor *, 1> SectionPtr;
};

/// This structure is used to update reference to the DIE.
struct DebugDieRefPatch : SectionPatch {
  DebugDieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU, CompileUnit *RefCU,
                   uint32_t RefIdx);

  PointerIntPair<CompileUnit *, 1> RefCU;
  uint64_t RefDieIdxOrClonedOffset = 0;
};

/// This structure is used to update reference to the DIE of ULEB128 form.
struct DebugULEB128DieRefPatch : SectionPatch {
  DebugULEB128DieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU,
                          CompileUnit *RefCU, uint32_t RefIdx);

  PointerIntPair<CompileUnit *, 1> RefCU;
  uint64_t RefDieIdxOrClonedOffset = 0;
};

/// This structure is used to update reference to the type DIE.
struct DebugDieTypeRefPatch : SectionPatch {
  DebugDieTypeRefPatch(uint64_t PatchOffset, TypeEntry *RefTypeName);

  TypeEntry *RefTypeName = nullptr;
};

/// This structure is used to update reference to the type DIE.
struct DebugType2TypeDieRefPatch : SectionPatch {
  DebugType2TypeDieRefPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
                            TypeEntry *RefTypeName);

  DIE *Die = nullptr;
  TypeEntry *TypeName = nullptr;
  TypeEntry *RefTypeName = nullptr;
};

struct DebugTypeStrPatch : SectionPatch {
  DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
                    StringEntry *String);

  DIE *Die = nullptr;
  TypeEntry *TypeName = nullptr;
  StringEntry *String = nullptr;
};

struct DebugTypeLineStrPatch : SectionPatch {
  DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
                        StringEntry *String);

  DIE *Die = nullptr;
  TypeEntry *TypeName = nullptr;
  StringEntry *String = nullptr;
};

struct DebugTypeDeclFilePatch {
  DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName, StringEntry *Directory,
                         StringEntry *FilePath);

  DIE *Die = nullptr;
  TypeEntry *TypeName = nullptr;
  StringEntry *Directory = nullptr;
  StringEntry *FilePath = nullptr;
  uint32_t FileID = 0;
};

/// Type for section data.
using OutSectionDataTy = SmallString<0>;

/// Type for list of pointers to patches offsets.
using OffsetsPtrVector = SmallVector<uint64_t *>;

class OutputSections;

/// This structure is used to keep data of the concrete section.
/// Like data bits, list of patches, format.
struct SectionDescriptor : SectionDescriptorBase {
  friend OutputSections;

  SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData,
                    dwarf::FormParams Format, llvm::endianness Endianess)
      : SectionDescriptorBase(SectionKind, Format, Endianess), OS(Contents),
        ListDebugStrPatch(&GlobalData.getAllocator()),
        ListDebugLineStrPatch(&GlobalData.getAllocator()),
        ListDebugRangePatch(&GlobalData.getAllocator()),
        ListDebugLocPatch(&GlobalData.getAllocator()),
        ListDebugDieRefPatch(&GlobalData.getAllocator()),
        ListDebugULEB128DieRefPatch(&GlobalData.getAllocator()),
        ListDebugOffsetPatch(&GlobalData.getAllocator()),
        ListDebugDieTypeRefPatch(&GlobalData.getAllocator()),
        ListDebugType2TypeDieRefPatch(&GlobalData.getAllocator()),
        ListDebugTypeStrPatch(&GlobalData.getAllocator()),
        ListDebugTypeLineStrPatch(&GlobalData.getAllocator()),
        ListDebugTypeDeclFilePatch(&GlobalData.getAllocator()),
        GlobalData(GlobalData) {}

  /// Erase whole section content(data bits, list of patches).
  void clearAllSectionData();

  /// Erase only section output data bits.
  void clearSectionContent();

  /// When objects(f.e. compile units) are glued into the single file,
  /// the debug sections corresponding to the concrete object are assigned
  /// with offsets inside the whole file. This field keeps offset
  /// to the debug section, corresponding to this object.
  uint64_t StartOffset = 0;

protected:
  /// Section data bits.
  OutSectionDataTy Contents;

public:
  /// Stream which stores data to the Contents.
  raw_svector_ostream OS;

  /// Section patches.
#define ADD_PATCHES_LIST(T)                                                    \
  T &notePatch(const T &Patch) { return List##T.add(Patch); }                  \
  ArrayList<T> List##T;

  ADD_PATCHES_LIST(DebugStrPatch)
  ADD_PATCHES_LIST(DebugLineStrPatch)
  ADD_PATCHES_LIST(DebugRangePatch)
  ADD_PATCHES_LIST(DebugLocPatch)
  ADD_PATCHES_LIST(DebugDieRefPatch)
  ADD_PATCHES_LIST(DebugULEB128DieRefPatch)
  ADD_PATCHES_LIST(DebugOffsetPatch)
  ADD_PATCHES_LIST(DebugDieTypeRefPatch)
  ADD_PATCHES_LIST(DebugType2TypeDieRefPatch)
  ADD_PATCHES_LIST(DebugTypeStrPatch)
  ADD_PATCHES_LIST(DebugTypeLineStrPatch)
  ADD_PATCHES_LIST(DebugTypeDeclFilePatch)

  /// While creating patches, offsets to attributes may be partially
  /// unknown(because size of abbreviation number is unknown). In such case we
  /// remember patch itself and pointer to patch application offset to add size
  /// of abbreviation number later.
  template <typename T>
  void notePatchWithOffsetUpdate(const T &Patch,
                                 OffsetsPtrVector &PatchesOffsetsList) {
    PatchesOffsetsList.emplace_back(&notePatch(Patch).PatchOffset);
  }

  /// Some sections are emitted using AsmPrinter. In that case "Contents"
  /// member of SectionDescriptor contains elf file. This method searches
  /// for section data inside elf file and remember offset to it.
  void setSizesForSectionCreatedByAsmPrinter();

  /// Returns section content.
  StringRef getContents() override {
    if (SectionOffsetInsideAsmPrinterOutputStart == 0)
      return Contents;

    return Contents.slice(SectionOffsetInsideAsmPrinterOutputStart,
                          SectionOffsetInsideAsmPrinterOutputEnd);
  }

  /// Emit unit length into the current section contents.
  void emitUnitLength(uint64_t Length) {
    maybeEmitDwarf64Mark();
    emitIntVal(Length, getFormParams().getDwarfOffsetByteSize());
  }

  /// Emit DWARF64 mark into the current section contents.
  void maybeEmitDwarf64Mark() {
    if (getFormParams().Format != dwarf::DWARF64)
      return;
    emitIntVal(dwarf::DW_LENGTH_DWARF64, 4);
  }

  /// Emit specified offset value into the current section contents.
  void emitOffset(uint64_t Val) {
    emitIntVal(Val, getFormParams().getDwarfOffsetByteSize());
  }

  /// Emit specified integer value into the current section contents.
  void emitIntVal(uint64_t Val, unsigned Size);

  void emitString(dwarf::Form StringForm, const char *StringVal);

  void emitBinaryData(llvm::StringRef Data);

  /// Emit specified inplace string value into the current section contents.
  void emitInplaceString(StringRef String) {
    OS << String;
    emitIntVal(0, 1);
  }

  /// Emit string placeholder into the current section contents.
  void emitStringPlaceholder() {
    // emit bad offset which should be updated later.
    emitOffset(0xBADDEF);
  }

  /// Write specified \p Value of \p AttrForm to the \p PatchOffset.
  void apply(uint64_t PatchOffset, dwarf::Form AttrForm, uint64_t Val);

  /// Returns integer value of \p Size located by specified \p PatchOffset.
  uint64_t getIntVal(uint64_t PatchOffset, unsigned Size);

protected:
  /// Writes integer value \p Val of \p Size by specified \p PatchOffset.
  void applyIntVal(uint64_t PatchOffset, uint64_t Val, unsigned Size);

  /// Writes integer value \p Val of ULEB128 format by specified \p PatchOffset.
  void applyULEB128(uint64_t PatchOffset, uint64_t Val);

  /// Writes integer value \p Val of SLEB128 format by specified \p PatchOffset.
  void applySLEB128(uint64_t PatchOffset, uint64_t Val);

  /// Sets output format.
  void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianess) {
    this->Format = Format;
    this->Endianess = Endianess;
  }

  LinkingGlobalData &GlobalData;

  /// Some sections are generated using AsmPrinter. The real section data
  /// located inside elf file in that case. Following fields points to the
  /// real section content inside elf file.
  size_t SectionOffsetInsideAsmPrinterOutputStart = 0;
  size_t SectionOffsetInsideAsmPrinterOutputEnd = 0;
};

/// This class keeps contents and offsets to the debug sections. Any objects
/// which is supposed to be emitted into the debug sections should use this
/// class to track debug sections offsets and keep sections data.
class OutputSections {
public:
  OutputSections(LinkingGlobalData &GlobalData) : GlobalData(GlobalData) {}

  /// Sets output format for all keeping sections.
  void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianness) {
    this->Format = Format;
    this->Endianness = Endianness;
  }

  /// Returns descriptor for the specified section of \p SectionKind.
  /// The descriptor should already be created. The llvm_unreachable
  /// would be raised if it is not.
  const SectionDescriptor &
  getSectionDescriptor(DebugSectionKind SectionKind) const {
    SectionsSetTy::const_iterator It = SectionDescriptors.find(SectionKind);

    if (It == SectionDescriptors.end())
      llvm_unreachable(
          formatv("Section {0} does not exist", getSectionName(SectionKind))
              .str()
              .c_str());

    return *It->second;
  }

  /// Returns descriptor for the specified section of \p SectionKind.
  /// The descriptor should already be created. The llvm_unreachable
  /// would be raised if it is not.
  SectionDescriptor &getSectionDescriptor(DebugSectionKind SectionKind) {
    SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);

    if (It == SectionDescriptors.end())
      llvm_unreachable(
          formatv("Section {0} does not exist", getSectionName(SectionKind))
              .str()
              .c_str());

    assert(It->second.get() != nullptr);

    return *It->second;
  }

  /// Returns descriptor for the specified section of \p SectionKind.
  /// Returns std::nullopt if section descriptor is not created yet.
  std::optional<const SectionDescriptor *>
  tryGetSectionDescriptor(DebugSectionKind SectionKind) const {
    SectionsSetTy::const_iterator It = SectionDescriptors.find(SectionKind);

    if (It == SectionDescriptors.end())
      return std::nullopt;

    return It->second.get();
  }

  /// Returns descriptor for the specified section of \p SectionKind.
  /// Returns std::nullopt if section descriptor is not created yet.
  std::optional<SectionDescriptor *>
  tryGetSectionDescriptor(DebugSectionKind SectionKind) {
    SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);

    if (It == SectionDescriptors.end())
      return std::nullopt;

    return It->second.get();
  }

  /// Returns descriptor for the specified section of \p SectionKind.
  /// If descriptor does not exist then creates it.
  SectionDescriptor &
  getOrCreateSectionDescriptor(DebugSectionKind SectionKind) {
    auto [It, Inserted] = SectionDescriptors.try_emplace(SectionKind);

    if (Inserted)
      It->second = std::make_shared<SectionDescriptor>(SectionKind, GlobalData,
                                                       Format, Endianness);

    return *It->second;
  }

  /// Erases data of all sections.
  void eraseSections() {
    for (auto &Section : SectionDescriptors)
      Section.second->clearAllSectionData();
  }

  /// Enumerate all sections and call \p Handler for each.
  void forEach(function_ref<void(SectionDescriptor &)> Handler) {
    for (auto &Section : SectionDescriptors) {
      assert(Section.second.get() != nullptr);
      Handler(*(Section.second));
    }
  }

  /// Enumerate all sections and call \p Handler for each.
  void forEach(
      function_ref<void(std::shared_ptr<SectionDescriptor> Section)> Handler) {
    for (auto &Section : SectionDescriptors)
      Handler(Section.second);
  }

  /// Enumerate all sections, for each section set current offset
  /// (kept by \p SectionSizesAccumulator), update current offset with section
  /// length.
  void assignSectionsOffsetAndAccumulateSize(
      std::array<uint64_t, SectionKindsNum> &SectionSizesAccumulator) {
    for (auto &Section : SectionDescriptors) {
      Section.second->StartOffset =
          SectionSizesAccumulator[static_cast<uint8_t>(
              Section.second->getKind())];
      SectionSizesAccumulator[static_cast<uint8_t>(
          Section.second->getKind())] += Section.second->getContents().size();
    }
  }

  /// Enumerate all sections, for each section apply all section patches.
  void applyPatches(SectionDescriptor &Section,
                    StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
                    StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings,
                    TypeUnit *TypeUnitPtr);

  /// Endiannes for the sections.
  llvm::endianness getEndianness() const { return Endianness; }

  /// Return DWARF version.
  uint16_t getVersion() const { return Format.Version; }

  /// Return size of header of debug_info table.
  uint16_t getDebugInfoHeaderSize() const {
    return Format.Version >= 5 ? 12 : 11;
  }

  /// Return size of header of debug_ table.
  uint16_t getDebugAddrHeaderSize() const {
    assert(Format.Version >= 5);
    return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
  }

  /// Return size of header of debug_str_offsets table.
  uint16_t getDebugStrOffsetsHeaderSize() const {
    assert(Format.Version >= 5);
    return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
  }

  /// Return size of address.
  const dwarf::FormParams &getFormParams() const { return Format; }

protected:
  LinkingGlobalData &GlobalData;

  /// Format for sections.
  dwarf::FormParams Format = {4, 4, dwarf::DWARF32};

  /// Endiannes for sections.
  llvm::endianness Endianness = llvm::endianness::native;

  /// All keeping sections.
  using SectionsSetTy =
      std::map<DebugSectionKind, std::shared_ptr<SectionDescriptor>>;
  SectionsSetTy SectionDescriptors;
};

} // end of namespace parallel
} // end of namespace dwarf_linker
} // end of namespace llvm

#endif // LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H