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 < : 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