17namespace dwarflinker_parallel {
23 TheDwarfEmitter = std::make_unique<DwarfEmitterImpl>(FileType, OutFile);
40 for (
const std::unique_ptr<DWARFUnit> &
CU :
71 ? support::endianness::little
72 : support::endianness::big;
76 if (
Context->InputDWARFFile.Dwarf.get() ==
nullptr) {
77 Context->setOutputFormat(
Context->getFormParams(), GlobalEndianness);
82 outs() <<
"OBJECT: " <<
Context->InputDWARFFile.FileName <<
"\n";
84 for (
const std::unique_ptr<DWARFUnit> &OrigCU :
85 Context->InputDWARFFile.Dwarf->compile_units()) {
86 outs() <<
"Input compilation unit:";
90 OrigCU->getUnitDIE().dump(
outs(), 0, DumpOpts);
99 GlobalEndianness =
Context->getEndianness();
103 Context->setOutputFormat(
Context->getFormParams(), GlobalEndianness);
129 Context->InputDWARFFile.unload();
139 Context->InputDWARFFile.unload();
168 "target DWARF version is not set");
175 "set number of threads to 1 to make --verbose to work properly.",
"");
189 CUDie.
find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id}));
198 if (ObjectPrefixMap.empty())
202 for (
const auto &Entry : ObjectPrefixMap)
205 return p.str().str();
211 CUDie.
find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
"");
217 PCMFile =
remapPath(PCMFile, *ObjectPrefixMap);
223 const DWARFDie &CUDie, std::string &PCMFile,
unsigned Indent,
bool Quiet) {
225 return std::make_pair(
false,
false);
233 GlobalData.
warn(
"anonymous module skeleton CU for " + PCMFile +
".",
235 return std::make_pair(
true,
true);
240 outs() <<
"Found clang module reference " << PCMFile;
250 Twine(
"hash mismatch: this object file was built against a "
251 "different version of the module ") +
255 outs() <<
" [cached].\n";
256 return std::make_pair(
true,
true);
259 return std::make_pair(
true,
false);
271 std::string PCMFile =
273 std::pair<bool, bool> IsClangModuleRef =
274 isClangModuleRef(CUDie, PCMFile, Indent,
false);
276 if (!IsClangModuleRef.first)
279 if (IsClangModuleRef.second)
290 loadClangModule(Loader, CUDie, PCMFile, OnCUDieLoaded, Indent + 2)) {
312 if (Loader ==
nullptr) {
314 InputDWARFFile.FileName);
318 auto ErrOrObj = Loader(InputDWARFFile.FileName, Path);
322 std::unique_ptr<CompileUnit> Unit;
323 for (
const auto &
CU : ErrOrObj->Dwarf->compile_units()) {
326 auto ChildCUDie =
CU->getUnitDIE();
329 if (!registerModuleReference(ChildCUDie, Loader, OnCUDieLoaded, Indent)) {
333 ": Clang modules are expected to have exactly 1 compile unit.\n");
341 if (PCMDwoId != DwoId) {
344 Twine(
"hash mismatch: this object file was built against a "
345 "different version of the module ") +
347 InputDWARFFile.FileName);
353 if (!ChildCUDie.hasChildren())
357 Unit = std::make_unique<CompileUnit>(
364 ModulesCompileUnits.emplace_back(
RefModuleUnit{*ErrOrObj, std::move(Unit)});
366 ModulesCompileUnits.back().Unit->loadLineTable();
373 InterCUProcessingStarted =
false;
374 if (!InputDWARFFile.Dwarf)
378 InputDWARFFile.Dwarf->getDebugMacinfo();
379 InputDWARFFile.Dwarf->getDebugMacro();
383 linkSingleCompileUnit(*RefModule.
Unit);
389 !InputDWARFFile.Addresses->hasValidRelocs()) {
391 outs() <<
"No valid relocations found. Skipping.\n";
395 OriginalDebugInfoSize = getInputDebugInfoSize();
399 for (
const auto &OrigCU : InputDWARFFile.Dwarf->compile_units()) {
401 auto CUDie = OrigCU->getUnitDIE();
402 std::string PCMFile =
408 !isClangModuleRef(CUDie, PCMFile, 0,
true).first) {
409 CompileUnits.emplace_back(std::make_unique<CompileUnit>(
414 CompileUnits.back()->loadLineTable();
418 HasNewInterconnectedCUs =
false;
423 linkSingleCompileUnit(*
CU);
427 if (HasNewInterconnectedCUs) {
428 InterCUProcessingStarted =
true;
431 HasNewInterconnectedCUs =
false;
435 if (
CU->isInterconnectedCU()) {
436 CU->maybeResetToLoadedStage();
437 linkSingleCompileUnit(*CU, CompileUnit::Stage::Loaded);
445 }
while (HasNewInterconnectedCUs);
466 if (
Error Err = emitInvariantSections())
468 }
else if (!CompileUnits.empty()) {
476 if (
Error Err = cloneAndEmitDebugFrame())
477 ResultErr = std::move(Err);
487 while (
CU.getStage() < DoUntilStage) {
488 if (InterCUProcessingStarted !=
CU.isInterconnectedCU())
491 switch (
CU.getStage()) {
495 if (!
CU.loadInputDIEs()) {
499 CU.analyzeDWARFStructure();
506 if (registerModuleReference(
507 CU.getOrigUnit().getUnitDIE(),
nullptr,
519 assert(HasNewInterconnectedCUs);
534 CU.getContaingFile().Addresses->hasValidRelocs()) {
535 if (
Error Err =
CU.cloneAndEmit(TargetTriple))
536 CU.error(std::move(Err));
544 CU.updateDieRefPatchesWithClonedOffsets();
550 CU.cleanupDataAfterClonning();
566 << InputDWARFFile.Dwarf->getDWARFObj().getLocSection().Data;
568 << InputDWARFFile.Dwarf->getDWARFObj().getLoclistsSection().Data;
570 << InputDWARFFile.Dwarf->getDWARFObj().getRangesSection().Data;
572 << InputDWARFFile.Dwarf->getDWARFObj().getRnglistsSection().Data;
574 << InputDWARFFile.Dwarf->getDWARFObj().getArangesSection();
576 << InputDWARFFile.Dwarf->getDWARFObj().getFrameSection().Data;
578 << InputDWARFFile.Dwarf->getDWARFObj().getAddrSection().Data;
587 if (InputDWARFFile.Dwarf.get() ==
nullptr)
590 const DWARFObject &InputDWARFObj = InputDWARFFile.Dwarf->getDWARFObj();
593 if (OrigFrameData.
empty())
597 for (std::unique_ptr<CompileUnit> &Unit : CompileUnits) {
598 for (
auto CurRange : Unit->getFunctionRanges())
599 AllUnitsRanges.
insert(CurRange.Range, CurRange.Value);
618 while (
Data.isValidOffset(InputOffset)) {
621 if (InitialLength == 0xFFFFFFFF)
624 "Dwarf64 bits no supported"));
627 if (CIEId == 0xFFFFFFFF) {
629 StringRef CIEData = OrigFrameData.
substr(EntryOffset, InitialLength + 4);
630 LocalCIES[EntryOffset] = CIEData;
632 InputOffset += InitialLength - 4;
636 uint64_t Loc =
Data.getUnsigned(&InputOffset, SrcAddrSize);
642 std::optional<AddressRangeValuePair> Range =
646 InputOffset = EntryOffset + InitialLength + 4;
657 "Inconsistent debug_frame content. Dropping."));
663 auto IteratorInserted =
664 EmittedCIEs.
insert(std::make_pair(CIEData, OffsetToCIERecord));
665 OffsetToCIERecord = IteratorInserted.first->getValue();
668 if (IteratorInserted.second)
669 OutSection.
OS << CIEData;
676 OutSection.notePatch(
682 unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize);
683 emitFDE(OffsetToCIERecord, SrcAddrSize, Loc + Range->Value,
684 OrigFrameData.
substr(InputOffset, FDERemainingBytes), OutSection);
685 InputOffset += FDERemainingBytes;
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());
737 uint64_t AllDebugInfoSectionsSize = 0;
739 for (std::unique_ptr<CompileUnit> &
CU :
Context->CompileUnits)
740 if (std::optional<SectionDescriptor *>
DebugInfo =
742 AllDebugInfoSectionsSize += (*DebugInfo)->getContents().size();
744 SizeByObject[
Context->InputDWARFFile.FileName].Input =
745 Context->OriginalDebugInfoSize;
746 SizeByObject[
Context->InputDWARFFile.FileName].Output =
747 AllDebugInfoSectionsSize;
751 std::vector<std::pair<StringRef, DebugInfoSize>> Sorted;
752 for (
auto &
E : SizeByObject)
753 Sorted.emplace_back(
E.first(),
E.second);
755 return LHS.second.Output >
RHS.second.Output;
758 auto ComputePercentange = [](int64_t Input, int64_t Output) ->
float {
759 const float Difference = Output - Input;
760 const float Sum = Input + Output;
763 return (Difference / (Sum / 2));
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";
771 outs() <<
".debug_info section size (in bytes)\n";
772 outs() <<
"----------------------------------------------------------------"
774 outs() <<
"Filename Object "
776 outs() <<
"----------------------------------------------------------------"
780 for (
auto &
E : Sorted) {
781 InputTotal +=
E.second.Input;
782 OutputTotal +=
E.second.Output;
785 E.second.Output, ComputePercentange(
E.second.Input,
E.second.Output));
788 outs() <<
"----------------------------------------------------------------"
791 ComputePercentange(InputTotal, OutputTotal));
792 outs() <<
"----------------------------------------------------------------"
793 "---------------\n\n";
803 size_t CurDebugStrIndex = 1;
806 size_t CurDebugLineStrIndex = 0;
821 CurDebugLineStrIndex, CurDebugLineStrOffset,
827template <
typename PatchTy>
836 Patches.
forEach([&](PatchTy &Patch) {
838 StringsForEmission.
add(Patch.String);
841 if (!Entry->isIndexed()) {
842 Entry->Offset = OffsetAccumulator;
843 OffsetAccumulator += Entry->String.size() + 1;
844 Entry->Index = IndexAccumulator++;
850 std::array<uint64_t, SectionKindsNum> SectionSizesAccumulator = {0};
862 SectionsSetHandler(*ModuleUnit.
Unit);
869 for (std::unique_ptr<CompileUnit> &
CU :
Context->CompileUnits)
870 SectionsSetHandler(*
CU);
883template <
typename PatchTy>
891 StringPatches.
forEach([&](
const PatchTy &Patch) {
893 Strings.getExistingEntry(Patch.String);
899 if (StringToEmit->
Offset >= NextOffset) {
900 NextOffset = StringToEmit->Offset + StringToEmit->String.size() + 1;
902 OutSection.emitInplaceString(StringToEmit->String);
923 DebugStrNextOffset++;
928 DebugStrNextOffset, OutDebugStrSection);
935 uint64_t DebugLineStrNextOffset = 0;
940 DebugLineStrNextOffset, OutDebugLineStrSection);
953 bool HasAbbreviations =
false;
959 HasAbbreviations =
true;
975 if (!HasAbbreviations) {
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
std::optional< T > getRangeThatContains(uint64_t Addr) const
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.
std::optional< DWARFFormValue > find(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE.
virtual bool isLittleEndian() const =0
virtual StringRef getFileName() const
virtual const DWARFSection & getFrameSection() const
virtual uint8_t getAddressSize() const
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
iterator find(StringRef Key)
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
StringRef - Represent a constant reference to a string, i.e.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
constexpr bool empty() const
empty - Check if the string is empty.
constexpr size_t size() const
size - Get the string size.
StringRef take_back(size_t N=1) const
Return a StringRef equal to 'this' but with only the last N elements remaining.
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
A ThreadPool for asynchronous parallel execution on a defined number of threads.
void wait()
Blocking wait for all the threads to complete and the queue to be empty.
auto async(Function &&F, Args &&...ArgList)
Asynchronous submission of a task to the pool.
Triple - Helper class for working with autoconf configuration names.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
This class is a simple list of T structures.
void forEach(ItemHandlerTy Handler)
Enumerate all items and apply specified Handler to each.
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.
@ Cloned
Output DWARF is generated.
@ CreatedNotLoaded
Created, linked with input DWARF file.
@ PatchesUpdated
Offsets inside patch records are updated.
@ Cleaned
Resources(Input DWARF, Output DWARF tree) are released.
@ Loaded
Input DWARF is loaded.
@ 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.
StringRef FileName
Object file name.
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.
friend class DependencyTracker
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
std::map< std::string, std::string > ObjectPrefixMapTy
OutputFileType
Type of output file.
static void verifyKeepChain(CompileUnit &CU)
Recursively walk the DIE tree and check "keepness" information.
StringPool & getStringPool()
Returns global string pool.
DWARFLinkerOptions Options
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.
LinkingGlobalData & GlobalData
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.
void clear()
Erase contents of StringsForEmission.
An efficient, type-erasing, non-owning reference to a callable.
void spawn(std::function< void()> f, bool Sequential=false)
uint64_t tell() const
tell - Return the current offset with the file.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
An abstract base class for streams implementations that also support a pwrite operation.
A raw_ostream that writes to an std::string.
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.
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
constexpr endianness system_endianness()
bool is_relative(const Twine &path, Style style=Style::native)
Is path relative?
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
bool replace_path_prefix(SmallVectorImpl< char > &Path, StringRef OldPrefix, StringRef NewPrefix, Style style=Style::native)
Replace matching path prefix with another path.
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
This is an optimization pass for GlobalISel generic memory operations.
ThreadPoolStrategy hardware_concurrency(unsigned ThreadCount=0)
Returns a default thread strategy where all available hardware resources are to be used,...
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.
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
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.
static CompileUnit * getUnitForOffset(const UnitListTy &Units, uint64_t Offset)
Similar to DWARFUnitSection::getUnitForOffset(), but returning our CompileUnit object instead.
void sort(IteratorTy Start, IteratorTy End)
ThreadPoolStrategy optimal_concurrency(unsigned TaskCount=0)
Returns an optimal thread strategy to execute specified amount of tasks.
void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn)
void consumeError(Error Err)
Consume a Error without doing anything.
Container for dump options that control which debug information will be dumped.
DIDumpOptions noImplicitRecursion() const
Return the options with RecurseDepth set to 0 unless explicitly required.
unsigned ChildRecurseDepth
DwarfStringPoolEntry with string keeping externally.
Keep information for referenced clang module: already loaded DWARF info of the clang module and a Com...
std::unique_ptr< CompileUnit > Unit
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 emitInvariantSections()
Emit invariant sections.
DWARFFile & InputDWARFFile
Object file descriptor.
Error cloneAndEmitDebugFrame()
Clone and emit .debug_frame.
StringMap< uint64_t > & ClangModules
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.
unsigned Threads
Number of threads.
bool UpdateIndexTablesOnly
Update index tables.
DWARFLinker::InputVerificationHandlerTy InputVerificationHandler
input verification handler(it might be called asynchronously).
bool VerifyInputDWARF
Verify the input DWARF.
DWARFLinker::ObjectPrefixMapTy * ObjectPrefixMap
A list of remappings to apply to file paths.
bool Statistics
Print statistics.
bool NoOutput
Do not emit output.
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.