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 | |
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(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 | |
125 | void 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 | |
133 | void DwarfEmitterImpl::(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 | |
157 | void DwarfEmitterImpl::emitDIE(DIE &Die) { |
158 | MS->switchSection(Section: MOFI->getDwarfInfoSection()); |
159 | Asm->emitDwarfDIE(Die); |
160 | DebugInfoSectionSize += Die.getSize(); |
161 | } |
162 | |
163 | void 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 | |
185 | void 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 | |
193 | void 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 | |
201 | void 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 | |
209 | void 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 | |