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