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 | |
21 | namespace llvm { |
22 | namespace dwarf_linker { |
23 | namespace parallel { |
24 | |
25 | /// This class links debug info. |
26 | class DWARFLinkerImpl : public DWARFLinker { |
27 | public: |
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 | |
141 | protected: |
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 | |