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 //===----------------------------------------------------------------------===//
8 
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"
35 
36 using namespace llvm;
37 using namespace dwarf;
38 
39 namespace {} // end anonymous namespace
40 
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);
48 }
49 
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));
54 }
55 
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));
60 }
61 
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;
71 
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;
77 
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;
88 
89   default:
90     llvm_unreachable("Unhandled form!");
91   }
92 }
93 
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));
99 }
100 
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]));
110 
111   Block->ComputeSize(DG.getAsmPrinter());
112   Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
113                 Block);
114 }
115 
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));
121 }
122 
123 void dwarfgen::DIE::addStrOffsetsBaseAttribute() {
124   auto &DG = CU->getGenerator();
125   auto &MC = *DG.getMCContext();
126   AsmPrinter *Asm = DG.getAsmPrinter();
127 
128   const MCSymbol *SectionStart =
129       Asm->getObjFileLowering().getDwarfStrOffSection()->getBeginSymbol();
130 
131   const MCExpr *Expr =
132       MCSymbolRefExpr::create(DG.getStringOffsetsStartSym(), MC);
133 
134   if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections())
135     Expr = MCBinaryExpr::createSub(
136         Expr, MCSymbolRefExpr::create(SectionStart, MC), MC);
137 
138   addAttribute(dwarf::DW_AT_str_offsets_base, DW_FORM_sec_offset, *Expr);
139 }
140 
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)));
145 }
146 
147 dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() {
148   return dwarfgen::DIE(this, &DU.getUnitDie());
149 }
150 
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");
173   }
174   if (Format == DWARF64) {
175     P.TotalLength += 4;
176     P.FormParams.Format = DWARF64;
177   }
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;
192 }
193 
194 void dwarfgen::LineTable::setPrologue(DWARFDebugLine::Prologue NewPrologue) {
195   Prologue = NewPrologue;
196   CustomPrologue.clear();
197 }
198 
199 void dwarfgen::LineTable::setCustomPrologue(
200     ArrayRef<ValueAndLength> NewPrologue) {
201   Prologue.reset();
202   CustomPrologue = NewPrologue;
203 }
204 
205 void dwarfgen::LineTable::addByte(uint8_t Value) {
206   Contents.push_back({Value, Byte});
207 }
208 
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());
213 }
214 
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());
221 }
222 
223 void dwarfgen::LineTable::generate(MCContext &MC, AsmPrinter &Asm) const {
224   MC.setDwarfVersion(Version);
225 
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);
233   }
234 
235   writeData(Contents, Asm);
236   if (EndSymbol != nullptr)
237     Asm.OutStreamer->EmitLabel(EndSymbol);
238 }
239 
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;
256     }
257     llvm_unreachable("unsupported ValueAndLength Length value");
258   }
259 }
260 
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);
269   }
270   Asm.OutStreamer->EmitLabel(UnitStart);
271   Asm.emitInt16(Version);
272   if (Version == 5) {
273     Asm.emitInt8(AddrSize);
274     Asm.emitInt8(SegSize);
275   }
276 
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);
282 
283   DWARFDebugLine::Prologue DefaultPrologue = createBasicPrologue();
284   writeProloguePayload(DefaultPrologue, Asm);
285   Asm.OutStreamer->EmitLabel(PrologueEnd);
286   return UnitEnd;
287 }
288 
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);
295   }
296   Asm.emitInt16(Prologue->getVersion());
297   if (Version == 5) {
298     Asm.emitInt8(Prologue->getAddressSize());
299     Asm.emitInt8(Prologue->SegSelectorSize);
300   }
301   if (Format == DwarfFormat::DWARF64)
302     Asm.emitInt64(Prologue->PrologueLength);
303   else
304     Asm.emitInt32(Prologue->PrologueLength);
305 
306   writeProloguePayload(*Prologue, Asm);
307 }
308 
309 static void writeCString(StringRef Str, AsmPrinter &Asm) {
310   Asm.OutStreamer->EmitBytes(Str);
311   Asm.emitInt8(0);
312 }
313 
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);
319   }
320   Asm.emitInt8(0);
321 
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);
328   }
329   Asm.emitInt8(0);
330 }
331 
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);
343   }
344 
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);
352   }
353 }
354 
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);
366   }
367 
368   if (Version < 5)
369     writeV2IncludeAndFileTable(Prologue, Asm);
370   else
371     writeV5IncludeAndFileTable(Prologue, Asm);
372 }
373 
374 //===----------------------------------------------------------------------===//
375 /// dwarfgen::Generator implementation.
376 //===----------------------------------------------------------------------===//
377 
378 dwarfgen::Generator::Generator()
379     : MAB(nullptr), MCE(nullptr), MS(nullptr), StringPool(nullptr),
380       Abbreviations(Allocator) {}
381 dwarfgen::Generator::~Generator() = default;
382 
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));
390 }
391 
392 llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) {
393   Version = V;
394   std::string ErrorStr;
395   std::string TripleName;
396 
397   // Get the target.
398   const Target *TheTarget =
399       TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
400   if (!TheTarget)
401     return make_error<StringError>(ErrorStr, inconvertibleErrorCode());
402 
403   TripleName = TheTriple.getTriple();
404 
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());
411 
412   MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName));
413   if (!MAI)
414     return make_error<StringError>("no asm info for target " + TripleName,
415                                    inconvertibleErrorCode());
416 
417   MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
418   if (!MSTI)
419     return make_error<StringError>("no subtarget info for target " + TripleName,
420                                    inconvertibleErrorCode());
421 
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());
427 
428   MII.reset(TheTarget->createMCInstrInfo());
429   if (!MII)
430     return make_error<StringError>("no instr info info for target " +
431                                        TripleName,
432                                    inconvertibleErrorCode());
433 
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());
439 
440   TLOF = TM->getObjFileLowering();
441   MC.reset(new MCContext(MAI.get(), MRI.get(), TLOF));
442   TLOF->Initialize(*MC, *TM);
443 
444   MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC);
445   if (!MCE)
446     return make_error<StringError>("no code emitter for target " + TripleName,
447                                    inconvertibleErrorCode());
448 
449   Stream = std::make_unique<raw_svector_ostream>(FileBytes);
450 
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());
460 
461 
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());
467 
468   // Set the DWARF version correctly on all classes that we use.
469   MC->setDwarfVersion(Version);
470   Asm->setDwarfVersion(Version);
471 
472   StringPool = std::make_unique<DwarfStringPool>(Allocator, *Asm, StringRef());
473   StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base");
474 
475   return Error::success();
476 }
477 
478 StringRef dwarfgen::Generator::generate() {
479   // Offset from the first CU in the debug info section is 0 initially.
480   unsigned SecOffset = 0;
481 
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);
493   }
494   Abbreviations.Emit(Asm.get(), TLOF->getDwarfAbbrevSection());
495 
496   StringPool->emitStringOffsetsTableHeader(*Asm, TLOF->getDwarfStrOffSection(),
497                                            StringOffsetsStartSym);
498   StringPool->emit(*Asm, TLOF->getDwarfStrSection(),
499                    TLOF->getDwarfStrOffSection());
500 
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);
516     }
517     Asm->emitDwarfDIE(*CU->getUnitDIE().Die);
518   }
519 
520   MS->SwitchSection(TLOF->getDwarfLineSection());
521   for (auto &LT : LineTables)
522     LT->generate(*MC, *Asm);
523 
524   MS->Finish();
525   if (FileBytes.empty())
526     return StringRef();
527   return StringRef(FileBytes.data(), FileBytes.size());
528 }
529 
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;
540 }
541 
542 dwarfgen::CompileUnit &dwarfgen::Generator::addCompileUnit() {
543   CompileUnits.push_back(
544       std::make_unique<CompileUnit>(*this, Version, Asm->getPointerSize()));
545   return *CompileUnits.back();
546 }
547 
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();
552 }
553