Daniel Jasper | 0f77869 | 2016-12-08 12:45:29 +0000 | [diff] [blame^] | 1 | //===--- unittests/DebugInfo/DWARF/DwarfGenerator.cpp -----------*- C++ -*-===// |
Greg Clayton | 3462a42 | 2016-12-08 01:03:48 +0000 | [diff] [blame] | 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
Daniel Jasper | 0f77869 | 2016-12-08 12:45:29 +0000 | [diff] [blame^] | 10 | #include "../lib/CodeGen/AsmPrinter/DwarfStringPool.h" |
Greg Clayton | 3462a42 | 2016-12-08 01:03:48 +0000 | [diff] [blame] | 11 | #include "DwarfGenerator.h" |
Greg Clayton | 3462a42 | 2016-12-08 01:03:48 +0000 | [diff] [blame] | 12 | #include "llvm/ADT/Triple.h" |
| 13 | #include "llvm/CodeGen/AsmPrinter.h" |
| 14 | #include "llvm/CodeGen/DIE.h" |
| 15 | #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
| 16 | #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" |
| 17 | #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" |
| 18 | #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" |
| 19 | #include "llvm/IR/LegacyPassManagers.h" |
| 20 | #include "llvm/MC/MCAsmBackend.h" |
| 21 | #include "llvm/MC/MCAsmInfo.h" |
| 22 | #include "llvm/MC/MCCodeEmitter.h" |
| 23 | #include "llvm/MC/MCContext.h" |
| 24 | #include "llvm/MC/MCDwarf.h" |
| 25 | #include "llvm/MC/MCInstrInfo.h" |
| 26 | #include "llvm/MC/MCObjectFileInfo.h" |
| 27 | #include "llvm/MC/MCRegisterInfo.h" |
| 28 | #include "llvm/MC/MCStreamer.h" |
| 29 | #include "llvm/MC/MCSubtargetInfo.h" |
| 30 | #include "llvm/MC/MCTargetOptionsCommandFlags.h" |
| 31 | #include "llvm/PassAnalysisSupport.h" |
| 32 | #include "llvm/Support/Dwarf.h" |
| 33 | #include "llvm/Support/LEB128.h" |
| 34 | #include "llvm/Support/TargetRegistry.h" |
| 35 | #include "llvm/Support/raw_ostream.h" |
| 36 | #include "llvm/Target/TargetMachine.h" |
| 37 | #include "llvm/Target/TargetOptions.h" |
| 38 | |
| 39 | using namespace llvm; |
| 40 | using namespace dwarf; |
| 41 | |
| 42 | namespace {} // end anonymous namespace |
| 43 | |
| 44 | //===----------------------------------------------------------------------===// |
| 45 | /// dwarfgen::DIE implementation. |
| 46 | //===----------------------------------------------------------------------===// |
| 47 | unsigned dwarfgen::DIE::computeSizeAndOffsets(unsigned Offset) { |
| 48 | auto &DG = CU->getGenerator(); |
| 49 | return Die->computeOffsetsAndAbbrevs(DG.getAsmPrinter(), DG.getAbbrevSet(), |
| 50 | Offset); |
| 51 | } |
| 52 | |
| 53 | void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) { |
| 54 | auto &DG = CU->getGenerator(); |
| 55 | Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, |
| 56 | DIEInteger(U)); |
| 57 | } |
| 58 | |
| 59 | void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, |
| 60 | StringRef String) { |
| 61 | auto &DG = CU->getGenerator(); |
| 62 | if (Form == DW_FORM_string) { |
| 63 | Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, |
| 64 | new (DG.getAllocator()) DIEInlineString(String)); |
| 65 | } else { |
| 66 | Die->addValue( |
| 67 | DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, |
| 68 | DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String))); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, |
| 73 | dwarfgen::DIE &RefDie) { |
| 74 | auto &DG = CU->getGenerator(); |
| 75 | Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, |
| 76 | DIEEntry(*RefDie.Die)); |
| 77 | } |
| 78 | |
| 79 | void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const void *P, |
| 80 | size_t S) { |
| 81 | auto &DG = CU->getGenerator(); |
| 82 | DIEBlock *Block = new (DG.getAllocator()) DIEBlock; |
| 83 | for (size_t I = 0; I < S; ++I) |
| 84 | Block->addValue(DG.getAllocator(), (dwarf::Attribute)0, |
| 85 | dwarf::DW_FORM_data1, DIEInteger(((uint8_t *)P)[I])); |
| 86 | |
| 87 | Block->ComputeSize(DG.getAsmPrinter()); |
| 88 | Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, |
| 89 | Block); |
| 90 | } |
| 91 | |
| 92 | void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form) { |
| 93 | auto &DG = CU->getGenerator(); |
| 94 | assert(Form == DW_FORM_flag_present); |
| 95 | Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, |
| 96 | DIEInteger(1)); |
| 97 | } |
| 98 | |
| 99 | dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) { |
| 100 | auto &DG = CU->getGenerator(); |
| 101 | return dwarfgen::DIE(CU, |
| 102 | &Die->addChild(llvm::DIE::get(DG.getAllocator(), Tag))); |
| 103 | } |
| 104 | |
| 105 | dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() { |
| 106 | return dwarfgen::DIE(this, &DU.getUnitDie()); |
| 107 | } |
| 108 | |
| 109 | //===----------------------------------------------------------------------===// |
| 110 | /// dwarfgen::Generator implementation. |
| 111 | //===----------------------------------------------------------------------===// |
| 112 | |
| 113 | dwarfgen::Generator::Generator() : Abbreviations(Allocator) {} |
| 114 | dwarfgen::Generator::~Generator() = default; |
| 115 | |
| 116 | llvm::Expected<std::unique_ptr<dwarfgen::Generator>> |
| 117 | dwarfgen::Generator::create(Triple TheTriple, uint16_t DwarfVersion) { |
| 118 | std::unique_ptr<dwarfgen::Generator> GenUP(new dwarfgen::Generator()); |
| 119 | llvm::Error error = GenUP->init(TheTriple, DwarfVersion); |
| 120 | if (error) |
| 121 | return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(error)); |
| 122 | return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(GenUP)); |
| 123 | } |
| 124 | |
| 125 | llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) { |
| 126 | Version = V; |
| 127 | std::string ErrorStr; |
| 128 | std::string TripleName; |
| 129 | |
| 130 | // Get the target. |
| 131 | const Target *TheTarget = |
| 132 | TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr); |
| 133 | if (!TheTarget) |
| 134 | return make_error<StringError>(ErrorStr, inconvertibleErrorCode()); |
| 135 | |
| 136 | TripleName = TheTriple.getTriple(); |
| 137 | |
| 138 | // Create all the MC Objects. |
| 139 | MRI.reset(TheTarget->createMCRegInfo(TripleName)); |
| 140 | if (!MRI) |
| 141 | return make_error<StringError>(Twine("no register info for target ") + |
| 142 | TripleName, |
| 143 | inconvertibleErrorCode()); |
| 144 | |
| 145 | MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName)); |
| 146 | if (!MAI) |
| 147 | return make_error<StringError>("no asm info for target " + TripleName, |
| 148 | inconvertibleErrorCode()); |
| 149 | |
| 150 | MOFI.reset(new MCObjectFileInfo); |
| 151 | MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get())); |
| 152 | MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, CodeModel::Default, *MC); |
| 153 | |
| 154 | MCTargetOptions Options; |
| 155 | MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "", Options); |
| 156 | if (!MAB) |
| 157 | return make_error<StringError>("no asm backend for target " + TripleName, |
| 158 | inconvertibleErrorCode()); |
| 159 | |
| 160 | MII.reset(TheTarget->createMCInstrInfo()); |
| 161 | if (!MII) |
| 162 | return make_error<StringError>("no instr info info for target " + |
| 163 | TripleName, |
| 164 | inconvertibleErrorCode()); |
| 165 | |
| 166 | MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); |
| 167 | if (!MSTI) |
| 168 | return make_error<StringError>("no subtarget info for target " + TripleName, |
| 169 | inconvertibleErrorCode()); |
| 170 | |
| 171 | MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC); |
| 172 | if (!MCE) |
| 173 | return make_error<StringError>("no code emitter for target " + TripleName, |
| 174 | inconvertibleErrorCode()); |
| 175 | |
| 176 | Stream = make_unique<raw_svector_ostream>(FileBytes); |
| 177 | |
| 178 | MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); |
| 179 | MS = TheTarget->createMCObjectStreamer( |
| 180 | TheTriple, *MC, *MAB, *Stream, MCE, *MSTI, MCOptions.MCRelaxAll, |
| 181 | MCOptions.MCIncrementalLinkerCompatible, |
| 182 | /*DWARFMustBeAtTheEnd*/ false); |
| 183 | if (!MS) |
| 184 | return make_error<StringError>("no object streamer for target " + |
| 185 | TripleName, |
| 186 | inconvertibleErrorCode()); |
| 187 | |
| 188 | // Finally create the AsmPrinter we'll use to emit the DIEs. |
| 189 | TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(), |
| 190 | None)); |
| 191 | if (!TM) |
| 192 | return make_error<StringError>("no target machine for target " + TripleName, |
| 193 | inconvertibleErrorCode()); |
| 194 | |
| 195 | Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS))); |
| 196 | if (!Asm) |
| 197 | return make_error<StringError>("no asm printer for target " + TripleName, |
| 198 | inconvertibleErrorCode()); |
| 199 | |
| 200 | // Set the DWARF version correctly on all classes that we use. |
| 201 | MC->setDwarfVersion(Version); |
| 202 | Asm->setDwarfVersion(Version); |
| 203 | |
| 204 | StringPool.reset(new DwarfStringPool(Allocator, *Asm, StringRef())); |
| 205 | |
| 206 | return Error::success(); |
| 207 | } |
| 208 | |
| 209 | StringRef dwarfgen::Generator::generate() { |
| 210 | // Offset from the first CU in the debug info section is 0 initially. |
| 211 | unsigned SecOffset = 0; |
| 212 | |
| 213 | // Iterate over each compile unit and set the size and offsets for each |
| 214 | // DIE within each compile unit. All offsets are CU relative. |
| 215 | for (auto &CU : CompileUnits) { |
| 216 | // Set the absolute .debug_info offset for this compile unit. |
| 217 | CU->setOffset(SecOffset); |
| 218 | // The DIEs contain compile unit relative offsets. |
| 219 | unsigned CUOffset = 11; |
| 220 | CUOffset = CU->getUnitDIE().computeSizeAndOffsets(CUOffset); |
| 221 | // Update our absolute .debug_info offset. |
| 222 | SecOffset += CUOffset; |
| 223 | CU->setLength(CUOffset - 4); |
| 224 | } |
| 225 | Abbreviations.Emit(Asm.get(), MOFI->getDwarfAbbrevSection()); |
| 226 | StringPool->emit(*Asm, MOFI->getDwarfStrSection()); |
| 227 | MS->SwitchSection(MOFI->getDwarfInfoSection()); |
| 228 | for (auto &CU : CompileUnits) { |
| 229 | uint16_t Version = CU->getVersion(); |
| 230 | auto Length = CU->getLength(); |
| 231 | MC->setDwarfVersion(Version); |
| 232 | assert(Length != -1U); |
| 233 | Asm->EmitInt32(Length); |
| 234 | Asm->EmitInt16(Version); |
| 235 | Asm->EmitInt32(0); |
| 236 | Asm->EmitInt8(CU->getAddressSize()); |
| 237 | Asm->emitDwarfDIE(*CU->getUnitDIE().Die); |
| 238 | } |
| 239 | |
| 240 | MS->Finish(); |
| 241 | if (FileBytes.empty()) |
| 242 | return StringRef(); |
| 243 | return StringRef(FileBytes.data(), FileBytes.size()); |
| 244 | } |
| 245 | |
| 246 | bool dwarfgen::Generator::saveFile(StringRef Path) { |
| 247 | if (FileBytes.empty()) |
| 248 | return false; |
| 249 | std::error_code EC; |
| 250 | raw_fd_ostream Strm(Path, EC, sys::fs::F_None); |
| 251 | if (EC) |
| 252 | return false; |
| 253 | Strm.write(FileBytes.data(), FileBytes.size()); |
| 254 | Strm.close(); |
| 255 | return true; |
| 256 | } |
| 257 | |
| 258 | dwarfgen::CompileUnit &dwarfgen::Generator::addCompileUnit() { |
| 259 | CompileUnits.push_back(std::unique_ptr<CompileUnit>( |
| 260 | new CompileUnit(*this, Version, Asm->getPointerSize()))); |
| 261 | return *CompileUnits.back(); |
| 262 | } |