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
|
//===--- 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;
uint64_t Length; /// The length in bytes of all of the DIEs in this unit.
const uint16_t Version; /// The Dwarf version number for this unit.
const uint8_t AddrSize; /// The size in bytes of an address for this unit.
public:
CompileUnit(Generator &D, uint16_t V, uint8_t A)
: DG(D), DU(dwarf::DW_TAG_compile_unit), Version(V), AddrSize(A) {}
DIE getUnitDIE();
Generator &getGenerator() { return DG; }
uint64_t getOffset() const { return DU.getDebugSectionOffset(); }
uint64_t getLength() const { return Length; }
uint16_t getVersion() const { return Version; }
uint16_t getAddressSize() const { return AddrSize; }
void setOffset(uint64_t Offset) { DU.setDebugSectionOffset(Offset); }
void setLength(uint64_t L) { Length = L; }
};
/// 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 = 0;
ValueLength Length = Byte;
};
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;
// Calculate the number of bytes the Contents will take up.
size_t getContentsSize() 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
|