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