reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    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
//===--- unittests/DebugInfo/DWARF/DwarfGenerator.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
//
//===----------------------------------------------------------------------===//
//
// A file that can generate DWARF debug info for unit tests.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H
#define LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H

#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/Support/Error.h"

#include <memory>
#include <string>
#include <tuple>
#include <vector>

namespace llvm {

class AsmPrinter;
class DIE;
class DIEAbbrev;
class DwarfStringPool;
class MCAsmBackend;
class MCAsmInfo;
class MCCodeEmitter;
class MCContext;
struct MCDwarfLineTableParams;
class MCInstrInfo;
class MCRegisterInfo;
class MCStreamer;
class MCSubtargetInfo;
class raw_fd_ostream;
class TargetLoweringObjectFile;
class TargetMachine;
class Triple;

namespace dwarfgen {

class Generator;
class CompileUnit;

/// A DWARF debug information entry class used to generate DWARF DIEs.
///
/// This class is used to quickly generate DWARF debug information by creating
/// child DIEs or adding attributes to the current DIE. Instances of this class
/// are created from the compile unit (dwarfgen::CompileUnit::getUnitDIE()) or
/// by calling dwarfgen::DIE::addChild(...) and using the returned DIE object.
class DIE {
  dwarfgen::CompileUnit *CU;
  llvm::DIE *Die;

protected:
  friend class Generator;
  friend class CompileUnit;

  DIE(CompileUnit *U = nullptr, llvm::DIE *D = nullptr) : CU(U), Die(D) {}

  /// Called with a compile/type unit relative offset prior to generating the
  /// DWARF debug info.
  ///
  /// \param CUOffset the compile/type unit relative offset where the
  /// abbreviation code for this DIE will be encoded.
  unsigned computeSizeAndOffsets(unsigned CUOffset);

public:
  /// Add an attribute value that has no value.
  ///
  /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
  /// represents a user defined DWARF attribute.
  /// \param Form the dwarf::Form to use when encoding the attribute. This is
  /// only used with the DW_FORM_flag_present form encoding.
  void addAttribute(uint16_t Attr, dwarf::Form Form);

  /// Add an attribute value to be encoded as a DIEInteger
  ///
  /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
  /// represents a user defined DWARF attribute.
  /// \param Form the dwarf::Form to use when encoding the attribute.
  /// \param U the unsigned integer to encode.
  void addAttribute(uint16_t Attr, dwarf::Form Form, uint64_t U);

  /// Add an attribute value to be encoded as a DIEExpr
  ///
  /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
  /// represents a user defined DWARF attribute.
  /// \param Form the dwarf::Form to use when encoding the attribute.
  /// \param Expr the MC expression used to compute the value.
  void addAttribute(uint16_t Attr, dwarf::Form Form, const MCExpr &Expr);

  /// Add an attribute value to be encoded as a DIEString or DIEInlinedString.
  ///
  /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
  /// represents a user defined DWARF attribute.
  /// \param Form the dwarf::Form to use when encoding the attribute. The form
  /// must be one of DW_FORM_strp or DW_FORM_string.
  /// \param String the string to encode.
  void addAttribute(uint16_t Attr, dwarf::Form Form, StringRef String);

  /// Add an attribute value to be encoded as a DIEEntry.
  ///
  /// DIEEntry attributes refer to other llvm::DIE objects that have been
  /// created.
  ///
  /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
  /// represents a user defined DWARF attribute.
  /// \param Form the dwarf::Form to use when encoding the attribute. The form
  /// must be one of DW_FORM_strp or DW_FORM_string.
  /// \param RefDie the DIE that this attriute refers to.
  void addAttribute(uint16_t Attr, dwarf::Form Form, dwarfgen::DIE &RefDie);

  /// Add an attribute value to be encoded as a DIEBlock.
  ///
  /// DIEBlock attributes refers to binary data that is stored as the
  /// attribute's value.
  ///
  /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
  /// represents a user defined DWARF attribute.
  /// \param Form the dwarf::Form to use when encoding the attribute. The form
  /// must be one of DW_FORM_strp or DW_FORM_string.
  /// \param P a pointer to the data to store as the attribute value.
  /// \param S the size in bytes of the data pointed to by P .
  void addAttribute(uint16_t Attr, dwarf::Form Form, const void *P, size_t S);

  /// Add a DW_AT_str_offsets_base attribute to this DIE.
  void addStrOffsetsBaseAttribute();

  /// Add a new child to this DIE object.
  ///
  /// \param Tag the dwarf::Tag to assing to the llvm::DIE object.
  /// \returns the newly created DIE object that is now a child owned by this
  /// object.
  dwarfgen::DIE addChild(dwarf::Tag Tag);
};

/// A DWARF compile unit used to generate DWARF compile/type units.
///
/// Instances of these classes are created by instances of the Generator
/// class. All information required to generate a DWARF compile unit is
/// contained inside this class.
class CompileUnit {
  Generator &DG;
  BasicDIEUnit DU;

public:
  CompileUnit(Generator &D, uint16_t V, uint8_t A)
      : DG(D), DU(V, A, dwarf::DW_TAG_compile_unit) {}
  DIE getUnitDIE();
  Generator &getGenerator() { return DG; }
  uint64_t getOffset() const { return DU.getDebugSectionOffset(); }
  uint64_t getLength() const { return DU.getLength(); }
  uint16_t getVersion() const { return DU.getDwarfVersion(); }
  uint16_t getAddressSize() const { return DU.getAddressSize(); }
  void setOffset(uint64_t Offset) { DU.setDebugSectionOffset(Offset); }
  void setLength(uint64_t Length) { DU.setLength(Length); }
};

/// A DWARF line unit-like class used to generate DWARF line units.
///
/// Instances of this class are created by instances of the Generator class.
class LineTable {
public:
  enum ValueLength { Byte = 1, Half = 2, Long = 4, Quad = 8, ULEB, SLEB };

  struct ValueAndLength {
    uint64_t Value;
    ValueLength Length;
  };

  LineTable(uint16_t Version, dwarf::DwarfFormat Format, uint8_t AddrSize,
            uint8_t SegSize = 0)
      : Version(Version), Format(Format), AddrSize(AddrSize), SegSize(SegSize) {
    assert(Version >= 2 && Version <= 5 && "unsupported version");
  }

  // Create a Prologue suitable to pass to setPrologue, with a single file and
  // include directory entry.
  DWARFDebugLine::Prologue createBasicPrologue() const;

  // Set or replace the current prologue with the specified prologue. If no
  // prologue is set, a default one will be used when generating.
  void setPrologue(DWARFDebugLine::Prologue NewPrologue);
  // Used to write an arbitrary payload instead of the standard prologue. This
  // is useful if you wish to test handling of corrupt .debug_line sections.
  void setCustomPrologue(ArrayRef<ValueAndLength> NewPrologue);

  // Add a byte to the program, with the given value. This can be used to
  // specify a special opcode, or to add arbitrary contents to the section.
  void addByte(uint8_t Value);
  // Add a standard opcode to the program. The opcode and operands do not have
  // to be valid.
  void addStandardOpcode(uint8_t Opcode, ArrayRef<ValueAndLength> Operands);
  // Add an extended opcode to the program with the specified length, opcode,
  // and operands. These values do not have to be valid.
  void addExtendedOpcode(uint64_t Length, uint8_t Opcode,
                         ArrayRef<ValueAndLength> Operands);

  // Write the contents of the LineUnit to the current section in the generator.
  void generate(MCContext &MC, AsmPrinter &Asm) const;

private:
  void writeData(ArrayRef<ValueAndLength> Data, AsmPrinter &Asm) const;
  MCSymbol *writeDefaultPrologue(AsmPrinter &Asm) const;
  void writePrologue(AsmPrinter &Asm) const;

  void writeProloguePayload(const DWARFDebugLine::Prologue &Prologue,
                            AsmPrinter &Asm) const;

  llvm::Optional<DWARFDebugLine::Prologue> Prologue;
  std::vector<ValueAndLength> CustomPrologue;
  std::vector<ValueAndLength> Contents;

  // The Version field is used for determining how to write the Prologue, if a
  // non-custom prologue is used. The version value actually written, will be
  // that specified in the Prologue, if a custom prologue has been passed in.
  // Otherwise, it will be this value.
  uint16_t Version;

  dwarf::DwarfFormat Format;
  uint8_t AddrSize;
  uint8_t SegSize;
};

/// A DWARF generator.
///
/// Generate DWARF for unit tests by creating any instance of this class and
/// calling Generator::addCompileUnit(), and then getting the dwarfgen::DIE from
/// the returned compile unit and adding attributes and children to each DIE.
class Generator {
  std::unique_ptr<MCRegisterInfo> MRI;
  std::unique_ptr<MCAsmInfo> MAI;
  std::unique_ptr<MCContext> MC;
  MCAsmBackend *MAB; // Owned by MCStreamer
  std::unique_ptr<MCInstrInfo> MII;
  std::unique_ptr<MCSubtargetInfo> MSTI;
  MCCodeEmitter *MCE; // Owned by MCStreamer
  MCStreamer *MS;     // Owned by AsmPrinter
  std::unique_ptr<TargetMachine> TM;
  TargetLoweringObjectFile *TLOF; // Owned by TargetMachine;
  std::unique_ptr<AsmPrinter> Asm;
  BumpPtrAllocator Allocator;
  std::unique_ptr<DwarfStringPool> StringPool; // Entries owned by Allocator.
  std::vector<std::unique_ptr<CompileUnit>> CompileUnits;
  std::vector<std::unique_ptr<LineTable>> LineTables;
  DIEAbbrevSet Abbreviations;

  MCSymbol *StringOffsetsStartSym;

  SmallString<4096> FileBytes;
  /// The stream we use to generate the DWARF into as an ELF file.
  std::unique_ptr<raw_svector_ostream> Stream;
  /// The DWARF version to generate.
  uint16_t Version;

  /// Private constructor, call Generator::Create(...) to get a DWARF generator
  /// expected.
  Generator();

  /// Create the streamer and setup the output buffer.
  llvm::Error init(Triple TheTriple, uint16_t DwarfVersion);

public:
  /// Create a DWARF generator or get an appropriate error.
  ///
  /// \param TheTriple the triple to use when creating any required support
  /// classes needed to emit the DWARF.
  /// \param DwarfVersion the version of DWARF to emit.
  ///
  /// \returns a llvm::Expected that either contains a unique_ptr to a Generator
  /// or a llvm::Error.
  static llvm::Expected<std::unique_ptr<Generator>>
  create(Triple TheTriple, uint16_t DwarfVersion);

  ~Generator();

  /// Generate all DWARF sections and return a memory buffer that
  /// contains an ELF file that contains the DWARF.
  StringRef generate();

  /// Add a compile unit to be generated.
  ///
  /// \returns a dwarfgen::CompileUnit that can be used to retrieve the compile
  /// unit dwarfgen::DIE that can be used to add attributes and add child DIE
  /// objects to.
  dwarfgen::CompileUnit &addCompileUnit();

  /// Add a line table unit to be generated.
  /// \param DwarfFormat the DWARF format to use (DWARF32 or DWARF64).
  ///
  /// \returns a dwarfgen::LineTable that can be used to customise the contents
  /// of the line table.
  LineTable &
  addLineTable(dwarf::DwarfFormat DwarfFormat = dwarf::DwarfFormat::DWARF32);

  BumpPtrAllocator &getAllocator() { return Allocator; }
  AsmPrinter *getAsmPrinter() const { return Asm.get(); }
  MCContext *getMCContext() const { return MC.get(); }
  DIEAbbrevSet &getAbbrevSet() { return Abbreviations; }
  DwarfStringPool &getStringPool() { return *StringPool; }
  MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; }

  /// Save the generated DWARF file to disk.
  ///
  /// \param Path the path to save the ELF file to.
  bool saveFile(StringRef Path);
};

} // end namespace dwarfgen

} // end namespace llvm

#endif // LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H