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