• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- unittests/DebugInfo/DWARF/DwarfGenerator.h -------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // A file that can generate DWARF debug info for unit tests.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H
15 #define LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H
16 
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/CodeGen/DIE.h"
19 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
20 #include "llvm/Support/Error.h"
21 
22 #include <memory>
23 #include <string>
24 #include <tuple>
25 #include <vector>
26 
27 namespace llvm {
28 
29 class AsmPrinter;
30 class DIE;
31 class DIEAbbrev;
32 class DwarfStringPool;
33 class MCAsmBackend;
34 class MCAsmInfo;
35 class MCCodeEmitter;
36 class MCContext;
37 struct MCDwarfLineTableParams;
38 class MCInstrInfo;
39 class MCRegisterInfo;
40 class MCStreamer;
41 class MCSubtargetInfo;
42 class raw_fd_ostream;
43 class TargetLoweringObjectFile;
44 class TargetMachine;
45 class Triple;
46 
47 namespace dwarfgen {
48 
49 class Generator;
50 class CompileUnit;
51 
52 /// A DWARF debug information entry class used to generate DWARF DIEs.
53 ///
54 /// This class is used to quickly generate DWARF debug information by creating
55 /// child DIEs or adding attributes to the current DIE. Instances of this class
56 /// are created from the compile unit (dwarfgen::CompileUnit::getUnitDIE()) or
57 /// by calling dwarfgen::DIE::addChild(...) and using the returned DIE object.
58 class DIE {
59   dwarfgen::CompileUnit *CU;
60   llvm::DIE *Die;
61 
62 protected:
63   friend class Generator;
64   friend class CompileUnit;
65 
CU(U)66   DIE(CompileUnit *U = nullptr, llvm::DIE *D = nullptr) : CU(U), Die(D) {}
67 
68   /// Called with a compile/type unit relative offset prior to generating the
69   /// DWARF debug info.
70   ///
71   /// \param CUOffset the compile/type unit relative offset where the
72   /// abbreviation code for this DIE will be encoded.
73   unsigned computeSizeAndOffsets(unsigned CUOffset);
74 
75 public:
76   /// Add an attribute value that has no value.
77   ///
78   /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
79   /// represents a user defined DWARF attribute.
80   /// \param Form the dwarf::Form to use when encoding the attribute. This is
81   /// only used with the DW_FORM_flag_present form encoding.
82   void addAttribute(uint16_t Attr, dwarf::Form Form);
83 
84   /// Add an attribute value to be encoded as a DIEInteger
85   ///
86   /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
87   /// represents a user defined DWARF attribute.
88   /// \param Form the dwarf::Form to use when encoding the attribute.
89   /// \param U the unsigned integer to encode.
90   void addAttribute(uint16_t Attr, dwarf::Form Form, uint64_t U);
91 
92   /// Add an attribute value to be encoded as a DIEExpr
93   ///
94   /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
95   /// represents a user defined DWARF attribute.
96   /// \param Form the dwarf::Form to use when encoding the attribute.
97   /// \param Expr the MC expression used to compute the value.
98   void addAttribute(uint16_t Attr, dwarf::Form Form, const MCExpr &Expr);
99 
100   /// Add an attribute value to be encoded as a DIEString or DIEInlinedString.
101   ///
102   /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
103   /// represents a user defined DWARF attribute.
104   /// \param Form the dwarf::Form to use when encoding the attribute. The form
105   /// must be one of DW_FORM_strp or DW_FORM_string.
106   /// \param String the string to encode.
107   void addAttribute(uint16_t Attr, dwarf::Form Form, StringRef String);
108 
109   /// Add an attribute value to be encoded as a DIEEntry.
110   ///
111   /// DIEEntry attributes refer to other llvm::DIE objects that have been
112   /// created.
113   ///
114   /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
115   /// represents a user defined DWARF attribute.
116   /// \param Form the dwarf::Form to use when encoding the attribute. The form
117   /// must be one of DW_FORM_strp or DW_FORM_string.
118   /// \param RefDie the DIE that this attriute refers to.
119   void addAttribute(uint16_t Attr, dwarf::Form Form, dwarfgen::DIE &RefDie);
120 
121   /// Add an attribute value to be encoded as a DIEBlock.
122   ///
123   /// DIEBlock attributes refers to binary data that is stored as the
124   /// attribute's value.
125   ///
126   /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
127   /// represents a user defined DWARF attribute.
128   /// \param Form the dwarf::Form to use when encoding the attribute. The form
129   /// must be one of DW_FORM_strp or DW_FORM_string.
130   /// \param P a pointer to the data to store as the attribute value.
131   /// \param S the size in bytes of the data pointed to by P .
132   void addAttribute(uint16_t Attr, dwarf::Form Form, const void *P, size_t S);
133 
134   /// Add a DW_AT_str_offsets_base attribute to this DIE.
135   void addStrOffsetsBaseAttribute();
136 
137   /// Add a new child to this DIE object.
138   ///
139   /// \param Tag the dwarf::Tag to assing to the llvm::DIE object.
140   /// \returns the newly created DIE object that is now a child owned by this
141   /// object.
142   dwarfgen::DIE addChild(dwarf::Tag Tag);
143 };
144 
145 /// A DWARF compile unit used to generate DWARF compile/type units.
146 ///
147 /// Instances of these classes are created by instances of the Generator
148 /// class. All information required to generate a DWARF compile unit is
149 /// contained inside this class.
150 class CompileUnit {
151   Generator &DG;
152   BasicDIEUnit DU;
153 
154 public:
CompileUnit(Generator & D,uint16_t V,uint8_t A)155   CompileUnit(Generator &D, uint16_t V, uint8_t A)
156       : DG(D), DU(V, A, dwarf::DW_TAG_compile_unit) {}
157   DIE getUnitDIE();
getGenerator()158   Generator &getGenerator() { return DG; }
getOffset()159   uint64_t getOffset() const { return DU.getDebugSectionOffset(); }
getLength()160   uint64_t getLength() const { return DU.getLength(); }
getVersion()161   uint16_t getVersion() const { return DU.getDwarfVersion(); }
getAddressSize()162   uint16_t getAddressSize() const { return DU.getAddressSize(); }
setOffset(uint64_t Offset)163   void setOffset(uint64_t Offset) { DU.setDebugSectionOffset(Offset); }
setLength(uint64_t Length)164   void setLength(uint64_t Length) { DU.setLength(Length); }
165 };
166 
167 /// A DWARF line unit-like class used to generate DWARF line units.
168 ///
169 /// Instances of this class are created by instances of the Generator class.
170 class LineTable {
171 public:
172   enum ValueLength { Byte = 1, Half = 2, Long = 4, Quad = 8, ULEB, SLEB };
173 
174   struct ValueAndLength {
175     uint64_t Value;
176     ValueLength Length;
177   };
178 
179   LineTable(uint16_t Version, dwarf::DwarfFormat Format, uint8_t AddrSize,
180             uint8_t SegSize = 0)
Version(Version)181       : Version(Version), Format(Format), AddrSize(AddrSize), SegSize(SegSize) {
182     assert(Version >= 2 && Version <= 5 && "unsupported version");
183   }
184 
185   // Create a Prologue suitable to pass to setPrologue, with a single file and
186   // include directory entry.
187   DWARFDebugLine::Prologue createBasicPrologue() const;
188 
189   // Set or replace the current prologue with the specified prologue. If no
190   // prologue is set, a default one will be used when generating.
191   void setPrologue(DWARFDebugLine::Prologue NewPrologue);
192   // Used to write an arbitrary payload instead of the standard prologue. This
193   // is useful if you wish to test handling of corrupt .debug_line sections.
194   void setCustomPrologue(ArrayRef<ValueAndLength> NewPrologue);
195 
196   // Add a byte to the program, with the given value. This can be used to
197   // specify a special opcode, or to add arbitrary contents to the section.
198   void addByte(uint8_t Value);
199   // Add a standard opcode to the program. The opcode and operands do not have
200   // to be valid.
201   void addStandardOpcode(uint8_t Opcode, ArrayRef<ValueAndLength> Operands);
202   // Add an extended opcode to the program with the specified length, opcode,
203   // and operands. These values do not have to be valid.
204   void addExtendedOpcode(uint64_t Length, uint8_t Opcode,
205                          ArrayRef<ValueAndLength> Operands);
206 
207   // Write the contents of the LineUnit to the current section in the generator.
208   void generate(MCContext &MC, AsmPrinter &Asm) const;
209 
210 private:
211   void writeData(ArrayRef<ValueAndLength> Data, AsmPrinter &Asm) const;
212   MCSymbol *writeDefaultPrologue(AsmPrinter &Asm) const;
213   void writePrologue(AsmPrinter &Asm) const;
214 
215   void writeProloguePayload(const DWARFDebugLine::Prologue &Prologue,
216                             AsmPrinter &Asm) const;
217 
218   llvm::Optional<DWARFDebugLine::Prologue> Prologue;
219   std::vector<ValueAndLength> CustomPrologue;
220   std::vector<ValueAndLength> Contents;
221 
222   // The Version field is used for determining how to write the Prologue, if a
223   // non-custom prologue is used. The version value actually written, will be
224   // that specified in the Prologue, if a custom prologue has been passed in.
225   // Otherwise, it will be this value.
226   uint16_t Version;
227 
228   dwarf::DwarfFormat Format;
229   uint8_t AddrSize;
230   uint8_t SegSize;
231 };
232 
233 /// A DWARF generator.
234 ///
235 /// Generate DWARF for unit tests by creating any instance of this class and
236 /// calling Generator::addCompileUnit(), and then getting the dwarfgen::DIE from
237 /// the returned compile unit and adding attributes and children to each DIE.
238 class Generator {
239   std::unique_ptr<MCRegisterInfo> MRI;
240   std::unique_ptr<MCAsmInfo> MAI;
241   std::unique_ptr<MCContext> MC;
242   MCAsmBackend *MAB; // Owned by MCStreamer
243   std::unique_ptr<MCInstrInfo> MII;
244   std::unique_ptr<MCSubtargetInfo> MSTI;
245   MCCodeEmitter *MCE; // Owned by MCStreamer
246   MCStreamer *MS;     // Owned by AsmPrinter
247   std::unique_ptr<TargetMachine> TM;
248   TargetLoweringObjectFile *TLOF; // Owned by TargetMachine;
249   std::unique_ptr<AsmPrinter> Asm;
250   BumpPtrAllocator Allocator;
251   std::unique_ptr<DwarfStringPool> StringPool; // Entries owned by Allocator.
252   std::vector<std::unique_ptr<CompileUnit>> CompileUnits;
253   std::vector<std::unique_ptr<LineTable>> LineTables;
254   DIEAbbrevSet Abbreviations;
255 
256   MCSymbol *StringOffsetsStartSym;
257 
258   SmallString<4096> FileBytes;
259   /// The stream we use to generate the DWARF into as an ELF file.
260   std::unique_ptr<raw_svector_ostream> Stream;
261   /// The DWARF version to generate.
262   uint16_t Version;
263 
264   /// Private constructor, call Generator::Create(...) to get a DWARF generator
265   /// expected.
266   Generator();
267 
268   /// Create the streamer and setup the output buffer.
269   llvm::Error init(Triple TheTriple, uint16_t DwarfVersion);
270 
271 public:
272   /// Create a DWARF generator or get an appropriate error.
273   ///
274   /// \param TheTriple the triple to use when creating any required support
275   /// classes needed to emit the DWARF.
276   /// \param DwarfVersion the version of DWARF to emit.
277   ///
278   /// \returns a llvm::Expected that either contains a unique_ptr to a Generator
279   /// or a llvm::Error.
280   static llvm::Expected<std::unique_ptr<Generator>>
281   create(Triple TheTriple, uint16_t DwarfVersion);
282 
283   ~Generator();
284 
285   /// Generate all DWARF sections and return a memory buffer that
286   /// contains an ELF file that contains the DWARF.
287   StringRef generate();
288 
289   /// Add a compile unit to be generated.
290   ///
291   /// \returns a dwarfgen::CompileUnit that can be used to retrieve the compile
292   /// unit dwarfgen::DIE that can be used to add attributes and add child DIE
293   /// objects to.
294   dwarfgen::CompileUnit &addCompileUnit();
295 
296   /// Add a line table unit to be generated.
297   /// \param DwarfFormat the DWARF format to use (DWARF32 or DWARF64).
298   ///
299   /// \returns a dwarfgen::LineTable that can be used to customise the contents
300   /// of the line table.
301   LineTable &
302   addLineTable(dwarf::DwarfFormat DwarfFormat = dwarf::DwarfFormat::DWARF32);
303 
getAllocator()304   BumpPtrAllocator &getAllocator() { return Allocator; }
getAsmPrinter()305   AsmPrinter *getAsmPrinter() const { return Asm.get(); }
getMCContext()306   MCContext *getMCContext() const { return MC.get(); }
getAbbrevSet()307   DIEAbbrevSet &getAbbrevSet() { return Abbreviations; }
getStringPool()308   DwarfStringPool &getStringPool() { return *StringPool; }
getStringOffsetsStartSym()309   MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; }
310 
311   /// Save the generated DWARF file to disk.
312   ///
313   /// \param Path the path to save the ELF file to.
314   bool saveFile(StringRef Path);
315 };
316 
317 } // end namespace dwarfgen
318 
319 } // end namespace llvm
320 
321 #endif // LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H
322