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 | |
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(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 | |
124 | void 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 | |
132 | void DwarfEmitterImpl::(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 | |
156 | void DwarfEmitterImpl::emitDIE(DIE &Die) { |
157 | MS->switchSection(Section: MOFI->getDwarfInfoSection()); |
158 | Asm->emitDwarfDIE(Die); |
159 | DebugInfoSectionSize += Die.getSize(); |
160 | } |
161 | |
162 | void 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 | |
184 | void 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 | |
192 | void 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 | |
200 | void 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 | |
208 | void 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 | |