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
init(Triple TheTriple,StringRef Swift5ReflectionSegmentName)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
emitAbbrevs(const SmallVector<std::unique_ptr<DIEAbbrev>> & Abbrevs,unsigned DwarfVersion)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
emitCompileUnitHeader(DwarfUnit & Unit)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
emitDIE(DIE & Die)157 void DwarfEmitterImpl::emitDIE(DIE &Die) {
158 MS->switchSection(MOFI->getDwarfInfoSection());
159 Asm->emitDwarfDIE(Die);
160 DebugInfoSectionSize += Die.getSize();
161 }
162
emitDebugNames(DWARF5AccelTable & Table,DebugNamesUnitsOffsets & CUOffsets,CompUnitIDToIdx & CUidToIdx)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
emitAppleNamespaces(AccelTable<AppleAccelTableStaticOffsetData> & Table)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
emitAppleNames(AccelTable<AppleAccelTableStaticOffsetData> & Table)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
emitAppleObjc(AccelTable<AppleAccelTableStaticOffsetData> & Table)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
emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> & Table)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