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