• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.h"
29 #include "llvm/Pass.h"
30 #include "llvm/Support/FileSystem.h"
31 #include "llvm/Support/LEB128.h"
32 #include "llvm/Support/TargetRegistry.h"
33 #include "llvm/Support/raw_ostream.h"
34 #include "llvm/Target/TargetLoweringObjectFile.h"
35 #include "llvm/Target/TargetMachine.h"
36 #include "llvm/Target/TargetOptions.h"
37 
38 using namespace llvm;
39 using namespace dwarf;
40 
41 mc::RegisterMCTargetOptionsFlags MOF;
42 
43 namespace {} // end anonymous namespace
44 
45 //===----------------------------------------------------------------------===//
46 /// dwarfgen::DIE implementation.
47 //===----------------------------------------------------------------------===//
computeSizeAndOffsets(unsigned Offset)48 unsigned dwarfgen::DIE::computeSizeAndOffsets(unsigned Offset) {
49   auto &DG = CU->getGenerator();
50   return Die->computeOffsetsAndAbbrevs(DG.getAsmPrinter(), DG.getAbbrevSet(),
51                                        Offset);
52 }
53 
addAttribute(uint16_t A,dwarf::Form Form,uint64_t U)54 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) {
55   auto &DG = CU->getGenerator();
56   Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
57                 DIEInteger(U));
58 }
59 
addAttribute(uint16_t A,dwarf::Form Form,const MCExpr & Expr)60 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const MCExpr &Expr) {
61   auto &DG = CU->getGenerator();
62   Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
63                 DIEExpr(&Expr));
64 }
65 
addAttribute(uint16_t A,dwarf::Form Form,StringRef String)66 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
67                                  StringRef String) {
68   auto &DG = CU->getGenerator();
69   switch (Form) {
70   case DW_FORM_string:
71     Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
72                   new (DG.getAllocator())
73                       DIEInlineString(String, DG.getAllocator()));
74     break;
75 
76   case DW_FORM_strp:
77     Die->addValue(
78         DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
79         DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));
80     break;
81 
82   case DW_FORM_GNU_str_index:
83   case DW_FORM_strx:
84   case DW_FORM_strx1:
85   case DW_FORM_strx2:
86   case DW_FORM_strx3:
87   case DW_FORM_strx4:
88     Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
89                   DIEString(DG.getStringPool().getIndexedEntry(
90                       *DG.getAsmPrinter(), String)));
91     break;
92 
93   default:
94     llvm_unreachable("Unhandled form!");
95   }
96 }
97 
addAttribute(uint16_t A,dwarf::Form Form,dwarfgen::DIE & RefDie)98 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
99                                  dwarfgen::DIE &RefDie) {
100   auto &DG = CU->getGenerator();
101   Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
102                 DIEEntry(*RefDie.Die));
103 }
104 
addAttribute(uint16_t A,dwarf::Form Form,const void * P,size_t S)105 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const void *P,
106                                  size_t S) {
107   auto &DG = CU->getGenerator();
108   DIEBlock *Block = new (DG.getAllocator()) DIEBlock;
109   for (size_t I = 0; I < S; ++I)
110     Block->addValue(
111         DG.getAllocator(), (dwarf::Attribute)0, dwarf::DW_FORM_data1,
112         DIEInteger(
113             (const_cast<uint8_t *>(static_cast<const uint8_t *>(P)))[I]));
114 
115   Block->ComputeSize(DG.getAsmPrinter());
116   Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
117                 Block);
118 }
119 
addAttribute(uint16_t A,dwarf::Form Form)120 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form) {
121   auto &DG = CU->getGenerator();
122   assert(Form == DW_FORM_flag_present);
123   Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
124                 DIEInteger(1));
125 }
126 
addStrOffsetsBaseAttribute()127 void dwarfgen::DIE::addStrOffsetsBaseAttribute() {
128   auto &DG = CU->getGenerator();
129   auto &MC = *DG.getMCContext();
130   AsmPrinter *Asm = DG.getAsmPrinter();
131 
132   const MCSymbol *SectionStart =
133       Asm->getObjFileLowering().getDwarfStrOffSection()->getBeginSymbol();
134 
135   const MCExpr *Expr =
136       MCSymbolRefExpr::create(DG.getStringOffsetsStartSym(), MC);
137 
138   if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections())
139     Expr = MCBinaryExpr::createSub(
140         Expr, MCSymbolRefExpr::create(SectionStart, MC), MC);
141 
142   addAttribute(dwarf::DW_AT_str_offsets_base, DW_FORM_sec_offset, *Expr);
143 }
144 
addChild(dwarf::Tag Tag)145 dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) {
146   auto &DG = CU->getGenerator();
147   return dwarfgen::DIE(CU,
148                        &Die->addChild(llvm::DIE::get(DG.getAllocator(), Tag)));
149 }
150 
getUnitDIE()151 dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() {
152   return dwarfgen::DIE(this, &DU.getUnitDie());
153 }
154 
155 //===----------------------------------------------------------------------===//
156 /// dwarfgen::LineTable implementation.
157 //===----------------------------------------------------------------------===//
createBasicPrologue() const158 DWARFDebugLine::Prologue dwarfgen::LineTable::createBasicPrologue() const {
159   DWARFDebugLine::Prologue P;
160   switch (Version) {
161   case 2:
162   case 3:
163     P.TotalLength = 41;
164     P.PrologueLength = 35;
165     break;
166   case 4:
167     P.TotalLength = 42;
168     P.PrologueLength = 36;
169     break;
170   case 5:
171     P.TotalLength = 50;
172     P.PrologueLength = 42;
173     P.FormParams.AddrSize = AddrSize;
174     break;
175   default:
176     llvm_unreachable("unsupported version");
177   }
178   if (Format == DWARF64) {
179     P.TotalLength += 4;
180     P.FormParams.Format = DWARF64;
181   }
182   P.TotalLength += getContentsSize();
183   P.FormParams.Version = Version;
184   P.MinInstLength = 1;
185   P.MaxOpsPerInst = 1;
186   P.DefaultIsStmt = 1;
187   P.LineBase = -5;
188   P.LineRange = 14;
189   P.OpcodeBase = 13;
190   P.StandardOpcodeLengths = {0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1};
191   P.IncludeDirectories.push_back(
192       DWARFFormValue::createFromPValue(DW_FORM_string, "a dir"));
193   P.FileNames.push_back(DWARFDebugLine::FileNameEntry());
194   P.FileNames.back().Name =
195       DWARFFormValue::createFromPValue(DW_FORM_string, "a file");
196   return P;
197 }
198 
setPrologue(DWARFDebugLine::Prologue NewPrologue)199 void dwarfgen::LineTable::setPrologue(DWARFDebugLine::Prologue NewPrologue) {
200   Prologue = NewPrologue;
201   CustomPrologue.clear();
202 }
203 
setCustomPrologue(ArrayRef<ValueAndLength> NewPrologue)204 void dwarfgen::LineTable::setCustomPrologue(
205     ArrayRef<ValueAndLength> NewPrologue) {
206   Prologue.reset();
207   CustomPrologue = NewPrologue;
208 }
209 
addByte(uint8_t Value)210 void dwarfgen::LineTable::addByte(uint8_t Value) {
211   Contents.push_back({Value, Byte});
212 }
213 
addStandardOpcode(uint8_t Opcode,ArrayRef<ValueAndLength> Operands)214 void dwarfgen::LineTable::addStandardOpcode(uint8_t Opcode,
215                                             ArrayRef<ValueAndLength> Operands) {
216   Contents.push_back({Opcode, Byte});
217   Contents.insert(Contents.end(), Operands.begin(), Operands.end());
218 }
219 
addExtendedOpcode(uint64_t Length,uint8_t Opcode,ArrayRef<ValueAndLength> Operands)220 void dwarfgen::LineTable::addExtendedOpcode(uint64_t Length, uint8_t Opcode,
221                                             ArrayRef<ValueAndLength> Operands) {
222   Contents.push_back({0, Byte});
223   Contents.push_back({Length, ULEB});
224   Contents.push_back({Opcode, Byte});
225   Contents.insert(Contents.end(), Operands.begin(), Operands.end());
226 }
227 
generate(MCContext & MC,AsmPrinter & Asm) const228 void dwarfgen::LineTable::generate(MCContext &MC, AsmPrinter &Asm) const {
229   MC.setDwarfVersion(Version);
230 
231   MCSymbol *EndSymbol = nullptr;
232   if (!CustomPrologue.empty()) {
233     writeData(CustomPrologue, Asm);
234   } else if (!Prologue) {
235     EndSymbol = writeDefaultPrologue(Asm);
236   } else {
237     writePrologue(Asm);
238   }
239 
240   writeData(Contents, Asm);
241   if (EndSymbol != nullptr)
242     Asm.OutStreamer->emitLabel(EndSymbol);
243 }
244 
writeData(ArrayRef<ValueAndLength> Data,AsmPrinter & Asm) const245 void dwarfgen::LineTable::writeData(ArrayRef<ValueAndLength> Data,
246                                     AsmPrinter &Asm) const {
247   for (auto Entry : Data) {
248     switch (Entry.Length) {
249     case Byte:
250     case Half:
251     case Long:
252     case Quad:
253       Asm.OutStreamer->emitIntValue(Entry.Value, Entry.Length);
254       continue;
255     case ULEB:
256       Asm.emitULEB128(Entry.Value);
257       continue;
258     case SLEB:
259       Asm.emitSLEB128(Entry.Value);
260       continue;
261     }
262     llvm_unreachable("unsupported ValueAndLength Length value");
263   }
264 }
265 
getContentsSize() const266 size_t dwarfgen::LineTable::getContentsSize() const {
267   size_t Size = 0;
268   for (auto Entry : Contents) {
269     switch (Entry.Length) {
270     case ULEB:
271       Size += getULEB128Size(Entry.Value);
272       break;
273     case SLEB:
274       Size += getSLEB128Size(Entry.Value);
275       break;
276     default:
277       Size += Entry.Length;
278       break;
279     }
280   }
281   return Size;
282 }
283 
writeDefaultPrologue(AsmPrinter & Asm) const284 MCSymbol *dwarfgen::LineTable::writeDefaultPrologue(AsmPrinter &Asm) const {
285   MCSymbol *UnitStart = Asm.createTempSymbol("line_unit_start");
286   MCSymbol *UnitEnd = Asm.createTempSymbol("line_unit_end");
287   if (Format == DwarfFormat::DWARF64) {
288     Asm.emitInt32((int)dwarf::DW_LENGTH_DWARF64);
289     Asm.emitLabelDifference(UnitEnd, UnitStart, 8);
290   } else {
291     Asm.emitLabelDifference(UnitEnd, UnitStart, 4);
292   }
293   Asm.OutStreamer->emitLabel(UnitStart);
294   Asm.emitInt16(Version);
295   if (Version == 5) {
296     Asm.emitInt8(AddrSize);
297     Asm.emitInt8(SegSize);
298   }
299 
300   MCSymbol *PrologueStart = Asm.createTempSymbol("line_prologue_start");
301   MCSymbol *PrologueEnd = Asm.createTempSymbol("line_prologue_end");
302   Asm.emitLabelDifference(PrologueEnd, PrologueStart,
303                           Format == DwarfFormat::DWARF64 ? 8 : 4);
304   Asm.OutStreamer->emitLabel(PrologueStart);
305 
306   DWARFDebugLine::Prologue DefaultPrologue = createBasicPrologue();
307   writeProloguePayload(DefaultPrologue, Asm);
308   Asm.OutStreamer->emitLabel(PrologueEnd);
309   return UnitEnd;
310 }
311 
writePrologue(AsmPrinter & Asm) const312 void dwarfgen::LineTable::writePrologue(AsmPrinter &Asm) const {
313   if (Format == DwarfFormat::DWARF64) {
314     Asm.emitInt32((int)dwarf::DW_LENGTH_DWARF64);
315     Asm.emitInt64(Prologue->TotalLength);
316   } else {
317     Asm.emitInt32(Prologue->TotalLength);
318   }
319   Asm.emitInt16(Prologue->getVersion());
320   if (Version == 5) {
321     Asm.emitInt8(Prologue->getAddressSize());
322     Asm.emitInt8(Prologue->SegSelectorSize);
323   }
324   if (Format == DwarfFormat::DWARF64)
325     Asm.emitInt64(Prologue->PrologueLength);
326   else
327     Asm.emitInt32(Prologue->PrologueLength);
328 
329   writeProloguePayload(*Prologue, Asm);
330 }
331 
writeCString(StringRef Str,AsmPrinter & Asm)332 static void writeCString(StringRef Str, AsmPrinter &Asm) {
333   Asm.OutStreamer->emitBytes(Str);
334   Asm.emitInt8(0);
335 }
336 
writeV2IncludeAndFileTable(const DWARFDebugLine::Prologue & Prologue,AsmPrinter & Asm)337 static void writeV2IncludeAndFileTable(const DWARFDebugLine::Prologue &Prologue,
338                                        AsmPrinter &Asm) {
339   for (auto Include : Prologue.IncludeDirectories) {
340     assert(Include.getAsCString() && "expected a string form for include dir");
341     writeCString(*Include.getAsCString(), Asm);
342   }
343   Asm.emitInt8(0);
344 
345   for (auto File : Prologue.FileNames) {
346     assert(File.Name.getAsCString() && "expected a string form for file name");
347     writeCString(*File.Name.getAsCString(), Asm);
348     Asm.emitULEB128(File.DirIdx);
349     Asm.emitULEB128(File.ModTime);
350     Asm.emitULEB128(File.Length);
351   }
352   Asm.emitInt8(0);
353 }
354 
writeV5IncludeAndFileTable(const DWARFDebugLine::Prologue & Prologue,AsmPrinter & Asm)355 static void writeV5IncludeAndFileTable(const DWARFDebugLine::Prologue &Prologue,
356                                        AsmPrinter &Asm) {
357   Asm.emitInt8(1); // directory_entry_format_count.
358   // TODO: Add support for other content descriptions - we currently only
359   // support a single DW_LNCT_path/DW_FORM_string.
360   Asm.emitULEB128(DW_LNCT_path);
361   Asm.emitULEB128(DW_FORM_string);
362   Asm.emitULEB128(Prologue.IncludeDirectories.size());
363   for (auto Include : Prologue.IncludeDirectories) {
364     assert(Include.getAsCString() && "expected a string form for include dir");
365     writeCString(*Include.getAsCString(), Asm);
366   }
367 
368   Asm.emitInt8(2); // file_name_entry_format_count.
369   Asm.emitULEB128(DW_LNCT_path);
370   Asm.emitULEB128(DW_FORM_string);
371   Asm.emitULEB128(DW_LNCT_directory_index);
372   Asm.emitULEB128(DW_FORM_data1);
373   Asm.emitULEB128(Prologue.FileNames.size());
374   for (auto File : Prologue.FileNames) {
375     assert(File.Name.getAsCString() && "expected a string form for file name");
376     writeCString(*File.Name.getAsCString(), Asm);
377     Asm.emitInt8(File.DirIdx);
378   }
379 }
380 
writeProloguePayload(const DWARFDebugLine::Prologue & Prologue,AsmPrinter & Asm) const381 void dwarfgen::LineTable::writeProloguePayload(
382     const DWARFDebugLine::Prologue &Prologue, AsmPrinter &Asm) const {
383   Asm.emitInt8(Prologue.MinInstLength);
384   if (Version >= 4)
385     Asm.emitInt8(Prologue.MaxOpsPerInst);
386   Asm.emitInt8(Prologue.DefaultIsStmt);
387   Asm.emitInt8(Prologue.LineBase);
388   Asm.emitInt8(Prologue.LineRange);
389   Asm.emitInt8(Prologue.OpcodeBase);
390   for (auto Length : Prologue.StandardOpcodeLengths) {
391     Asm.emitInt8(Length);
392   }
393 
394   if (Version < 5)
395     writeV2IncludeAndFileTable(Prologue, Asm);
396   else
397     writeV5IncludeAndFileTable(Prologue, Asm);
398 }
399 
400 //===----------------------------------------------------------------------===//
401 /// dwarfgen::Generator implementation.
402 //===----------------------------------------------------------------------===//
403 
Generator()404 dwarfgen::Generator::Generator()
405     : MAB(nullptr), MCE(nullptr), MS(nullptr), TLOF(nullptr),
406       StringPool(nullptr), Abbreviations(Allocator),
407       StringOffsetsStartSym(nullptr), Version(0) {}
408 dwarfgen::Generator::~Generator() = default;
409 
410 llvm::Expected<std::unique_ptr<dwarfgen::Generator>>
create(Triple TheTriple,uint16_t DwarfVersion)411 dwarfgen::Generator::create(Triple TheTriple, uint16_t DwarfVersion) {
412   std::unique_ptr<dwarfgen::Generator> GenUP(new dwarfgen::Generator());
413   llvm::Error error = GenUP->init(TheTriple, DwarfVersion);
414   if (error)
415     return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(error));
416   return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(GenUP));
417 }
418 
init(Triple TheTriple,uint16_t V)419 llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) {
420   Version = V;
421   std::string ErrorStr;
422   std::string TripleName;
423 
424   // Get the target.
425   const Target *TheTarget =
426       TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
427   if (!TheTarget)
428     return make_error<StringError>(ErrorStr, inconvertibleErrorCode());
429 
430   TripleName = TheTriple.getTriple();
431 
432   // Create all the MC Objects.
433   MRI.reset(TheTarget->createMCRegInfo(TripleName));
434   if (!MRI)
435     return make_error<StringError>(Twine("no register info for target ") +
436                                        TripleName,
437                                    inconvertibleErrorCode());
438 
439   MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
440   MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
441   if (!MAI)
442     return make_error<StringError>("no asm info for target " + TripleName,
443                                    inconvertibleErrorCode());
444 
445   MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
446   if (!MSTI)
447     return make_error<StringError>("no subtarget info for target " + TripleName,
448                                    inconvertibleErrorCode());
449 
450   MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions);
451   if (!MAB)
452     return make_error<StringError>("no asm backend for target " + TripleName,
453                                    inconvertibleErrorCode());
454 
455   MII.reset(TheTarget->createMCInstrInfo());
456   if (!MII)
457     return make_error<StringError>("no instr info info for target " +
458                                        TripleName,
459                                    inconvertibleErrorCode());
460 
461   TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
462                                           None));
463   if (!TM)
464     return make_error<StringError>("no target machine for target " + TripleName,
465                                    inconvertibleErrorCode());
466 
467   TLOF = TM->getObjFileLowering();
468   MC.reset(new MCContext(MAI.get(), MRI.get(), TLOF));
469   TLOF->Initialize(*MC, *TM);
470 
471   MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC);
472   if (!MCE)
473     return make_error<StringError>("no code emitter for target " + TripleName,
474                                    inconvertibleErrorCode());
475 
476   Stream = std::make_unique<raw_svector_ostream>(FileBytes);
477 
478   MS = TheTarget->createMCObjectStreamer(
479       TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
480       MAB->createObjectWriter(*Stream), std::unique_ptr<MCCodeEmitter>(MCE),
481       *MSTI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible,
482       /*DWARFMustBeAtTheEnd*/ false);
483   if (!MS)
484     return make_error<StringError>("no object streamer for target " +
485                                        TripleName,
486                                    inconvertibleErrorCode());
487 
488 
489   // Finally create the AsmPrinter we'll use to emit the DIEs.
490   Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
491   if (!Asm)
492     return make_error<StringError>("no asm printer for target " + TripleName,
493                                    inconvertibleErrorCode());
494 
495   // Set the DWARF version correctly on all classes that we use.
496   MC->setDwarfVersion(Version);
497   Asm->setDwarfVersion(Version);
498 
499   StringPool = std::make_unique<DwarfStringPool>(Allocator, *Asm, StringRef());
500   StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base");
501 
502   return Error::success();
503 }
504 
generate()505 StringRef dwarfgen::Generator::generate() {
506   // Offset from the first CU in the debug info section is 0 initially.
507   uint64_t SecOffset = 0;
508 
509   // Iterate over each compile unit and set the size and offsets for each
510   // DIE within each compile unit. All offsets are CU relative.
511   for (auto &CU : CompileUnits) {
512     // Set the absolute .debug_info offset for this compile unit.
513     CU->setOffset(SecOffset);
514     // The DIEs contain compile unit relative offsets.
515     unsigned CUOffset = 11;
516     CUOffset = CU->getUnitDIE().computeSizeAndOffsets(CUOffset);
517     // Update our absolute .debug_info offset.
518     SecOffset += CUOffset;
519     CU->setLength(CUOffset - 4);
520   }
521   Abbreviations.Emit(Asm.get(), TLOF->getDwarfAbbrevSection());
522 
523   StringPool->emitStringOffsetsTableHeader(*Asm, TLOF->getDwarfStrOffSection(),
524                                            StringOffsetsStartSym);
525   StringPool->emit(*Asm, TLOF->getDwarfStrSection(),
526                    TLOF->getDwarfStrOffSection());
527 
528   MS->SwitchSection(TLOF->getDwarfInfoSection());
529   for (auto &CU : CompileUnits) {
530     uint16_t Version = CU->getVersion();
531     auto Length = CU->getLength();
532     MC->setDwarfVersion(Version);
533     assert(Length != -1U);
534     Asm->emitInt32(Length);
535     Asm->emitInt16(Version);
536     if (Version <= 4) {
537       Asm->emitInt32(0);
538       Asm->emitInt8(CU->getAddressSize());
539     } else {
540       Asm->emitInt8(dwarf::DW_UT_compile);
541       Asm->emitInt8(CU->getAddressSize());
542       Asm->emitInt32(0);
543     }
544     Asm->emitDwarfDIE(*CU->getUnitDIE().Die);
545   }
546 
547   MS->SwitchSection(TLOF->getDwarfLineSection());
548   for (auto &LT : LineTables)
549     LT->generate(*MC, *Asm);
550 
551   MS->Finish();
552   if (FileBytes.empty())
553     return StringRef();
554   return StringRef(FileBytes.data(), FileBytes.size());
555 }
556 
saveFile(StringRef Path)557 bool dwarfgen::Generator::saveFile(StringRef Path) {
558   if (FileBytes.empty())
559     return false;
560   std::error_code EC;
561   raw_fd_ostream Strm(Path, EC, sys::fs::OF_None);
562   if (EC)
563     return false;
564   Strm.write(FileBytes.data(), FileBytes.size());
565   Strm.close();
566   return true;
567 }
568 
addCompileUnit()569 dwarfgen::CompileUnit &dwarfgen::Generator::addCompileUnit() {
570   CompileUnits.push_back(
571       std::make_unique<CompileUnit>(*this, Version, Asm->getPointerSize()));
572   return *CompileUnits.back();
573 }
574 
addLineTable(DwarfFormat Format)575 dwarfgen::LineTable &dwarfgen::Generator::addLineTable(DwarfFormat Format) {
576   LineTables.push_back(
577       std::make_unique<LineTable>(Version, Format, Asm->getPointerSize()));
578   return *LineTables.back();
579 }
580