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