1//===- DWARFLinkerImpl.h ----------------------------------------*- C++ -*-===//
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#ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H
10#define LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H
11
12#include "DWARFEmitterImpl.h"
13#include "DWARFLinkerCompileUnit.h"
14#include "DWARFLinkerTypeUnit.h"
15#include "StringEntryToDwarfStringPoolEntryMap.h"
16#include "llvm/ADT/AddressRanges.h"
17#include "llvm/CodeGen/AccelTable.h"
18#include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
19#include "llvm/DWARFLinker/StringPool.h"
20
21namespace llvm {
22namespace dwarf_linker {
23namespace parallel {
24
25/// This class links debug info.
26class DWARFLinkerImpl : public DWARFLinker {
27public:
28 DWARFLinkerImpl(MessageHandlerTy ErrorHandler,
29 MessageHandlerTy WarningHandler);
30
31 /// Add object file to be linked. Pre-load compile unit die. Call
32 /// \p OnCUDieLoaded for each compile unit die. If specified \p File
33 /// has reference to the Clang module then such module would be
34 /// pre-loaded by \p Loader for !Update case.
35 ///
36 /// \pre NoODR, Update options should be set before call to addObjectFile.
37 void addObjectFile(
38 DWARFFile &File, ObjFileLoaderTy Loader = nullptr,
39
40 CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) override;
41
42 /// Link debug info for added files.
43 Error link() override;
44
45 /// Set output DWARF handler. May be not set if output generation is not
46 /// necessary.
47 void setOutputDWARFHandler(const Triple &TargetTriple,
48 SectionHandlerTy SectionHandler) override {
49 GlobalData.setTargetTriple(TargetTriple);
50 this->SectionHandler = SectionHandler;
51 }
52
53 /// \defgroup Methods setting various linking options:
54 ///
55 /// @{
56 ///
57
58 /// Allows to generate log of linking process to the standard output.
59 void setVerbosity(bool Verbose) override {
60 GlobalData.Options.Verbose = Verbose;
61 }
62
63 /// Print statistics to standard output.
64 void setStatistics(bool Statistics) override {
65 GlobalData.Options.Statistics = Statistics;
66 }
67
68 /// Verify the input DWARF.
69 void setVerifyInputDWARF(bool Verify) override {
70 GlobalData.Options.VerifyInputDWARF = Verify;
71 }
72
73 /// Do not unique types according to ODR.
74 void setNoODR(bool NoODR) override { GlobalData.Options.NoODR = NoODR; }
75
76 /// Update index tables only(do not modify rest of DWARF).
77 void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override {
78 GlobalData.Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly;
79 }
80
81 /// Allow generating valid, but non-deterministic output.
82 void
83 setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override {
84 GlobalData.Options.AllowNonDeterministicOutput =
85 AllowNonDeterministicOutput;
86 }
87
88 /// Set to keep the enclosing function for a static variable.
89 void setKeepFunctionForStatic(bool KeepFunctionForStatic) override {
90 GlobalData.Options.KeepFunctionForStatic = KeepFunctionForStatic;
91 }
92
93 /// Use specified number of threads for parallel files linking.
94 void setNumThreads(unsigned NumThreads) override {
95 GlobalData.Options.Threads = NumThreads;
96 }
97
98 /// Add kind of accelerator tables to be generated.
99 void addAccelTableKind(AccelTableKind Kind) override {
100 assert(!llvm::is_contained(GlobalData.getOptions().AccelTables, Kind));
101 GlobalData.Options.AccelTables.emplace_back(Args&: Kind);
102 }
103
104 /// Set prepend path for clang modules.
105 void setPrependPath(StringRef Ppath) override {
106 GlobalData.Options.PrependPath = Ppath;
107 }
108
109 /// Set estimated objects files amount, for preliminary data allocation.
110 void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override;
111
112 /// Set verification handler which would be used to report verification
113 /// errors.
114 void
115 setInputVerificationHandler(InputVerificationHandlerTy Handler) override {
116 GlobalData.Options.InputVerificationHandler = Handler;
117 }
118
119 /// Set map for Swift interfaces.
120 void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override {
121 GlobalData.Options.ParseableSwiftInterfaces = Map;
122 }
123
124 /// Set prefix map for objects.
125 void setObjectPrefixMap(ObjectPrefixMapTy *Map) override {
126 GlobalData.Options.ObjectPrefixMap = Map;
127 }
128
129 /// Set target DWARF version.
130 Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) override {
131 if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5))
132 return createStringError(EC: std::errc::invalid_argument,
133 Fmt: "unsupported DWARF version: %d",
134 Vals: TargetDWARFVersion);
135
136 GlobalData.Options.TargetDWARFVersion = TargetDWARFVersion;
137 return Error::success();
138 }
139 /// @}
140
141protected:
142 /// Verify input DWARF file.
143 void verifyInput(const DWARFFile &File);
144
145 /// Validate specified options.
146 Error validateAndUpdateOptions();
147
148 /// Take already linked compile units and glue them into single file.
149 void glueCompileUnitsAndWriteToTheOutput();
150
151 /// Hold the input and output of the debug info size in bytes.
152 struct DebugInfoSize {
153 uint64_t Input;
154 uint64_t Output;
155 };
156
157 friend class DependencyTracker;
158 /// Keeps track of data associated with one object during linking.
159 /// i.e. source file descriptor, compilation units, output data
160 /// for compilation units common tables.
161 struct LinkContext : public OutputSections {
162 using UnitListTy = SmallVector<std::unique_ptr<CompileUnit>>;
163
164 /// Keep information for referenced clang module: already loaded DWARF info
165 /// of the clang module and a CompileUnit of the module.
166 struct RefModuleUnit {
167 RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit);
168 RefModuleUnit(RefModuleUnit &&Other);
169 RefModuleUnit(const RefModuleUnit &) = delete;
170
171 DWARFFile &File;
172 std::unique_ptr<CompileUnit> Unit;
173 };
174 using ModuleUnitListTy = SmallVector<RefModuleUnit>;
175
176 /// Object file descriptor.
177 DWARFFile &InputDWARFFile;
178
179 /// Set of Compilation Units(may be accessed asynchroniously for reading).
180 UnitListTy CompileUnits;
181
182 /// Set of Compile Units for modules.
183 ModuleUnitListTy ModulesCompileUnits;
184
185 /// Size of Debug info before optimizing.
186 uint64_t OriginalDebugInfoSize = 0;
187
188 /// Flag indicating that all inter-connected units are loaded
189 /// and the dwarf linking process for these units is started.
190 bool InterCUProcessingStarted = false;
191
192 StringMap<uint64_t> &ClangModules;
193
194 /// Flag indicating that new inter-connected compilation units were
195 /// discovered. It is used for restarting units processing
196 /// if new inter-connected units were found.
197 std::atomic<bool> HasNewInterconnectedCUs = {false};
198
199 std::atomic<bool> HasNewGlobalDependency = {false};
200
201 /// Counter for compile units ID.
202 std::atomic<size_t> &UniqueUnitID;
203
204 LinkContext(LinkingGlobalData &GlobalData, DWARFFile &File,
205 StringMap<uint64_t> &ClangModules,
206 std::atomic<size_t> &UniqueUnitID);
207
208 /// Check whether specified \p CUDie is a Clang module reference.
209 /// if \p Quiet is false then display error messages.
210 /// \return first == true if CUDie is a Clang module reference.
211 /// second == true if module is already loaded.
212 std::pair<bool, bool> isClangModuleRef(const DWARFDie &CUDie,
213 std::string &PCMFile,
214 unsigned Indent, bool Quiet);
215
216 /// If this compile unit is really a skeleton CU that points to a
217 /// clang module, register it in ClangModules and return true.
218 ///
219 /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
220 /// pointing to the module, and a DW_AT_gnu_dwo_id with the module
221 /// hash.
222 bool registerModuleReference(const DWARFDie &CUDie, ObjFileLoaderTy Loader,
223 CompileUnitHandlerTy OnCUDieLoaded,
224 unsigned Indent = 0);
225
226 /// Recursively add the debug info in this clang module .pcm
227 /// file (and all the modules imported by it in a bottom-up fashion)
228 /// to ModuleUnits.
229 Error loadClangModule(ObjFileLoaderTy Loader, const DWARFDie &CUDie,
230 const std::string &PCMFile,
231 CompileUnitHandlerTy OnCUDieLoaded,
232 unsigned Indent = 0);
233
234 /// Add Compile Unit corresponding to the module.
235 void addModulesCompileUnit(RefModuleUnit &&Unit);
236
237 /// Computes the total size of the debug info.
238 uint64_t getInputDebugInfoSize() const {
239 uint64_t Size = 0;
240
241 if (InputDWARFFile.Dwarf == nullptr)
242 return Size;
243
244 for (auto &Unit : InputDWARFFile.Dwarf->compile_units())
245 Size += Unit->getLength();
246
247 return Size;
248 }
249
250 /// Link compile units for this context.
251 Error link(TypeUnit *ArtificialTypeUnit);
252
253 /// Link specified compile unit until specified stage.
254 void linkSingleCompileUnit(
255 CompileUnit &CU, TypeUnit *ArtificialTypeUnit,
256 enum CompileUnit::Stage DoUntilStage = CompileUnit::Stage::Cleaned);
257
258 /// Emit invariant sections.
259 Error emitInvariantSections();
260
261 /// Clone and emit .debug_frame.
262 Error cloneAndEmitDebugFrame();
263
264 /// Emit FDE record.
265 void emitFDE(uint32_t CIEOffset, uint32_t AddrSize, uint64_t Address,
266 StringRef FDEBytes, SectionDescriptor &Section);
267
268 std::function<CompileUnit *(uint64_t)> getUnitForOffset =
269 [&](uint64_t Offset) -> CompileUnit * {
270 auto CU = llvm::upper_bound(
271 Range&: CompileUnits, Value&: Offset,
272 C: [](uint64_t LHS, const std::unique_ptr<CompileUnit> &RHS) {
273 return LHS < RHS->getOrigUnit().getNextUnitOffset();
274 });
275
276 return CU != CompileUnits.end() ? CU->get() : nullptr;
277 };
278 };
279
280 /// Enumerate all compile units and assign offsets to their sections and
281 /// strings.
282 void assignOffsets();
283
284 /// Enumerate all compile units and assign offsets to their sections.
285 void assignOffsetsToSections();
286
287 /// Enumerate all compile units and assign offsets to their strings.
288 void assignOffsetsToStrings();
289
290 /// Print statistic for processed Debug Info.
291 void printStatistic();
292
293 enum StringDestinationKind : uint8_t { DebugStr, DebugLineStr };
294
295 /// Enumerates all strings.
296 void forEachOutputString(
297 function_ref<void(StringDestinationKind, const StringEntry *)>
298 StringHandler);
299
300 /// Enumerates sections for modules, invariant for object files, compile
301 /// units.
302 void forEachObjectSectionsSet(
303 function_ref<void(OutputSections &SectionsSet)> SectionsSetHandler);
304
305 /// Enumerates all compile and type units.
306 void forEachCompileAndTypeUnit(function_ref<void(DwarfUnit *CU)> UnitHandler);
307
308 /// Enumerates all comple units.
309 void forEachCompileUnit(function_ref<void(CompileUnit *CU)> UnitHandler);
310
311 /// Enumerates all patches and update them with the correct values.
312 void patchOffsetsAndSizes();
313
314 /// Emit debug sections common for all input files.
315 void emitCommonSectionsAndWriteCompileUnitsToTheOutput();
316
317 /// Emit apple accelerator sections.
318 void emitAppleAcceleratorSections(const Triple &TargetTriple);
319
320 /// Emit .debug_names section.
321 void emitDWARFv5DebugNamesSection(const Triple &TargetTriple);
322
323 /// Emit string sections.
324 void emitStringSections();
325
326 /// Cleanup data(string pools) after output sections are generated.
327 void cleanupDataAfterDWARFOutputIsWritten();
328
329 /// Enumerate all compile units and put their data into the output stream.
330 void writeCompileUnitsToTheOutput();
331
332 /// Enumerate common sections and put their data into the output stream.
333 void writeCommonSectionsToTheOutput();
334
335 /// \defgroup Data members accessed asinchroniously.
336 ///
337 /// @{
338
339 /// Unique ID for compile unit.
340 std::atomic<size_t> UniqueUnitID;
341
342 /// Mapping the PCM filename to the DwoId.
343 StringMap<uint64_t> ClangModules;
344 std::mutex ClangModulesMutex;
345
346 /// Type unit.
347 std::unique_ptr<TypeUnit> ArtificialTypeUnit;
348 /// @}
349
350 /// \defgroup Data members accessed sequentially.
351 ///
352 /// @{
353 /// Data global for the whole linking process.
354 LinkingGlobalData GlobalData;
355
356 /// DwarfStringPoolEntries for .debug_str section.
357 StringEntryToDwarfStringPoolEntryMap DebugStrStrings;
358
359 /// DwarfStringPoolEntries for .debug_line_str section.
360 StringEntryToDwarfStringPoolEntryMap DebugLineStrStrings;
361
362 /// Keeps all linking contexts.
363 SmallVector<std::unique_ptr<LinkContext>> ObjectContexts;
364
365 /// Common sections.
366 OutputSections CommonSections;
367
368 /// Hanler for output sections.
369 SectionHandlerTy SectionHandler = nullptr;
370
371 /// Overall compile units number.
372 uint64_t OverallNumberOfCU = 0;
373 /// @}
374};
375
376} // end of namespace parallel
377} // end of namespace dwarf_linker
378} // end of namespace llvm
379
380#endif // LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H
381