[yaml2obj/obj2yaml] - Add support for .stack_sizes sections.
[llvm-complete.git] / unittests / DebugInfo / DWARF / DwarfGenerator.cpp
blob2e062e8fe9621822b3f8168d8b33820cb1a197c3
1 //===--- unittests/DebugInfo/DWARF/DwarfGenerator.cpp -----------*- 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 //===----------------------------------------------------------------------===//
9 #include "DwarfGenerator.h"
10 #include "../lib/CodeGen/AsmPrinter/DwarfStringPool.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/BinaryFormat/Dwarf.h"
13 #include "llvm/CodeGen/AsmPrinter.h"
14 #include "llvm/CodeGen/DIE.h"
15 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
16 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
17 #include "llvm/MC/MCAsmBackend.h"
18 #include "llvm/MC/MCAsmInfo.h"
19 #include "llvm/MC/MCCodeEmitter.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCDwarf.h"
22 #include "llvm/MC/MCInstrInfo.h"
23 #include "llvm/MC/MCObjectFileInfo.h"
24 #include "llvm/MC/MCObjectWriter.h"
25 #include "llvm/MC/MCRegisterInfo.h"
26 #include "llvm/MC/MCStreamer.h"
27 #include "llvm/MC/MCSubtargetInfo.h"
28 #include "llvm/MC/MCTargetOptionsCommandFlags.inc"
29 #include "llvm/PassAnalysisSupport.h"
30 #include "llvm/Support/TargetRegistry.h"
31 #include "llvm/Support/raw_ostream.h"
32 #include "llvm/Target/TargetLoweringObjectFile.h"
33 #include "llvm/Target/TargetMachine.h"
34 #include "llvm/Target/TargetOptions.h"
36 using namespace llvm;
37 using namespace dwarf;
39 namespace {} // end anonymous namespace
41 //===----------------------------------------------------------------------===//
42 /// dwarfgen::DIE implementation.
43 //===----------------------------------------------------------------------===//
44 unsigned dwarfgen::DIE::computeSizeAndOffsets(unsigned Offset) {
45 auto &DG = CU->getGenerator();
46 return Die->computeOffsetsAndAbbrevs(DG.getAsmPrinter(), DG.getAbbrevSet(),
47 Offset);
50 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) {
51 auto &DG = CU->getGenerator();
52 Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
53 DIEInteger(U));
56 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const MCExpr &Expr) {
57 auto &DG = CU->getGenerator();
58 Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
59 DIEExpr(&Expr));
62 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
63 StringRef String) {
64 auto &DG = CU->getGenerator();
65 switch (Form) {
66 case DW_FORM_string:
67 Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
68 new (DG.getAllocator())
69 DIEInlineString(String, DG.getAllocator()));
70 break;
72 case DW_FORM_strp:
73 Die->addValue(
74 DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
75 DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));
76 break;
78 case DW_FORM_GNU_str_index:
79 case DW_FORM_strx:
80 case DW_FORM_strx1:
81 case DW_FORM_strx2:
82 case DW_FORM_strx3:
83 case DW_FORM_strx4:
84 Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
85 DIEString(DG.getStringPool().getIndexedEntry(
86 *DG.getAsmPrinter(), String)));
87 break;
89 default:
90 llvm_unreachable("Unhandled form!");
94 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
95 dwarfgen::DIE &RefDie) {
96 auto &DG = CU->getGenerator();
97 Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
98 DIEEntry(*RefDie.Die));
101 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const void *P,
102 size_t S) {
103 auto &DG = CU->getGenerator();
104 DIEBlock *Block = new (DG.getAllocator()) DIEBlock;
105 for (size_t I = 0; I < S; ++I)
106 Block->addValue(
107 DG.getAllocator(), (dwarf::Attribute)0, dwarf::DW_FORM_data1,
108 DIEInteger(
109 (const_cast<uint8_t *>(static_cast<const uint8_t *>(P)))[I]));
111 Block->ComputeSize(DG.getAsmPrinter());
112 Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
113 Block);
116 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form) {
117 auto &DG = CU->getGenerator();
118 assert(Form == DW_FORM_flag_present);
119 Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
120 DIEInteger(1));
123 void dwarfgen::DIE::addStrOffsetsBaseAttribute() {
124 auto &DG = CU->getGenerator();
125 auto &MC = *DG.getMCContext();
126 AsmPrinter *Asm = DG.getAsmPrinter();
128 const MCSymbol *SectionStart =
129 Asm->getObjFileLowering().getDwarfStrOffSection()->getBeginSymbol();
131 const MCExpr *Expr =
132 MCSymbolRefExpr::create(DG.getStringOffsetsStartSym(), MC);
134 if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections())
135 Expr = MCBinaryExpr::createSub(
136 Expr, MCSymbolRefExpr::create(SectionStart, MC), MC);
138 addAttribute(dwarf::DW_AT_str_offsets_base, DW_FORM_sec_offset, *Expr);
141 dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) {
142 auto &DG = CU->getGenerator();
143 return dwarfgen::DIE(CU,
144 &Die->addChild(llvm::DIE::get(DG.getAllocator(), Tag)));
147 dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() {
148 return dwarfgen::DIE(this, &DU.getUnitDie());
151 //===----------------------------------------------------------------------===//
152 /// dwarfgen::LineTable implementation.
153 //===----------------------------------------------------------------------===//
154 DWARFDebugLine::Prologue dwarfgen::LineTable::createBasicPrologue() const {
155 DWARFDebugLine::Prologue P;
156 switch (Version) {
157 case 2:
158 case 3:
159 P.TotalLength = 41;
160 P.PrologueLength = 35;
161 break;
162 case 4:
163 P.TotalLength = 42;
164 P.PrologueLength = 36;
165 break;
166 case 5:
167 P.TotalLength = 47;
168 P.PrologueLength = 39;
169 P.FormParams.AddrSize = AddrSize;
170 break;
171 default:
172 llvm_unreachable("unsupported version");
174 if (Format == DWARF64) {
175 P.TotalLength += 4;
176 P.FormParams.Format = DWARF64;
178 P.FormParams.Version = Version;
179 P.MinInstLength = 1;
180 P.MaxOpsPerInst = 1;
181 P.DefaultIsStmt = 1;
182 P.LineBase = -5;
183 P.LineRange = 14;
184 P.OpcodeBase = 13;
185 P.StandardOpcodeLengths = {0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1};
186 P.IncludeDirectories.push_back(
187 DWARFFormValue::createFromPValue(DW_FORM_string, "a dir"));
188 P.FileNames.push_back(DWARFDebugLine::FileNameEntry());
189 P.FileNames.back().Name =
190 DWARFFormValue::createFromPValue(DW_FORM_string, "a file");
191 return P;
194 void dwarfgen::LineTable::setPrologue(DWARFDebugLine::Prologue NewPrologue) {
195 Prologue = NewPrologue;
196 CustomPrologue.clear();
199 void dwarfgen::LineTable::setCustomPrologue(
200 ArrayRef<ValueAndLength> NewPrologue) {
201 Prologue.reset();
202 CustomPrologue = NewPrologue;
205 void dwarfgen::LineTable::addByte(uint8_t Value) {
206 Contents.push_back({Value, Byte});
209 void dwarfgen::LineTable::addStandardOpcode(uint8_t Opcode,
210 ArrayRef<ValueAndLength> Operands) {
211 Contents.push_back({Opcode, Byte});
212 Contents.insert(Contents.end(), Operands.begin(), Operands.end());
215 void dwarfgen::LineTable::addExtendedOpcode(uint64_t Length, uint8_t Opcode,
216 ArrayRef<ValueAndLength> Operands) {
217 Contents.push_back({0, Byte});
218 Contents.push_back({Length, ULEB});
219 Contents.push_back({Opcode, Byte});
220 Contents.insert(Contents.end(), Operands.begin(), Operands.end());
223 void dwarfgen::LineTable::generate(MCContext &MC, AsmPrinter &Asm) const {
224 MC.setDwarfVersion(Version);
226 MCSymbol *EndSymbol = nullptr;
227 if (!CustomPrologue.empty()) {
228 writeData(CustomPrologue, Asm);
229 } else if (!Prologue) {
230 EndSymbol = writeDefaultPrologue(Asm);
231 } else {
232 writePrologue(Asm);
235 writeData(Contents, Asm);
236 if (EndSymbol != nullptr)
237 Asm.OutStreamer->EmitLabel(EndSymbol);
240 void dwarfgen::LineTable::writeData(ArrayRef<ValueAndLength> Data,
241 AsmPrinter &Asm) const {
242 for (auto Entry : Data) {
243 switch (Entry.Length) {
244 case Byte:
245 case Half:
246 case Long:
247 case Quad:
248 Asm.OutStreamer->EmitIntValue(Entry.Value, Entry.Length);
249 continue;
250 case ULEB:
251 Asm.EmitULEB128(Entry.Value);
252 continue;
253 case SLEB:
254 Asm.EmitSLEB128(Entry.Value);
255 continue;
257 llvm_unreachable("unsupported ValueAndLength Length value");
261 MCSymbol *dwarfgen::LineTable::writeDefaultPrologue(AsmPrinter &Asm) const {
262 MCSymbol *UnitStart = Asm.createTempSymbol("line_unit_start");
263 MCSymbol *UnitEnd = Asm.createTempSymbol("line_unit_end");
264 if (Format == DwarfFormat::DWARF64) {
265 Asm.emitInt32((int)dwarf::DW_LENGTH_DWARF64);
266 Asm.EmitLabelDifference(UnitEnd, UnitStart, 8);
267 } else {
268 Asm.EmitLabelDifference(UnitEnd, UnitStart, 4);
270 Asm.OutStreamer->EmitLabel(UnitStart);
271 Asm.emitInt16(Version);
272 if (Version == 5) {
273 Asm.emitInt8(AddrSize);
274 Asm.emitInt8(SegSize);
277 MCSymbol *PrologueStart = Asm.createTempSymbol("line_prologue_start");
278 MCSymbol *PrologueEnd = Asm.createTempSymbol("line_prologue_end");
279 Asm.EmitLabelDifference(PrologueEnd, PrologueStart,
280 Format == DwarfFormat::DWARF64 ? 8 : 4);
281 Asm.OutStreamer->EmitLabel(PrologueStart);
283 DWARFDebugLine::Prologue DefaultPrologue = createBasicPrologue();
284 writeProloguePayload(DefaultPrologue, Asm);
285 Asm.OutStreamer->EmitLabel(PrologueEnd);
286 return UnitEnd;
289 void dwarfgen::LineTable::writePrologue(AsmPrinter &Asm) const {
290 if (Format == DwarfFormat::DWARF64) {
291 Asm.emitInt32((int)dwarf::DW_LENGTH_DWARF64);
292 Asm.emitInt64(Prologue->TotalLength);
293 } else {
294 Asm.emitInt32(Prologue->TotalLength);
296 Asm.emitInt16(Prologue->getVersion());
297 if (Version == 5) {
298 Asm.emitInt8(Prologue->getAddressSize());
299 Asm.emitInt8(Prologue->SegSelectorSize);
301 if (Format == DwarfFormat::DWARF64)
302 Asm.emitInt64(Prologue->PrologueLength);
303 else
304 Asm.emitInt32(Prologue->PrologueLength);
306 writeProloguePayload(*Prologue, Asm);
309 static void writeCString(StringRef Str, AsmPrinter &Asm) {
310 Asm.OutStreamer->EmitBytes(Str);
311 Asm.emitInt8(0);
314 static void writeV2IncludeAndFileTable(const DWARFDebugLine::Prologue &Prologue,
315 AsmPrinter &Asm) {
316 for (auto Include : Prologue.IncludeDirectories) {
317 assert(Include.getAsCString() && "expected a string form for include dir");
318 writeCString(*Include.getAsCString(), Asm);
320 Asm.emitInt8(0);
322 for (auto File : Prologue.FileNames) {
323 assert(File.Name.getAsCString() && "expected a string form for file name");
324 writeCString(*File.Name.getAsCString(), Asm);
325 Asm.EmitULEB128(File.DirIdx);
326 Asm.EmitULEB128(File.ModTime);
327 Asm.EmitULEB128(File.Length);
329 Asm.emitInt8(0);
332 static void writeV5IncludeAndFileTable(const DWARFDebugLine::Prologue &Prologue,
333 AsmPrinter &Asm) {
334 Asm.emitInt8(1); // directory_entry_format_count.
335 // TODO: Add support for other content descriptions - we currently only
336 // support a single DW_LNCT_path/DW_FORM_string.
337 Asm.EmitULEB128(DW_LNCT_path);
338 Asm.EmitULEB128(DW_FORM_string);
339 Asm.EmitULEB128(Prologue.IncludeDirectories.size());
340 for (auto Include : Prologue.IncludeDirectories) {
341 assert(Include.getAsCString() && "expected a string form for include dir");
342 writeCString(*Include.getAsCString(), Asm);
345 Asm.emitInt8(1); // file_name_entry_format_count.
346 Asm.EmitULEB128(DW_LNCT_path);
347 Asm.EmitULEB128(DW_FORM_string);
348 Asm.EmitULEB128(Prologue.FileNames.size());
349 for (auto File : Prologue.FileNames) {
350 assert(File.Name.getAsCString() && "expected a string form for file name");
351 writeCString(*File.Name.getAsCString(), Asm);
355 void dwarfgen::LineTable::writeProloguePayload(
356 const DWARFDebugLine::Prologue &Prologue, AsmPrinter &Asm) const {
357 Asm.emitInt8(Prologue.MinInstLength);
358 if (Version >= 4)
359 Asm.emitInt8(Prologue.MaxOpsPerInst);
360 Asm.emitInt8(Prologue.DefaultIsStmt);
361 Asm.emitInt8(Prologue.LineBase);
362 Asm.emitInt8(Prologue.LineRange);
363 Asm.emitInt8(Prologue.OpcodeBase);
364 for (auto Length : Prologue.StandardOpcodeLengths) {
365 Asm.emitInt8(Length);
368 if (Version < 5)
369 writeV2IncludeAndFileTable(Prologue, Asm);
370 else
371 writeV5IncludeAndFileTable(Prologue, Asm);
374 //===----------------------------------------------------------------------===//
375 /// dwarfgen::Generator implementation.
376 //===----------------------------------------------------------------------===//
378 dwarfgen::Generator::Generator()
379 : MAB(nullptr), MCE(nullptr), MS(nullptr), StringPool(nullptr),
380 Abbreviations(Allocator) {}
381 dwarfgen::Generator::~Generator() = default;
383 llvm::Expected<std::unique_ptr<dwarfgen::Generator>>
384 dwarfgen::Generator::create(Triple TheTriple, uint16_t DwarfVersion) {
385 std::unique_ptr<dwarfgen::Generator> GenUP(new dwarfgen::Generator());
386 llvm::Error error = GenUP->init(TheTriple, DwarfVersion);
387 if (error)
388 return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(error));
389 return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(GenUP));
392 llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) {
393 Version = V;
394 std::string ErrorStr;
395 std::string TripleName;
397 // Get the target.
398 const Target *TheTarget =
399 TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
400 if (!TheTarget)
401 return make_error<StringError>(ErrorStr, inconvertibleErrorCode());
403 TripleName = TheTriple.getTriple();
405 // Create all the MC Objects.
406 MRI.reset(TheTarget->createMCRegInfo(TripleName));
407 if (!MRI)
408 return make_error<StringError>(Twine("no register info for target ") +
409 TripleName,
410 inconvertibleErrorCode());
412 MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName));
413 if (!MAI)
414 return make_error<StringError>("no asm info for target " + TripleName,
415 inconvertibleErrorCode());
417 MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
418 if (!MSTI)
419 return make_error<StringError>("no subtarget info for target " + TripleName,
420 inconvertibleErrorCode());
422 MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
423 MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions);
424 if (!MAB)
425 return make_error<StringError>("no asm backend for target " + TripleName,
426 inconvertibleErrorCode());
428 MII.reset(TheTarget->createMCInstrInfo());
429 if (!MII)
430 return make_error<StringError>("no instr info info for target " +
431 TripleName,
432 inconvertibleErrorCode());
434 TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
435 None));
436 if (!TM)
437 return make_error<StringError>("no target machine for target " + TripleName,
438 inconvertibleErrorCode());
440 TLOF = TM->getObjFileLowering();
441 MC.reset(new MCContext(MAI.get(), MRI.get(), TLOF));
442 TLOF->Initialize(*MC, *TM);
444 MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC);
445 if (!MCE)
446 return make_error<StringError>("no code emitter for target " + TripleName,
447 inconvertibleErrorCode());
449 Stream = std::make_unique<raw_svector_ostream>(FileBytes);
451 MS = TheTarget->createMCObjectStreamer(
452 TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
453 MAB->createObjectWriter(*Stream), std::unique_ptr<MCCodeEmitter>(MCE),
454 *MSTI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible,
455 /*DWARFMustBeAtTheEnd*/ false);
456 if (!MS)
457 return make_error<StringError>("no object streamer for target " +
458 TripleName,
459 inconvertibleErrorCode());
462 // Finally create the AsmPrinter we'll use to emit the DIEs.
463 Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
464 if (!Asm)
465 return make_error<StringError>("no asm printer for target " + TripleName,
466 inconvertibleErrorCode());
468 // Set the DWARF version correctly on all classes that we use.
469 MC->setDwarfVersion(Version);
470 Asm->setDwarfVersion(Version);
472 StringPool = std::make_unique<DwarfStringPool>(Allocator, *Asm, StringRef());
473 StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base");
475 return Error::success();
478 StringRef dwarfgen::Generator::generate() {
479 // Offset from the first CU in the debug info section is 0 initially.
480 unsigned SecOffset = 0;
482 // Iterate over each compile unit and set the size and offsets for each
483 // DIE within each compile unit. All offsets are CU relative.
484 for (auto &CU : CompileUnits) {
485 // Set the absolute .debug_info offset for this compile unit.
486 CU->setOffset(SecOffset);
487 // The DIEs contain compile unit relative offsets.
488 unsigned CUOffset = 11;
489 CUOffset = CU->getUnitDIE().computeSizeAndOffsets(CUOffset);
490 // Update our absolute .debug_info offset.
491 SecOffset += CUOffset;
492 CU->setLength(CUOffset - 4);
494 Abbreviations.Emit(Asm.get(), TLOF->getDwarfAbbrevSection());
496 StringPool->emitStringOffsetsTableHeader(*Asm, TLOF->getDwarfStrOffSection(),
497 StringOffsetsStartSym);
498 StringPool->emit(*Asm, TLOF->getDwarfStrSection(),
499 TLOF->getDwarfStrOffSection());
501 MS->SwitchSection(TLOF->getDwarfInfoSection());
502 for (auto &CU : CompileUnits) {
503 uint16_t Version = CU->getVersion();
504 auto Length = CU->getLength();
505 MC->setDwarfVersion(Version);
506 assert(Length != -1U);
507 Asm->emitInt32(Length);
508 Asm->emitInt16(Version);
509 if (Version <= 4) {
510 Asm->emitInt32(0);
511 Asm->emitInt8(CU->getAddressSize());
512 } else {
513 Asm->emitInt8(dwarf::DW_UT_compile);
514 Asm->emitInt8(CU->getAddressSize());
515 Asm->emitInt32(0);
517 Asm->emitDwarfDIE(*CU->getUnitDIE().Die);
520 MS->SwitchSection(TLOF->getDwarfLineSection());
521 for (auto &LT : LineTables)
522 LT->generate(*MC, *Asm);
524 MS->Finish();
525 if (FileBytes.empty())
526 return StringRef();
527 return StringRef(FileBytes.data(), FileBytes.size());
530 bool dwarfgen::Generator::saveFile(StringRef Path) {
531 if (FileBytes.empty())
532 return false;
533 std::error_code EC;
534 raw_fd_ostream Strm(Path, EC, sys::fs::OF_None);
535 if (EC)
536 return false;
537 Strm.write(FileBytes.data(), FileBytes.size());
538 Strm.close();
539 return true;
542 dwarfgen::CompileUnit &dwarfgen::Generator::addCompileUnit() {
543 CompileUnits.push_back(
544 std::make_unique<CompileUnit>(*this, Version, Asm->getPointerSize()));
545 return *CompileUnits.back();
548 dwarfgen::LineTable &dwarfgen::Generator::addLineTable(DwarfFormat Format) {
549 LineTables.push_back(
550 std::make_unique<LineTable>(Version, Format, Asm->getPointerSize()));
551 return *LineTables.back();