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