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