xref: /freebsd/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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.
setOutputDWARFHandler(const Triple & TargetTriple,SectionHandlerTy SectionHandler)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.
setVerbosity(bool Verbose)59   void setVerbosity(bool Verbose) override {
60     GlobalData.Options.Verbose = Verbose;
61   }
62 
63   /// Print statistics to standard output.
setStatistics(bool Statistics)64   void setStatistics(bool Statistics) override {
65     GlobalData.Options.Statistics = Statistics;
66   }
67 
68   /// Verify the input DWARF.
setVerifyInputDWARF(bool Verify)69   void setVerifyInputDWARF(bool Verify) override {
70     GlobalData.Options.VerifyInputDWARF = Verify;
71   }
72 
73   /// Do not unique types according to ODR.
setNoODR(bool NoODR)74   void setNoODR(bool NoODR) override { GlobalData.Options.NoODR = NoODR; }
75 
76   /// Update index tables only(do not modify rest of DWARF).
setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly)77   void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override {
78     GlobalData.Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly;
79   }
80 
81   /// Allow generating valid, but non-deterministic output.
82   void
setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput)83   setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override {
84     GlobalData.Options.AllowNonDeterministicOutput =
85         AllowNonDeterministicOutput;
86   }
87 
88   /// Set to keep the enclosing function for a static variable.
setKeepFunctionForStatic(bool KeepFunctionForStatic)89   void setKeepFunctionForStatic(bool KeepFunctionForStatic) override {
90     GlobalData.Options.KeepFunctionForStatic = KeepFunctionForStatic;
91   }
92 
93   /// Use specified number of threads for parallel files linking.
setNumThreads(unsigned NumThreads)94   void setNumThreads(unsigned NumThreads) override {
95     GlobalData.Options.Threads = NumThreads;
96   }
97 
98   /// Add kind of accelerator tables to be generated.
addAccelTableKind(AccelTableKind Kind)99   void addAccelTableKind(AccelTableKind Kind) override {
100     assert(!llvm::is_contained(GlobalData.getOptions().AccelTables, Kind));
101     GlobalData.Options.AccelTables.emplace_back(Kind);
102   }
103 
104   /// Set prepend path for clang modules.
setPrependPath(StringRef Ppath)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
setInputVerificationHandler(InputVerificationHandlerTy Handler)115   setInputVerificationHandler(InputVerificationHandlerTy Handler) override {
116     GlobalData.Options.InputVerificationHandler = Handler;
117   }
118 
119   /// Set map for Swift interfaces.
setSwiftInterfacesMap(SwiftInterfacesMapTy * Map)120   void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override {
121     GlobalData.Options.ParseableSwiftInterfaces = Map;
122   }
123 
124   /// Set prefix map for objects.
setObjectPrefixMap(ObjectPrefixMapTy * Map)125   void setObjectPrefixMap(ObjectPrefixMapTy *Map) override {
126     GlobalData.Options.ObjectPrefixMap = Map;
127   }
128 
129   /// Set target DWARF version.
setTargetDWARFVersion(uint16_t TargetDWARFVersion)130   Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) override {
131     if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5))
132       return createStringError(std::errc::invalid_argument,
133                                "unsupported DWARF version: %d",
134                                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.
getInputDebugInfoSizeLinkContext238     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           CompileUnits, Offset,
272           [](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