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(TripleName, TheTriple, ErrorStr); 33 if (!TheTarget) 34 return createStringError(std::errc::invalid_argument, ErrorStr.c_str()); 35 TripleName = TheTriple.getTriple(); 36 37 // Create all the MC Objects. 38 MRI.reset(TheTarget->createMCRegInfo(TripleName)); 39 if (!MRI) 40 return createStringError(std::errc::invalid_argument, 41 "no register info for target %s", 42 TripleName.c_str()); 43 44 MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags(); 45 MCOptions.AsmVerbose = true; 46 MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory; 47 MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 48 if (!MAI) 49 return createStringError(std::errc::invalid_argument, 50 "no asm info for target %s", TripleName.c_str()); 51 52 MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); 53 if (!MSTI) 54 return createStringError(std::errc::invalid_argument, 55 "no subtarget info for target %s", 56 TripleName.c_str()); 57 58 MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr, 59 nullptr, true, Swift5ReflectionSegmentName)); 60 MOFI.reset(TheTarget->createMCObjectFileInfo(*MC, /*PIC=*/false, false)); 61 MC->setObjectFileInfo(MOFI.get()); 62 63 MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions); 64 if (!MAB) 65 return createStringError(std::errc::invalid_argument, 66 "no asm backend for target %s", 67 TripleName.c_str()); 68 69 MII.reset(TheTarget->createMCInstrInfo()); 70 if (!MII) 71 return createStringError(std::errc::invalid_argument, 72 "no instr info info for target %s", 73 TripleName.c_str()); 74 75 MCE = TheTarget->createMCCodeEmitter(*MII, *MC); 76 if (!MCE) 77 return createStringError(std::errc::invalid_argument, 78 "no code emitter for target %s", 79 TripleName.c_str()); 80 81 switch (OutFileType) { 82 case DWARFLinker::OutputFileType::Assembly: { 83 std::unique_ptr<MCInstPrinter> MIP(TheTarget->createMCInstPrinter( 84 TheTriple, MAI->getAssemblerDialect(), *MAI, *MII, *MRI)); 85 MS = TheTarget->createAsmStreamer( 86 *MC, std::make_unique<formatted_raw_ostream>(OutFile), std::move(MIP), 87 std::unique_ptr<MCCodeEmitter>(MCE), 88 std::unique_ptr<MCAsmBackend>(MAB)); 89 break; 90 } 91 case DWARFLinker::OutputFileType::Object: { 92 MS = TheTarget->createMCObjectStreamer( 93 TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB), 94 MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE), 95 *MSTI); 96 break; 97 } 98 } 99 100 if (!MS) 101 return createStringError(std::errc::invalid_argument, 102 "no object streamer for target %s", 103 TripleName.c_str()); 104 105 // Finally create the AsmPrinter we'll use to emit the DIEs. 106 TM.reset(TheTarget->createTargetMachine(TheTriple, "", "", TargetOptions(), 107 std::nullopt)); 108 if (!TM) 109 return createStringError(std::errc::invalid_argument, 110 "no target machine for target %s", 111 TripleName.c_str()); 112 113 Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS))); 114 if (!Asm) 115 return createStringError(std::errc::invalid_argument, 116 "no asm printer for target %s", 117 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(MOFI->getDwarfAbbrevSection()); 129 MC->setDwarfVersion(DwarfVersion); 130 Asm->emitDwarfAbbrevs(Abbrevs); 131 } 132 133 void DwarfEmitterImpl::emitCompileUnitHeader(DwarfUnit &Unit) { 134 MS->switchSection(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(Unit.getUnitSize() - 4); 141 Asm->emitInt16(Unit.getVersion()); 142 143 if (Unit.getVersion() >= 5) { 144 Asm->emitInt8(dwarf::DW_UT_compile); 145 Asm->emitInt8(Unit.getFormParams().AddrSize); 146 // Proper offset to the abbreviations table will be set later. 147 Asm->emitInt32(0); 148 DebugInfoSectionSize += 12; 149 } else { 150 // Proper offset to the abbreviations table will be set later. 151 Asm->emitInt32(0); 152 Asm->emitInt8(Unit.getFormParams().AddrSize); 153 DebugInfoSectionSize += 11; 154 } 155 } 156 157 void DwarfEmitterImpl::emitDIE(DIE &Die) { 158 MS->switchSection(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(MOFI->getDwarfDebugNamesSection()); 170 dwarf::Form Form = 171 DIEInteger::BestForm(/*IsSigned*/ false, (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.get(), Table, CUOffsets, 176 [&](const DWARF5AccelTableData &Entry) 177 -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> { 178 if (CUidToIdx.size() > 1) 179 return {{CUidToIdx[Entry.getUnitID()], 180 {dwarf::DW_IDX_compile_unit, Form}}}; 181 return std::nullopt; 182 }); 183 } 184 185 void DwarfEmitterImpl::emitAppleNamespaces( 186 AccelTable<AppleAccelTableStaticOffsetData> &Table) { 187 Asm->OutStreamer->switchSection(MOFI->getDwarfAccelNamespaceSection()); 188 auto *SectionBegin = Asm->createTempSymbol("namespac_begin"); 189 Asm->OutStreamer->emitLabel(SectionBegin); 190 emitAppleAccelTable(Asm.get(), Table, "namespac", SectionBegin); 191 } 192 193 void DwarfEmitterImpl::emitAppleNames( 194 AccelTable<AppleAccelTableStaticOffsetData> &Table) { 195 Asm->OutStreamer->switchSection(MOFI->getDwarfAccelNamesSection()); 196 auto *SectionBegin = Asm->createTempSymbol("names_begin"); 197 Asm->OutStreamer->emitLabel(SectionBegin); 198 emitAppleAccelTable(Asm.get(), Table, "names", SectionBegin); 199 } 200 201 void DwarfEmitterImpl::emitAppleObjc( 202 AccelTable<AppleAccelTableStaticOffsetData> &Table) { 203 Asm->OutStreamer->switchSection(MOFI->getDwarfAccelObjCSection()); 204 auto *SectionBegin = Asm->createTempSymbol("objc_begin"); 205 Asm->OutStreamer->emitLabel(SectionBegin); 206 emitAppleAccelTable(Asm.get(), Table, "objc", SectionBegin); 207 } 208 209 void DwarfEmitterImpl::emitAppleTypes( 210 AccelTable<AppleAccelTableStaticTypeData> &Table) { 211 Asm->OutStreamer->switchSection(MOFI->getDwarfAccelTypesSection()); 212 auto *SectionBegin = Asm->createTempSymbol("types_begin"); 213 Asm->OutStreamer->emitLabel(SectionBegin); 214 emitAppleAccelTable(Asm.get(), Table, "types", SectionBegin); 215 } 216