| 1 | //===- DWARFEmitterImpl.cpp -----------------------------------------------===// |
| 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 "DWARFEmitterImpl.h" |
| 10 | #include "llvm/MC/MCAsmBackend.h" |
| 11 | #include "llvm/MC/MCCodeEmitter.h" |
| 12 | #include "llvm/MC/MCInstPrinter.h" |
| 13 | #include "llvm/MC/MCObjectWriter.h" |
| 14 | #include "llvm/MC/MCTargetOptions.h" |
| 15 | #include "llvm/MC/MCTargetOptionsCommandFlags.h" |
| 16 | #include "llvm/MC/TargetRegistry.h" |
| 17 | #include "llvm/Support/FormattedStream.h" |
| 18 | |
| 19 | using namespace llvm; |
| 20 | using namespace dwarf_linker; |
| 21 | using namespace dwarf_linker::parallel; |
| 22 | |
| 23 | Error DwarfEmitterImpl::init(Triple TheTriple, |
| 24 | StringRef Swift5ReflectionSegmentName) { |
| 25 | std::string ErrorStr; |
| 26 | std::string TripleName; |
| 27 | |
| 28 | // Get the target. |
| 29 | const Target *TheTarget = |
| 30 | TargetRegistry::lookupTarget(ArchName: TripleName, TheTriple, Error&: ErrorStr); |
| 31 | if (!TheTarget) |
| 32 | return createStringError(EC: std::errc::invalid_argument, Fmt: ErrorStr.c_str()); |
| 33 | TripleName = TheTriple.getTriple(); |
| 34 | |
| 35 | // Create all the MC Objects. |
| 36 | MRI.reset(p: TheTarget->createMCRegInfo(TT: TheTriple)); |
| 37 | if (!MRI) |
| 38 | return createStringError(EC: std::errc::invalid_argument, |
| 39 | Fmt: "no register info for target %s" , |
| 40 | Vals: TripleName.c_str()); |
| 41 | |
| 42 | MCOptions = mc::InitMCTargetOptionsFromFlags(); |
| 43 | MCOptions.AsmVerbose = true; |
| 44 | MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory; |
| 45 | MAI.reset(p: TheTarget->createMCAsmInfo(MRI: *MRI, TheTriple, Options: MCOptions)); |
| 46 | if (!MAI) |
| 47 | return createStringError(EC: std::errc::invalid_argument, |
| 48 | Fmt: "no asm info for target %s" , Vals: TripleName.c_str()); |
| 49 | |
| 50 | MSTI.reset(p: TheTarget->createMCSubtargetInfo(TheTriple, CPU: "" , Features: "" )); |
| 51 | if (!MSTI) |
| 52 | return createStringError(EC: std::errc::invalid_argument, |
| 53 | Fmt: "no subtarget info for target %s" , |
| 54 | Vals: TripleName.c_str()); |
| 55 | |
| 56 | MC.reset(p: new MCContext(TheTriple, *MAI, *MRI, *MSTI, nullptr, true, |
| 57 | Swift5ReflectionSegmentName)); |
| 58 | MOFI.reset(p: TheTarget->createMCObjectFileInfo(Ctx&: *MC, /*PIC=*/false, LargeCodeModel: false)); |
| 59 | MC->setObjectFileInfo(MOFI.get()); |
| 60 | |
| 61 | MAB = TheTarget->createMCAsmBackend(STI: *MSTI, MRI: *MRI, Options: MCOptions); |
| 62 | if (!MAB) |
| 63 | return createStringError(EC: std::errc::invalid_argument, |
| 64 | Fmt: "no asm backend for target %s" , |
| 65 | Vals: TripleName.c_str()); |
| 66 | |
| 67 | MII.reset(p: TheTarget->createMCInstrInfo()); |
| 68 | if (!MII) |
| 69 | return createStringError(EC: std::errc::invalid_argument, |
| 70 | Fmt: "no instr info info for target %s" , |
| 71 | Vals: TripleName.c_str()); |
| 72 | |
| 73 | MCE = TheTarget->createMCCodeEmitter(II: *MII, Ctx&: *MC); |
| 74 | if (!MCE) |
| 75 | return createStringError(EC: std::errc::invalid_argument, |
| 76 | Fmt: "no code emitter for target %s" , |
| 77 | Vals: TripleName.c_str()); |
| 78 | |
| 79 | switch (OutFileType) { |
| 80 | case DWARFLinker::OutputFileType::Assembly: { |
| 81 | std::unique_ptr<MCInstPrinter> MIP(TheTarget->createMCInstPrinter( |
| 82 | T: TheTriple, SyntaxVariant: MAI->getAssemblerDialect(), MAI: *MAI, MII: *MII, MRI: *MRI)); |
| 83 | MS = TheTarget->createAsmStreamer( |
| 84 | Ctx&: *MC, OS: std::make_unique<formatted_raw_ostream>(args&: OutFile), IP: std::move(MIP), |
| 85 | CE: std::unique_ptr<MCCodeEmitter>(MCE), |
| 86 | TAB: std::unique_ptr<MCAsmBackend>(MAB)); |
| 87 | break; |
| 88 | } |
| 89 | case DWARFLinker::OutputFileType::Object: { |
| 90 | MS = TheTarget->createMCObjectStreamer( |
| 91 | T: TheTriple, Ctx&: *MC, TAB: std::unique_ptr<MCAsmBackend>(MAB), |
| 92 | OW: MAB->createObjectWriter(OS&: OutFile), Emitter: std::unique_ptr<MCCodeEmitter>(MCE), |
| 93 | STI: *MSTI); |
| 94 | break; |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | if (!MS) |
| 99 | return createStringError(EC: std::errc::invalid_argument, |
| 100 | Fmt: "no object streamer for target %s" , |
| 101 | Vals: TripleName.c_str()); |
| 102 | |
| 103 | // Finally create the AsmPrinter we'll use to emit the DIEs. |
| 104 | TM.reset(p: TheTarget->createTargetMachine(TT: TheTriple, CPU: "" , Features: "" , Options: TargetOptions(), |
| 105 | RM: std::nullopt)); |
| 106 | if (!TM) |
| 107 | return createStringError(EC: std::errc::invalid_argument, |
| 108 | Fmt: "no target machine for target %s" , |
| 109 | Vals: TripleName.c_str()); |
| 110 | |
| 111 | Asm.reset(p: TheTarget->createAsmPrinter(TM&: *TM, Streamer: std::unique_ptr<MCStreamer>(MS))); |
| 112 | if (!Asm) |
| 113 | return createStringError(EC: std::errc::invalid_argument, |
| 114 | Fmt: "no asm printer for target %s" , |
| 115 | Vals: TripleName.c_str()); |
| 116 | Asm->setDwarfUsesRelocationsAcrossSections(false); |
| 117 | |
| 118 | DebugInfoSectionSize = 0; |
| 119 | |
| 120 | return Error::success(); |
| 121 | } |
| 122 | |
| 123 | void DwarfEmitterImpl::emitAbbrevs( |
| 124 | const SmallVector<std::unique_ptr<DIEAbbrev>> &Abbrevs, |
| 125 | unsigned DwarfVersion) { |
| 126 | MS->switchSection(Section: MOFI->getDwarfAbbrevSection()); |
| 127 | MC->setDwarfVersion(DwarfVersion); |
| 128 | Asm->emitDwarfAbbrevs(Abbrevs); |
| 129 | } |
| 130 | |
| 131 | void DwarfEmitterImpl::(DwarfUnit &Unit) { |
| 132 | MS->switchSection(Section: MOFI->getDwarfInfoSection()); |
| 133 | MC->setDwarfVersion(Unit.getVersion()); |
| 134 | |
| 135 | // Emit size of content not including length itself. The size has already |
| 136 | // been computed in CompileUnit::computeOffsets(). Subtract 4 to that size to |
| 137 | // account for the length field. |
| 138 | Asm->emitInt32(Value: Unit.getUnitSize() - 4); |
| 139 | Asm->emitInt16(Value: Unit.getVersion()); |
| 140 | |
| 141 | if (Unit.getVersion() >= 5) { |
| 142 | Asm->emitInt8(Value: dwarf::DW_UT_compile); |
| 143 | Asm->emitInt8(Value: Unit.getFormParams().AddrSize); |
| 144 | // Proper offset to the abbreviations table will be set later. |
| 145 | Asm->emitInt32(Value: 0); |
| 146 | DebugInfoSectionSize += 12; |
| 147 | } else { |
| 148 | // Proper offset to the abbreviations table will be set later. |
| 149 | Asm->emitInt32(Value: 0); |
| 150 | Asm->emitInt8(Value: Unit.getFormParams().AddrSize); |
| 151 | DebugInfoSectionSize += 11; |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | void DwarfEmitterImpl::emitDIE(DIE &Die) { |
| 156 | MS->switchSection(Section: MOFI->getDwarfInfoSection()); |
| 157 | Asm->emitDwarfDIE(Die); |
| 158 | DebugInfoSectionSize += Die.getSize(); |
| 159 | } |
| 160 | |
| 161 | void DwarfEmitterImpl::emitDebugNames(DWARF5AccelTable &Table, |
| 162 | DebugNamesUnitsOffsets &CUOffsets, |
| 163 | CompUnitIDToIdx &CUidToIdx) { |
| 164 | if (CUOffsets.empty()) |
| 165 | return; |
| 166 | |
| 167 | Asm->OutStreamer->switchSection(Section: MOFI->getDwarfDebugNamesSection()); |
| 168 | dwarf::Form Form = |
| 169 | DIEInteger::BestForm(/*IsSigned*/ false, Int: (uint64_t)CUidToIdx.size() - 1); |
| 170 | // FIXME: add support for type units + .debug_names. For now the behavior is |
| 171 | // unsuported. |
| 172 | emitDWARF5AccelTable( |
| 173 | Asm: Asm.get(), Contents&: Table, CUs: CUOffsets, |
| 174 | getIndexForEntry: [&](const DWARF5AccelTableData &Entry) |
| 175 | -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> { |
| 176 | if (CUidToIdx.size() > 1) |
| 177 | return {{.Index: CUidToIdx[Entry.getUnitID()], |
| 178 | .Encoding: {.Index: dwarf::DW_IDX_compile_unit, .Form: Form}}}; |
| 179 | return std::nullopt; |
| 180 | }); |
| 181 | } |
| 182 | |
| 183 | void DwarfEmitterImpl::emitAppleNamespaces( |
| 184 | AccelTable<AppleAccelTableStaticOffsetData> &Table) { |
| 185 | Asm->OutStreamer->switchSection(Section: MOFI->getDwarfAccelNamespaceSection()); |
| 186 | auto *SectionBegin = Asm->createTempSymbol(Name: "namespac_begin" ); |
| 187 | Asm->OutStreamer->emitLabel(Symbol: SectionBegin); |
| 188 | emitAppleAccelTable(Asm: Asm.get(), Contents&: Table, Prefix: "namespac" , SecBegin: SectionBegin); |
| 189 | } |
| 190 | |
| 191 | void DwarfEmitterImpl::emitAppleNames( |
| 192 | AccelTable<AppleAccelTableStaticOffsetData> &Table) { |
| 193 | Asm->OutStreamer->switchSection(Section: MOFI->getDwarfAccelNamesSection()); |
| 194 | auto *SectionBegin = Asm->createTempSymbol(Name: "names_begin" ); |
| 195 | Asm->OutStreamer->emitLabel(Symbol: SectionBegin); |
| 196 | emitAppleAccelTable(Asm: Asm.get(), Contents&: Table, Prefix: "names" , SecBegin: SectionBegin); |
| 197 | } |
| 198 | |
| 199 | void DwarfEmitterImpl::emitAppleObjc( |
| 200 | AccelTable<AppleAccelTableStaticOffsetData> &Table) { |
| 201 | Asm->OutStreamer->switchSection(Section: MOFI->getDwarfAccelObjCSection()); |
| 202 | auto *SectionBegin = Asm->createTempSymbol(Name: "objc_begin" ); |
| 203 | Asm->OutStreamer->emitLabel(Symbol: SectionBegin); |
| 204 | emitAppleAccelTable(Asm: Asm.get(), Contents&: Table, Prefix: "objc" , SecBegin: SectionBegin); |
| 205 | } |
| 206 | |
| 207 | void DwarfEmitterImpl::emitAppleTypes( |
| 208 | AccelTable<AppleAccelTableStaticTypeData> &Table) { |
| 209 | Asm->OutStreamer->switchSection(Section: MOFI->getDwarfAccelTypesSection()); |
| 210 | auto *SectionBegin = Asm->createTempSymbol(Name: "types_begin" ); |
| 211 | Asm->OutStreamer->emitLabel(Symbol: SectionBegin); |
| 212 | emitAppleAccelTable(Asm: Asm.get(), Contents&: Table, Prefix: "types" , SecBegin: SectionBegin); |
| 213 | } |
| 214 | |