1 | //=== DWARFLinkerImpl.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 "DWARFLinkerImpl.h" |
10 | #include "DependencyTracker.h" |
11 | #include "llvm/DWARFLinker/Utils.h" |
12 | #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" |
13 | #include "llvm/Support/FormatVariadic.h" |
14 | #include "llvm/Support/Parallel.h" |
15 | #include "llvm/Support/ThreadPool.h" |
16 | |
17 | using namespace llvm; |
18 | using namespace dwarf_linker; |
19 | using namespace dwarf_linker::parallel; |
20 | |
21 | DWARFLinkerImpl::DWARFLinkerImpl(MessageHandlerTy ErrorHandler, |
22 | MessageHandlerTy WarningHandler) |
23 | : UniqueUnitID(0), DebugStrStrings(GlobalData), |
24 | DebugLineStrStrings(GlobalData), CommonSections(GlobalData) { |
25 | GlobalData.setErrorHandler(ErrorHandler); |
26 | GlobalData.setWarningHandler(WarningHandler); |
27 | } |
28 | |
29 | DWARFLinkerImpl::LinkContext::LinkContext(LinkingGlobalData &GlobalData, |
30 | DWARFFile &File, |
31 | StringMap<uint64_t> &ClangModules, |
32 | std::atomic<size_t> &UniqueUnitID) |
33 | : OutputSections(GlobalData), InputDWARFFile(File), |
34 | ClangModules(ClangModules), UniqueUnitID(UniqueUnitID) { |
35 | |
36 | if (File.Dwarf) { |
37 | if (!File.Dwarf->compile_units().empty()) |
38 | CompileUnits.reserve(N: File.Dwarf->getNumCompileUnits()); |
39 | |
40 | // Set context format&endianness based on the input file. |
41 | Format.Version = File.Dwarf->getMaxVersion(); |
42 | Format.AddrSize = File.Dwarf->getCUAddrSize(); |
43 | Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little |
44 | : llvm::endianness::big; |
45 | } |
46 | } |
47 | |
48 | DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit( |
49 | DWARFFile &File, std::unique_ptr<CompileUnit> Unit) |
50 | : File(File), Unit(std::move(Unit)) {} |
51 | |
52 | DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit( |
53 | LinkContext::RefModuleUnit &&Other) |
54 | : File(Other.File), Unit(std::move(Other.Unit)) {} |
55 | |
56 | void DWARFLinkerImpl::LinkContext::addModulesCompileUnit( |
57 | LinkContext::RefModuleUnit &&Unit) { |
58 | ModulesCompileUnits.emplace_back(Args: std::move(Unit)); |
59 | } |
60 | |
61 | void DWARFLinkerImpl::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader, |
62 | CompileUnitHandlerTy OnCUDieLoaded) { |
63 | ObjectContexts.emplace_back(Args: std::make_unique<LinkContext>( |
64 | args&: GlobalData, args&: File, args&: ClangModules, args&: UniqueUnitID)); |
65 | |
66 | if (ObjectContexts.back()->InputDWARFFile.Dwarf) { |
67 | for (const std::unique_ptr<DWARFUnit> &CU : |
68 | ObjectContexts.back()->InputDWARFFile.Dwarf->compile_units()) { |
69 | DWARFDie CUDie = CU->getUnitDIE(); |
70 | OverallNumberOfCU++; |
71 | |
72 | if (!CUDie) |
73 | continue; |
74 | |
75 | OnCUDieLoaded(*CU); |
76 | |
77 | // Register mofule reference. |
78 | if (!GlobalData.getOptions().UpdateIndexTablesOnly) |
79 | ObjectContexts.back()->registerModuleReference(CUDie, Loader, |
80 | OnCUDieLoaded); |
81 | } |
82 | } |
83 | } |
84 | |
85 | void DWARFLinkerImpl::setEstimatedObjfilesAmount(unsigned ObjFilesNum) { |
86 | ObjectContexts.reserve(N: ObjFilesNum); |
87 | } |
88 | |
89 | Error DWARFLinkerImpl::link() { |
90 | // reset compile unit unique ID counter. |
91 | UniqueUnitID = 0; |
92 | |
93 | if (Error Err = validateAndUpdateOptions()) |
94 | return Err; |
95 | |
96 | dwarf::FormParams GlobalFormat = {.Version: GlobalData.getOptions().TargetDWARFVersion, |
97 | .AddrSize: 0, .Format: dwarf::DwarfFormat::DWARF32}; |
98 | llvm::endianness GlobalEndianness = llvm::endianness::native; |
99 | |
100 | if (std::optional<std::reference_wrapper<const Triple>> CurTriple = |
101 | GlobalData.getTargetTriple()) { |
102 | GlobalEndianness = (*CurTriple).get().isLittleEndian() |
103 | ? llvm::endianness::little |
104 | : llvm::endianness::big; |
105 | } |
106 | std::optional<uint16_t> Language; |
107 | |
108 | for (std::unique_ptr<LinkContext> &Context : ObjectContexts) { |
109 | if (Context->InputDWARFFile.Dwarf == nullptr) { |
110 | Context->setOutputFormat(Format: Context->getFormParams(), Endianness: GlobalEndianness); |
111 | continue; |
112 | } |
113 | |
114 | if (GlobalData.getOptions().Verbose) { |
115 | outs() << "DEBUG MAP OBJECT: " << Context->InputDWARFFile.FileName |
116 | << "\n" ; |
117 | |
118 | for (const std::unique_ptr<DWARFUnit> &OrigCU : |
119 | Context->InputDWARFFile.Dwarf->compile_units()) { |
120 | outs() << "Input compilation unit:" ; |
121 | DIDumpOptions DumpOpts; |
122 | DumpOpts.ChildRecurseDepth = 0; |
123 | DumpOpts.Verbose = GlobalData.getOptions().Verbose; |
124 | OrigCU->getUnitDIE().dump(OS&: outs(), indent: 0, DumpOpts); |
125 | } |
126 | } |
127 | |
128 | // Verify input DWARF if requested. |
129 | if (GlobalData.getOptions().VerifyInputDWARF) |
130 | verifyInput(File: Context->InputDWARFFile); |
131 | |
132 | if (!GlobalData.getTargetTriple()) |
133 | GlobalEndianness = Context->getEndianness(); |
134 | GlobalFormat.AddrSize = |
135 | std::max(a: GlobalFormat.AddrSize, b: Context->getFormParams().AddrSize); |
136 | |
137 | Context->setOutputFormat(Format: Context->getFormParams(), Endianness: GlobalEndianness); |
138 | |
139 | // FIXME: move creation of CompileUnits into the addObjectFile. |
140 | // This would allow to not scan for context Language and Modules state |
141 | // twice. And then following handling might be removed. |
142 | for (const std::unique_ptr<DWARFUnit> &OrigCU : |
143 | Context->InputDWARFFile.Dwarf->compile_units()) { |
144 | DWARFDie UnitDie = OrigCU->getUnitDIE(); |
145 | |
146 | if (!Language) { |
147 | if (std::optional<DWARFFormValue> Val = |
148 | UnitDie.find(Attr: dwarf::DW_AT_language)) { |
149 | uint16_t LangVal = dwarf::toUnsigned(V: Val, Default: 0); |
150 | if (isODRLanguage(Language: LangVal)) |
151 | Language = LangVal; |
152 | } |
153 | } |
154 | } |
155 | } |
156 | |
157 | if (GlobalFormat.AddrSize == 0) { |
158 | if (std::optional<std::reference_wrapper<const Triple>> TargetTriple = |
159 | GlobalData.getTargetTriple()) |
160 | GlobalFormat.AddrSize = (*TargetTriple).get().isArch32Bit() ? 4 : 8; |
161 | else |
162 | GlobalFormat.AddrSize = 8; |
163 | } |
164 | |
165 | CommonSections.setOutputFormat(Format: GlobalFormat, Endianness: GlobalEndianness); |
166 | |
167 | if (!GlobalData.Options.NoODR && Language.has_value()) { |
168 | llvm::parallel::TaskGroup TGroup; |
169 | TGroup.spawn(f: [&]() { |
170 | ArtificialTypeUnit = std::make_unique<TypeUnit>( |
171 | args&: GlobalData, args: UniqueUnitID++, args&: Language, args&: GlobalFormat, args&: GlobalEndianness); |
172 | }); |
173 | } |
174 | |
175 | // Set parallel options. |
176 | if (GlobalData.getOptions().Threads == 0) |
177 | llvm::parallel::strategy = optimal_concurrency(TaskCount: OverallNumberOfCU); |
178 | else |
179 | llvm::parallel::strategy = |
180 | hardware_concurrency(ThreadCount: GlobalData.getOptions().Threads); |
181 | |
182 | // Link object files. |
183 | if (GlobalData.getOptions().Threads == 1) { |
184 | for (std::unique_ptr<LinkContext> &Context : ObjectContexts) { |
185 | // Link object file. |
186 | if (Error Err = Context->link(ArtificialTypeUnit: ArtificialTypeUnit.get())) |
187 | GlobalData.error(Err: std::move(Err), Context: Context->InputDWARFFile.FileName); |
188 | |
189 | Context->InputDWARFFile.unload(); |
190 | } |
191 | } else { |
192 | DefaultThreadPool Pool(llvm::parallel::strategy); |
193 | for (std::unique_ptr<LinkContext> &Context : ObjectContexts) |
194 | Pool.async(F: [&]() { |
195 | // Link object file. |
196 | if (Error Err = Context->link(ArtificialTypeUnit: ArtificialTypeUnit.get())) |
197 | GlobalData.error(Err: std::move(Err), Context: Context->InputDWARFFile.FileName); |
198 | |
199 | Context->InputDWARFFile.unload(); |
200 | }); |
201 | |
202 | Pool.wait(); |
203 | } |
204 | |
205 | if (ArtificialTypeUnit != nullptr && !ArtificialTypeUnit->getTypePool() |
206 | .getRoot() |
207 | ->getValue() |
208 | .load() |
209 | ->Children.empty()) { |
210 | if (GlobalData.getTargetTriple().has_value()) |
211 | if (Error Err = ArtificialTypeUnit->finishCloningAndEmit( |
212 | TargetTriple: (*GlobalData.getTargetTriple()).get())) |
213 | return Err; |
214 | } |
215 | |
216 | // At this stage each compile units are cloned to their own set of debug |
217 | // sections. Now, update patches, assign offsets and assemble final file |
218 | // glueing debug tables from each compile unit. |
219 | glueCompileUnitsAndWriteToTheOutput(); |
220 | |
221 | return Error::success(); |
222 | } |
223 | |
224 | void DWARFLinkerImpl::verifyInput(const DWARFFile &File) { |
225 | assert(File.Dwarf); |
226 | |
227 | std::string Buffer; |
228 | raw_string_ostream OS(Buffer); |
229 | DIDumpOptions DumpOpts; |
230 | if (!File.Dwarf->verify(OS, DumpOpts: DumpOpts.noImplicitRecursion())) { |
231 | if (GlobalData.getOptions().InputVerificationHandler) |
232 | GlobalData.getOptions().InputVerificationHandler(File, OS.str()); |
233 | } |
234 | } |
235 | |
236 | Error DWARFLinkerImpl::validateAndUpdateOptions() { |
237 | if (GlobalData.getOptions().TargetDWARFVersion == 0) |
238 | return createStringError(EC: std::errc::invalid_argument, |
239 | Fmt: "target DWARF version is not set" ); |
240 | |
241 | if (GlobalData.getOptions().Verbose && GlobalData.getOptions().Threads != 1) { |
242 | GlobalData.Options.Threads = 1; |
243 | GlobalData.warn( |
244 | Warning: "set number of threads to 1 to make --verbose to work properly." , Context: "" ); |
245 | } |
246 | |
247 | // Do not do types deduplication in case --update. |
248 | if (GlobalData.getOptions().UpdateIndexTablesOnly && |
249 | !GlobalData.Options.NoODR) |
250 | GlobalData.Options.NoODR = true; |
251 | |
252 | return Error::success(); |
253 | } |
254 | |
255 | /// Resolve the relative path to a build artifact referenced by DWARF by |
256 | /// applying DW_AT_comp_dir. |
257 | static void resolveRelativeObjectPath(SmallVectorImpl<char> &Buf, DWARFDie CU) { |
258 | sys::path::append(path&: Buf, a: dwarf::toString(V: CU.find(Attr: dwarf::DW_AT_comp_dir), Default: "" )); |
259 | } |
260 | |
261 | static uint64_t getDwoId(const DWARFDie &CUDie) { |
262 | auto DwoId = dwarf::toUnsigned( |
263 | V: CUDie.find(Attrs: {dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id})); |
264 | if (DwoId) |
265 | return *DwoId; |
266 | return 0; |
267 | } |
268 | |
269 | static std::string |
270 | remapPath(StringRef Path, |
271 | const DWARFLinker::ObjectPrefixMapTy &ObjectPrefixMap) { |
272 | if (ObjectPrefixMap.empty()) |
273 | return Path.str(); |
274 | |
275 | SmallString<256> p = Path; |
276 | for (const auto &Entry : ObjectPrefixMap) |
277 | if (llvm::sys::path::replace_path_prefix(Path&: p, OldPrefix: Entry.first, NewPrefix: Entry.second)) |
278 | break; |
279 | return p.str().str(); |
280 | } |
281 | |
282 | static std::string getPCMFile(const DWARFDie &CUDie, |
283 | DWARFLinker::ObjectPrefixMapTy *ObjectPrefixMap) { |
284 | std::string PCMFile = dwarf::toString( |
285 | V: CUDie.find(Attrs: {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), Default: "" ); |
286 | |
287 | if (PCMFile.empty()) |
288 | return PCMFile; |
289 | |
290 | if (ObjectPrefixMap) |
291 | PCMFile = remapPath(Path: PCMFile, ObjectPrefixMap: *ObjectPrefixMap); |
292 | |
293 | return PCMFile; |
294 | } |
295 | |
296 | std::pair<bool, bool> DWARFLinkerImpl::LinkContext::isClangModuleRef( |
297 | const DWARFDie &CUDie, std::string &PCMFile, unsigned Indent, bool Quiet) { |
298 | if (PCMFile.empty()) |
299 | return std::make_pair(x: false, y: false); |
300 | |
301 | // Clang module DWARF skeleton CUs abuse this for the path to the module. |
302 | uint64_t DwoId = getDwoId(CUDie); |
303 | |
304 | std::string Name = dwarf::toString(V: CUDie.find(Attr: dwarf::DW_AT_name), Default: "" ); |
305 | if (Name.empty()) { |
306 | if (!Quiet) |
307 | GlobalData.warn(Warning: "anonymous module skeleton CU for " + PCMFile + "." , |
308 | Context: InputDWARFFile.FileName); |
309 | return std::make_pair(x: true, y: true); |
310 | } |
311 | |
312 | if (!Quiet && GlobalData.getOptions().Verbose) { |
313 | outs().indent(NumSpaces: Indent); |
314 | outs() << "Found clang module reference " << PCMFile; |
315 | } |
316 | |
317 | auto Cached = ClangModules.find(Key: PCMFile); |
318 | if (Cached != ClangModules.end()) { |
319 | // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is |
320 | // fixed in clang, only warn about DWO_id mismatches in verbose mode. |
321 | // ASTFileSignatures will change randomly when a module is rebuilt. |
322 | if (!Quiet && GlobalData.getOptions().Verbose && (Cached->second != DwoId)) |
323 | GlobalData.warn( |
324 | Warning: Twine("hash mismatch: this object file was built against a " |
325 | "different version of the module " ) + |
326 | PCMFile + "." , |
327 | Context: InputDWARFFile.FileName); |
328 | if (!Quiet && GlobalData.getOptions().Verbose) |
329 | outs() << " [cached].\n" ; |
330 | return std::make_pair(x: true, y: true); |
331 | } |
332 | |
333 | return std::make_pair(x: true, y: false); |
334 | } |
335 | |
336 | /// If this compile unit is really a skeleton CU that points to a |
337 | /// clang module, register it in ClangModules and return true. |
338 | /// |
339 | /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name |
340 | /// pointing to the module, and a DW_AT_gnu_dwo_id with the module |
341 | /// hash. |
342 | bool DWARFLinkerImpl::LinkContext::registerModuleReference( |
343 | const DWARFDie &CUDie, ObjFileLoaderTy Loader, |
344 | CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) { |
345 | std::string PCMFile = |
346 | getPCMFile(CUDie, ObjectPrefixMap: GlobalData.getOptions().ObjectPrefixMap); |
347 | std::pair<bool, bool> IsClangModuleRef = |
348 | isClangModuleRef(CUDie, PCMFile, Indent, Quiet: false); |
349 | |
350 | if (!IsClangModuleRef.first) |
351 | return false; |
352 | |
353 | if (IsClangModuleRef.second) |
354 | return true; |
355 | |
356 | if (GlobalData.getOptions().Verbose) |
357 | outs() << " ...\n" ; |
358 | |
359 | // Cyclic dependencies are disallowed by Clang, but we still |
360 | // shouldn't run into an infinite loop, so mark it as processed now. |
361 | ClangModules.insert(KV: {PCMFile, getDwoId(CUDie)}); |
362 | |
363 | if (Error E = |
364 | loadClangModule(Loader, CUDie, PCMFile, OnCUDieLoaded, Indent: Indent + 2)) { |
365 | consumeError(Err: std::move(E)); |
366 | return false; |
367 | } |
368 | return true; |
369 | } |
370 | |
371 | Error DWARFLinkerImpl::LinkContext::loadClangModule( |
372 | ObjFileLoaderTy Loader, const DWARFDie &CUDie, const std::string &PCMFile, |
373 | CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) { |
374 | |
375 | uint64_t DwoId = getDwoId(CUDie); |
376 | std::string ModuleName = dwarf::toString(V: CUDie.find(Attr: dwarf::DW_AT_name), Default: "" ); |
377 | |
378 | /// Using a SmallString<0> because loadClangModule() is recursive. |
379 | SmallString<0> Path(GlobalData.getOptions().PrependPath); |
380 | if (sys::path::is_relative(path: PCMFile)) |
381 | resolveRelativeObjectPath(Buf&: Path, CU: CUDie); |
382 | sys::path::append(path&: Path, a: PCMFile); |
383 | // Don't use the cached binary holder because we have no thread-safety |
384 | // guarantee and the lifetime is limited. |
385 | |
386 | if (Loader == nullptr) { |
387 | GlobalData.error(Err: "cann't load clang module: loader is not specified." , |
388 | Context: InputDWARFFile.FileName); |
389 | return Error::success(); |
390 | } |
391 | |
392 | auto ErrOrObj = Loader(InputDWARFFile.FileName, Path); |
393 | if (!ErrOrObj) |
394 | return Error::success(); |
395 | |
396 | std::unique_ptr<CompileUnit> Unit; |
397 | for (const auto &CU : ErrOrObj->Dwarf->compile_units()) { |
398 | OnCUDieLoaded(*CU); |
399 | // Recursively get all modules imported by this one. |
400 | auto ChildCUDie = CU->getUnitDIE(); |
401 | if (!ChildCUDie) |
402 | continue; |
403 | if (!registerModuleReference(CUDie: ChildCUDie, Loader, OnCUDieLoaded, Indent)) { |
404 | if (Unit) { |
405 | std::string Err = |
406 | (PCMFile + |
407 | ": Clang modules are expected to have exactly 1 compile unit.\n" ); |
408 | GlobalData.error(Err, Context: InputDWARFFile.FileName); |
409 | return make_error<StringError>(Args&: Err, Args: inconvertibleErrorCode()); |
410 | } |
411 | // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is |
412 | // fixed in clang, only warn about DWO_id mismatches in verbose mode. |
413 | // ASTFileSignatures will change randomly when a module is rebuilt. |
414 | uint64_t PCMDwoId = getDwoId(CUDie: ChildCUDie); |
415 | if (PCMDwoId != DwoId) { |
416 | if (GlobalData.getOptions().Verbose) |
417 | GlobalData.warn( |
418 | Warning: Twine("hash mismatch: this object file was built against a " |
419 | "different version of the module " ) + |
420 | PCMFile + "." , |
421 | Context: InputDWARFFile.FileName); |
422 | // Update the cache entry with the DwoId of the module loaded from disk. |
423 | ClangModules[PCMFile] = PCMDwoId; |
424 | } |
425 | |
426 | // Empty modules units should not be cloned. |
427 | if (!ChildCUDie.hasChildren()) |
428 | continue; |
429 | |
430 | // Add this module. |
431 | Unit = std::make_unique<CompileUnit>( |
432 | args&: GlobalData, args&: *CU, args: UniqueUnitID.fetch_add(i: 1), args&: ModuleName, args&: *ErrOrObj, |
433 | args&: getUnitForOffset, args: CU->getFormParams(), args: getEndianness()); |
434 | } |
435 | } |
436 | |
437 | if (Unit) { |
438 | ModulesCompileUnits.emplace_back(Args: RefModuleUnit{*ErrOrObj, std::move(Unit)}); |
439 | // Preload line table, as it can't be loaded asynchronously. |
440 | ModulesCompileUnits.back().Unit->loadLineTable(); |
441 | } |
442 | |
443 | return Error::success(); |
444 | } |
445 | |
446 | Error DWARFLinkerImpl::LinkContext::link(TypeUnit *ArtificialTypeUnit) { |
447 | InterCUProcessingStarted = false; |
448 | if (!InputDWARFFile.Dwarf) |
449 | return Error::success(); |
450 | |
451 | // Preload macro tables, as they can't be loaded asynchronously. |
452 | InputDWARFFile.Dwarf->getDebugMacinfo(); |
453 | InputDWARFFile.Dwarf->getDebugMacro(); |
454 | |
455 | // Link modules compile units first. |
456 | parallelForEach(R&: ModulesCompileUnits, Fn: [&](RefModuleUnit &RefModule) { |
457 | linkSingleCompileUnit(CU&: *RefModule.Unit, ArtificialTypeUnit); |
458 | }); |
459 | |
460 | // Check for live relocations. If there is no any live relocation then we |
461 | // can skip entire object file. |
462 | if (!GlobalData.getOptions().UpdateIndexTablesOnly && |
463 | !InputDWARFFile.Addresses->hasValidRelocs()) { |
464 | if (GlobalData.getOptions().Verbose) |
465 | outs() << "No valid relocations found. Skipping.\n" ; |
466 | return Error::success(); |
467 | } |
468 | |
469 | OriginalDebugInfoSize = getInputDebugInfoSize(); |
470 | |
471 | // Create CompileUnit structures to keep information about source |
472 | // DWARFUnit`s, load line tables. |
473 | for (const auto &OrigCU : InputDWARFFile.Dwarf->compile_units()) { |
474 | // Load only unit DIE at this stage. |
475 | auto CUDie = OrigCU->getUnitDIE(); |
476 | std::string PCMFile = |
477 | getPCMFile(CUDie, ObjectPrefixMap: GlobalData.getOptions().ObjectPrefixMap); |
478 | |
479 | // The !isClangModuleRef condition effectively skips over fully resolved |
480 | // skeleton units. |
481 | if (!CUDie || GlobalData.getOptions().UpdateIndexTablesOnly || |
482 | !isClangModuleRef(CUDie, PCMFile, Indent: 0, Quiet: true).first) { |
483 | CompileUnits.emplace_back(Args: std::make_unique<CompileUnit>( |
484 | args&: GlobalData, args&: *OrigCU, args: UniqueUnitID.fetch_add(i: 1), args: "" , args&: InputDWARFFile, |
485 | args&: getUnitForOffset, args: OrigCU->getFormParams(), args: getEndianness())); |
486 | |
487 | // Preload line table, as it can't be loaded asynchronously. |
488 | CompileUnits.back()->loadLineTable(); |
489 | } |
490 | }; |
491 | |
492 | HasNewInterconnectedCUs = false; |
493 | |
494 | // Link self-sufficient compile units and discover inter-connected compile |
495 | // units. |
496 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
497 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit); |
498 | }); |
499 | |
500 | // Link all inter-connected units. |
501 | if (HasNewInterconnectedCUs) { |
502 | InterCUProcessingStarted = true; |
503 | |
504 | if (Error Err = finiteLoop(Iteration: [&]() -> Expected<bool> { |
505 | HasNewInterconnectedCUs = false; |
506 | |
507 | // Load inter-connected units. |
508 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
509 | if (CU->isInterconnectedCU()) { |
510 | CU->maybeResetToLoadedStage(); |
511 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
512 | DoUntilStage: CompileUnit::Stage::Loaded); |
513 | } |
514 | }); |
515 | |
516 | // Do liveness analysis for inter-connected units. |
517 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
518 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
519 | DoUntilStage: CompileUnit::Stage::LivenessAnalysisDone); |
520 | }); |
521 | |
522 | return HasNewInterconnectedCUs.load(); |
523 | })) |
524 | return Err; |
525 | |
526 | // Update dependencies. |
527 | if (Error Err = finiteLoop(Iteration: [&]() -> Expected<bool> { |
528 | HasNewGlobalDependency = false; |
529 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
530 | linkSingleCompileUnit( |
531 | CU&: *CU, ArtificialTypeUnit, |
532 | DoUntilStage: CompileUnit::Stage::UpdateDependenciesCompleteness); |
533 | }); |
534 | return HasNewGlobalDependency.load(); |
535 | })) |
536 | return Err; |
537 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
538 | if (CU->isInterconnectedCU() && |
539 | CU->getStage() == CompileUnit::Stage::LivenessAnalysisDone) |
540 | CU->setStage(CompileUnit::Stage::UpdateDependenciesCompleteness); |
541 | }); |
542 | |
543 | // Assign type names. |
544 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
545 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
546 | DoUntilStage: CompileUnit::Stage::TypeNamesAssigned); |
547 | }); |
548 | |
549 | // Clone inter-connected units. |
550 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
551 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
552 | DoUntilStage: CompileUnit::Stage::Cloned); |
553 | }); |
554 | |
555 | // Update patches for inter-connected units. |
556 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
557 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
558 | DoUntilStage: CompileUnit::Stage::PatchesUpdated); |
559 | }); |
560 | |
561 | // Release data. |
562 | parallelForEach(R&: CompileUnits, Fn: [&](std::unique_ptr<CompileUnit> &CU) { |
563 | linkSingleCompileUnit(CU&: *CU, ArtificialTypeUnit, |
564 | DoUntilStage: CompileUnit::Stage::Cleaned); |
565 | }); |
566 | } |
567 | |
568 | if (GlobalData.getOptions().UpdateIndexTablesOnly) { |
569 | // Emit Invariant sections. |
570 | |
571 | if (Error Err = emitInvariantSections()) |
572 | return Err; |
573 | } else if (!CompileUnits.empty()) { |
574 | // Emit .debug_frame section. |
575 | |
576 | Error ResultErr = Error::success(); |
577 | llvm::parallel::TaskGroup TGroup; |
578 | // We use task group here as PerThreadBumpPtrAllocator should be called from |
579 | // the threads created by ThreadPoolExecutor. |
580 | TGroup.spawn(f: [&]() { |
581 | if (Error Err = cloneAndEmitDebugFrame()) |
582 | ResultErr = std::move(Err); |
583 | }); |
584 | return ResultErr; |
585 | } |
586 | |
587 | return Error::success(); |
588 | } |
589 | |
590 | void DWARFLinkerImpl::LinkContext::linkSingleCompileUnit( |
591 | CompileUnit &CU, TypeUnit *ArtificialTypeUnit, |
592 | enum CompileUnit::Stage DoUntilStage) { |
593 | if (InterCUProcessingStarted != CU.isInterconnectedCU()) |
594 | return; |
595 | |
596 | if (Error Err = finiteLoop(Iteration: [&]() -> Expected<bool> { |
597 | if (CU.getStage() >= DoUntilStage) |
598 | return false; |
599 | |
600 | switch (CU.getStage()) { |
601 | case CompileUnit::Stage::CreatedNotLoaded: { |
602 | // Load input compilation unit DIEs. |
603 | // Analyze properties of DIEs. |
604 | if (!CU.loadInputDIEs()) { |
605 | // We do not need to do liveness analysis for invalid compilation |
606 | // unit. |
607 | CU.setStage(CompileUnit::Stage::Skipped); |
608 | } else { |
609 | CU.analyzeDWARFStructure(); |
610 | |
611 | // The registerModuleReference() condition effectively skips |
612 | // over fully resolved skeleton units. This second pass of |
613 | // registerModuleReferences doesn't do any new work, but it |
614 | // will collect top-level errors, which are suppressed. Module |
615 | // warnings were already displayed in the first iteration. |
616 | if (registerModuleReference( |
617 | CUDie: CU.getOrigUnit().getUnitDIE(), Loader: nullptr, |
618 | OnCUDieLoaded: [](const DWARFUnit &) {}, Indent: 0)) |
619 | CU.setStage(CompileUnit::Stage::PatchesUpdated); |
620 | else |
621 | CU.setStage(CompileUnit::Stage::Loaded); |
622 | } |
623 | } break; |
624 | |
625 | case CompileUnit::Stage::Loaded: { |
626 | // Mark all the DIEs that need to be present in the generated output. |
627 | // If ODR requested, build type names. |
628 | if (!CU.resolveDependenciesAndMarkLiveness(InterCUProcessingStarted, |
629 | HasNewInterconnectedCUs)) { |
630 | assert(HasNewInterconnectedCUs && |
631 | "Flag indicating new inter-connections is not set" ); |
632 | return false; |
633 | } |
634 | |
635 | CU.setStage(CompileUnit::Stage::LivenessAnalysisDone); |
636 | } break; |
637 | |
638 | case CompileUnit::Stage::LivenessAnalysisDone: { |
639 | if (InterCUProcessingStarted) { |
640 | if (CU.updateDependenciesCompleteness()) |
641 | HasNewGlobalDependency = true; |
642 | return false; |
643 | } else { |
644 | if (Error Err = finiteLoop(Iteration: [&]() -> Expected<bool> { |
645 | return CU.updateDependenciesCompleteness(); |
646 | })) |
647 | return std::move(Err); |
648 | |
649 | CU.setStage(CompileUnit::Stage::UpdateDependenciesCompleteness); |
650 | } |
651 | } break; |
652 | |
653 | case CompileUnit::Stage::UpdateDependenciesCompleteness: |
654 | #ifndef NDEBUG |
655 | CU.verifyDependencies(); |
656 | #endif |
657 | |
658 | if (ArtificialTypeUnit) { |
659 | if (Error Err = |
660 | CU.assignTypeNames(TypePoolRef&: ArtificialTypeUnit->getTypePool())) |
661 | return std::move(Err); |
662 | } |
663 | CU.setStage(CompileUnit::Stage::TypeNamesAssigned); |
664 | break; |
665 | |
666 | case CompileUnit::Stage::TypeNamesAssigned: |
667 | // Clone input compile unit. |
668 | if (CU.isClangModule() || |
669 | GlobalData.getOptions().UpdateIndexTablesOnly || |
670 | CU.getContaingFile().Addresses->hasValidRelocs()) { |
671 | if (Error Err = CU.cloneAndEmit(TargetTriple: GlobalData.getTargetTriple(), |
672 | ArtificialTypeUnit)) |
673 | return std::move(Err); |
674 | } |
675 | |
676 | CU.setStage(CompileUnit::Stage::Cloned); |
677 | break; |
678 | |
679 | case CompileUnit::Stage::Cloned: |
680 | // Update DIEs referencies. |
681 | CU.updateDieRefPatchesWithClonedOffsets(); |
682 | CU.setStage(CompileUnit::Stage::PatchesUpdated); |
683 | break; |
684 | |
685 | case CompileUnit::Stage::PatchesUpdated: |
686 | // Cleanup resources. |
687 | CU.cleanupDataAfterClonning(); |
688 | CU.setStage(CompileUnit::Stage::Cleaned); |
689 | break; |
690 | |
691 | case CompileUnit::Stage::Cleaned: |
692 | assert(false); |
693 | break; |
694 | |
695 | case CompileUnit::Stage::Skipped: |
696 | // Nothing to do. |
697 | break; |
698 | } |
699 | |
700 | return true; |
701 | })) { |
702 | CU.error(Err: std::move(Err)); |
703 | CU.cleanupDataAfterClonning(); |
704 | CU.setStage(CompileUnit::Stage::Skipped); |
705 | } |
706 | } |
707 | |
708 | Error DWARFLinkerImpl::LinkContext::emitInvariantSections() { |
709 | if (!GlobalData.getTargetTriple().has_value()) |
710 | return Error::success(); |
711 | |
712 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugLoc).OS |
713 | << InputDWARFFile.Dwarf->getDWARFObj().getLocSection().Data; |
714 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugLocLists).OS |
715 | << InputDWARFFile.Dwarf->getDWARFObj().getLoclistsSection().Data; |
716 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugRange).OS |
717 | << InputDWARFFile.Dwarf->getDWARFObj().getRangesSection().Data; |
718 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugRngLists).OS |
719 | << InputDWARFFile.Dwarf->getDWARFObj().getRnglistsSection().Data; |
720 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugARanges).OS |
721 | << InputDWARFFile.Dwarf->getDWARFObj().getArangesSection(); |
722 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugFrame).OS |
723 | << InputDWARFFile.Dwarf->getDWARFObj().getFrameSection().Data; |
724 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugAddr).OS |
725 | << InputDWARFFile.Dwarf->getDWARFObj().getAddrSection().Data; |
726 | |
727 | return Error::success(); |
728 | } |
729 | |
730 | Error DWARFLinkerImpl::LinkContext::cloneAndEmitDebugFrame() { |
731 | if (!GlobalData.getTargetTriple().has_value()) |
732 | return Error::success(); |
733 | |
734 | if (InputDWARFFile.Dwarf == nullptr) |
735 | return Error::success(); |
736 | |
737 | const DWARFObject &InputDWARFObj = InputDWARFFile.Dwarf->getDWARFObj(); |
738 | |
739 | StringRef OrigFrameData = InputDWARFObj.getFrameSection().Data; |
740 | if (OrigFrameData.empty()) |
741 | return Error::success(); |
742 | |
743 | RangesTy AllUnitsRanges; |
744 | for (std::unique_ptr<CompileUnit> &Unit : CompileUnits) { |
745 | for (auto CurRange : Unit->getFunctionRanges()) |
746 | AllUnitsRanges.insert(Range: CurRange.Range, Value: CurRange.Value); |
747 | } |
748 | |
749 | unsigned SrcAddrSize = InputDWARFObj.getAddressSize(); |
750 | |
751 | SectionDescriptor &OutSection = |
752 | getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugFrame); |
753 | |
754 | DataExtractor Data(OrigFrameData, InputDWARFObj.isLittleEndian(), 0); |
755 | uint64_t InputOffset = 0; |
756 | |
757 | // Store the data of the CIEs defined in this object, keyed by their |
758 | // offsets. |
759 | DenseMap<uint64_t, StringRef> LocalCIES; |
760 | |
761 | /// The CIEs that have been emitted in the output section. The actual CIE |
762 | /// data serves a the key to this StringMap. |
763 | StringMap<uint32_t> EmittedCIEs; |
764 | |
765 | while (Data.isValidOffset(offset: InputOffset)) { |
766 | uint64_t EntryOffset = InputOffset; |
767 | uint32_t InitialLength = Data.getU32(offset_ptr: &InputOffset); |
768 | if (InitialLength == 0xFFFFFFFF) |
769 | return createFileError(F: InputDWARFObj.getFileName(), |
770 | E: createStringError(EC: std::errc::invalid_argument, |
771 | Fmt: "Dwarf64 bits no supported" )); |
772 | |
773 | uint32_t CIEId = Data.getU32(offset_ptr: &InputOffset); |
774 | if (CIEId == 0xFFFFFFFF) { |
775 | // This is a CIE, store it. |
776 | StringRef CIEData = OrigFrameData.substr(Start: EntryOffset, N: InitialLength + 4); |
777 | LocalCIES[EntryOffset] = CIEData; |
778 | // The -4 is to account for the CIEId we just read. |
779 | InputOffset += InitialLength - 4; |
780 | continue; |
781 | } |
782 | |
783 | uint64_t Loc = Data.getUnsigned(offset_ptr: &InputOffset, byte_size: SrcAddrSize); |
784 | |
785 | // Some compilers seem to emit frame info that doesn't start at |
786 | // the function entry point, thus we can't just lookup the address |
787 | // in the debug map. Use the AddressInfo's range map to see if the FDE |
788 | // describes something that we can relocate. |
789 | std::optional<AddressRangeValuePair> Range = |
790 | AllUnitsRanges.getRangeThatContains(Addr: Loc); |
791 | if (!Range) { |
792 | // The +4 is to account for the size of the InitialLength field itself. |
793 | InputOffset = EntryOffset + InitialLength + 4; |
794 | continue; |
795 | } |
796 | |
797 | // This is an FDE, and we have a mapping. |
798 | // Have we already emitted a corresponding CIE? |
799 | StringRef CIEData = LocalCIES[CIEId]; |
800 | if (CIEData.empty()) |
801 | return createFileError( |
802 | F: InputDWARFObj.getFileName(), |
803 | E: createStringError(EC: std::errc::invalid_argument, |
804 | Fmt: "Inconsistent debug_frame content. Dropping." )); |
805 | |
806 | uint64_t OffsetToCIERecord = OutSection.OS.tell(); |
807 | |
808 | // Look if we already emitted a CIE that corresponds to the |
809 | // referenced one (the CIE data is the key of that lookup). |
810 | auto IteratorInserted = |
811 | EmittedCIEs.insert(KV: std::make_pair(x&: CIEData, y&: OffsetToCIERecord)); |
812 | OffsetToCIERecord = IteratorInserted.first->getValue(); |
813 | |
814 | // Emit CIE for this ID if it is not emitted yet. |
815 | if (IteratorInserted.second) |
816 | OutSection.OS << CIEData; |
817 | |
818 | // Remember offset to the FDE record, so that we might update |
819 | // field referencing CIE record(containing OffsetToCIERecord), |
820 | // when final offsets are known. OffsetToCIERecord(which is written later) |
821 | // is local to the current .debug_frame section, it should be updated |
822 | // with final offset of the .debug_frame section. |
823 | OutSection.notePatch( |
824 | Patch: DebugOffsetPatch{OutSection.OS.tell() + 4, &OutSection, true}); |
825 | |
826 | // Emit the FDE with updated address and CIE pointer. |
827 | // (4 + AddrSize) is the size of the CIEId + initial_location |
828 | // fields that will get reconstructed by emitFDE(). |
829 | unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize); |
830 | emitFDE(CIEOffset: OffsetToCIERecord, AddrSize: SrcAddrSize, Address: Loc + Range->Value, |
831 | FDEBytes: OrigFrameData.substr(Start: InputOffset, N: FDERemainingBytes), Section&: OutSection); |
832 | InputOffset += FDERemainingBytes; |
833 | } |
834 | |
835 | return Error::success(); |
836 | } |
837 | |
838 | /// Emit a FDE into the debug_frame section. \p FDEBytes |
839 | /// contains the FDE data without the length, CIE offset and address |
840 | /// which will be replaced with the parameter values. |
841 | void DWARFLinkerImpl::LinkContext::emitFDE(uint32_t CIEOffset, |
842 | uint32_t AddrSize, uint64_t Address, |
843 | StringRef FDEBytes, |
844 | SectionDescriptor &Section) { |
845 | Section.emitIntVal(Val: FDEBytes.size() + 4 + AddrSize, Size: 4); |
846 | Section.emitIntVal(Val: CIEOffset, Size: 4); |
847 | Section.emitIntVal(Val: Address, Size: AddrSize); |
848 | Section.OS.write(Ptr: FDEBytes.data(), Size: FDEBytes.size()); |
849 | } |
850 | |
851 | void DWARFLinkerImpl::glueCompileUnitsAndWriteToTheOutput() { |
852 | if (!GlobalData.getTargetTriple().has_value()) |
853 | return; |
854 | assert(SectionHandler); |
855 | |
856 | // Go through all object files, all compile units and assign |
857 | // offsets to them. |
858 | assignOffsets(); |
859 | |
860 | // Patch size/offsets fields according to the assigned CU offsets. |
861 | patchOffsetsAndSizes(); |
862 | |
863 | // Emit common sections and write debug tables from all object files/compile |
864 | // units into the resulting file. |
865 | emitCommonSectionsAndWriteCompileUnitsToTheOutput(); |
866 | |
867 | if (ArtificialTypeUnit != nullptr) |
868 | ArtificialTypeUnit.reset(); |
869 | |
870 | // Write common debug sections into the resulting file. |
871 | writeCommonSectionsToTheOutput(); |
872 | |
873 | // Cleanup data. |
874 | cleanupDataAfterDWARFOutputIsWritten(); |
875 | |
876 | if (GlobalData.getOptions().Statistics) |
877 | printStatistic(); |
878 | } |
879 | |
880 | void DWARFLinkerImpl::printStatistic() { |
881 | |
882 | // For each object file map how many bytes were emitted. |
883 | StringMap<DebugInfoSize> SizeByObject; |
884 | |
885 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) { |
886 | uint64_t AllDebugInfoSectionsSize = 0; |
887 | |
888 | for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) |
889 | if (std::optional<SectionDescriptor *> DebugInfo = |
890 | CU->tryGetSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo)) |
891 | AllDebugInfoSectionsSize += (*DebugInfo)->getContents().size(); |
892 | |
893 | auto &Size = SizeByObject[Context->InputDWARFFile.FileName]; |
894 | Size.Input = Context->OriginalDebugInfoSize; |
895 | Size.Output = AllDebugInfoSectionsSize; |
896 | } |
897 | |
898 | // Create a vector sorted in descending order by output size. |
899 | std::vector<std::pair<StringRef, DebugInfoSize>> Sorted; |
900 | for (auto &E : SizeByObject) |
901 | Sorted.emplace_back(args: E.first(), args&: E.second); |
902 | llvm::sort(C&: Sorted, Comp: [](auto &LHS, auto &RHS) { |
903 | return LHS.second.Output > RHS.second.Output; |
904 | }); |
905 | |
906 | auto ComputePercentange = [](int64_t Input, int64_t Output) -> float { |
907 | const float Difference = Output - Input; |
908 | const float Sum = Input + Output; |
909 | if (Sum == 0) |
910 | return 0; |
911 | return (Difference / (Sum / 2)); |
912 | }; |
913 | |
914 | int64_t InputTotal = 0; |
915 | int64_t OutputTotal = 0; |
916 | const char *FormatStr = "{0,-45} {1,10}b {2,10}b {3,8:P}\n" ; |
917 | |
918 | // Print header. |
919 | outs() << ".debug_info section size (in bytes)\n" ; |
920 | outs() << "----------------------------------------------------------------" |
921 | "---------------\n" ; |
922 | outs() << "Filename Object " |
923 | " dSYM Change\n" ; |
924 | outs() << "----------------------------------------------------------------" |
925 | "---------------\n" ; |
926 | |
927 | // Print body. |
928 | for (auto &E : Sorted) { |
929 | InputTotal += E.second.Input; |
930 | OutputTotal += E.second.Output; |
931 | llvm::outs() << formatv( |
932 | Fmt: FormatStr, Vals: sys::path::filename(path: E.first).take_back(N: 45), Vals&: E.second.Input, |
933 | Vals&: E.second.Output, Vals: ComputePercentange(E.second.Input, E.second.Output)); |
934 | } |
935 | // Print total and footer. |
936 | outs() << "----------------------------------------------------------------" |
937 | "---------------\n" ; |
938 | llvm::outs() << formatv(Fmt: FormatStr, Vals: "Total" , Vals&: InputTotal, Vals&: OutputTotal, |
939 | Vals: ComputePercentange(InputTotal, OutputTotal)); |
940 | outs() << "----------------------------------------------------------------" |
941 | "---------------\n\n" ; |
942 | } |
943 | |
944 | void DWARFLinkerImpl::assignOffsets() { |
945 | llvm::parallel::TaskGroup TGroup; |
946 | TGroup.spawn(f: [&]() { assignOffsetsToStrings(); }); |
947 | TGroup.spawn(f: [&]() { assignOffsetsToSections(); }); |
948 | } |
949 | |
950 | void DWARFLinkerImpl::assignOffsetsToStrings() { |
951 | size_t CurDebugStrIndex = 1; // start from 1 to take into account zero entry. |
952 | uint64_t CurDebugStrOffset = |
953 | 1; // start from 1 to take into account zero entry. |
954 | size_t CurDebugLineStrIndex = 0; |
955 | uint64_t CurDebugLineStrOffset = 0; |
956 | |
957 | // Enumerates all strings, add them into the DwarfStringPoolEntry map, |
958 | // assign offset and index to the string if it is not indexed yet. |
959 | forEachOutputString(StringHandler: [&](StringDestinationKind Kind, |
960 | const StringEntry *String) { |
961 | switch (Kind) { |
962 | case StringDestinationKind::DebugStr: { |
963 | DwarfStringPoolEntryWithExtString *Entry = DebugStrStrings.add(String); |
964 | assert(Entry != nullptr); |
965 | |
966 | if (!Entry->isIndexed()) { |
967 | Entry->Offset = CurDebugStrOffset; |
968 | CurDebugStrOffset += Entry->String.size() + 1; |
969 | Entry->Index = CurDebugStrIndex++; |
970 | } |
971 | } break; |
972 | case StringDestinationKind::DebugLineStr: { |
973 | DwarfStringPoolEntryWithExtString *Entry = |
974 | DebugLineStrStrings.add(String); |
975 | assert(Entry != nullptr); |
976 | |
977 | if (!Entry->isIndexed()) { |
978 | Entry->Offset = CurDebugLineStrOffset; |
979 | CurDebugLineStrOffset += Entry->String.size() + 1; |
980 | Entry->Index = CurDebugLineStrIndex++; |
981 | } |
982 | } break; |
983 | } |
984 | }); |
985 | } |
986 | |
987 | void DWARFLinkerImpl::assignOffsetsToSections() { |
988 | std::array<uint64_t, SectionKindsNum> SectionSizesAccumulator = {0}; |
989 | |
990 | forEachObjectSectionsSet(SectionsSetHandler: [&](OutputSections &UnitSections) { |
991 | UnitSections.assignSectionsOffsetAndAccumulateSize(SectionSizesAccumulator); |
992 | }); |
993 | } |
994 | |
995 | void DWARFLinkerImpl::forEachOutputString( |
996 | function_ref<void(StringDestinationKind Kind, const StringEntry *String)> |
997 | StringHandler) { |
998 | // To save space we do not create any separate string table. |
999 | // We use already allocated string patches and accelerator entries: |
1000 | // enumerate them in natural order and assign offsets. |
1001 | // ASSUMPTION: strings should be stored into .debug_str/.debug_line_str |
1002 | // sections in the same order as they were assigned offsets. |
1003 | forEachCompileUnit(UnitHandler: [&](CompileUnit *CU) { |
1004 | CU->forEach(Handler: [&](SectionDescriptor &OutSection) { |
1005 | OutSection.ListDebugStrPatch.forEach(Handler: [&](DebugStrPatch &Patch) { |
1006 | StringHandler(StringDestinationKind::DebugStr, Patch.String); |
1007 | }); |
1008 | |
1009 | OutSection.ListDebugLineStrPatch.forEach(Handler: [&](DebugLineStrPatch &Patch) { |
1010 | StringHandler(StringDestinationKind::DebugLineStr, Patch.String); |
1011 | }); |
1012 | }); |
1013 | |
1014 | CU->forEachAcceleratorRecord(Handler: [&](DwarfUnit::AccelInfo &Info) { |
1015 | StringHandler(DebugStr, Info.String); |
1016 | }); |
1017 | }); |
1018 | |
1019 | if (ArtificialTypeUnit != nullptr) { |
1020 | ArtificialTypeUnit->forEach(Handler: [&](SectionDescriptor &OutSection) { |
1021 | OutSection.ListDebugStrPatch.forEach(Handler: [&](DebugStrPatch &Patch) { |
1022 | StringHandler(StringDestinationKind::DebugStr, Patch.String); |
1023 | }); |
1024 | |
1025 | OutSection.ListDebugLineStrPatch.forEach(Handler: [&](DebugLineStrPatch &Patch) { |
1026 | StringHandler(StringDestinationKind::DebugLineStr, Patch.String); |
1027 | }); |
1028 | |
1029 | OutSection.ListDebugTypeStrPatch.forEach(Handler: [&](DebugTypeStrPatch &Patch) { |
1030 | if (Patch.Die == nullptr) |
1031 | return; |
1032 | |
1033 | StringHandler(StringDestinationKind::DebugStr, Patch.String); |
1034 | }); |
1035 | |
1036 | OutSection.ListDebugTypeLineStrPatch.forEach( |
1037 | Handler: [&](DebugTypeLineStrPatch &Patch) { |
1038 | if (Patch.Die == nullptr) |
1039 | return; |
1040 | |
1041 | StringHandler(StringDestinationKind::DebugStr, Patch.String); |
1042 | }); |
1043 | }); |
1044 | } |
1045 | } |
1046 | |
1047 | void DWARFLinkerImpl::forEachObjectSectionsSet( |
1048 | function_ref<void(OutputSections &)> SectionsSetHandler) { |
1049 | // Handle artificial type unit first. |
1050 | if (ArtificialTypeUnit != nullptr) |
1051 | SectionsSetHandler(*ArtificialTypeUnit); |
1052 | |
1053 | // Then all modules(before regular compilation units). |
1054 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1055 | for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) |
1056 | if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) |
1057 | SectionsSetHandler(*ModuleUnit.Unit); |
1058 | |
1059 | // Finally all compilation units. |
1060 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) { |
1061 | // Handle object file common sections. |
1062 | SectionsSetHandler(*Context); |
1063 | |
1064 | // Handle compilation units. |
1065 | for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) |
1066 | if (CU->getStage() != CompileUnit::Stage::Skipped) |
1067 | SectionsSetHandler(*CU); |
1068 | } |
1069 | } |
1070 | |
1071 | void DWARFLinkerImpl::forEachCompileAndTypeUnit( |
1072 | function_ref<void(DwarfUnit *CU)> UnitHandler) { |
1073 | if (ArtificialTypeUnit != nullptr) |
1074 | UnitHandler(ArtificialTypeUnit.get()); |
1075 | |
1076 | // Enumerate module units. |
1077 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1078 | for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) |
1079 | if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) |
1080 | UnitHandler(ModuleUnit.Unit.get()); |
1081 | |
1082 | // Enumerate compile units. |
1083 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1084 | for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) |
1085 | if (CU->getStage() != CompileUnit::Stage::Skipped) |
1086 | UnitHandler(CU.get()); |
1087 | } |
1088 | |
1089 | void DWARFLinkerImpl::forEachCompileUnit( |
1090 | function_ref<void(CompileUnit *CU)> UnitHandler) { |
1091 | // Enumerate module units. |
1092 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1093 | for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) |
1094 | if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) |
1095 | UnitHandler(ModuleUnit.Unit.get()); |
1096 | |
1097 | // Enumerate compile units. |
1098 | for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) |
1099 | for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) |
1100 | if (CU->getStage() != CompileUnit::Stage::Skipped) |
1101 | UnitHandler(CU.get()); |
1102 | } |
1103 | |
1104 | void DWARFLinkerImpl::patchOffsetsAndSizes() { |
1105 | forEachObjectSectionsSet(SectionsSetHandler: [&](OutputSections &SectionsSet) { |
1106 | SectionsSet.forEach(Handler: [&](SectionDescriptor &OutSection) { |
1107 | SectionsSet.applyPatches(Section&: OutSection, DebugStrStrings, DebugLineStrStrings, |
1108 | TypeUnitPtr: ArtificialTypeUnit.get()); |
1109 | }); |
1110 | }); |
1111 | } |
1112 | |
1113 | void DWARFLinkerImpl::emitCommonSectionsAndWriteCompileUnitsToTheOutput() { |
1114 | llvm::parallel::TaskGroup TG; |
1115 | |
1116 | // Create section descriptors ahead if they are not exist at the moment. |
1117 | // SectionDescriptors container is not thread safe. Thus we should be sure |
1118 | // that descriptors would not be created in following parallel tasks. |
1119 | |
1120 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugStr); |
1121 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugLineStr); |
1122 | |
1123 | if (llvm::is_contained(Range&: GlobalData.Options.AccelTables, |
1124 | Element: AccelTableKind::Apple)) { |
1125 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::AppleNames); |
1126 | CommonSections.getOrCreateSectionDescriptor( |
1127 | SectionKind: DebugSectionKind::AppleNamespaces); |
1128 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::AppleObjC); |
1129 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::AppleTypes); |
1130 | } |
1131 | |
1132 | if (llvm::is_contained(Range&: GlobalData.Options.AccelTables, |
1133 | Element: AccelTableKind::DebugNames)) |
1134 | CommonSections.getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugNames); |
1135 | |
1136 | // Emit .debug_str and .debug_line_str sections. |
1137 | TG.spawn(f: [&]() { emitStringSections(); }); |
1138 | |
1139 | if (llvm::is_contained(Range&: GlobalData.Options.AccelTables, |
1140 | Element: AccelTableKind::Apple)) { |
1141 | // Emit apple accelerator sections. |
1142 | TG.spawn(f: [&]() { |
1143 | emitAppleAcceleratorSections(TargetTriple: (*GlobalData.getTargetTriple()).get()); |
1144 | }); |
1145 | } |
1146 | |
1147 | if (llvm::is_contained(Range&: GlobalData.Options.AccelTables, |
1148 | Element: AccelTableKind::DebugNames)) { |
1149 | // Emit .debug_names section. |
1150 | TG.spawn(f: [&]() { |
1151 | emitDWARFv5DebugNamesSection(TargetTriple: (*GlobalData.getTargetTriple()).get()); |
1152 | }); |
1153 | } |
1154 | |
1155 | // Write compile units to the output file. |
1156 | TG.spawn(f: [&]() { writeCompileUnitsToTheOutput(); }); |
1157 | } |
1158 | |
1159 | void DWARFLinkerImpl::emitStringSections() { |
1160 | uint64_t DebugStrNextOffset = 0; |
1161 | uint64_t DebugLineStrNextOffset = 0; |
1162 | |
1163 | // Emit zero length string. Accelerator tables does not work correctly |
1164 | // if the first string is not zero length string. |
1165 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::DebugStr) |
1166 | .emitInplaceString(String: "" ); |
1167 | DebugStrNextOffset++; |
1168 | |
1169 | forEachOutputString( |
1170 | StringHandler: [&](StringDestinationKind Kind, const StringEntry *String) { |
1171 | switch (Kind) { |
1172 | case StringDestinationKind::DebugStr: { |
1173 | DwarfStringPoolEntryWithExtString *StringToEmit = |
1174 | DebugStrStrings.getExistingEntry(String); |
1175 | assert(StringToEmit->isIndexed()); |
1176 | |
1177 | // Strings may be repeated. Use accumulated DebugStrNextOffset |
1178 | // to understand whether corresponding string is already emitted. |
1179 | // Skip string if its offset less than accumulated offset. |
1180 | if (StringToEmit->Offset >= DebugStrNextOffset) { |
1181 | DebugStrNextOffset = |
1182 | StringToEmit->Offset + StringToEmit->String.size() + 1; |
1183 | // Emit the string itself. |
1184 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::DebugStr) |
1185 | .emitInplaceString(String: StringToEmit->String); |
1186 | } |
1187 | } break; |
1188 | case StringDestinationKind::DebugLineStr: { |
1189 | DwarfStringPoolEntryWithExtString *StringToEmit = |
1190 | DebugLineStrStrings.getExistingEntry(String); |
1191 | assert(StringToEmit->isIndexed()); |
1192 | |
1193 | // Strings may be repeated. Use accumulated DebugLineStrStrings |
1194 | // to understand whether corresponding string is already emitted. |
1195 | // Skip string if its offset less than accumulated offset. |
1196 | if (StringToEmit->Offset >= DebugLineStrNextOffset) { |
1197 | DebugLineStrNextOffset = |
1198 | StringToEmit->Offset + StringToEmit->String.size() + 1; |
1199 | // Emit the string itself. |
1200 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::DebugLineStr) |
1201 | .emitInplaceString(String: StringToEmit->String); |
1202 | } |
1203 | } break; |
1204 | } |
1205 | }); |
1206 | } |
1207 | |
1208 | void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) { |
1209 | AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces; |
1210 | AccelTable<AppleAccelTableStaticOffsetData> AppleNames; |
1211 | AccelTable<AppleAccelTableStaticOffsetData> AppleObjC; |
1212 | AccelTable<AppleAccelTableStaticTypeData> AppleTypes; |
1213 | |
1214 | forEachCompileAndTypeUnit(UnitHandler: [&](DwarfUnit *CU) { |
1215 | CU->forEachAcceleratorRecord(Handler: [&](const DwarfUnit::AccelInfo &Info) { |
1216 | uint64_t OutOffset = Info.OutOffset; |
1217 | switch (Info.Type) { |
1218 | case DwarfUnit::AccelType::None: { |
1219 | llvm_unreachable("Unknown accelerator record" ); |
1220 | } break; |
1221 | case DwarfUnit::AccelType::Namespace: { |
1222 | AppleNamespaces.addName( |
1223 | Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1224 | Args: CU->getSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo).StartOffset + |
1225 | OutOffset); |
1226 | } break; |
1227 | case DwarfUnit::AccelType::Name: { |
1228 | AppleNames.addName( |
1229 | Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1230 | Args: CU->getSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo).StartOffset + |
1231 | OutOffset); |
1232 | } break; |
1233 | case DwarfUnit::AccelType::ObjC: { |
1234 | AppleObjC.addName( |
1235 | Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1236 | Args: CU->getSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo).StartOffset + |
1237 | OutOffset); |
1238 | } break; |
1239 | case DwarfUnit::AccelType::Type: { |
1240 | AppleTypes.addName( |
1241 | Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1242 | Args: CU->getSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo).StartOffset + |
1243 | OutOffset, |
1244 | Args: Info.Tag, |
1245 | Args: Info.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation |
1246 | : 0, |
1247 | Args: Info.QualifiedNameHash); |
1248 | } break; |
1249 | } |
1250 | }); |
1251 | }); |
1252 | |
1253 | { |
1254 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1255 | // It might be beneficial to directly emit accelerator data |
1256 | // to the raw_svector_ostream. |
1257 | SectionDescriptor &OutSection = |
1258 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::AppleNamespaces); |
1259 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1260 | OutSection.OS); |
1261 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1262 | consumeError(Err: std::move(Err)); |
1263 | return; |
1264 | } |
1265 | |
1266 | // Emit table. |
1267 | Emitter.emitAppleNamespaces(Table&: AppleNamespaces); |
1268 | Emitter.finish(); |
1269 | |
1270 | // Set start offset and size for output section. |
1271 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1272 | } |
1273 | |
1274 | { |
1275 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1276 | // It might be beneficial to directly emit accelerator data |
1277 | // to the raw_svector_ostream. |
1278 | SectionDescriptor &OutSection = |
1279 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::AppleNames); |
1280 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1281 | OutSection.OS); |
1282 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1283 | consumeError(Err: std::move(Err)); |
1284 | return; |
1285 | } |
1286 | |
1287 | // Emit table. |
1288 | Emitter.emitAppleNames(Table&: AppleNames); |
1289 | Emitter.finish(); |
1290 | |
1291 | // Set start offset ans size for output section. |
1292 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1293 | } |
1294 | |
1295 | { |
1296 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1297 | // It might be beneficial to directly emit accelerator data |
1298 | // to the raw_svector_ostream. |
1299 | SectionDescriptor &OutSection = |
1300 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::AppleObjC); |
1301 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1302 | OutSection.OS); |
1303 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1304 | consumeError(Err: std::move(Err)); |
1305 | return; |
1306 | } |
1307 | |
1308 | // Emit table. |
1309 | Emitter.emitAppleObjc(Table&: AppleObjC); |
1310 | Emitter.finish(); |
1311 | |
1312 | // Set start offset ans size for output section. |
1313 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1314 | } |
1315 | |
1316 | { |
1317 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1318 | // It might be beneficial to directly emit accelerator data |
1319 | // to the raw_svector_ostream. |
1320 | SectionDescriptor &OutSection = |
1321 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::AppleTypes); |
1322 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1323 | OutSection.OS); |
1324 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1325 | consumeError(Err: std::move(Err)); |
1326 | return; |
1327 | } |
1328 | |
1329 | // Emit table. |
1330 | Emitter.emitAppleTypes(Table&: AppleTypes); |
1331 | Emitter.finish(); |
1332 | |
1333 | // Set start offset ans size for output section. |
1334 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1335 | } |
1336 | } |
1337 | |
1338 | void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) { |
1339 | std::unique_ptr<DWARF5AccelTable> DebugNames; |
1340 | |
1341 | DebugNamesUnitsOffsets CompUnits; |
1342 | CompUnitIDToIdx CUidToIdx; |
1343 | |
1344 | unsigned Id = 0; |
1345 | |
1346 | forEachCompileAndTypeUnit(UnitHandler: [&](DwarfUnit *CU) { |
1347 | bool HasRecords = false; |
1348 | CU->forEachAcceleratorRecord(Handler: [&](const DwarfUnit::AccelInfo &Info) { |
1349 | if (DebugNames == nullptr) |
1350 | DebugNames = std::make_unique<DWARF5AccelTable>(); |
1351 | |
1352 | HasRecords = true; |
1353 | switch (Info.Type) { |
1354 | case DwarfUnit::AccelType::Name: |
1355 | case DwarfUnit::AccelType::Namespace: |
1356 | case DwarfUnit::AccelType::Type: { |
1357 | DebugNames->addName(Name: *DebugStrStrings.getExistingEntry(String: Info.String), |
1358 | Args: Info.OutOffset, Args: std::nullopt /*ParentDIEOffset*/, |
1359 | Args: Info.Tag, Args: CU->getUniqueID(), |
1360 | Args: CU->getTag() == dwarf::DW_TAG_type_unit); |
1361 | } break; |
1362 | |
1363 | default: |
1364 | break; // Nothing to do. |
1365 | }; |
1366 | }); |
1367 | |
1368 | if (HasRecords) { |
1369 | CompUnits.push_back( |
1370 | x: CU->getOrCreateSectionDescriptor(SectionKind: DebugSectionKind::DebugInfo) |
1371 | .StartOffset); |
1372 | CUidToIdx[CU->getUniqueID()] = Id++; |
1373 | } |
1374 | }); |
1375 | |
1376 | if (DebugNames != nullptr) { |
1377 | // FIXME: we use AsmPrinter to emit accelerator sections. |
1378 | // It might be beneficial to directly emit accelerator data |
1379 | // to the raw_svector_ostream. |
1380 | SectionDescriptor &OutSection = |
1381 | CommonSections.getSectionDescriptor(SectionKind: DebugSectionKind::DebugNames); |
1382 | DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, |
1383 | OutSection.OS); |
1384 | if (Error Err = Emitter.init(TheTriple: TargetTriple, Swift5ReflectionSegmentName: "__DWARF" )) { |
1385 | consumeError(Err: std::move(Err)); |
1386 | return; |
1387 | } |
1388 | |
1389 | // Emit table. |
1390 | Emitter.emitDebugNames(Table&: *DebugNames, CUOffsets&: CompUnits, UnitIDToIdxMap&: CUidToIdx); |
1391 | Emitter.finish(); |
1392 | |
1393 | // Set start offset ans size for output section. |
1394 | OutSection.setSizesForSectionCreatedByAsmPrinter(); |
1395 | } |
1396 | } |
1397 | |
1398 | void DWARFLinkerImpl::cleanupDataAfterDWARFOutputIsWritten() { |
1399 | GlobalData.getStringPool().clear(); |
1400 | DebugStrStrings.clear(); |
1401 | DebugLineStrStrings.clear(); |
1402 | } |
1403 | |
1404 | void DWARFLinkerImpl::writeCompileUnitsToTheOutput() { |
1405 | // Enumerate all sections and store them into the final emitter. |
1406 | forEachObjectSectionsSet(SectionsSetHandler: [&](OutputSections &Sections) { |
1407 | Sections.forEach(Handler: [&](std::shared_ptr<SectionDescriptor> OutSection) { |
1408 | // Emit section content. |
1409 | SectionHandler(OutSection); |
1410 | }); |
1411 | }); |
1412 | } |
1413 | |
1414 | void DWARFLinkerImpl::writeCommonSectionsToTheOutput() { |
1415 | CommonSections.forEach(Handler: [&](std::shared_ptr<SectionDescriptor> OutSection) { |
1416 | SectionHandler(OutSection); |
1417 | }); |
1418 | } |
1419 | |