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