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