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

source code of llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp