LLVM 18.0.0git
DWARFLinkerImpl.cpp
Go to the documentation of this file.
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"
15
16namespace llvm {
17namespace dwarflinker_parallel {
18
20 OutputFileType FileType,
21 raw_pwrite_stream &OutFile) {
22
23 TheDwarfEmitter = std::make_unique<DwarfEmitterImpl>(FileType, OutFile);
24
25 return TheDwarfEmitter->init(TheTriple, "__DWARF");
26}
27
29 return TheDwarfEmitter.get();
30}
31
33 CompileUnitHandlerTy OnCUDieLoaded) {
34 ObjectContexts.emplace_back(std::make_unique<LinkContext>(
36 (TheDwarfEmitter.get() == nullptr ? std::optional<Triple>(std::nullopt)
37 : TheDwarfEmitter->getTargetTriple())));
38
39 if (ObjectContexts.back()->InputDWARFFile.Dwarf) {
40 for (const std::unique_ptr<DWARFUnit> &CU :
41 ObjectContexts.back()->InputDWARFFile.Dwarf->compile_units()) {
42 DWARFDie CUDie = CU->getUnitDIE();
44
45 if (!CUDie)
46 continue;
47
48 OnCUDieLoaded(*CU);
49
50 // Register mofule reference.
52 ObjectContexts.back()->registerModuleReference(CUDie, Loader,
53 OnCUDieLoaded);
54 }
55 }
56}
57
59 // reset compile unit unique ID counter.
60 UniqueUnitID = 0;
61
63 return Err;
64
68
69 if (TheDwarfEmitter) {
70 GlobalEndianness = TheDwarfEmitter->getTargetTriple().isLittleEndian()
71 ? support::endianness::little
72 : support::endianness::big;
73 }
74
75 for (std::unique_ptr<LinkContext> &Context : ObjectContexts) {
76 if (Context->InputDWARFFile.Dwarf.get() == nullptr) {
77 Context->setOutputFormat(Context->getFormParams(), GlobalEndianness);
78 continue;
79 }
80
82 outs() << "OBJECT: " << Context->InputDWARFFile.FileName << "\n";
83
84 for (const std::unique_ptr<DWARFUnit> &OrigCU :
85 Context->InputDWARFFile.Dwarf->compile_units()) {
86 outs() << "Input compilation unit:";
87 DIDumpOptions DumpOpts;
88 DumpOpts.ChildRecurseDepth = 0;
90 OrigCU->getUnitDIE().dump(outs(), 0, DumpOpts);
91 }
92 }
93
94 // Verify input DWARF if requested.
96 verifyInput(Context->InputDWARFFile);
97
98 if (!TheDwarfEmitter)
99 GlobalEndianness = Context->getEndianness();
100 GlobalFormat.AddrSize =
101 std::max(GlobalFormat.AddrSize, Context->getFormParams().AddrSize);
102
103 Context->setOutputFormat(Context->getFormParams(), GlobalEndianness);
104 }
105
106 if (GlobalFormat.AddrSize == 0) {
107 if (TheDwarfEmitter)
108 GlobalFormat.AddrSize =
109 TheDwarfEmitter->getTargetTriple().isArch32Bit() ? 4 : 8;
110 else
111 GlobalFormat.AddrSize = 8;
112 }
113
114 CommonSections.setOutputFormat(GlobalFormat, GlobalEndianness);
115
116 // Set parallel options.
117 if (GlobalData.getOptions().Threads == 0)
119 else
121
122 // Link object files.
123 if (GlobalData.getOptions().Threads == 1) {
124 for (std::unique_ptr<LinkContext> &Context : ObjectContexts) {
125 // Link object file.
126 if (Error Err = Context->link())
127 GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName);
128
129 Context->InputDWARFFile.unload();
130 }
131 } else {
133 for (std::unique_ptr<LinkContext> &Context : ObjectContexts)
134 Pool.async([&]() {
135 // Link object file.
136 if (Error Err = Context->link())
137 GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName);
138
139 Context->InputDWARFFile.unload();
140 });
141
142 Pool.wait();
143 }
144
145 // At this stage each compile units are cloned to their own set of debug
146 // sections. Now, update patches, assign offsets and assemble final file
147 // glueing debug tables from each compile unit.
149
150 return Error::success();
151}
152
154 assert(File.Dwarf);
155
156 std::string Buffer;
157 raw_string_ostream OS(Buffer);
158 DIDumpOptions DumpOpts;
159 if (!File.Dwarf->verify(OS, DumpOpts.noImplicitRecursion())) {
162 }
163}
164
167 return createStringError(std::errc::invalid_argument,
168 "target DWARF version is not set");
169
170 GlobalData.Options.NoOutput = TheDwarfEmitter.get() == nullptr;
171
175 "set number of threads to 1 to make --verbose to work properly.", "");
176 }
177
178 return Error::success();
179}
180
181/// Resolve the relative path to a build artifact referenced by DWARF by
182/// applying DW_AT_comp_dir.
184 sys::path::append(Buf, dwarf::toString(CU.find(dwarf::DW_AT_comp_dir), ""));
185}
186
187static uint64_t getDwoId(const DWARFDie &CUDie) {
188 auto DwoId = dwarf::toUnsigned(
189 CUDie.find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id}));
190 if (DwoId)
191 return *DwoId;
192 return 0;
193}
194
195static std::string
197 const DWARFLinker::ObjectPrefixMapTy &ObjectPrefixMap) {
198 if (ObjectPrefixMap.empty())
199 return Path.str();
200
201 SmallString<256> p = Path;
202 for (const auto &Entry : ObjectPrefixMap)
203 if (llvm::sys::path::replace_path_prefix(p, Entry.first, Entry.second))
204 break;
205 return p.str().str();
206}
207
208static std::string getPCMFile(const DWARFDie &CUDie,
209 DWARFLinker::ObjectPrefixMapTy *ObjectPrefixMap) {
210 std::string PCMFile = dwarf::toString(
211 CUDie.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), "");
212
213 if (PCMFile.empty())
214 return PCMFile;
215
216 if (ObjectPrefixMap)
217 PCMFile = remapPath(PCMFile, *ObjectPrefixMap);
218
219 return PCMFile;
220}
221
223 const DWARFDie &CUDie, std::string &PCMFile, unsigned Indent, bool Quiet) {
224 if (PCMFile.empty())
225 return std::make_pair(false, false);
226
227 // Clang module DWARF skeleton CUs abuse this for the path to the module.
228 uint64_t DwoId = getDwoId(CUDie);
229
230 std::string Name = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");
231 if (Name.empty()) {
232 if (!Quiet)
233 GlobalData.warn("anonymous module skeleton CU for " + PCMFile + ".",
235 return std::make_pair(true, true);
236 }
237
239 outs().indent(Indent);
240 outs() << "Found clang module reference " << PCMFile;
241 }
242
243 auto Cached = ClangModules.find(PCMFile);
244 if (Cached != ClangModules.end()) {
245 // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is
246 // fixed in clang, only warn about DWO_id mismatches in verbose mode.
247 // ASTFileSignatures will change randomly when a module is rebuilt.
248 if (!Quiet && GlobalData.getOptions().Verbose && (Cached->second != DwoId))
250 Twine("hash mismatch: this object file was built against a "
251 "different version of the module ") +
252 PCMFile + ".",
255 outs() << " [cached].\n";
256 return std::make_pair(true, true);
257 }
258
259 return std::make_pair(true, false);
260}
261
262/// If this compile unit is really a skeleton CU that points to a
263/// clang module, register it in ClangModules and return true.
264///
265/// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
266/// pointing to the module, and a DW_AT_gnu_dwo_id with the module
267/// hash.
269 const DWARFDie &CUDie, ObjFileLoaderTy Loader,
270 CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) {
271 std::string PCMFile =
273 std::pair<bool, bool> IsClangModuleRef =
274 isClangModuleRef(CUDie, PCMFile, Indent, false);
275
276 if (!IsClangModuleRef.first)
277 return false;
278
279 if (IsClangModuleRef.second)
280 return true;
281
283 outs() << " ...\n";
284
285 // Cyclic dependencies are disallowed by Clang, but we still
286 // shouldn't run into an infinite loop, so mark it as processed now.
287 ClangModules.insert({PCMFile, getDwoId(CUDie)});
288
289 if (Error E =
290 loadClangModule(Loader, CUDie, PCMFile, OnCUDieLoaded, Indent + 2)) {
291 consumeError(std::move(E));
292 return false;
293 }
294 return true;
295}
296
298 ObjFileLoaderTy Loader, const DWARFDie &CUDie, const std::string &PCMFile,
299 CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) {
300
301 uint64_t DwoId = getDwoId(CUDie);
302 std::string ModuleName = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");
303
304 /// Using a SmallString<0> because loadClangModule() is recursive.
306 if (sys::path::is_relative(PCMFile))
307 resolveRelativeObjectPath(Path, CUDie);
308 sys::path::append(Path, PCMFile);
309 // Don't use the cached binary holder because we have no thread-safety
310 // guarantee and the lifetime is limited.
311
312 if (Loader == nullptr) {
313 GlobalData.error("cann't load clang module: loader is not specified.",
314 InputDWARFFile.FileName);
315 return Error::success();
316 }
317
318 auto ErrOrObj = Loader(InputDWARFFile.FileName, Path);
319 if (!ErrOrObj)
320 return Error::success();
321
322 std::unique_ptr<CompileUnit> Unit;
323 for (const auto &CU : ErrOrObj->Dwarf->compile_units()) {
324 OnCUDieLoaded(*CU);
325 // Recursively get all modules imported by this one.
326 auto ChildCUDie = CU->getUnitDIE();
327 if (!ChildCUDie)
328 continue;
329 if (!registerModuleReference(ChildCUDie, Loader, OnCUDieLoaded, Indent)) {
330 if (Unit) {
331 std::string Err =
332 (PCMFile +
333 ": Clang modules are expected to have exactly 1 compile unit.\n");
334 GlobalData.error(Err, InputDWARFFile.FileName);
335 return make_error<StringError>(Err, inconvertibleErrorCode());
336 }
337 // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is
338 // fixed in clang, only warn about DWO_id mismatches in verbose mode.
339 // ASTFileSignatures will change randomly when a module is rebuilt.
340 uint64_t PCMDwoId = getDwoId(ChildCUDie);
341 if (PCMDwoId != DwoId) {
344 Twine("hash mismatch: this object file was built against a "
345 "different version of the module ") +
346 PCMFile + ".",
347 InputDWARFFile.FileName);
348 // Update the cache entry with the DwoId of the module loaded from disk.
349 ClangModules[PCMFile] = PCMDwoId;
350 }
351
352 // Empty modules units should not be cloned.
353 if (!ChildCUDie.hasChildren())
354 continue;
355
356 // Add this module.
357 Unit = std::make_unique<CompileUnit>(
358 GlobalData, *CU, UniqueUnitID.fetch_add(1), ModuleName, *ErrOrObj,
359 getUnitForOffset, CU->getFormParams(), getEndianness());
360 }
361 }
362
363 if (Unit) {
364 ModulesCompileUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)});
365 // Preload line table, as it can't be loaded asynchronously.
366 ModulesCompileUnits.back().Unit->loadLineTable();
367 }
368
369 return Error::success();
370}
371
373 InterCUProcessingStarted = false;
374 if (!InputDWARFFile.Dwarf)
375 return Error::success();
376
377 // Preload macro tables, as they can't be loaded asynchronously.
378 InputDWARFFile.Dwarf->getDebugMacinfo();
379 InputDWARFFile.Dwarf->getDebugMacro();
380
381 // Link modules compile units first.
382 parallelForEach(ModulesCompileUnits, [&](RefModuleUnit &RefModule) {
383 linkSingleCompileUnit(*RefModule.Unit);
384 });
385
386 // Check for live relocations. If there is no any live relocation then we
387 // can skip entire object file.
389 !InputDWARFFile.Addresses->hasValidRelocs()) {
391 outs() << "No valid relocations found. Skipping.\n";
392 return Error::success();
393 }
394
395 OriginalDebugInfoSize = getInputDebugInfoSize();
396
397 // Create CompileUnit structures to keep information about source
398 // DWARFUnit`s, load line tables.
399 for (const auto &OrigCU : InputDWARFFile.Dwarf->compile_units()) {
400 // Load only unit DIE at this stage.
401 auto CUDie = OrigCU->getUnitDIE();
402 std::string PCMFile =
404
405 // The !isClangModuleRef condition effectively skips over fully resolved
406 // skeleton units.
408 !isClangModuleRef(CUDie, PCMFile, 0, true).first) {
409 CompileUnits.emplace_back(std::make_unique<CompileUnit>(
410 GlobalData, *OrigCU, UniqueUnitID.fetch_add(1), "", InputDWARFFile,
411 getUnitForOffset, OrigCU->getFormParams(), getEndianness()));
412
413 // Preload line table, as it can't be loaded asynchronously.
414 CompileUnits.back()->loadLineTable();
415 }
416 };
417
418 HasNewInterconnectedCUs = false;
419
420 // Link self-sufficient compile units and discover inter-connected compile
421 // units.
422 parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
423 linkSingleCompileUnit(*CU);
424 });
425
426 // Link all inter-connected units.
427 if (HasNewInterconnectedCUs) {
428 InterCUProcessingStarted = true;
429
430 do {
431 HasNewInterconnectedCUs = false;
432
433 // Load inter-connected units.
434 parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
435 if (CU->isInterconnectedCU()) {
436 CU->maybeResetToLoadedStage();
437 linkSingleCompileUnit(*CU, CompileUnit::Stage::Loaded);
438 }
439 });
440
441 // Do liveness analysis for inter-connected units.
442 parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
443 linkSingleCompileUnit(*CU, CompileUnit::Stage::LivenessAnalysisDone);
444 });
445 } while (HasNewInterconnectedCUs);
446
447 // Clone inter-connected units.
448 parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
449 linkSingleCompileUnit(*CU, CompileUnit::Stage::Cloned);
450 });
451
452 // Update patches for inter-connected units.
453 parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
454 linkSingleCompileUnit(*CU, CompileUnit::Stage::PatchesUpdated);
455 });
456
457 // Release data.
458 parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
459 linkSingleCompileUnit(*CU, CompileUnit::Stage::Cleaned);
460 });
461 }
462
464 // Emit Invariant sections.
465
466 if (Error Err = emitInvariantSections())
467 return Err;
468 } else if (!CompileUnits.empty()) {
469 // Emit .debug_frame section.
470
471 Error ResultErr = Error::success();
472 parallel::TaskGroup TGroup;
473 // We use task group here as PerThreadBumpPtrAllocator should be called from
474 // the threads created by ThreadPoolExecutor.
475 TGroup.spawn([&]() {
476 if (Error Err = cloneAndEmitDebugFrame())
477 ResultErr = std::move(Err);
478 });
479 return ResultErr;
480 }
481
482 return Error::success();
483}
484
486 CompileUnit &CU, enum CompileUnit::Stage DoUntilStage) {
487 while (CU.getStage() < DoUntilStage) {
488 if (InterCUProcessingStarted != CU.isInterconnectedCU())
489 return;
490
491 switch (CU.getStage()) {
493 // Load input compilation unit DIEs.
494 // Analyze properties of DIEs.
495 if (!CU.loadInputDIEs()) {
496 // We do not need to do liveness analysis for invalud compilation unit.
498 } else {
499 CU.analyzeDWARFStructure();
500
501 // The registerModuleReference() condition effectively skips
502 // over fully resolved skeleton units. This second pass of
503 // registerModuleReferences doesn't do any new work, but it
504 // will collect top-level errors, which are suppressed. Module
505 // warnings were already displayed in the first iteration.
506 if (registerModuleReference(
507 CU.getOrigUnit().getUnitDIE(), nullptr,
508 [](const DWARFUnit &) {}, 0))
510 else
512 }
513 } break;
514
516 // Mark all the DIEs that need to be present in the generated output.
517 // If ODR requested, build type names.
518 if (!DependencyTracker(*this).resolveDependenciesAndMarkLiveness(CU)) {
519 assert(HasNewInterconnectedCUs);
520 return;
521 }
522
524 } break;
525
527
528#ifndef NDEBUG
530#endif
531
532 // Clone input compile unit.
533 if (CU.isClangModule() || GlobalData.getOptions().UpdateIndexTablesOnly ||
534 CU.getContaingFile().Addresses->hasValidRelocs()) {
535 if (Error Err = CU.cloneAndEmit(TargetTriple))
536 CU.error(std::move(Err));
537 }
538
540 break;
541
543 // Update DIEs referencies.
544 CU.updateDieRefPatchesWithClonedOffsets();
546 break;
547
549 // Cleanup resources.
550 CU.cleanupDataAfterClonning();
552 break;
553
555 assert(false);
556 break;
557 }
558 }
559}
560
563 return Error::success();
564
565 getOrCreateSectionDescriptor(DebugSectionKind::DebugLoc).OS
566 << InputDWARFFile.Dwarf->getDWARFObj().getLocSection().Data;
567 getOrCreateSectionDescriptor(DebugSectionKind::DebugLocLists).OS
568 << InputDWARFFile.Dwarf->getDWARFObj().getLoclistsSection().Data;
569 getOrCreateSectionDescriptor(DebugSectionKind::DebugRange).OS
570 << InputDWARFFile.Dwarf->getDWARFObj().getRangesSection().Data;
571 getOrCreateSectionDescriptor(DebugSectionKind::DebugRngLists).OS
572 << InputDWARFFile.Dwarf->getDWARFObj().getRnglistsSection().Data;
573 getOrCreateSectionDescriptor(DebugSectionKind::DebugARanges).OS
574 << InputDWARFFile.Dwarf->getDWARFObj().getArangesSection();
575 getOrCreateSectionDescriptor(DebugSectionKind::DebugFrame).OS
576 << InputDWARFFile.Dwarf->getDWARFObj().getFrameSection().Data;
577 getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr).OS
578 << InputDWARFFile.Dwarf->getDWARFObj().getAddrSection().Data;
579
580 return Error::success();
581}
582
585 return Error::success();
586
587 if (InputDWARFFile.Dwarf.get() == nullptr)
588 return Error::success();
589
590 const DWARFObject &InputDWARFObj = InputDWARFFile.Dwarf->getDWARFObj();
591
592 StringRef OrigFrameData = InputDWARFObj.getFrameSection().Data;
593 if (OrigFrameData.empty())
594 return Error::success();
595
596 RangesTy AllUnitsRanges;
597 for (std::unique_ptr<CompileUnit> &Unit : CompileUnits) {
598 for (auto CurRange : Unit->getFunctionRanges())
599 AllUnitsRanges.insert(CurRange.Range, CurRange.Value);
600 }
601
602 unsigned SrcAddrSize = InputDWARFObj.getAddressSize();
603
604 SectionDescriptor &OutSection =
605 getOrCreateSectionDescriptor(DebugSectionKind::DebugFrame);
606
607 DataExtractor Data(OrigFrameData, InputDWARFObj.isLittleEndian(), 0);
608 uint64_t InputOffset = 0;
609
610 // Store the data of the CIEs defined in this object, keyed by their
611 // offsets.
613
614 /// The CIEs that have been emitted in the output section. The actual CIE
615 /// data serves a the key to this StringMap.
616 StringMap<uint32_t> EmittedCIEs;
617
618 while (Data.isValidOffset(InputOffset)) {
619 uint64_t EntryOffset = InputOffset;
620 uint32_t InitialLength = Data.getU32(&InputOffset);
621 if (InitialLength == 0xFFFFFFFF)
622 return createFileError(InputDWARFObj.getFileName(),
623 createStringError(std::errc::invalid_argument,
624 "Dwarf64 bits no supported"));
625
626 uint32_t CIEId = Data.getU32(&InputOffset);
627 if (CIEId == 0xFFFFFFFF) {
628 // This is a CIE, store it.
629 StringRef CIEData = OrigFrameData.substr(EntryOffset, InitialLength + 4);
630 LocalCIES[EntryOffset] = CIEData;
631 // The -4 is to account for the CIEId we just read.
632 InputOffset += InitialLength - 4;
633 continue;
634 }
635
636 uint64_t Loc = Data.getUnsigned(&InputOffset, SrcAddrSize);
637
638 // Some compilers seem to emit frame info that doesn't start at
639 // the function entry point, thus we can't just lookup the address
640 // in the debug map. Use the AddressInfo's range map to see if the FDE
641 // describes something that we can relocate.
642 std::optional<AddressRangeValuePair> Range =
643 AllUnitsRanges.getRangeThatContains(Loc);
644 if (!Range) {
645 // The +4 is to account for the size of the InitialLength field itself.
646 InputOffset = EntryOffset + InitialLength + 4;
647 continue;
648 }
649
650 // This is an FDE, and we have a mapping.
651 // Have we already emitted a corresponding CIE?
652 StringRef CIEData = LocalCIES[CIEId];
653 if (CIEData.empty())
654 return createFileError(
655 InputDWARFObj.getFileName(),
656 createStringError(std::errc::invalid_argument,
657 "Inconsistent debug_frame content. Dropping."));
658
659 uint64_t OffsetToCIERecord = OutSection.OS.tell();
660
661 // Look if we already emitted a CIE that corresponds to the
662 // referenced one (the CIE data is the key of that lookup).
663 auto IteratorInserted =
664 EmittedCIEs.insert(std::make_pair(CIEData, OffsetToCIERecord));
665 OffsetToCIERecord = IteratorInserted.first->getValue();
666
667 // Emit CIE for this ID if it is not emitted yet.
668 if (IteratorInserted.second)
669 OutSection.OS << CIEData;
670
671 // Remember offset to the FDE record, so that we might update
672 // field referencing CIE record(containing OffsetToCIERecord),
673 // when final offsets are known. OffsetToCIERecord(which is written later)
674 // is local to the current .debug_frame section, it should be updated
675 // with final offset of the .debug_frame section.
676 OutSection.notePatch(
677 DebugOffsetPatch{OutSection.OS.tell() + 4, &OutSection, true});
678
679 // Emit the FDE with updated address and CIE pointer.
680 // (4 + AddrSize) is the size of the CIEId + initial_location
681 // fields that will get reconstructed by emitFDE().
682 unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize);
683 emitFDE(OffsetToCIERecord, SrcAddrSize, Loc + Range->Value,
684 OrigFrameData.substr(InputOffset, FDERemainingBytes), OutSection);
685 InputOffset += FDERemainingBytes;
686 }
687
688 return Error::success();
689}
690
691/// Emit a FDE into the debug_frame section. \p FDEBytes
692/// contains the FDE data without the length, CIE offset and address
693/// which will be replaced with the parameter values.
695 uint32_t AddrSize, uint64_t Address,
696 StringRef FDEBytes,
697 SectionDescriptor &Section) {
698 Section.emitIntVal(FDEBytes.size() + 4 + AddrSize, 4);
699 Section.emitIntVal(CIEOffset, 4);
700 Section.emitIntVal(Address, AddrSize);
701 Section.OS.write(FDEBytes.data(), FDEBytes.size());
702}
703
706 return;
707
708 // Go through all object files, all compile units and assign
709 // offsets to them.
711
712 // Patch size/offsets fields according to the assigned CU offsets.
714
715 // FIXME: Build accelerator tables.
716
717 // Emit common sections.
719
720 // Cleanup data.
722
723 // Write debug tables from all object files/compile units into the
724 // resulting file.
726
729}
730
732
733 // For each object file map how many bytes were emitted.
734 StringMap<DebugInfoSize> SizeByObject;
735
736 for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) {
737 uint64_t AllDebugInfoSectionsSize = 0;
738
739 for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)
740 if (std::optional<SectionDescriptor *> DebugInfo =
741 CU->getSectionDescriptor(DebugSectionKind::DebugInfo))
742 AllDebugInfoSectionsSize += (*DebugInfo)->getContents().size();
743
744 SizeByObject[Context->InputDWARFFile.FileName].Input =
745 Context->OriginalDebugInfoSize;
746 SizeByObject[Context->InputDWARFFile.FileName].Output =
747 AllDebugInfoSectionsSize;
748 }
749
750 // Create a vector sorted in descending order by output size.
751 std::vector<std::pair<StringRef, DebugInfoSize>> Sorted;
752 for (auto &E : SizeByObject)
753 Sorted.emplace_back(E.first(), E.second);
754 llvm::sort(Sorted, [](auto &LHS, auto &RHS) {
755 return LHS.second.Output > RHS.second.Output;
756 });
757
758 auto ComputePercentange = [](int64_t Input, int64_t Output) -> float {
759 const float Difference = Output - Input;
760 const float Sum = Input + Output;
761 if (Sum == 0)
762 return 0;
763 return (Difference / (Sum / 2));
764 };
765
766 int64_t InputTotal = 0;
767 int64_t OutputTotal = 0;
768 const char *FormatStr = "{0,-45} {1,10}b {2,10}b {3,8:P}\n";
769
770 // Print header.
771 outs() << ".debug_info section size (in bytes)\n";
772 outs() << "----------------------------------------------------------------"
773 "---------------\n";
774 outs() << "Filename Object "
775 " dSYM Change\n";
776 outs() << "----------------------------------------------------------------"
777 "---------------\n";
778
779 // Print body.
780 for (auto &E : Sorted) {
781 InputTotal += E.second.Input;
782 OutputTotal += E.second.Output;
783 llvm::outs() << formatv(
784 FormatStr, sys::path::filename(E.first).take_back(45), E.second.Input,
785 E.second.Output, ComputePercentange(E.second.Input, E.second.Output));
786 }
787 // Print total and footer.
788 outs() << "----------------------------------------------------------------"
789 "---------------\n";
790 llvm::outs() << formatv(FormatStr, "Total", InputTotal, OutputTotal,
791 ComputePercentange(InputTotal, OutputTotal));
792 outs() << "----------------------------------------------------------------"
793 "---------------\n\n";
794}
795
797 parallel::TaskGroup TGroup;
798 TGroup.spawn([&]() { assignOffsetsToStrings(); });
799 TGroup.spawn([&]() { assignOffsetsToSections(); });
800}
801
803 size_t CurDebugStrIndex = 1; // start from 1 to take into account zero entry.
804 uint64_t CurDebugStrOffset =
805 1; // start from 1 to take into account zero entry.
806 size_t CurDebugLineStrIndex = 0;
807 uint64_t CurDebugLineStrOffset = 0;
808
809 // To save space we do not create any separate string table.
810 // We use already allocated string patches and assign offsets
811 // to them in the natural order.
812 // ASSUMPTION: strings should be stored into .debug_str/.debug_line_str
813 // sections in the same order as they were assigned offsets.
814
815 forEachObjectSectionsSet([&](OutputSections &SectionsSet) {
816 SectionsSet.forEach([&](SectionDescriptor &OutSection) {
817 assignOffsetsToStringsImpl(OutSection.ListDebugStrPatch, CurDebugStrIndex,
818 CurDebugStrOffset, DebugStrStrings);
819
820 assignOffsetsToStringsImpl(OutSection.ListDebugLineStrPatch,
821 CurDebugLineStrIndex, CurDebugLineStrOffset,
823 });
824 });
825}
826
827template <typename PatchTy>
829 ArrayList<PatchTy> &Patches, size_t &IndexAccumulator,
830 uint64_t &OffsetAccumulator,
831 StringEntryToDwarfStringPoolEntryMap &StringsForEmission) {
832
833 // Enumerates all patches, adds string into the
834 // StringEntry->DwarfStringPoolEntry map, assign offset and index to the
835 // string if it is not indexed yet.
836 Patches.forEach([&](PatchTy &Patch) {
838 StringsForEmission.add(Patch.String);
839 assert(Entry != nullptr);
840
841 if (!Entry->isIndexed()) {
842 Entry->Offset = OffsetAccumulator;
843 OffsetAccumulator += Entry->String.size() + 1;
844 Entry->Index = IndexAccumulator++;
845 }
846 });
847}
848
850 std::array<uint64_t, SectionKindsNum> SectionSizesAccumulator = {0};
851
852 forEachObjectSectionsSet([&](OutputSections &UnitSections) {
853 UnitSections.assignSectionsOffsetAndAccumulateSize(SectionSizesAccumulator);
854 });
855}
856
858 function_ref<void(OutputSections &)> SectionsSetHandler) {
859 // Handle all modules first(before regular compilation units).
860 for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
861 for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)
862 SectionsSetHandler(*ModuleUnit.Unit);
863
864 for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) {
865 // Handle object file common sections.
866 SectionsSetHandler(*Context);
867
868 // Handle compilation units.
869 for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)
870 SectionsSetHandler(*CU);
871 }
872}
873
875 forEachObjectSectionsSet([&](OutputSections &SectionsSet) {
876 SectionsSet.forEach([&](SectionDescriptor &OutSection) {
877 SectionsSet.applyPatches(OutSection, DebugStrStrings,
879 });
880 });
881}
882
883template <typename PatchTy>
885 ArrayList<PatchTy> &StringPatches,
886 const StringEntryToDwarfStringPoolEntryMap &Strings, uint64_t &NextOffset,
887 SectionDescriptor &OutSection) {
888 // Enumerate all string patches and write strings into the destination
889 // section. We enumerate patches to have a predictable order of strings(i.e.
890 // strings are emitted in the order as they appear in the patches).
891 StringPatches.forEach([&](const PatchTy &Patch) {
893 Strings.getExistingEntry(Patch.String);
894 assert(StringToEmit->isIndexed());
895
896 // Patches can refer the same strings. We use accumulated NextOffset
897 // to understand whether corresponding string is already emitted.
898 // Skip patch if string is already emitted.
899 if (StringToEmit->Offset >= NextOffset) {
900 NextOffset = StringToEmit->Offset + StringToEmit->String.size() + 1;
901 // Emit the string itself.
902 OutSection.emitInplaceString(StringToEmit->String);
903 }
904 });
905}
906
909
910 SectionDescriptor &OutDebugStrSection =
912 SectionDescriptor &OutDebugLineStrSection =
915
916 // Emit .debug_str section.
917 TG.spawn([&]() {
918 uint64_t DebugStrNextOffset = 0;
919
920 // Emit zero length string. Accelerator tables does not work correctly
921 // if the first string is not zero length string.
922 OutDebugStrSection.emitInplaceString("");
923 DebugStrNextOffset++;
924
926 Sections.forEach([&](SectionDescriptor &Section) {
927 emitStringsImpl(Section.ListDebugStrPatch, DebugStrStrings,
928 DebugStrNextOffset, OutDebugStrSection);
929 });
930 });
931 });
932
933 // Emit .debug_line_str section.
934 TG.spawn([&]() {
935 uint64_t DebugLineStrNextOffset = 0;
936
938 Sections.forEach([&](SectionDescriptor &Section) {
939 emitStringsImpl(Section.ListDebugLineStrPatch, DebugLineStrStrings,
940 DebugLineStrNextOffset, OutDebugLineStrSection);
941 });
942 });
943 });
944}
945
950}
951
953 bool HasAbbreviations = false;
954
956 Sections.forEach([&](SectionDescriptor &OutSection) {
957 if (!HasAbbreviations && !OutSection.getContents().empty() &&
959 HasAbbreviations = true;
960
961 // Emit section content.
962 TheDwarfEmitter->emitSectionContents(OutSection.getContents(),
963 OutSection.getName());
964 OutSection.erase();
965 });
966 });
967
968 CommonSections.forEach([&](SectionDescriptor &OutSection) {
969 // Emit section content.
970 TheDwarfEmitter->emitSectionContents(OutSection.getContents(),
971 OutSection.getName());
972 OutSection.erase();
973 });
974
975 if (!HasAbbreviations) {
976 const SmallVector<std::unique_ptr<DIEAbbrev>> Abbreviations;
977 TheDwarfEmitter->emitAbbrevs(Abbreviations, 3);
978 }
979}
980
981} // end of namespace dwarflinker_parallel
982} // namespace llvm
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::string Name
LLVMContext & Context
if(VerifyEach)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
Value * RHS
Value * LHS
std::optional< T > getRangeThatContains(uint64_t Addr) const
Definition: AddressRanges.h:75
AddressRangesMap class maps values to the address ranges.
void insert(AddressRange Range, int64_t Value)
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition: DWARFDie.h:42
std::optional< DWARFFormValue > find(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE.
Definition: DWARFDie.cpp:247
virtual bool isLittleEndian() const =0
virtual StringRef getFileName() const
Definition: DWARFObject.h:31
virtual const DWARFSection & getFrameSection() const
Definition: DWARFObject.h:44
virtual uint8_t getAddressSize() const
Definition: DWARFObject.h:35
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:577
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:112
iterator end()
Definition: StringMap.h:205
iterator find(StringRef Key)
Definition: StringMap.h:218
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
Definition: StringMap.h:287
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:575
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
StringRef take_back(size_t N=1) const
Return a StringRef equal to 'this' but with only the last N elements remaining.
Definition: StringRef.h:593
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:131
A ThreadPool for asynchronous parallel execution on a defined number of threads.
Definition: ThreadPool.h:52
void wait()
Blocking wait for all the threads to complete and the queue to be empty.
Definition: ThreadPool.cpp:202
auto async(Function &&F, Args &&...ArgList)
Asynchronous submission of a task to the pool.
Definition: ThreadPool.h:66
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
This class is a simple list of T structures.
Definition: ArrayList.h:21
void forEach(ItemHandlerTy Handler)
Enumerate all items and apply specified Handler to each.
Definition: ArrayList.h:55
Stores all information related to a compile unit, be it in its original instance of the object file o...
Stage
The stages of new compile unit processing.
@ CreatedNotLoaded
Created, linked with input DWARF file.
@ PatchesUpdated
Offsets inside patch records are updated.
@ Cleaned
Resources(Input DWARF, Output DWARF tree) are released.
@ LivenessAnalysisDone
Input DWARF is analysed(DIEs pointing to the real code section are discovered,...
This class represents DWARF information for source file and it's address map.
Definition: DWARFFile.h:26
StringRef FileName
Object file name.
Definition: DWARFFile.h:35
void writeDWARFToTheOutput()
Enumerate all compile units and put their data into the output stream.
void glueCompileUnitsAndWriteToTheOutput()
Take already linked compile units and glue them into single file.
void verifyInput(const DWARFFile &File)
Verify input DWARF file.
void emitCommonSections()
Emit debug sections common for all input files.
void cleanupDataAfterOutputSectionsAreGenerated()
Cleanup data(string pools) after output sections are generated.
void addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader=nullptr, CompileUnitHandlerTy OnCUDieLoaded=[](const DWARFUnit &) {}) override
Add object file to be linked.
void printStatistic()
Print statistic for processed Debug Info.
void emitStringsImpl(ArrayList< PatchTy > &StringPatches, const StringEntryToDwarfStringPoolEntryMap &Strings, uint64_t &NextOffset, SectionDescriptor &OutSection)
void forEachObjectSectionsSet(function_ref< void(OutputSections &SectionsSet)> SectionsSetHandler)
Enumerates sections for modules, invariant for object files, compile units.
Error createEmitter(const Triple &TheTriple, OutputFileType FileType, raw_pwrite_stream &OutFile) override
Create debug info emitter.
void assignOffsetsToStringsImpl(ArrayList< PatchTy > &Section, size_t &IndexAccumulator, uint64_t &OffsetAccumulator, StringEntryToDwarfStringPoolEntryMap &StringsForEmission)
Enumerates specified string patches, assigns offset and index.
ExtraDwarfEmitter * getEmitter() override
Returns previously created dwarf emitter. May be nullptr.
Error link() override
Link debug info for added files.
void assignOffsetsToSections()
Enumerate all compile units and assign offsets to their sections.
Error validateAndUpdateOptions()
Validate specified options.
void assignOffsets()
Enumerate all compile units and assign offsets to their sections and strings.
void patchOffsetsAndSizes()
Enumerates all patches and update them with the correct values.
void assignOffsetsToStrings()
Enumerate all compile units and assign offsets to their strings.
std::function< ErrorOr< DWARFFile & >(StringRef ContainerName, StringRef Path)> ObjFileLoaderTy
Definition: DWARFLinker.h:136
std::map< std::string, std::string > ObjectPrefixMapTy
Definition: DWARFLinker.h:138
static void verifyKeepChain(CompileUnit &CU)
Recursively walk the DIE tree and check "keepness" information.
ExtraDwarfEmitter allows adding extra data to the DWARFLinker output.
Definition: DWARFLinker.h:93
StringPool & getStringPool()
Returns global string pool.
const DWARFLinkerOptions & getOptions() const
Returns linking options.
void error(const Twine &Err, StringRef Context, const DWARFDie *DIE=nullptr)
Report error.
void warn(const Twine &Warning, StringRef Context, const DWARFDie *DIE=nullptr)
Report warning.
This class keeps contents and offsets to the debug sections.
void assignSectionsOffsetAndAccumulateSize(std::array< uint64_t, SectionKindsNum > &SectionSizesAccumulator)
Enumerate all sections, for each section set current offset (kept by SectionSizesAccumulator),...
void forEach(function_ref< void(SectionDescriptor &)> Handler)
Enumerate all sections and call Handler for each.
void applyPatches(SectionDescriptor &Section, StringEntryToDwarfStringPoolEntryMap &DebugStrStrings, StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings)
Enumerate all sections, for each section apply all section patches.
SectionDescriptor & getOrCreateSectionDescriptor(DebugSectionKind SectionKind)
Returns descriptor for the specified section of SectionKind.
void setOutputFormat(dwarf::FormParams Format, support::endianness Endianness)
Sets output format for all keeping sections.
This class creates a DwarfStringPoolEntry for the corresponding StringEntry.
DwarfStringPoolEntryWithExtString * add(const StringEntry *String)
Create DwarfStringPoolEntry for specified StringEntry if necessary.
An efficient, type-erasing, non-owning reference to a callable.
void spawn(std::function< void()> f, bool Sequential=false)
Definition: Parallel.cpp:208
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:134
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
An abstract base class for streams implementations that also support a pwrite operation.
Definition: raw_ostream.h:428
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:642
std::atomic< size_t > UniqueUnitID
Unique ID for compile unit.
OutputSections CommonSections
Common sections.
std::unique_ptr< DwarfEmitterImpl > TheDwarfEmitter
The emitter of final dwarf file.
uint64_t OverallNumberOfCU
Overall compile units number.
StringEntryToDwarfStringPoolEntryMap DebugLineStrStrings
DwarfStringPoolEntries for .debug_line_str section.
SmallVector< std::unique_ptr< LinkContext > > ObjectContexts
Keeps all linking contexts.
LinkingGlobalData GlobalData
Data global for the whole linking process.
StringEntryToDwarfStringPoolEntryMap DebugStrStrings
StringMap< uint64_t > ClangModules
Mapping the PCM filename to the DwoId.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
@ DWARF32
Definition: Dwarf.h:91
std::optional< uint64_t > toUnsigned(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an unsigned constant.
static std::string remapPath(StringRef Path, const DWARFLinker::ObjectPrefixMapTy &ObjectPrefixMap)
static std::string getPCMFile(const DWARFDie &CUDie, DWARFLinker::ObjectPrefixMapTy *ObjectPrefixMap)
static void resolveRelativeObjectPath(SmallVectorImpl< char > &Buf, DWARFDie CU)
Resolve the relative path to a build artifact referenced by DWARF by applying DW_AT_comp_dir.
static uint64_t getDwoId(const DWARFDie &CUDie)
ThreadPoolStrategy strategy
Definition: Parallel.cpp:20
constexpr endianness system_endianness()
Definition: Endian.h:44
bool is_relative(const Twine &path, Style style=Style::native)
Is path relative?
Definition: Path.cpp:701
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:579
bool replace_path_prefix(SmallVectorImpl< char > &Path, StringRef OldPrefix, StringRef NewPrefix, Style style=Style::native)
Replace matching path prefix with another path.
Definition: Path.cpp:520
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:458
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
ThreadPoolStrategy hardware_concurrency(unsigned ThreadCount=0)
Returns a default thread strategy where all available hardware resources are to be used,...
Definition: Threading.h:185
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition: Error.h:1325
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:90
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1244
static CompileUnit * getUnitForOffset(const UnitListTy &Units, uint64_t Offset)
Similar to DWARFUnitSection::getUnitForOffset(), but returning our CompileUnit object instead.
Definition: DWARFLinker.cpp:59
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1652
ThreadPoolStrategy optimal_concurrency(unsigned TaskCount=0)
Returns an optimal thread strategy to execute specified amount of tasks.
Definition: Threading.h:194
void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn)
Definition: Parallel.h:233
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1041
Container for dump options that control which debug information will be dumped.
Definition: DIContext.h:193
DIDumpOptions noImplicitRecursion() const
Return the options with RecurseDepth set to 0 unless explicitly required.
Definition: DIContext.h:219
unsigned ChildRecurseDepth
Definition: DIContext.h:195
DwarfStringPoolEntry with string keeping externally.
A helper struct providing information about the byte size of DW_FORM values that vary in size dependi...
Definition: Dwarf.h:743
Keep information for referenced clang module: already loaded DWARF info of the clang module and a Com...
Error link()
Link compile units for this context.
void emitFDE(uint32_t CIEOffset, uint32_t AddrSize, uint64_t Address, StringRef FDEBytes, SectionDescriptor &Section)
Emit FDE record.
Error cloneAndEmitDebugFrame()
Clone and emit .debug_frame.
Error loadClangModule(ObjFileLoaderTy Loader, const DWARFDie &CUDie, const std::string &PCMFile, CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent=0)
Recursively add the debug info in this clang module .pcm file (and all the modules imported by it in ...
void linkSingleCompileUnit(CompileUnit &CU, enum CompileUnit::Stage DoUntilStage=CompileUnit::Stage::Cleaned)
Link specified compile unit until specified stage.
bool registerModuleReference(const DWARFDie &CUDie, ObjFileLoaderTy Loader, CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent=0)
If this compile unit is really a skeleton CU that points to a clang module, register it in ClangModul...
std::pair< bool, bool > isClangModuleRef(const DWARFDie &CUDie, std::string &PCMFile, unsigned Indent, bool Quiet)
Check whether specified CUDie is a Clang module reference.
uint16_t TargetDWARFVersion
DWARF version for the output.
std::string PrependPath
Prepend path for the clang modules.
bool Verbose
Generate processing log to the standard output.
DWARFLinker::InputVerificationHandlerTy InputVerificationHandler
input verification handler(it might be called asynchronously).
DWARFLinker::ObjectPrefixMapTy * ObjectPrefixMap
A list of remappings to apply to file paths.
This structure is used to keep data of the concrete section.
void emitInplaceString(StringRef String)
Emit specified inplace string value into the current section contents.
raw_svector_ostream OS
Stream which stores data to the Contents.
void erase()
Erase whole section contents(data bits, list of patches, format).
DebugSectionKind getKind()
Returns section kind.
const StringLiteral & getName() const
Returns section name.
StringRef getContents()
Returns section content.