Path: blob/main/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
35291 views
//=== DWARFLinkerImpl.cpp -------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "DWARFLinkerImpl.h"9#include "DIEGenerator.h"10#include "DependencyTracker.h"11#include "llvm/DWARFLinker/Utils.h"12#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"13#include "llvm/Support/FormatVariadic.h"14#include "llvm/Support/Parallel.h"15#include "llvm/Support/ThreadPool.h"1617using namespace llvm;18using namespace dwarf_linker;19using namespace dwarf_linker::parallel;2021DWARFLinkerImpl::DWARFLinkerImpl(MessageHandlerTy ErrorHandler,22MessageHandlerTy WarningHandler)23: UniqueUnitID(0), DebugStrStrings(GlobalData),24DebugLineStrStrings(GlobalData), CommonSections(GlobalData) {25GlobalData.setErrorHandler(ErrorHandler);26GlobalData.setWarningHandler(WarningHandler);27}2829DWARFLinkerImpl::LinkContext::LinkContext(LinkingGlobalData &GlobalData,30DWARFFile &File,31StringMap<uint64_t> &ClangModules,32std::atomic<size_t> &UniqueUnitID)33: OutputSections(GlobalData), InputDWARFFile(File),34ClangModules(ClangModules), UniqueUnitID(UniqueUnitID) {3536if (File.Dwarf) {37if (!File.Dwarf->compile_units().empty())38CompileUnits.reserve(File.Dwarf->getNumCompileUnits());3940// Set context format&endianness based on the input file.41Format.Version = File.Dwarf->getMaxVersion();42Format.AddrSize = File.Dwarf->getCUAddrSize();43Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little44: llvm::endianness::big;45}46}4748DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit(49DWARFFile &File, std::unique_ptr<CompileUnit> Unit)50: File(File), Unit(std::move(Unit)) {}5152DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit(53LinkContext::RefModuleUnit &&Other)54: File(Other.File), Unit(std::move(Other.Unit)) {}5556void DWARFLinkerImpl::LinkContext::addModulesCompileUnit(57LinkContext::RefModuleUnit &&Unit) {58ModulesCompileUnits.emplace_back(std::move(Unit));59}6061void DWARFLinkerImpl::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader,62CompileUnitHandlerTy OnCUDieLoaded) {63ObjectContexts.emplace_back(std::make_unique<LinkContext>(64GlobalData, File, ClangModules, UniqueUnitID));6566if (ObjectContexts.back()->InputDWARFFile.Dwarf) {67for (const std::unique_ptr<DWARFUnit> &CU :68ObjectContexts.back()->InputDWARFFile.Dwarf->compile_units()) {69DWARFDie CUDie = CU->getUnitDIE();70OverallNumberOfCU++;7172if (!CUDie)73continue;7475OnCUDieLoaded(*CU);7677// Register mofule reference.78if (!GlobalData.getOptions().UpdateIndexTablesOnly)79ObjectContexts.back()->registerModuleReference(CUDie, Loader,80OnCUDieLoaded);81}82}83}8485void DWARFLinkerImpl::setEstimatedObjfilesAmount(unsigned ObjFilesNum) {86ObjectContexts.reserve(ObjFilesNum);87}8889Error DWARFLinkerImpl::link() {90// reset compile unit unique ID counter.91UniqueUnitID = 0;9293if (Error Err = validateAndUpdateOptions())94return Err;9596dwarf::FormParams GlobalFormat = {GlobalData.getOptions().TargetDWARFVersion,970, dwarf::DwarfFormat::DWARF32};98llvm::endianness GlobalEndianness = llvm::endianness::native;99100if (std::optional<std::reference_wrapper<const Triple>> CurTriple =101GlobalData.getTargetTriple()) {102GlobalEndianness = (*CurTriple).get().isLittleEndian()103? llvm::endianness::little104: llvm::endianness::big;105}106std::optional<uint16_t> Language;107108for (std::unique_ptr<LinkContext> &Context : ObjectContexts) {109if (Context->InputDWARFFile.Dwarf == nullptr) {110Context->setOutputFormat(Context->getFormParams(), GlobalEndianness);111continue;112}113114if (GlobalData.getOptions().Verbose) {115outs() << "DEBUG MAP OBJECT: " << Context->InputDWARFFile.FileName116<< "\n";117118for (const std::unique_ptr<DWARFUnit> &OrigCU :119Context->InputDWARFFile.Dwarf->compile_units()) {120outs() << "Input compilation unit:";121DIDumpOptions DumpOpts;122DumpOpts.ChildRecurseDepth = 0;123DumpOpts.Verbose = GlobalData.getOptions().Verbose;124OrigCU->getUnitDIE().dump(outs(), 0, DumpOpts);125}126}127128// Verify input DWARF if requested.129if (GlobalData.getOptions().VerifyInputDWARF)130verifyInput(Context->InputDWARFFile);131132if (!GlobalData.getTargetTriple())133GlobalEndianness = Context->getEndianness();134GlobalFormat.AddrSize =135std::max(GlobalFormat.AddrSize, Context->getFormParams().AddrSize);136137Context->setOutputFormat(Context->getFormParams(), GlobalEndianness);138139// FIXME: move creation of CompileUnits into the addObjectFile.140// This would allow to not scan for context Language and Modules state141// twice. And then following handling might be removed.142for (const std::unique_ptr<DWARFUnit> &OrigCU :143Context->InputDWARFFile.Dwarf->compile_units()) {144DWARFDie UnitDie = OrigCU->getUnitDIE();145146if (!Language) {147if (std::optional<DWARFFormValue> Val =148UnitDie.find(dwarf::DW_AT_language)) {149uint16_t LangVal = dwarf::toUnsigned(Val, 0);150if (isODRLanguage(LangVal))151Language = LangVal;152}153}154}155}156157if (GlobalFormat.AddrSize == 0) {158if (std::optional<std::reference_wrapper<const Triple>> TargetTriple =159GlobalData.getTargetTriple())160GlobalFormat.AddrSize = (*TargetTriple).get().isArch32Bit() ? 4 : 8;161else162GlobalFormat.AddrSize = 8;163}164165CommonSections.setOutputFormat(GlobalFormat, GlobalEndianness);166167if (!GlobalData.Options.NoODR && Language.has_value()) {168llvm::parallel::TaskGroup TGroup;169TGroup.spawn([&]() {170ArtificialTypeUnit = std::make_unique<TypeUnit>(171GlobalData, UniqueUnitID++, Language, GlobalFormat, GlobalEndianness);172});173}174175// Set parallel options.176if (GlobalData.getOptions().Threads == 0)177llvm::parallel::strategy = optimal_concurrency(OverallNumberOfCU);178else179llvm::parallel::strategy =180hardware_concurrency(GlobalData.getOptions().Threads);181182// Link object files.183if (GlobalData.getOptions().Threads == 1) {184for (std::unique_ptr<LinkContext> &Context : ObjectContexts) {185// Link object file.186if (Error Err = Context->link(ArtificialTypeUnit.get()))187GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName);188189Context->InputDWARFFile.unload();190}191} else {192DefaultThreadPool Pool(llvm::parallel::strategy);193for (std::unique_ptr<LinkContext> &Context : ObjectContexts)194Pool.async([&]() {195// Link object file.196if (Error Err = Context->link(ArtificialTypeUnit.get()))197GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName);198199Context->InputDWARFFile.unload();200});201202Pool.wait();203}204205if (ArtificialTypeUnit != nullptr && !ArtificialTypeUnit->getTypePool()206.getRoot()207->getValue()208.load()209->Children.empty()) {210if (GlobalData.getTargetTriple().has_value())211if (Error Err = ArtificialTypeUnit->finishCloningAndEmit(212(*GlobalData.getTargetTriple()).get()))213return Err;214}215216// At this stage each compile units are cloned to their own set of debug217// sections. Now, update patches, assign offsets and assemble final file218// glueing debug tables from each compile unit.219glueCompileUnitsAndWriteToTheOutput();220221return Error::success();222}223224void DWARFLinkerImpl::verifyInput(const DWARFFile &File) {225assert(File.Dwarf);226227std::string Buffer;228raw_string_ostream OS(Buffer);229DIDumpOptions DumpOpts;230if (!File.Dwarf->verify(OS, DumpOpts.noImplicitRecursion())) {231if (GlobalData.getOptions().InputVerificationHandler)232GlobalData.getOptions().InputVerificationHandler(File, OS.str());233}234}235236Error DWARFLinkerImpl::validateAndUpdateOptions() {237if (GlobalData.getOptions().TargetDWARFVersion == 0)238return createStringError(std::errc::invalid_argument,239"target DWARF version is not set");240241if (GlobalData.getOptions().Verbose && GlobalData.getOptions().Threads != 1) {242GlobalData.Options.Threads = 1;243GlobalData.warn(244"set number of threads to 1 to make --verbose to work properly.", "");245}246247// Do not do types deduplication in case --update.248if (GlobalData.getOptions().UpdateIndexTablesOnly &&249!GlobalData.Options.NoODR)250GlobalData.Options.NoODR = true;251252return Error::success();253}254255/// Resolve the relative path to a build artifact referenced by DWARF by256/// applying DW_AT_comp_dir.257static void resolveRelativeObjectPath(SmallVectorImpl<char> &Buf, DWARFDie CU) {258sys::path::append(Buf, dwarf::toString(CU.find(dwarf::DW_AT_comp_dir), ""));259}260261static uint64_t getDwoId(const DWARFDie &CUDie) {262auto DwoId = dwarf::toUnsigned(263CUDie.find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id}));264if (DwoId)265return *DwoId;266return 0;267}268269static std::string270remapPath(StringRef Path,271const DWARFLinker::ObjectPrefixMapTy &ObjectPrefixMap) {272if (ObjectPrefixMap.empty())273return Path.str();274275SmallString<256> p = Path;276for (const auto &Entry : ObjectPrefixMap)277if (llvm::sys::path::replace_path_prefix(p, Entry.first, Entry.second))278break;279return p.str().str();280}281282static std::string getPCMFile(const DWARFDie &CUDie,283DWARFLinker::ObjectPrefixMapTy *ObjectPrefixMap) {284std::string PCMFile = dwarf::toString(285CUDie.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), "");286287if (PCMFile.empty())288return PCMFile;289290if (ObjectPrefixMap)291PCMFile = remapPath(PCMFile, *ObjectPrefixMap);292293return PCMFile;294}295296std::pair<bool, bool> DWARFLinkerImpl::LinkContext::isClangModuleRef(297const DWARFDie &CUDie, std::string &PCMFile, unsigned Indent, bool Quiet) {298if (PCMFile.empty())299return std::make_pair(false, false);300301// Clang module DWARF skeleton CUs abuse this for the path to the module.302uint64_t DwoId = getDwoId(CUDie);303304std::string Name = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");305if (Name.empty()) {306if (!Quiet)307GlobalData.warn("anonymous module skeleton CU for " + PCMFile + ".",308InputDWARFFile.FileName);309return std::make_pair(true, true);310}311312if (!Quiet && GlobalData.getOptions().Verbose) {313outs().indent(Indent);314outs() << "Found clang module reference " << PCMFile;315}316317auto Cached = ClangModules.find(PCMFile);318if (Cached != ClangModules.end()) {319// FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is320// fixed in clang, only warn about DWO_id mismatches in verbose mode.321// ASTFileSignatures will change randomly when a module is rebuilt.322if (!Quiet && GlobalData.getOptions().Verbose && (Cached->second != DwoId))323GlobalData.warn(324Twine("hash mismatch: this object file was built against a "325"different version of the module ") +326PCMFile + ".",327InputDWARFFile.FileName);328if (!Quiet && GlobalData.getOptions().Verbose)329outs() << " [cached].\n";330return std::make_pair(true, true);331}332333return std::make_pair(true, false);334}335336/// If this compile unit is really a skeleton CU that points to a337/// clang module, register it in ClangModules and return true.338///339/// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name340/// pointing to the module, and a DW_AT_gnu_dwo_id with the module341/// hash.342bool DWARFLinkerImpl::LinkContext::registerModuleReference(343const DWARFDie &CUDie, ObjFileLoaderTy Loader,344CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) {345std::string PCMFile =346getPCMFile(CUDie, GlobalData.getOptions().ObjectPrefixMap);347std::pair<bool, bool> IsClangModuleRef =348isClangModuleRef(CUDie, PCMFile, Indent, false);349350if (!IsClangModuleRef.first)351return false;352353if (IsClangModuleRef.second)354return true;355356if (GlobalData.getOptions().Verbose)357outs() << " ...\n";358359// Cyclic dependencies are disallowed by Clang, but we still360// shouldn't run into an infinite loop, so mark it as processed now.361ClangModules.insert({PCMFile, getDwoId(CUDie)});362363if (Error E =364loadClangModule(Loader, CUDie, PCMFile, OnCUDieLoaded, Indent + 2)) {365consumeError(std::move(E));366return false;367}368return true;369}370371Error DWARFLinkerImpl::LinkContext::loadClangModule(372ObjFileLoaderTy Loader, const DWARFDie &CUDie, const std::string &PCMFile,373CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) {374375uint64_t DwoId = getDwoId(CUDie);376std::string ModuleName = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");377378/// Using a SmallString<0> because loadClangModule() is recursive.379SmallString<0> Path(GlobalData.getOptions().PrependPath);380if (sys::path::is_relative(PCMFile))381resolveRelativeObjectPath(Path, CUDie);382sys::path::append(Path, PCMFile);383// Don't use the cached binary holder because we have no thread-safety384// guarantee and the lifetime is limited.385386if (Loader == nullptr) {387GlobalData.error("cann't load clang module: loader is not specified.",388InputDWARFFile.FileName);389return Error::success();390}391392auto ErrOrObj = Loader(InputDWARFFile.FileName, Path);393if (!ErrOrObj)394return Error::success();395396std::unique_ptr<CompileUnit> Unit;397for (const auto &CU : ErrOrObj->Dwarf->compile_units()) {398OnCUDieLoaded(*CU);399// Recursively get all modules imported by this one.400auto ChildCUDie = CU->getUnitDIE();401if (!ChildCUDie)402continue;403if (!registerModuleReference(ChildCUDie, Loader, OnCUDieLoaded, Indent)) {404if (Unit) {405std::string Err =406(PCMFile +407": Clang modules are expected to have exactly 1 compile unit.\n");408GlobalData.error(Err, InputDWARFFile.FileName);409return make_error<StringError>(Err, inconvertibleErrorCode());410}411// FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is412// fixed in clang, only warn about DWO_id mismatches in verbose mode.413// ASTFileSignatures will change randomly when a module is rebuilt.414uint64_t PCMDwoId = getDwoId(ChildCUDie);415if (PCMDwoId != DwoId) {416if (GlobalData.getOptions().Verbose)417GlobalData.warn(418Twine("hash mismatch: this object file was built against a "419"different version of the module ") +420PCMFile + ".",421InputDWARFFile.FileName);422// Update the cache entry with the DwoId of the module loaded from disk.423ClangModules[PCMFile] = PCMDwoId;424}425426// Empty modules units should not be cloned.427if (!ChildCUDie.hasChildren())428continue;429430// Add this module.431Unit = std::make_unique<CompileUnit>(432GlobalData, *CU, UniqueUnitID.fetch_add(1), ModuleName, *ErrOrObj,433getUnitForOffset, CU->getFormParams(), getEndianness());434}435}436437if (Unit) {438ModulesCompileUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)});439// Preload line table, as it can't be loaded asynchronously.440ModulesCompileUnits.back().Unit->loadLineTable();441}442443return Error::success();444}445446Error DWARFLinkerImpl::LinkContext::link(TypeUnit *ArtificialTypeUnit) {447InterCUProcessingStarted = false;448if (!InputDWARFFile.Dwarf)449return Error::success();450451// Preload macro tables, as they can't be loaded asynchronously.452InputDWARFFile.Dwarf->getDebugMacinfo();453InputDWARFFile.Dwarf->getDebugMacro();454455// Link modules compile units first.456parallelForEach(ModulesCompileUnits, [&](RefModuleUnit &RefModule) {457linkSingleCompileUnit(*RefModule.Unit, ArtificialTypeUnit);458});459460// Check for live relocations. If there is no any live relocation then we461// can skip entire object file.462if (!GlobalData.getOptions().UpdateIndexTablesOnly &&463!InputDWARFFile.Addresses->hasValidRelocs()) {464if (GlobalData.getOptions().Verbose)465outs() << "No valid relocations found. Skipping.\n";466return Error::success();467}468469OriginalDebugInfoSize = getInputDebugInfoSize();470471// Create CompileUnit structures to keep information about source472// DWARFUnit`s, load line tables.473for (const auto &OrigCU : InputDWARFFile.Dwarf->compile_units()) {474// Load only unit DIE at this stage.475auto CUDie = OrigCU->getUnitDIE();476std::string PCMFile =477getPCMFile(CUDie, GlobalData.getOptions().ObjectPrefixMap);478479// The !isClangModuleRef condition effectively skips over fully resolved480// skeleton units.481if (!CUDie || GlobalData.getOptions().UpdateIndexTablesOnly ||482!isClangModuleRef(CUDie, PCMFile, 0, true).first) {483CompileUnits.emplace_back(std::make_unique<CompileUnit>(484GlobalData, *OrigCU, UniqueUnitID.fetch_add(1), "", InputDWARFFile,485getUnitForOffset, OrigCU->getFormParams(), getEndianness()));486487// Preload line table, as it can't be loaded asynchronously.488CompileUnits.back()->loadLineTable();489}490};491492HasNewInterconnectedCUs = false;493494// Link self-sufficient compile units and discover inter-connected compile495// units.496parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {497linkSingleCompileUnit(*CU, ArtificialTypeUnit);498});499500// Link all inter-connected units.501if (HasNewInterconnectedCUs) {502InterCUProcessingStarted = true;503504if (Error Err = finiteLoop([&]() -> Expected<bool> {505HasNewInterconnectedCUs = false;506507// Load inter-connected units.508parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {509if (CU->isInterconnectedCU()) {510CU->maybeResetToLoadedStage();511linkSingleCompileUnit(*CU, ArtificialTypeUnit,512CompileUnit::Stage::Loaded);513}514});515516// Do liveness analysis for inter-connected units.517parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {518linkSingleCompileUnit(*CU, ArtificialTypeUnit,519CompileUnit::Stage::LivenessAnalysisDone);520});521522return HasNewInterconnectedCUs.load();523}))524return Err;525526// Update dependencies.527if (Error Err = finiteLoop([&]() -> Expected<bool> {528HasNewGlobalDependency = false;529parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {530linkSingleCompileUnit(531*CU, ArtificialTypeUnit,532CompileUnit::Stage::UpdateDependenciesCompleteness);533});534return HasNewGlobalDependency.load();535}))536return Err;537parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {538if (CU->isInterconnectedCU() &&539CU->getStage() == CompileUnit::Stage::LivenessAnalysisDone)540CU->setStage(CompileUnit::Stage::UpdateDependenciesCompleteness);541});542543// Assign type names.544parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {545linkSingleCompileUnit(*CU, ArtificialTypeUnit,546CompileUnit::Stage::TypeNamesAssigned);547});548549// Clone inter-connected units.550parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {551linkSingleCompileUnit(*CU, ArtificialTypeUnit,552CompileUnit::Stage::Cloned);553});554555// Update patches for inter-connected units.556parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {557linkSingleCompileUnit(*CU, ArtificialTypeUnit,558CompileUnit::Stage::PatchesUpdated);559});560561// Release data.562parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {563linkSingleCompileUnit(*CU, ArtificialTypeUnit,564CompileUnit::Stage::Cleaned);565});566}567568if (GlobalData.getOptions().UpdateIndexTablesOnly) {569// Emit Invariant sections.570571if (Error Err = emitInvariantSections())572return Err;573} else if (!CompileUnits.empty()) {574// Emit .debug_frame section.575576Error ResultErr = Error::success();577llvm::parallel::TaskGroup TGroup;578// We use task group here as PerThreadBumpPtrAllocator should be called from579// the threads created by ThreadPoolExecutor.580TGroup.spawn([&]() {581if (Error Err = cloneAndEmitDebugFrame())582ResultErr = std::move(Err);583});584return ResultErr;585}586587return Error::success();588}589590void DWARFLinkerImpl::LinkContext::linkSingleCompileUnit(591CompileUnit &CU, TypeUnit *ArtificialTypeUnit,592enum CompileUnit::Stage DoUntilStage) {593if (InterCUProcessingStarted != CU.isInterconnectedCU())594return;595596if (Error Err = finiteLoop([&]() -> Expected<bool> {597if (CU.getStage() >= DoUntilStage)598return false;599600switch (CU.getStage()) {601case CompileUnit::Stage::CreatedNotLoaded: {602// Load input compilation unit DIEs.603// Analyze properties of DIEs.604if (!CU.loadInputDIEs()) {605// We do not need to do liveness analysis for invalid compilation606// unit.607CU.setStage(CompileUnit::Stage::Skipped);608} else {609CU.analyzeDWARFStructure();610611// The registerModuleReference() condition effectively skips612// over fully resolved skeleton units. This second pass of613// registerModuleReferences doesn't do any new work, but it614// will collect top-level errors, which are suppressed. Module615// warnings were already displayed in the first iteration.616if (registerModuleReference(617CU.getOrigUnit().getUnitDIE(), nullptr,618[](const DWARFUnit &) {}, 0))619CU.setStage(CompileUnit::Stage::PatchesUpdated);620else621CU.setStage(CompileUnit::Stage::Loaded);622}623} break;624625case CompileUnit::Stage::Loaded: {626// Mark all the DIEs that need to be present in the generated output.627// If ODR requested, build type names.628if (!CU.resolveDependenciesAndMarkLiveness(InterCUProcessingStarted,629HasNewInterconnectedCUs)) {630assert(HasNewInterconnectedCUs &&631"Flag indicating new inter-connections is not set");632return false;633}634635CU.setStage(CompileUnit::Stage::LivenessAnalysisDone);636} break;637638case CompileUnit::Stage::LivenessAnalysisDone: {639if (InterCUProcessingStarted) {640if (CU.updateDependenciesCompleteness())641HasNewGlobalDependency = true;642return false;643} else {644if (Error Err = finiteLoop([&]() -> Expected<bool> {645return CU.updateDependenciesCompleteness();646}))647return std::move(Err);648649CU.setStage(CompileUnit::Stage::UpdateDependenciesCompleteness);650}651} break;652653case CompileUnit::Stage::UpdateDependenciesCompleteness:654#ifndef NDEBUG655CU.verifyDependencies();656#endif657658if (ArtificialTypeUnit) {659if (Error Err =660CU.assignTypeNames(ArtificialTypeUnit->getTypePool()))661return std::move(Err);662}663CU.setStage(CompileUnit::Stage::TypeNamesAssigned);664break;665666case CompileUnit::Stage::TypeNamesAssigned:667// Clone input compile unit.668if (CU.isClangModule() ||669GlobalData.getOptions().UpdateIndexTablesOnly ||670CU.getContaingFile().Addresses->hasValidRelocs()) {671if (Error Err = CU.cloneAndEmit(GlobalData.getTargetTriple(),672ArtificialTypeUnit))673return std::move(Err);674}675676CU.setStage(CompileUnit::Stage::Cloned);677break;678679case CompileUnit::Stage::Cloned:680// Update DIEs referencies.681CU.updateDieRefPatchesWithClonedOffsets();682CU.setStage(CompileUnit::Stage::PatchesUpdated);683break;684685case CompileUnit::Stage::PatchesUpdated:686// Cleanup resources.687CU.cleanupDataAfterClonning();688CU.setStage(CompileUnit::Stage::Cleaned);689break;690691case CompileUnit::Stage::Cleaned:692assert(false);693break;694695case CompileUnit::Stage::Skipped:696// Nothing to do.697break;698}699700return true;701})) {702CU.error(std::move(Err));703CU.cleanupDataAfterClonning();704CU.setStage(CompileUnit::Stage::Skipped);705}706}707708Error DWARFLinkerImpl::LinkContext::emitInvariantSections() {709if (!GlobalData.getTargetTriple().has_value())710return Error::success();711712getOrCreateSectionDescriptor(DebugSectionKind::DebugLoc).OS713<< InputDWARFFile.Dwarf->getDWARFObj().getLocSection().Data;714getOrCreateSectionDescriptor(DebugSectionKind::DebugLocLists).OS715<< InputDWARFFile.Dwarf->getDWARFObj().getLoclistsSection().Data;716getOrCreateSectionDescriptor(DebugSectionKind::DebugRange).OS717<< InputDWARFFile.Dwarf->getDWARFObj().getRangesSection().Data;718getOrCreateSectionDescriptor(DebugSectionKind::DebugRngLists).OS719<< InputDWARFFile.Dwarf->getDWARFObj().getRnglistsSection().Data;720getOrCreateSectionDescriptor(DebugSectionKind::DebugARanges).OS721<< InputDWARFFile.Dwarf->getDWARFObj().getArangesSection();722getOrCreateSectionDescriptor(DebugSectionKind::DebugFrame).OS723<< InputDWARFFile.Dwarf->getDWARFObj().getFrameSection().Data;724getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr).OS725<< InputDWARFFile.Dwarf->getDWARFObj().getAddrSection().Data;726727return Error::success();728}729730Error DWARFLinkerImpl::LinkContext::cloneAndEmitDebugFrame() {731if (!GlobalData.getTargetTriple().has_value())732return Error::success();733734if (InputDWARFFile.Dwarf == nullptr)735return Error::success();736737const DWARFObject &InputDWARFObj = InputDWARFFile.Dwarf->getDWARFObj();738739StringRef OrigFrameData = InputDWARFObj.getFrameSection().Data;740if (OrigFrameData.empty())741return Error::success();742743RangesTy AllUnitsRanges;744for (std::unique_ptr<CompileUnit> &Unit : CompileUnits) {745for (auto CurRange : Unit->getFunctionRanges())746AllUnitsRanges.insert(CurRange.Range, CurRange.Value);747}748749unsigned SrcAddrSize = InputDWARFObj.getAddressSize();750751SectionDescriptor &OutSection =752getOrCreateSectionDescriptor(DebugSectionKind::DebugFrame);753754DataExtractor Data(OrigFrameData, InputDWARFObj.isLittleEndian(), 0);755uint64_t InputOffset = 0;756757// Store the data of the CIEs defined in this object, keyed by their758// offsets.759DenseMap<uint64_t, StringRef> LocalCIES;760761/// The CIEs that have been emitted in the output section. The actual CIE762/// data serves a the key to this StringMap.763StringMap<uint32_t> EmittedCIEs;764765while (Data.isValidOffset(InputOffset)) {766uint64_t EntryOffset = InputOffset;767uint32_t InitialLength = Data.getU32(&InputOffset);768if (InitialLength == 0xFFFFFFFF)769return createFileError(InputDWARFObj.getFileName(),770createStringError(std::errc::invalid_argument,771"Dwarf64 bits no supported"));772773uint32_t CIEId = Data.getU32(&InputOffset);774if (CIEId == 0xFFFFFFFF) {775// This is a CIE, store it.776StringRef CIEData = OrigFrameData.substr(EntryOffset, InitialLength + 4);777LocalCIES[EntryOffset] = CIEData;778// The -4 is to account for the CIEId we just read.779InputOffset += InitialLength - 4;780continue;781}782783uint64_t Loc = Data.getUnsigned(&InputOffset, SrcAddrSize);784785// Some compilers seem to emit frame info that doesn't start at786// the function entry point, thus we can't just lookup the address787// in the debug map. Use the AddressInfo's range map to see if the FDE788// describes something that we can relocate.789std::optional<AddressRangeValuePair> Range =790AllUnitsRanges.getRangeThatContains(Loc);791if (!Range) {792// The +4 is to account for the size of the InitialLength field itself.793InputOffset = EntryOffset + InitialLength + 4;794continue;795}796797// This is an FDE, and we have a mapping.798// Have we already emitted a corresponding CIE?799StringRef CIEData = LocalCIES[CIEId];800if (CIEData.empty())801return createFileError(802InputDWARFObj.getFileName(),803createStringError(std::errc::invalid_argument,804"Inconsistent debug_frame content. Dropping."));805806uint64_t OffsetToCIERecord = OutSection.OS.tell();807808// Look if we already emitted a CIE that corresponds to the809// referenced one (the CIE data is the key of that lookup).810auto IteratorInserted =811EmittedCIEs.insert(std::make_pair(CIEData, OffsetToCIERecord));812OffsetToCIERecord = IteratorInserted.first->getValue();813814// Emit CIE for this ID if it is not emitted yet.815if (IteratorInserted.second)816OutSection.OS << CIEData;817818// Remember offset to the FDE record, so that we might update819// field referencing CIE record(containing OffsetToCIERecord),820// when final offsets are known. OffsetToCIERecord(which is written later)821// is local to the current .debug_frame section, it should be updated822// with final offset of the .debug_frame section.823OutSection.notePatch(824DebugOffsetPatch{OutSection.OS.tell() + 4, &OutSection, true});825826// Emit the FDE with updated address and CIE pointer.827// (4 + AddrSize) is the size of the CIEId + initial_location828// fields that will get reconstructed by emitFDE().829unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize);830emitFDE(OffsetToCIERecord, SrcAddrSize, Loc + Range->Value,831OrigFrameData.substr(InputOffset, FDERemainingBytes), OutSection);832InputOffset += FDERemainingBytes;833}834835return Error::success();836}837838/// Emit a FDE into the debug_frame section. \p FDEBytes839/// contains the FDE data without the length, CIE offset and address840/// which will be replaced with the parameter values.841void DWARFLinkerImpl::LinkContext::emitFDE(uint32_t CIEOffset,842uint32_t AddrSize, uint64_t Address,843StringRef FDEBytes,844SectionDescriptor &Section) {845Section.emitIntVal(FDEBytes.size() + 4 + AddrSize, 4);846Section.emitIntVal(CIEOffset, 4);847Section.emitIntVal(Address, AddrSize);848Section.OS.write(FDEBytes.data(), FDEBytes.size());849}850851void DWARFLinkerImpl::glueCompileUnitsAndWriteToTheOutput() {852if (!GlobalData.getTargetTriple().has_value())853return;854assert(SectionHandler);855856// Go through all object files, all compile units and assign857// offsets to them.858assignOffsets();859860// Patch size/offsets fields according to the assigned CU offsets.861patchOffsetsAndSizes();862863// Emit common sections and write debug tables from all object files/compile864// units into the resulting file.865emitCommonSectionsAndWriteCompileUnitsToTheOutput();866867if (ArtificialTypeUnit != nullptr)868ArtificialTypeUnit.reset();869870// Write common debug sections into the resulting file.871writeCommonSectionsToTheOutput();872873// Cleanup data.874cleanupDataAfterDWARFOutputIsWritten();875876if (GlobalData.getOptions().Statistics)877printStatistic();878}879880void DWARFLinkerImpl::printStatistic() {881882// For each object file map how many bytes were emitted.883StringMap<DebugInfoSize> SizeByObject;884885for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) {886uint64_t AllDebugInfoSectionsSize = 0;887888for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)889if (std::optional<SectionDescriptor *> DebugInfo =890CU->tryGetSectionDescriptor(DebugSectionKind::DebugInfo))891AllDebugInfoSectionsSize += (*DebugInfo)->getContents().size();892893SizeByObject[Context->InputDWARFFile.FileName].Input =894Context->OriginalDebugInfoSize;895SizeByObject[Context->InputDWARFFile.FileName].Output =896AllDebugInfoSectionsSize;897}898899// Create a vector sorted in descending order by output size.900std::vector<std::pair<StringRef, DebugInfoSize>> Sorted;901for (auto &E : SizeByObject)902Sorted.emplace_back(E.first(), E.second);903llvm::sort(Sorted, [](auto &LHS, auto &RHS) {904return LHS.second.Output > RHS.second.Output;905});906907auto ComputePercentange = [](int64_t Input, int64_t Output) -> float {908const float Difference = Output - Input;909const float Sum = Input + Output;910if (Sum == 0)911return 0;912return (Difference / (Sum / 2));913};914915int64_t InputTotal = 0;916int64_t OutputTotal = 0;917const char *FormatStr = "{0,-45} {1,10}b {2,10}b {3,8:P}\n";918919// Print header.920outs() << ".debug_info section size (in bytes)\n";921outs() << "----------------------------------------------------------------"922"---------------\n";923outs() << "Filename Object "924" dSYM Change\n";925outs() << "----------------------------------------------------------------"926"---------------\n";927928// Print body.929for (auto &E : Sorted) {930InputTotal += E.second.Input;931OutputTotal += E.second.Output;932llvm::outs() << formatv(933FormatStr, sys::path::filename(E.first).take_back(45), E.second.Input,934E.second.Output, ComputePercentange(E.second.Input, E.second.Output));935}936// Print total and footer.937outs() << "----------------------------------------------------------------"938"---------------\n";939llvm::outs() << formatv(FormatStr, "Total", InputTotal, OutputTotal,940ComputePercentange(InputTotal, OutputTotal));941outs() << "----------------------------------------------------------------"942"---------------\n\n";943}944945void DWARFLinkerImpl::assignOffsets() {946llvm::parallel::TaskGroup TGroup;947TGroup.spawn([&]() { assignOffsetsToStrings(); });948TGroup.spawn([&]() { assignOffsetsToSections(); });949}950951void DWARFLinkerImpl::assignOffsetsToStrings() {952size_t CurDebugStrIndex = 1; // start from 1 to take into account zero entry.953uint64_t CurDebugStrOffset =9541; // start from 1 to take into account zero entry.955size_t CurDebugLineStrIndex = 0;956uint64_t CurDebugLineStrOffset = 0;957958// Enumerates all strings, add them into the DwarfStringPoolEntry map,959// assign offset and index to the string if it is not indexed yet.960forEachOutputString([&](StringDestinationKind Kind,961const StringEntry *String) {962switch (Kind) {963case StringDestinationKind::DebugStr: {964DwarfStringPoolEntryWithExtString *Entry = DebugStrStrings.add(String);965assert(Entry != nullptr);966967if (!Entry->isIndexed()) {968Entry->Offset = CurDebugStrOffset;969CurDebugStrOffset += Entry->String.size() + 1;970Entry->Index = CurDebugStrIndex++;971}972} break;973case StringDestinationKind::DebugLineStr: {974DwarfStringPoolEntryWithExtString *Entry =975DebugLineStrStrings.add(String);976assert(Entry != nullptr);977978if (!Entry->isIndexed()) {979Entry->Offset = CurDebugLineStrOffset;980CurDebugLineStrOffset += Entry->String.size() + 1;981Entry->Index = CurDebugLineStrIndex++;982}983} break;984}985});986}987988void DWARFLinkerImpl::assignOffsetsToSections() {989std::array<uint64_t, SectionKindsNum> SectionSizesAccumulator = {0};990991forEachObjectSectionsSet([&](OutputSections &UnitSections) {992UnitSections.assignSectionsOffsetAndAccumulateSize(SectionSizesAccumulator);993});994}995996void DWARFLinkerImpl::forEachOutputString(997function_ref<void(StringDestinationKind Kind, const StringEntry *String)>998StringHandler) {999// To save space we do not create any separate string table.1000// We use already allocated string patches and accelerator entries:1001// enumerate them in natural order and assign offsets.1002// ASSUMPTION: strings should be stored into .debug_str/.debug_line_str1003// sections in the same order as they were assigned offsets.1004forEachCompileUnit([&](CompileUnit *CU) {1005CU->forEach([&](SectionDescriptor &OutSection) {1006OutSection.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) {1007StringHandler(StringDestinationKind::DebugStr, Patch.String);1008});10091010OutSection.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) {1011StringHandler(StringDestinationKind::DebugLineStr, Patch.String);1012});1013});10141015CU->forEachAcceleratorRecord([&](DwarfUnit::AccelInfo &Info) {1016StringHandler(DebugStr, Info.String);1017});1018});10191020if (ArtificialTypeUnit != nullptr) {1021ArtificialTypeUnit->forEach([&](SectionDescriptor &OutSection) {1022OutSection.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) {1023StringHandler(StringDestinationKind::DebugStr, Patch.String);1024});10251026OutSection.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) {1027StringHandler(StringDestinationKind::DebugLineStr, Patch.String);1028});10291030OutSection.ListDebugTypeStrPatch.forEach([&](DebugTypeStrPatch &Patch) {1031if (Patch.Die == nullptr)1032return;10331034StringHandler(StringDestinationKind::DebugStr, Patch.String);1035});10361037OutSection.ListDebugTypeLineStrPatch.forEach(1038[&](DebugTypeLineStrPatch &Patch) {1039if (Patch.Die == nullptr)1040return;10411042StringHandler(StringDestinationKind::DebugStr, Patch.String);1043});1044});1045}1046}10471048void DWARFLinkerImpl::forEachObjectSectionsSet(1049function_ref<void(OutputSections &)> SectionsSetHandler) {1050// Handle artificial type unit first.1051if (ArtificialTypeUnit != nullptr)1052SectionsSetHandler(*ArtificialTypeUnit);10531054// Then all modules(before regular compilation units).1055for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)1056for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)1057if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped)1058SectionsSetHandler(*ModuleUnit.Unit);10591060// Finally all compilation units.1061for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) {1062// Handle object file common sections.1063SectionsSetHandler(*Context);10641065// Handle compilation units.1066for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)1067if (CU->getStage() != CompileUnit::Stage::Skipped)1068SectionsSetHandler(*CU);1069}1070}10711072void DWARFLinkerImpl::forEachCompileAndTypeUnit(1073function_ref<void(DwarfUnit *CU)> UnitHandler) {1074if (ArtificialTypeUnit != nullptr)1075UnitHandler(ArtificialTypeUnit.get());10761077// Enumerate module units.1078for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)1079for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)1080if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped)1081UnitHandler(ModuleUnit.Unit.get());10821083// Enumerate compile units.1084for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)1085for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)1086if (CU->getStage() != CompileUnit::Stage::Skipped)1087UnitHandler(CU.get());1088}10891090void DWARFLinkerImpl::forEachCompileUnit(1091function_ref<void(CompileUnit *CU)> UnitHandler) {1092// Enumerate module units.1093for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)1094for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)1095if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped)1096UnitHandler(ModuleUnit.Unit.get());10971098// Enumerate compile units.1099for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)1100for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)1101if (CU->getStage() != CompileUnit::Stage::Skipped)1102UnitHandler(CU.get());1103}11041105void DWARFLinkerImpl::patchOffsetsAndSizes() {1106forEachObjectSectionsSet([&](OutputSections &SectionsSet) {1107SectionsSet.forEach([&](SectionDescriptor &OutSection) {1108SectionsSet.applyPatches(OutSection, DebugStrStrings, DebugLineStrStrings,1109ArtificialTypeUnit.get());1110});1111});1112}11131114void DWARFLinkerImpl::emitCommonSectionsAndWriteCompileUnitsToTheOutput() {1115llvm::parallel::TaskGroup TG;11161117// Create section descriptors ahead if they are not exist at the moment.1118// SectionDescriptors container is not thread safe. Thus we should be sure1119// that descriptors would not be created in following parallel tasks.11201121CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::DebugStr);1122CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::DebugLineStr);11231124if (llvm::is_contained(GlobalData.Options.AccelTables,1125AccelTableKind::Apple)) {1126CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::AppleNames);1127CommonSections.getOrCreateSectionDescriptor(1128DebugSectionKind::AppleNamespaces);1129CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::AppleObjC);1130CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::AppleTypes);1131}11321133if (llvm::is_contained(GlobalData.Options.AccelTables,1134AccelTableKind::DebugNames))1135CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::DebugNames);11361137// Emit .debug_str and .debug_line_str sections.1138TG.spawn([&]() { emitStringSections(); });11391140if (llvm::is_contained(GlobalData.Options.AccelTables,1141AccelTableKind::Apple)) {1142// Emit apple accelerator sections.1143TG.spawn([&]() {1144emitAppleAcceleratorSections((*GlobalData.getTargetTriple()).get());1145});1146}11471148if (llvm::is_contained(GlobalData.Options.AccelTables,1149AccelTableKind::DebugNames)) {1150// Emit .debug_names section.1151TG.spawn([&]() {1152emitDWARFv5DebugNamesSection((*GlobalData.getTargetTriple()).get());1153});1154}11551156// Write compile units to the output file.1157TG.spawn([&]() { writeCompileUnitsToTheOutput(); });1158}11591160void DWARFLinkerImpl::emitStringSections() {1161uint64_t DebugStrNextOffset = 0;1162uint64_t DebugLineStrNextOffset = 0;11631164// Emit zero length string. Accelerator tables does not work correctly1165// if the first string is not zero length string.1166CommonSections.getSectionDescriptor(DebugSectionKind::DebugStr)1167.emitInplaceString("");1168DebugStrNextOffset++;11691170forEachOutputString(1171[&](StringDestinationKind Kind, const StringEntry *String) {1172switch (Kind) {1173case StringDestinationKind::DebugStr: {1174DwarfStringPoolEntryWithExtString *StringToEmit =1175DebugStrStrings.getExistingEntry(String);1176assert(StringToEmit->isIndexed());11771178// Strings may be repeated. Use accumulated DebugStrNextOffset1179// to understand whether corresponding string is already emitted.1180// Skip string if its offset less than accumulated offset.1181if (StringToEmit->Offset >= DebugStrNextOffset) {1182DebugStrNextOffset =1183StringToEmit->Offset + StringToEmit->String.size() + 1;1184// Emit the string itself.1185CommonSections.getSectionDescriptor(DebugSectionKind::DebugStr)1186.emitInplaceString(StringToEmit->String);1187}1188} break;1189case StringDestinationKind::DebugLineStr: {1190DwarfStringPoolEntryWithExtString *StringToEmit =1191DebugLineStrStrings.getExistingEntry(String);1192assert(StringToEmit->isIndexed());11931194// Strings may be repeated. Use accumulated DebugLineStrStrings1195// to understand whether corresponding string is already emitted.1196// Skip string if its offset less than accumulated offset.1197if (StringToEmit->Offset >= DebugLineStrNextOffset) {1198DebugLineStrNextOffset =1199StringToEmit->Offset + StringToEmit->String.size() + 1;1200// Emit the string itself.1201CommonSections.getSectionDescriptor(DebugSectionKind::DebugLineStr)1202.emitInplaceString(StringToEmit->String);1203}1204} break;1205}1206});1207}12081209void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) {1210AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces;1211AccelTable<AppleAccelTableStaticOffsetData> AppleNames;1212AccelTable<AppleAccelTableStaticOffsetData> AppleObjC;1213AccelTable<AppleAccelTableStaticTypeData> AppleTypes;12141215forEachCompileAndTypeUnit([&](DwarfUnit *CU) {1216CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) {1217uint64_t OutOffset = Info.OutOffset;1218switch (Info.Type) {1219case DwarfUnit::AccelType::None: {1220llvm_unreachable("Unknown accelerator record");1221} break;1222case DwarfUnit::AccelType::Namespace: {1223AppleNamespaces.addName(1224*DebugStrStrings.getExistingEntry(Info.String),1225CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +1226OutOffset);1227} break;1228case DwarfUnit::AccelType::Name: {1229AppleNames.addName(1230*DebugStrStrings.getExistingEntry(Info.String),1231CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +1232OutOffset);1233} break;1234case DwarfUnit::AccelType::ObjC: {1235AppleObjC.addName(1236*DebugStrStrings.getExistingEntry(Info.String),1237CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +1238OutOffset);1239} break;1240case DwarfUnit::AccelType::Type: {1241AppleTypes.addName(1242*DebugStrStrings.getExistingEntry(Info.String),1243CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +1244OutOffset,1245Info.Tag,1246Info.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation1247: 0,1248Info.QualifiedNameHash);1249} break;1250}1251});1252});12531254{1255// FIXME: we use AsmPrinter to emit accelerator sections.1256// It might be beneficial to directly emit accelerator data1257// to the raw_svector_ostream.1258SectionDescriptor &OutSection =1259CommonSections.getSectionDescriptor(DebugSectionKind::AppleNamespaces);1260DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object,1261OutSection.OS);1262if (Error Err = Emitter.init(TargetTriple, "__DWARF")) {1263consumeError(std::move(Err));1264return;1265}12661267// Emit table.1268Emitter.emitAppleNamespaces(AppleNamespaces);1269Emitter.finish();12701271// Set start offset and size for output section.1272OutSection.setSizesForSectionCreatedByAsmPrinter();1273}12741275{1276// FIXME: we use AsmPrinter to emit accelerator sections.1277// It might be beneficial to directly emit accelerator data1278// to the raw_svector_ostream.1279SectionDescriptor &OutSection =1280CommonSections.getSectionDescriptor(DebugSectionKind::AppleNames);1281DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object,1282OutSection.OS);1283if (Error Err = Emitter.init(TargetTriple, "__DWARF")) {1284consumeError(std::move(Err));1285return;1286}12871288// Emit table.1289Emitter.emitAppleNames(AppleNames);1290Emitter.finish();12911292// Set start offset ans size for output section.1293OutSection.setSizesForSectionCreatedByAsmPrinter();1294}12951296{1297// FIXME: we use AsmPrinter to emit accelerator sections.1298// It might be beneficial to directly emit accelerator data1299// to the raw_svector_ostream.1300SectionDescriptor &OutSection =1301CommonSections.getSectionDescriptor(DebugSectionKind::AppleObjC);1302DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object,1303OutSection.OS);1304if (Error Err = Emitter.init(TargetTriple, "__DWARF")) {1305consumeError(std::move(Err));1306return;1307}13081309// Emit table.1310Emitter.emitAppleObjc(AppleObjC);1311Emitter.finish();13121313// Set start offset ans size for output section.1314OutSection.setSizesForSectionCreatedByAsmPrinter();1315}13161317{1318// FIXME: we use AsmPrinter to emit accelerator sections.1319// It might be beneficial to directly emit accelerator data1320// to the raw_svector_ostream.1321SectionDescriptor &OutSection =1322CommonSections.getSectionDescriptor(DebugSectionKind::AppleTypes);1323DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object,1324OutSection.OS);1325if (Error Err = Emitter.init(TargetTriple, "__DWARF")) {1326consumeError(std::move(Err));1327return;1328}13291330// Emit table.1331Emitter.emitAppleTypes(AppleTypes);1332Emitter.finish();13331334// Set start offset ans size for output section.1335OutSection.setSizesForSectionCreatedByAsmPrinter();1336}1337}13381339void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) {1340std::unique_ptr<DWARF5AccelTable> DebugNames;13411342DebugNamesUnitsOffsets CompUnits;1343CompUnitIDToIdx CUidToIdx;13441345unsigned Id = 0;13461347forEachCompileAndTypeUnit([&](DwarfUnit *CU) {1348bool HasRecords = false;1349CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) {1350if (DebugNames == nullptr)1351DebugNames = std::make_unique<DWARF5AccelTable>();13521353HasRecords = true;1354switch (Info.Type) {1355case DwarfUnit::AccelType::Name:1356case DwarfUnit::AccelType::Namespace:1357case DwarfUnit::AccelType::Type: {1358DebugNames->addName(*DebugStrStrings.getExistingEntry(Info.String),1359Info.OutOffset, std::nullopt /*ParentDIEOffset*/,1360Info.Tag, CU->getUniqueID(),1361CU->getTag() == dwarf::DW_TAG_type_unit);1362} break;13631364default:1365break; // Nothing to do.1366};1367});13681369if (HasRecords) {1370CompUnits.push_back(1371CU->getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo)1372.StartOffset);1373CUidToIdx[CU->getUniqueID()] = Id++;1374}1375});13761377if (DebugNames != nullptr) {1378// FIXME: we use AsmPrinter to emit accelerator sections.1379// It might be beneficial to directly emit accelerator data1380// to the raw_svector_ostream.1381SectionDescriptor &OutSection =1382CommonSections.getSectionDescriptor(DebugSectionKind::DebugNames);1383DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object,1384OutSection.OS);1385if (Error Err = Emitter.init(TargetTriple, "__DWARF")) {1386consumeError(std::move(Err));1387return;1388}13891390// Emit table.1391Emitter.emitDebugNames(*DebugNames, CompUnits, CUidToIdx);1392Emitter.finish();13931394// Set start offset ans size for output section.1395OutSection.setSizesForSectionCreatedByAsmPrinter();1396}1397}13981399void DWARFLinkerImpl::cleanupDataAfterDWARFOutputIsWritten() {1400GlobalData.getStringPool().clear();1401DebugStrStrings.clear();1402DebugLineStrStrings.clear();1403}14041405void DWARFLinkerImpl::writeCompileUnitsToTheOutput() {1406// Enumerate all sections and store them into the final emitter.1407forEachObjectSectionsSet([&](OutputSections &Sections) {1408Sections.forEach([&](std::shared_ptr<SectionDescriptor> OutSection) {1409// Emit section content.1410SectionHandler(OutSection);1411});1412});1413}14141415void DWARFLinkerImpl::writeCommonSectionsToTheOutput() {1416CommonSections.forEach([&](std::shared_ptr<SectionDescriptor> OutSection) {1417SectionHandler(OutSection);1418});1419}142014211422