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