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