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 | |
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: |
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(); |
163 | Generator &getGenerator() { return DG; } |
164 | uint64_t getOffset() const { return DU.getDebugSectionOffset(); } |
165 | uint64_t getLength() const { return Length; } |
166 | uint16_t getVersion() const { return Version; } |
167 | uint16_t getAddressSize() const { return AddrSize; } |
168 | void setOffset(uint64_t Offset) { DU.setDebugSectionOffset(Offset); } |
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) |
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 | |
322 | BumpPtrAllocator &getAllocator() { return Allocator; } |
323 | AsmPrinter *getAsmPrinter() const { return Asm.get(); } |
324 | MCContext *getMCContext() const { return MC.get(); } |
325 | DIEAbbrevSet &getAbbrevSet() { return Abbreviations; } |
326 | DwarfStringPool &getStringPool() { return *StringPool; } |
327 | MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; } |
328 | DummyAddressPool &getAddressPool() { return AddressPool; } |
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 | |