1 //===--- unittests/DebugInfo/DWARF/DwarfGenerator.cpp -----------*- C++ -*-===//
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
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"
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(),
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
,
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
,
62 void dwarfgen::DIE::addAttribute(uint16_t A
, dwarf::Form Form
,
64 auto &DG
= CU
->getGenerator();
67 Die
->addValue(DG
.getAllocator(), static_cast<dwarf::Attribute
>(A
), Form
,
68 new (DG
.getAllocator())
69 DIEInlineString(String
, DG
.getAllocator()));
74 DG
.getAllocator(), static_cast<dwarf::Attribute
>(A
), Form
,
75 DIEString(DG
.getStringPool().getEntry(*DG
.getAsmPrinter(), String
)));
78 case DW_FORM_GNU_str_index
:
84 Die
->addValue(DG
.getAllocator(), static_cast<dwarf::Attribute
>(A
), Form
,
85 DIEString(DG
.getStringPool().getIndexedEntry(
86 *DG
.getAsmPrinter(), String
)));
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
,
103 auto &DG
= CU
->getGenerator();
104 DIEBlock
*Block
= new (DG
.getAllocator()) DIEBlock
;
105 for (size_t I
= 0; I
< S
; ++I
)
107 DG
.getAllocator(), (dwarf::Attribute
)0, dwarf::DW_FORM_data1
,
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
,
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
,
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();
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
;
160 P
.PrologueLength
= 35;
164 P
.PrologueLength
= 36;
168 P
.PrologueLength
= 39;
169 P
.FormParams
.AddrSize
= AddrSize
;
172 llvm_unreachable("unsupported version");
174 if (Format
== DWARF64
) {
176 P
.FormParams
.Format
= DWARF64
;
178 P
.FormParams
.Version
= Version
;
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");
194 void dwarfgen::LineTable::setPrologue(DWARFDebugLine::Prologue NewPrologue
) {
195 Prologue
= NewPrologue
;
196 CustomPrologue
.clear();
199 void dwarfgen::LineTable::setCustomPrologue(
200 ArrayRef
<ValueAndLength
> NewPrologue
) {
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
);
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
) {
248 Asm
.OutStreamer
->EmitIntValue(Entry
.Value
, Entry
.Length
);
251 Asm
.EmitULEB128(Entry
.Value
);
254 Asm
.EmitSLEB128(Entry
.Value
);
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);
268 Asm
.EmitLabelDifference(UnitEnd
, UnitStart
, 4);
270 Asm
.OutStreamer
->EmitLabel(UnitStart
);
271 Asm
.emitInt16(Version
);
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
);
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
);
294 Asm
.emitInt32(Prologue
->TotalLength
);
296 Asm
.emitInt16(Prologue
->getVersion());
298 Asm
.emitInt8(Prologue
->getAddressSize());
299 Asm
.emitInt8(Prologue
->SegSelectorSize
);
301 if (Format
== DwarfFormat::DWARF64
)
302 Asm
.emitInt64(Prologue
->PrologueLength
);
304 Asm
.emitInt32(Prologue
->PrologueLength
);
306 writeProloguePayload(*Prologue
, Asm
);
309 static void writeCString(StringRef Str
, AsmPrinter
&Asm
) {
310 Asm
.OutStreamer
->EmitBytes(Str
);
314 static void writeV2IncludeAndFileTable(const DWARFDebugLine::Prologue
&Prologue
,
316 for (auto Include
: Prologue
.IncludeDirectories
) {
317 assert(Include
.getAsCString() && "expected a string form for include dir");
318 writeCString(*Include
.getAsCString(), Asm
);
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
);
332 static void writeV5IncludeAndFileTable(const DWARFDebugLine::Prologue
&Prologue
,
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
);
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
);
369 writeV2IncludeAndFileTable(Prologue
, Asm
);
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
);
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
) {
394 std::string ErrorStr
;
395 std::string TripleName
;
398 const Target
*TheTarget
=
399 TargetRegistry::lookupTarget(TripleName
, TheTriple
, ErrorStr
);
401 return make_error
<StringError
>(ErrorStr
, inconvertibleErrorCode());
403 TripleName
= TheTriple
.getTriple();
405 // Create all the MC Objects.
406 MRI
.reset(TheTarget
->createMCRegInfo(TripleName
));
408 return make_error
<StringError
>(Twine("no register info for target ") +
410 inconvertibleErrorCode());
412 MAI
.reset(TheTarget
->createMCAsmInfo(*MRI
, TripleName
));
414 return make_error
<StringError
>("no asm info for target " + TripleName
,
415 inconvertibleErrorCode());
417 MSTI
.reset(TheTarget
->createMCSubtargetInfo(TripleName
, "", ""));
419 return make_error
<StringError
>("no subtarget info for target " + TripleName
,
420 inconvertibleErrorCode());
422 MCTargetOptions MCOptions
= InitMCTargetOptionsFromFlags();
423 MAB
= TheTarget
->createMCAsmBackend(*MSTI
, *MRI
, MCOptions
);
425 return make_error
<StringError
>("no asm backend for target " + TripleName
,
426 inconvertibleErrorCode());
428 MII
.reset(TheTarget
->createMCInstrInfo());
430 return make_error
<StringError
>("no instr info info for target " +
432 inconvertibleErrorCode());
434 TM
.reset(TheTarget
->createTargetMachine(TripleName
, "", "", TargetOptions(),
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
);
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);
457 return make_error
<StringError
>("no object streamer for target " +
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
)));
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
);
511 Asm
->emitInt8(CU
->getAddressSize());
513 Asm
->emitInt8(dwarf::DW_UT_compile
);
514 Asm
->emitInt8(CU
->getAddressSize());
517 Asm
->emitDwarfDIE(*CU
->getUnitDIE().Die
);
520 MS
->SwitchSection(TLOF
->getDwarfLineSection());
521 for (auto <
: LineTables
)
522 LT
->generate(*MC
, *Asm
);
525 if (FileBytes
.empty())
527 return StringRef(FileBytes
.data(), FileBytes
.size());
530 bool dwarfgen::Generator::saveFile(StringRef Path
) {
531 if (FileBytes
.empty())
534 raw_fd_ostream
Strm(Path
, EC
, sys::fs::OF_None
);
537 Strm
.write(FileBytes
.data(), FileBytes
.size());
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();