diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp | 1451 | 
1 files changed, 1451 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp new file mode 100644 index 000000000000..bb59cbfdb347 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp @@ -0,0 +1,1451 @@ +//=== DWARFLinkerImpl.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DWARFLinkerImpl.h" +#include "DIEGenerator.h" +#include "DependencyTracker.h" +#include "Utils.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Parallel.h" +#include "llvm/Support/ThreadPool.h" + +using namespace llvm; +using namespace dwarf_linker; +using namespace dwarf_linker::parallel; + +DWARFLinkerImpl::DWARFLinkerImpl(MessageHandlerTy ErrorHandler, +                                 MessageHandlerTy WarningHandler, +                                 TranslatorFuncTy StringsTranslator) +    : UniqueUnitID(0), DebugStrStrings(GlobalData), +      DebugLineStrStrings(GlobalData), CommonSections(GlobalData) { +  GlobalData.setTranslator(StringsTranslator); +  GlobalData.setErrorHandler(ErrorHandler); +  GlobalData.setWarningHandler(WarningHandler); +} + +DWARFLinkerImpl::LinkContext::LinkContext(LinkingGlobalData &GlobalData, +                                          DWARFFile &File, +                                          StringMap<uint64_t> &ClangModules, +                                          std::atomic<size_t> &UniqueUnitID, +                                          std::optional<Triple> TargetTriple) +    : OutputSections(GlobalData), InputDWARFFile(File), +      ClangModules(ClangModules), TargetTriple(TargetTriple), +      UniqueUnitID(UniqueUnitID) { + +  if (File.Dwarf) { +    if (!File.Dwarf->compile_units().empty()) +      CompileUnits.reserve(File.Dwarf->getNumCompileUnits()); + +    // Set context format&endianness based on the input file. +    Format.Version = File.Dwarf->getMaxVersion(); +    Format.AddrSize = File.Dwarf->getCUAddrSize(); +    Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little +                                              : llvm::endianness::big; +  } +} + +DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit( +    DWARFFile &File, std::unique_ptr<CompileUnit> Unit) +    : File(File), Unit(std::move(Unit)) {} + +DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit( +    LinkContext::RefModuleUnit &&Other) +    : File(Other.File), Unit(std::move(Other.Unit)) {} + +void DWARFLinkerImpl::LinkContext::addModulesCompileUnit( +    LinkContext::RefModuleUnit &&Unit) { +  ModulesCompileUnits.emplace_back(std::move(Unit)); +} + +Error DWARFLinkerImpl::createEmitter(const Triple &TheTriple, +                                     OutputFileType FileType, +                                     raw_pwrite_stream &OutFile) { + +  TheDwarfEmitter = std::make_unique<DwarfEmitterImpl>(FileType, OutFile); + +  return TheDwarfEmitter->init(TheTriple, "__DWARF"); +} + +ExtraDwarfEmitter *DWARFLinkerImpl::getEmitter() { +  return TheDwarfEmitter.get(); +} + +void DWARFLinkerImpl::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader, +                                    CompileUnitHandlerTy OnCUDieLoaded) { +  ObjectContexts.emplace_back(std::make_unique<LinkContext>( +      GlobalData, File, ClangModules, UniqueUnitID, +      (TheDwarfEmitter.get() == nullptr ? std::optional<Triple>(std::nullopt) +                                        : TheDwarfEmitter->getTargetTriple()))); + +  if (ObjectContexts.back()->InputDWARFFile.Dwarf) { +    for (const std::unique_ptr<DWARFUnit> &CU : +         ObjectContexts.back()->InputDWARFFile.Dwarf->compile_units()) { +      DWARFDie CUDie = CU->getUnitDIE(); +      OverallNumberOfCU++; + +      if (!CUDie) +        continue; + +      OnCUDieLoaded(*CU); + +      // Register mofule reference. +      if (!GlobalData.getOptions().UpdateIndexTablesOnly) +        ObjectContexts.back()->registerModuleReference(CUDie, Loader, +                                                       OnCUDieLoaded); +    } +  } +} + +void DWARFLinkerImpl::setEstimatedObjfilesAmount(unsigned ObjFilesNum) { +  ObjectContexts.reserve(ObjFilesNum); +} + +Error DWARFLinkerImpl::link() { +  // reset compile unit unique ID counter. +  UniqueUnitID = 0; + +  if (Error Err = validateAndUpdateOptions()) +    return Err; + +  dwarf::FormParams GlobalFormat = {GlobalData.getOptions().TargetDWARFVersion, +                                    0, dwarf::DwarfFormat::DWARF32}; +  llvm::endianness GlobalEndianness = llvm::endianness::native; + +  if (TheDwarfEmitter) { +    GlobalEndianness = TheDwarfEmitter->getTargetTriple().isLittleEndian() +                           ? llvm::endianness::little +                           : llvm::endianness::big; +  } +  std::optional<uint16_t> Language; + +  for (std::unique_ptr<LinkContext> &Context : ObjectContexts) { +    if (Context->InputDWARFFile.Dwarf.get() == nullptr) { +      Context->setOutputFormat(Context->getFormParams(), GlobalEndianness); +      continue; +    } + +    if (GlobalData.getOptions().Verbose) { +      outs() << "OBJECT: " << Context->InputDWARFFile.FileName << "\n"; + +      for (const std::unique_ptr<DWARFUnit> &OrigCU : +           Context->InputDWARFFile.Dwarf->compile_units()) { +        outs() << "Input compilation unit:"; +        DIDumpOptions DumpOpts; +        DumpOpts.ChildRecurseDepth = 0; +        DumpOpts.Verbose = GlobalData.getOptions().Verbose; +        OrigCU->getUnitDIE().dump(outs(), 0, DumpOpts); +      } +    } + +    // Verify input DWARF if requested. +    if (GlobalData.getOptions().VerifyInputDWARF) +      verifyInput(Context->InputDWARFFile); + +    if (!TheDwarfEmitter) +      GlobalEndianness = Context->getEndianness(); +    GlobalFormat.AddrSize = +        std::max(GlobalFormat.AddrSize, Context->getFormParams().AddrSize); + +    Context->setOutputFormat(Context->getFormParams(), GlobalEndianness); + +    // FIXME: move creation of CompileUnits into the addObjectFile. +    // This would allow to not scan for context Language and Modules state +    // twice. And then following handling might be removed. +    for (const std::unique_ptr<DWARFUnit> &OrigCU : +         Context->InputDWARFFile.Dwarf->compile_units()) { +      DWARFDie UnitDie = OrigCU.get()->getUnitDIE(); + +      if (!Language) { +        if (std::optional<DWARFFormValue> Val = +                UnitDie.find(dwarf::DW_AT_language)) { +          uint16_t LangVal = dwarf::toUnsigned(Val, 0); +          if (isODRLanguage(LangVal)) +            Language = LangVal; +        } +      } +    } +  } + +  if (GlobalFormat.AddrSize == 0) { +    if (TheDwarfEmitter) +      GlobalFormat.AddrSize = +          TheDwarfEmitter->getTargetTriple().isArch32Bit() ? 4 : 8; +    else +      GlobalFormat.AddrSize = 8; +  } + +  CommonSections.setOutputFormat(GlobalFormat, GlobalEndianness); + +  if (!GlobalData.Options.NoODR && Language.has_value()) { +    llvm::parallel::TaskGroup TGroup; +    TGroup.spawn([&]() { +      ArtificialTypeUnit = std::make_unique<TypeUnit>( +          GlobalData, UniqueUnitID++, Language, GlobalFormat, GlobalEndianness); +    }); +  } + +  // Set parallel options. +  if (GlobalData.getOptions().Threads == 0) +    llvm::parallel::strategy = optimal_concurrency(OverallNumberOfCU); +  else +    llvm::parallel::strategy = +        hardware_concurrency(GlobalData.getOptions().Threads); + +  // Link object files. +  if (GlobalData.getOptions().Threads == 1) { +    for (std::unique_ptr<LinkContext> &Context : ObjectContexts) { +      // Link object file. +      if (Error Err = Context->link(ArtificialTypeUnit.get())) +        GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName); + +      Context->InputDWARFFile.unload(); +    } +  } else { +    ThreadPool Pool(llvm::parallel::strategy); +    for (std::unique_ptr<LinkContext> &Context : ObjectContexts) +      Pool.async([&]() { +        // Link object file. +        if (Error Err = Context->link(ArtificialTypeUnit.get())) +          GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName); + +        Context->InputDWARFFile.unload(); +      }); + +    Pool.wait(); +  } + +  if (ArtificialTypeUnit.get() != nullptr && !ArtificialTypeUnit->getTypePool() +                                                  .getRoot() +                                                  ->getValue() +                                                  .load() +                                                  ->Children.empty()) { +    std::optional<Triple> OutTriple = TheDwarfEmitter.get() == nullptr +                                          ? std::optional<Triple>(std::nullopt) +                                          : TheDwarfEmitter->getTargetTriple(); + +    if (Error Err = ArtificialTypeUnit.get()->finishCloningAndEmit(OutTriple)) +      return Err; +  } + +  // At this stage each compile units are cloned to their own set of debug +  // sections. Now, update patches, assign offsets and assemble final file +  // glueing debug tables from each compile unit. +  glueCompileUnitsAndWriteToTheOutput(); + +  return Error::success(); +} + +void DWARFLinkerImpl::verifyInput(const DWARFFile &File) { +  assert(File.Dwarf); + +  std::string Buffer; +  raw_string_ostream OS(Buffer); +  DIDumpOptions DumpOpts; +  if (!File.Dwarf->verify(OS, DumpOpts.noImplicitRecursion())) { +    if (GlobalData.getOptions().InputVerificationHandler) +      GlobalData.getOptions().InputVerificationHandler(File, OS.str()); +  } +} + +Error DWARFLinkerImpl::validateAndUpdateOptions() { +  if (GlobalData.getOptions().TargetDWARFVersion == 0) +    return createStringError(std::errc::invalid_argument, +                             "target DWARF version is not set"); + +  GlobalData.Options.NoOutput = TheDwarfEmitter.get() == nullptr; + +  if (GlobalData.getOptions().Verbose && GlobalData.getOptions().Threads != 1) { +    GlobalData.Options.Threads = 1; +    GlobalData.warn( +        "set number of threads to 1 to make --verbose to work properly.", ""); +  } + +  // Do not do types deduplication in case --update. +  if (GlobalData.getOptions().UpdateIndexTablesOnly && +      !GlobalData.Options.NoODR) +    GlobalData.Options.NoODR = true; + +  return Error::success(); +} + +/// Resolve the relative path to a build artifact referenced by DWARF by +/// applying DW_AT_comp_dir. +static void resolveRelativeObjectPath(SmallVectorImpl<char> &Buf, DWARFDie CU) { +  sys::path::append(Buf, dwarf::toString(CU.find(dwarf::DW_AT_comp_dir), "")); +} + +static uint64_t getDwoId(const DWARFDie &CUDie) { +  auto DwoId = dwarf::toUnsigned( +      CUDie.find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id})); +  if (DwoId) +    return *DwoId; +  return 0; +} + +static std::string +remapPath(StringRef Path, +          const DWARFLinker::ObjectPrefixMapTy &ObjectPrefixMap) { +  if (ObjectPrefixMap.empty()) +    return Path.str(); + +  SmallString<256> p = Path; +  for (const auto &Entry : ObjectPrefixMap) +    if (llvm::sys::path::replace_path_prefix(p, Entry.first, Entry.second)) +      break; +  return p.str().str(); +} + +static std::string getPCMFile(const DWARFDie &CUDie, +                              DWARFLinker::ObjectPrefixMapTy *ObjectPrefixMap) { +  std::string PCMFile = dwarf::toString( +      CUDie.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), ""); + +  if (PCMFile.empty()) +    return PCMFile; + +  if (ObjectPrefixMap) +    PCMFile = remapPath(PCMFile, *ObjectPrefixMap); + +  return PCMFile; +} + +std::pair<bool, bool> DWARFLinkerImpl::LinkContext::isClangModuleRef( +    const DWARFDie &CUDie, std::string &PCMFile, unsigned Indent, bool Quiet) { +  if (PCMFile.empty()) +    return std::make_pair(false, false); + +  // Clang module DWARF skeleton CUs abuse this for the path to the module. +  uint64_t DwoId = getDwoId(CUDie); + +  std::string Name = dwarf::toString(CUDie.find(dwarf::DW_AT_name), ""); +  if (Name.empty()) { +    if (!Quiet) +      GlobalData.warn("anonymous module skeleton CU for " + PCMFile + ".", +                      InputDWARFFile.FileName); +    return std::make_pair(true, true); +  } + +  if (!Quiet && GlobalData.getOptions().Verbose) { +    outs().indent(Indent); +    outs() << "Found clang module reference " << PCMFile; +  } + +  auto Cached = ClangModules.find(PCMFile); +  if (Cached != ClangModules.end()) { +    // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is +    // fixed in clang, only warn about DWO_id mismatches in verbose mode. +    // ASTFileSignatures will change randomly when a module is rebuilt. +    if (!Quiet && GlobalData.getOptions().Verbose && (Cached->second != DwoId)) +      GlobalData.warn( +          Twine("hash mismatch: this object file was built against a " +                "different version of the module ") + +              PCMFile + ".", +          InputDWARFFile.FileName); +    if (!Quiet && GlobalData.getOptions().Verbose) +      outs() << " [cached].\n"; +    return std::make_pair(true, true); +  } + +  return std::make_pair(true, false); +} + +/// If this compile unit is really a skeleton CU that points to a +/// clang module, register it in ClangModules and return true. +/// +/// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name +/// pointing to the module, and a DW_AT_gnu_dwo_id with the module +/// hash. +bool DWARFLinkerImpl::LinkContext::registerModuleReference( +    const DWARFDie &CUDie, ObjFileLoaderTy Loader, +    CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) { +  std::string PCMFile = +      getPCMFile(CUDie, GlobalData.getOptions().ObjectPrefixMap); +  std::pair<bool, bool> IsClangModuleRef = +      isClangModuleRef(CUDie, PCMFile, Indent, false); + +  if (!IsClangModuleRef.first) +    return false; + +  if (IsClangModuleRef.second) +    return true; + +  if (GlobalData.getOptions().Verbose) +    outs() << " ...\n"; + +  // Cyclic dependencies are disallowed by Clang, but we still +  // shouldn't run into an infinite loop, so mark it as processed now. +  ClangModules.insert({PCMFile, getDwoId(CUDie)}); + +  if (Error E = +          loadClangModule(Loader, CUDie, PCMFile, OnCUDieLoaded, Indent + 2)) { +    consumeError(std::move(E)); +    return false; +  } +  return true; +} + +Error DWARFLinkerImpl::LinkContext::loadClangModule( +    ObjFileLoaderTy Loader, const DWARFDie &CUDie, const std::string &PCMFile, +    CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) { + +  uint64_t DwoId = getDwoId(CUDie); +  std::string ModuleName = dwarf::toString(CUDie.find(dwarf::DW_AT_name), ""); + +  /// Using a SmallString<0> because loadClangModule() is recursive. +  SmallString<0> Path(GlobalData.getOptions().PrependPath); +  if (sys::path::is_relative(PCMFile)) +    resolveRelativeObjectPath(Path, CUDie); +  sys::path::append(Path, PCMFile); +  // Don't use the cached binary holder because we have no thread-safety +  // guarantee and the lifetime is limited. + +  if (Loader == nullptr) { +    GlobalData.error("cann't load clang module: loader is not specified.", +                     InputDWARFFile.FileName); +    return Error::success(); +  } + +  auto ErrOrObj = Loader(InputDWARFFile.FileName, Path); +  if (!ErrOrObj) +    return Error::success(); + +  std::unique_ptr<CompileUnit> Unit; +  for (const auto &CU : ErrOrObj->Dwarf->compile_units()) { +    OnCUDieLoaded(*CU); +    // Recursively get all modules imported by this one. +    auto ChildCUDie = CU->getUnitDIE(); +    if (!ChildCUDie) +      continue; +    if (!registerModuleReference(ChildCUDie, Loader, OnCUDieLoaded, Indent)) { +      if (Unit) { +        std::string Err = +            (PCMFile + +             ": Clang modules are expected to have exactly 1 compile unit.\n"); +        GlobalData.error(Err, InputDWARFFile.FileName); +        return make_error<StringError>(Err, inconvertibleErrorCode()); +      } +      // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is +      // fixed in clang, only warn about DWO_id mismatches in verbose mode. +      // ASTFileSignatures will change randomly when a module is rebuilt. +      uint64_t PCMDwoId = getDwoId(ChildCUDie); +      if (PCMDwoId != DwoId) { +        if (GlobalData.getOptions().Verbose) +          GlobalData.warn( +              Twine("hash mismatch: this object file was built against a " +                    "different version of the module ") + +                  PCMFile + ".", +              InputDWARFFile.FileName); +        // Update the cache entry with the DwoId of the module loaded from disk. +        ClangModules[PCMFile] = PCMDwoId; +      } + +      // Empty modules units should not be cloned. +      if (!ChildCUDie.hasChildren()) +        continue; + +      // Add this module. +      Unit = std::make_unique<CompileUnit>( +          GlobalData, *CU, UniqueUnitID.fetch_add(1), ModuleName, *ErrOrObj, +          getUnitForOffset, CU->getFormParams(), getEndianness()); +    } +  } + +  if (Unit) { +    ModulesCompileUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)}); +    // Preload line table, as it can't be loaded asynchronously. +    ModulesCompileUnits.back().Unit->loadLineTable(); +  } + +  return Error::success(); +} + +Error DWARFLinkerImpl::LinkContext::link(TypeUnit *ArtificialTypeUnit) { +  InterCUProcessingStarted = false; +  if (!InputDWARFFile.Dwarf) +    return Error::success(); + +  // Preload macro tables, as they can't be loaded asynchronously. +  InputDWARFFile.Dwarf->getDebugMacinfo(); +  InputDWARFFile.Dwarf->getDebugMacro(); + +  // Link modules compile units first. +  parallelForEach(ModulesCompileUnits, [&](RefModuleUnit &RefModule) { +    linkSingleCompileUnit(*RefModule.Unit, ArtificialTypeUnit); +  }); + +  // Check for live relocations. If there is no any live relocation then we +  // can skip entire object file. +  if (!GlobalData.getOptions().UpdateIndexTablesOnly && +      !InputDWARFFile.Addresses->hasValidRelocs()) { +    if (GlobalData.getOptions().Verbose) +      outs() << "No valid relocations found. Skipping.\n"; +    return Error::success(); +  } + +  OriginalDebugInfoSize = getInputDebugInfoSize(); + +  // Create CompileUnit structures to keep information about source +  // DWARFUnit`s, load line tables. +  for (const auto &OrigCU : InputDWARFFile.Dwarf->compile_units()) { +    // Load only unit DIE at this stage. +    auto CUDie = OrigCU->getUnitDIE(); +    std::string PCMFile = +        getPCMFile(CUDie, GlobalData.getOptions().ObjectPrefixMap); + +    // The !isClangModuleRef condition effectively skips over fully resolved +    // skeleton units. +    if (!CUDie || GlobalData.getOptions().UpdateIndexTablesOnly || +        !isClangModuleRef(CUDie, PCMFile, 0, true).first) { +      CompileUnits.emplace_back(std::make_unique<CompileUnit>( +          GlobalData, *OrigCU, UniqueUnitID.fetch_add(1), "", InputDWARFFile, +          getUnitForOffset, OrigCU->getFormParams(), getEndianness())); + +      // Preload line table, as it can't be loaded asynchronously. +      CompileUnits.back()->loadLineTable(); +    } +  }; + +  HasNewInterconnectedCUs = false; + +  // Link self-sufficient compile units and discover inter-connected compile +  // units. +  parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) { +    linkSingleCompileUnit(*CU, ArtificialTypeUnit); +  }); + +  // Link all inter-connected units. +  if (HasNewInterconnectedCUs) { +    InterCUProcessingStarted = true; + +    if (Error Err = finiteLoop([&]() -> Expected<bool> { +          HasNewInterconnectedCUs = false; + +          // Load inter-connected units. +          parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) { +            if (CU->isInterconnectedCU()) { +              CU->maybeResetToLoadedStage(); +              linkSingleCompileUnit(*CU, ArtificialTypeUnit, +                                    CompileUnit::Stage::Loaded); +            } +          }); + +          // Do liveness analysis for inter-connected units. +          parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) { +            linkSingleCompileUnit(*CU, ArtificialTypeUnit, +                                  CompileUnit::Stage::LivenessAnalysisDone); +          }); + +          return HasNewInterconnectedCUs.load(); +        })) +      return Err; + +    // Update dependencies. +    if (Error Err = finiteLoop([&]() -> Expected<bool> { +          HasNewGlobalDependency = false; +          parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) { +            linkSingleCompileUnit( +                *CU, ArtificialTypeUnit, +                CompileUnit::Stage::UpdateDependenciesCompleteness); +          }); +          return HasNewGlobalDependency.load(); +        })) +      return Err; +    parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) { +      if (CU->isInterconnectedCU() && +          CU->getStage() == CompileUnit::Stage::LivenessAnalysisDone) +        CU->setStage(CompileUnit::Stage::UpdateDependenciesCompleteness); +    }); + +    // Assign type names. +    parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) { +      linkSingleCompileUnit(*CU, ArtificialTypeUnit, +                            CompileUnit::Stage::TypeNamesAssigned); +    }); + +    // Clone inter-connected units. +    parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) { +      linkSingleCompileUnit(*CU, ArtificialTypeUnit, +                            CompileUnit::Stage::Cloned); +    }); + +    // Update patches for inter-connected units. +    parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) { +      linkSingleCompileUnit(*CU, ArtificialTypeUnit, +                            CompileUnit::Stage::PatchesUpdated); +    }); + +    // Release data. +    parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) { +      linkSingleCompileUnit(*CU, ArtificialTypeUnit, +                            CompileUnit::Stage::Cleaned); +    }); +  } + +  if (GlobalData.getOptions().UpdateIndexTablesOnly) { +    // Emit Invariant sections. + +    if (Error Err = emitInvariantSections()) +      return Err; +  } else if (!CompileUnits.empty()) { +    // Emit .debug_frame section. + +    Error ResultErr = Error::success(); +    llvm::parallel::TaskGroup TGroup; +    // We use task group here as PerThreadBumpPtrAllocator should be called from +    // the threads created by ThreadPoolExecutor. +    TGroup.spawn([&]() { +      if (Error Err = cloneAndEmitDebugFrame()) +        ResultErr = std::move(Err); +    }); +    return ResultErr; +  } + +  return Error::success(); +} + +void DWARFLinkerImpl::LinkContext::linkSingleCompileUnit( +    CompileUnit &CU, TypeUnit *ArtificialTypeUnit, +    enum CompileUnit::Stage DoUntilStage) { +  if (InterCUProcessingStarted != CU.isInterconnectedCU()) +    return; + +  if (Error Err = finiteLoop([&]() -> Expected<bool> { +        if (CU.getStage() >= DoUntilStage) +          return false; + +        switch (CU.getStage()) { +        case CompileUnit::Stage::CreatedNotLoaded: { +          // Load input compilation unit DIEs. +          // Analyze properties of DIEs. +          if (!CU.loadInputDIEs()) { +            // We do not need to do liveness analysis for invalid compilation +            // unit. +            CU.setStage(CompileUnit::Stage::Skipped); +          } else { +            CU.analyzeDWARFStructure(); + +            // The registerModuleReference() condition effectively skips +            // over fully resolved skeleton units. This second pass of +            // registerModuleReferences doesn't do any new work, but it +            // will collect top-level errors, which are suppressed. Module +            // warnings were already displayed in the first iteration. +            if (registerModuleReference( +                    CU.getOrigUnit().getUnitDIE(), nullptr, +                    [](const DWARFUnit &) {}, 0)) +              CU.setStage(CompileUnit::Stage::PatchesUpdated); +            else +              CU.setStage(CompileUnit::Stage::Loaded); +          } +        } break; + +        case CompileUnit::Stage::Loaded: { +          // Mark all the DIEs that need to be present in the generated output. +          // If ODR requested, build type names. +          if (!CU.resolveDependenciesAndMarkLiveness(InterCUProcessingStarted, +                                                     HasNewInterconnectedCUs)) { +            assert(HasNewInterconnectedCUs && +                   "Flag indicating new inter-connections is not set"); +            return false; +          } + +          CU.setStage(CompileUnit::Stage::LivenessAnalysisDone); +        } break; + +        case CompileUnit::Stage::LivenessAnalysisDone: { +          if (InterCUProcessingStarted) { +            if (CU.updateDependenciesCompleteness()) +              HasNewGlobalDependency = true; +            return false; +          } else { +            if (Error Err = finiteLoop([&]() -> Expected<bool> { +                  return CU.updateDependenciesCompleteness(); +                })) +              return std::move(Err); + +            CU.setStage(CompileUnit::Stage::UpdateDependenciesCompleteness); +          } +        } break; + +        case CompileUnit::Stage::UpdateDependenciesCompleteness: +#ifndef NDEBUG +          CU.verifyDependencies(); +#endif + +          if (ArtificialTypeUnit) { +            if (Error Err = +                    CU.assignTypeNames(ArtificialTypeUnit->getTypePool())) +              return std::move(Err); +          } +          CU.setStage(CompileUnit::Stage::TypeNamesAssigned); +          break; + +        case CompileUnit::Stage::TypeNamesAssigned: +          // Clone input compile unit. +          if (CU.isClangModule() || +              GlobalData.getOptions().UpdateIndexTablesOnly || +              CU.getContaingFile().Addresses->hasValidRelocs()) { +            if (Error Err = CU.cloneAndEmit(TargetTriple, ArtificialTypeUnit)) +              return std::move(Err); +          } + +          CU.setStage(CompileUnit::Stage::Cloned); +          break; + +        case CompileUnit::Stage::Cloned: +          // Update DIEs referencies. +          CU.updateDieRefPatchesWithClonedOffsets(); +          CU.setStage(CompileUnit::Stage::PatchesUpdated); +          break; + +        case CompileUnit::Stage::PatchesUpdated: +          // Cleanup resources. +          CU.cleanupDataAfterClonning(); +          CU.setStage(CompileUnit::Stage::Cleaned); +          break; + +        case CompileUnit::Stage::Cleaned: +          assert(false); +          break; + +        case CompileUnit::Stage::Skipped: +          // Nothing to do. +          break; +        } + +        return true; +      })) { +    CU.error(std::move(Err)); +    CU.cleanupDataAfterClonning(); +    CU.setStage(CompileUnit::Stage::Skipped); +  } +} + +Error DWARFLinkerImpl::LinkContext::emitInvariantSections() { +  if (GlobalData.getOptions().NoOutput) +    return Error::success(); + +  getOrCreateSectionDescriptor(DebugSectionKind::DebugLoc).OS +      << InputDWARFFile.Dwarf->getDWARFObj().getLocSection().Data; +  getOrCreateSectionDescriptor(DebugSectionKind::DebugLocLists).OS +      << InputDWARFFile.Dwarf->getDWARFObj().getLoclistsSection().Data; +  getOrCreateSectionDescriptor(DebugSectionKind::DebugRange).OS +      << InputDWARFFile.Dwarf->getDWARFObj().getRangesSection().Data; +  getOrCreateSectionDescriptor(DebugSectionKind::DebugRngLists).OS +      << InputDWARFFile.Dwarf->getDWARFObj().getRnglistsSection().Data; +  getOrCreateSectionDescriptor(DebugSectionKind::DebugARanges).OS +      << InputDWARFFile.Dwarf->getDWARFObj().getArangesSection(); +  getOrCreateSectionDescriptor(DebugSectionKind::DebugFrame).OS +      << InputDWARFFile.Dwarf->getDWARFObj().getFrameSection().Data; +  getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr).OS +      << InputDWARFFile.Dwarf->getDWARFObj().getAddrSection().Data; + +  return Error::success(); +} + +Error DWARFLinkerImpl::LinkContext::cloneAndEmitDebugFrame() { +  if (GlobalData.getOptions().NoOutput) +    return Error::success(); + +  if (InputDWARFFile.Dwarf.get() == nullptr) +    return Error::success(); + +  const DWARFObject &InputDWARFObj = InputDWARFFile.Dwarf->getDWARFObj(); + +  StringRef OrigFrameData = InputDWARFObj.getFrameSection().Data; +  if (OrigFrameData.empty()) +    return Error::success(); + +  RangesTy AllUnitsRanges; +  for (std::unique_ptr<CompileUnit> &Unit : CompileUnits) { +    for (auto CurRange : Unit->getFunctionRanges()) +      AllUnitsRanges.insert(CurRange.Range, CurRange.Value); +  } + +  unsigned SrcAddrSize = InputDWARFObj.getAddressSize(); + +  SectionDescriptor &OutSection = +      getOrCreateSectionDescriptor(DebugSectionKind::DebugFrame); + +  DataExtractor Data(OrigFrameData, InputDWARFObj.isLittleEndian(), 0); +  uint64_t InputOffset = 0; + +  // Store the data of the CIEs defined in this object, keyed by their +  // offsets. +  DenseMap<uint64_t, StringRef> LocalCIES; + +  /// The CIEs that have been emitted in the output section. The actual CIE +  /// data serves a the key to this StringMap. +  StringMap<uint32_t> EmittedCIEs; + +  while (Data.isValidOffset(InputOffset)) { +    uint64_t EntryOffset = InputOffset; +    uint32_t InitialLength = Data.getU32(&InputOffset); +    if (InitialLength == 0xFFFFFFFF) +      return createFileError(InputDWARFObj.getFileName(), +                             createStringError(std::errc::invalid_argument, +                                               "Dwarf64 bits no supported")); + +    uint32_t CIEId = Data.getU32(&InputOffset); +    if (CIEId == 0xFFFFFFFF) { +      // This is a CIE, store it. +      StringRef CIEData = OrigFrameData.substr(EntryOffset, InitialLength + 4); +      LocalCIES[EntryOffset] = CIEData; +      // The -4 is to account for the CIEId we just read. +      InputOffset += InitialLength - 4; +      continue; +    } + +    uint64_t Loc = Data.getUnsigned(&InputOffset, SrcAddrSize); + +    // Some compilers seem to emit frame info that doesn't start at +    // the function entry point, thus we can't just lookup the address +    // in the debug map. Use the AddressInfo's range map to see if the FDE +    // describes something that we can relocate. +    std::optional<AddressRangeValuePair> Range = +        AllUnitsRanges.getRangeThatContains(Loc); +    if (!Range) { +      // The +4 is to account for the size of the InitialLength field itself. +      InputOffset = EntryOffset + InitialLength + 4; +      continue; +    } + +    // This is an FDE, and we have a mapping. +    // Have we already emitted a corresponding CIE? +    StringRef CIEData = LocalCIES[CIEId]; +    if (CIEData.empty()) +      return createFileError( +          InputDWARFObj.getFileName(), +          createStringError(std::errc::invalid_argument, +                            "Inconsistent debug_frame content. Dropping.")); + +    uint64_t OffsetToCIERecord = OutSection.OS.tell(); + +    // Look if we already emitted a CIE that corresponds to the +    // referenced one (the CIE data is the key of that lookup). +    auto IteratorInserted = +        EmittedCIEs.insert(std::make_pair(CIEData, OffsetToCIERecord)); +    OffsetToCIERecord = IteratorInserted.first->getValue(); + +    // Emit CIE for this ID if it is not emitted yet. +    if (IteratorInserted.second) +      OutSection.OS << CIEData; + +    // Remember offset to the FDE record, so that we might update +    // field referencing CIE record(containing OffsetToCIERecord), +    // when final offsets are known. OffsetToCIERecord(which is written later) +    // is local to the current .debug_frame section, it should be updated +    // with final offset of the .debug_frame section. +    OutSection.notePatch( +        DebugOffsetPatch{OutSection.OS.tell() + 4, &OutSection, true}); + +    // Emit the FDE with updated address and CIE pointer. +    // (4 + AddrSize) is the size of the CIEId + initial_location +    // fields that will get reconstructed by emitFDE(). +    unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize); +    emitFDE(OffsetToCIERecord, SrcAddrSize, Loc + Range->Value, +            OrigFrameData.substr(InputOffset, FDERemainingBytes), OutSection); +    InputOffset += FDERemainingBytes; +  } + +  return Error::success(); +} + +/// Emit a FDE into the debug_frame section. \p FDEBytes +/// contains the FDE data without the length, CIE offset and address +/// which will be replaced with the parameter values. +void DWARFLinkerImpl::LinkContext::emitFDE(uint32_t CIEOffset, +                                           uint32_t AddrSize, uint64_t Address, +                                           StringRef FDEBytes, +                                           SectionDescriptor &Section) { +  Section.emitIntVal(FDEBytes.size() + 4 + AddrSize, 4); +  Section.emitIntVal(CIEOffset, 4); +  Section.emitIntVal(Address, AddrSize); +  Section.OS.write(FDEBytes.data(), FDEBytes.size()); +} + +void DWARFLinkerImpl::glueCompileUnitsAndWriteToTheOutput() { +  if (GlobalData.getOptions().NoOutput) +    return; + +  // Go through all object files, all compile units and assign +  // offsets to them. +  assignOffsets(); + +  // Patch size/offsets fields according to the assigned CU offsets. +  patchOffsetsAndSizes(); + +  // Emit common sections and write debug tables from all object files/compile +  // units into the resulting file. +  emitCommonSectionsAndWriteCompileUnitsToTheOutput(); + +  if (ArtificialTypeUnit.get() != nullptr) +    ArtificialTypeUnit.reset(); + +  // Write common debug sections into the resulting file. +  writeCommonSectionsToTheOutput(); + +  // Cleanup data. +  cleanupDataAfterDWARFOutputIsWritten(); + +  if (GlobalData.getOptions().Statistics) +    printStatistic(); +} + +void DWARFLinkerImpl::printStatistic() { + +  // For each object file map how many bytes were emitted. +  StringMap<DebugInfoSize> SizeByObject; + +  for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) { +    uint64_t AllDebugInfoSectionsSize = 0; + +    for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) +      if (std::optional<SectionDescriptor *> DebugInfo = +              CU->tryGetSectionDescriptor(DebugSectionKind::DebugInfo)) +        AllDebugInfoSectionsSize += (*DebugInfo)->getContents().size(); + +    SizeByObject[Context->InputDWARFFile.FileName].Input = +        Context->OriginalDebugInfoSize; +    SizeByObject[Context->InputDWARFFile.FileName].Output = +        AllDebugInfoSectionsSize; +  } + +  // Create a vector sorted in descending order by output size. +  std::vector<std::pair<StringRef, DebugInfoSize>> Sorted; +  for (auto &E : SizeByObject) +    Sorted.emplace_back(E.first(), E.second); +  llvm::sort(Sorted, [](auto &LHS, auto &RHS) { +    return LHS.second.Output > RHS.second.Output; +  }); + +  auto ComputePercentange = [](int64_t Input, int64_t Output) -> float { +    const float Difference = Output - Input; +    const float Sum = Input + Output; +    if (Sum == 0) +      return 0; +    return (Difference / (Sum / 2)); +  }; + +  int64_t InputTotal = 0; +  int64_t OutputTotal = 0; +  const char *FormatStr = "{0,-45} {1,10}b  {2,10}b {3,8:P}\n"; + +  // Print header. +  outs() << ".debug_info section size (in bytes)\n"; +  outs() << "----------------------------------------------------------------" +            "---------------\n"; +  outs() << "Filename                                           Object       " +            "  dSYM   Change\n"; +  outs() << "----------------------------------------------------------------" +            "---------------\n"; + +  // Print body. +  for (auto &E : Sorted) { +    InputTotal += E.second.Input; +    OutputTotal += E.second.Output; +    llvm::outs() << formatv( +        FormatStr, sys::path::filename(E.first).take_back(45), E.second.Input, +        E.second.Output, ComputePercentange(E.second.Input, E.second.Output)); +  } +  // Print total and footer. +  outs() << "----------------------------------------------------------------" +            "---------------\n"; +  llvm::outs() << formatv(FormatStr, "Total", InputTotal, OutputTotal, +                          ComputePercentange(InputTotal, OutputTotal)); +  outs() << "----------------------------------------------------------------" +            "---------------\n\n"; +} + +void DWARFLinkerImpl::assignOffsets() { +  llvm::parallel::TaskGroup TGroup; +  TGroup.spawn([&]() { assignOffsetsToStrings(); }); +  TGroup.spawn([&]() { assignOffsetsToSections(); }); +} + +void DWARFLinkerImpl::assignOffsetsToStrings() { +  size_t CurDebugStrIndex = 1; // start from 1 to take into account zero entry. +  uint64_t CurDebugStrOffset = +      1; // start from 1 to take into account zero entry. +  size_t CurDebugLineStrIndex = 0; +  uint64_t CurDebugLineStrOffset = 0; + +  // Enumerates all strings, add them into the DwarfStringPoolEntry map, +  // assign offset and index to the string if it is not indexed yet. +  forEachOutputString([&](StringDestinationKind Kind, +                          const StringEntry *String) { +    switch (Kind) { +    case StringDestinationKind::DebugStr: { +      DwarfStringPoolEntryWithExtString *Entry = DebugStrStrings.add(String); +      assert(Entry != nullptr); + +      if (!Entry->isIndexed()) { +        Entry->Offset = CurDebugStrOffset; +        CurDebugStrOffset += Entry->String.size() + 1; +        Entry->Index = CurDebugStrIndex++; +      } +    } break; +    case StringDestinationKind::DebugLineStr: { +      DwarfStringPoolEntryWithExtString *Entry = +          DebugLineStrStrings.add(String); +      assert(Entry != nullptr); + +      if (!Entry->isIndexed()) { +        Entry->Offset = CurDebugLineStrOffset; +        CurDebugLineStrOffset += Entry->String.size() + 1; +        Entry->Index = CurDebugLineStrIndex++; +      } +    } break; +    } +  }); +} + +void DWARFLinkerImpl::assignOffsetsToSections() { +  std::array<uint64_t, SectionKindsNum> SectionSizesAccumulator = {0}; + +  forEachObjectSectionsSet([&](OutputSections &UnitSections) { +    UnitSections.assignSectionsOffsetAndAccumulateSize(SectionSizesAccumulator); +  }); +} + +void DWARFLinkerImpl::forEachOutputString( +    function_ref<void(StringDestinationKind Kind, const StringEntry *String)> +        StringHandler) { +  // To save space we do not create any separate string table. +  // We use already allocated string patches and accelerator entries: +  // enumerate them in natural order and assign offsets. +  // ASSUMPTION: strings should be stored into .debug_str/.debug_line_str +  // sections in the same order as they were assigned offsets. +  forEachCompileUnit([&](CompileUnit *CU) { +    CU->forEach([&](SectionDescriptor &OutSection) { +      OutSection.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) { +        StringHandler(StringDestinationKind::DebugStr, Patch.String); +      }); + +      OutSection.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) { +        StringHandler(StringDestinationKind::DebugLineStr, Patch.String); +      }); +    }); + +    CU->forEachAcceleratorRecord([&](DwarfUnit::AccelInfo &Info) { +      StringHandler(DebugStr, Info.String); +    }); +  }); + +  if (ArtificialTypeUnit.get() != nullptr) { +    ArtificialTypeUnit->forEach([&](SectionDescriptor &OutSection) { +      OutSection.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) { +        StringHandler(StringDestinationKind::DebugStr, Patch.String); +      }); + +      OutSection.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) { +        StringHandler(StringDestinationKind::DebugLineStr, Patch.String); +      }); + +      OutSection.ListDebugTypeStrPatch.forEach([&](DebugTypeStrPatch &Patch) { +        if (Patch.Die == nullptr) +          return; + +        StringHandler(StringDestinationKind::DebugStr, Patch.String); +      }); + +      OutSection.ListDebugTypeLineStrPatch.forEach( +          [&](DebugTypeLineStrPatch &Patch) { +            if (Patch.Die == nullptr) +              return; + +            StringHandler(StringDestinationKind::DebugStr, Patch.String); +          }); +    }); +  } +} + +void DWARFLinkerImpl::forEachObjectSectionsSet( +    function_ref<void(OutputSections &)> SectionsSetHandler) { +  // Handle artificial type unit first. +  if (ArtificialTypeUnit.get() != nullptr) +    SectionsSetHandler(*ArtificialTypeUnit); + +  // Then all modules(before regular compilation units). +  for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) +    for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) +      if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) +        SectionsSetHandler(*ModuleUnit.Unit); + +  // Finally all compilation units. +  for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) { +    // Handle object file common sections. +    SectionsSetHandler(*Context); + +    // Handle compilation units. +    for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) +      if (CU->getStage() != CompileUnit::Stage::Skipped) +        SectionsSetHandler(*CU); +  } +} + +void DWARFLinkerImpl::forEachCompileAndTypeUnit( +    function_ref<void(DwarfUnit *CU)> UnitHandler) { +  if (ArtificialTypeUnit.get() != nullptr) +    UnitHandler(ArtificialTypeUnit.get()); + +  // Enumerate module units. +  for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) +    for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) +      if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) +        UnitHandler(ModuleUnit.Unit.get()); + +  // Enumerate compile units. +  for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) +    for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) +      if (CU->getStage() != CompileUnit::Stage::Skipped) +        UnitHandler(CU.get()); +} + +void DWARFLinkerImpl::forEachCompileUnit( +    function_ref<void(CompileUnit *CU)> UnitHandler) { +  // Enumerate module units. +  for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) +    for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) +      if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) +        UnitHandler(ModuleUnit.Unit.get()); + +  // Enumerate compile units. +  for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) +    for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits) +      if (CU->getStage() != CompileUnit::Stage::Skipped) +        UnitHandler(CU.get()); +} + +void DWARFLinkerImpl::patchOffsetsAndSizes() { +  forEachObjectSectionsSet([&](OutputSections &SectionsSet) { +    SectionsSet.forEach([&](SectionDescriptor &OutSection) { +      SectionsSet.applyPatches(OutSection, DebugStrStrings, DebugLineStrStrings, +                               ArtificialTypeUnit.get()); +    }); +  }); +} + +void DWARFLinkerImpl::emitCommonSectionsAndWriteCompileUnitsToTheOutput() { +  llvm::parallel::TaskGroup TG; + +  // Create section descriptors ahead if they are not exist at the moment. +  // SectionDescriptors container is not thread safe. Thus we should be sure +  // that descriptors would not be created in following parallel tasks. + +  CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::DebugStr); +  CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::DebugLineStr); + +  if (llvm::is_contained(GlobalData.Options.AccelTables, +                         AccelTableKind::Apple)) { +    CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::AppleNames); +    CommonSections.getOrCreateSectionDescriptor( +        DebugSectionKind::AppleNamespaces); +    CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::AppleObjC); +    CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::AppleTypes); +  } + +  if (llvm::is_contained(GlobalData.Options.AccelTables, +                         AccelTableKind::DebugNames)) +    CommonSections.getOrCreateSectionDescriptor(DebugSectionKind::DebugNames); + +  const Triple &TargetTriple = TheDwarfEmitter->getTargetTriple(); + +  // Emit .debug_str and .debug_line_str sections. +  TG.spawn([&]() { emitStringSections(); }); + +  if (llvm::is_contained(GlobalData.Options.AccelTables, +                         AccelTableKind::Apple)) { +    // Emit apple accelerator sections. +    TG.spawn([&]() { emitAppleAcceleratorSections(TargetTriple); }); +  } + +  if (llvm::is_contained(GlobalData.Options.AccelTables, +                         AccelTableKind::DebugNames)) { +    // Emit .debug_names section. +    TG.spawn([&]() { emitDWARFv5DebugNamesSection(TargetTriple); }); +  } + +  // Write compile units to the output file. +  TG.spawn([&]() { writeCompileUnitsToTheOutput(); }); +} + +void DWARFLinkerImpl::emitStringSections() { +  uint64_t DebugStrNextOffset = 0; +  uint64_t DebugLineStrNextOffset = 0; + +  // Emit zero length string. Accelerator tables does not work correctly +  // if the first string is not zero length string. +  CommonSections.getSectionDescriptor(DebugSectionKind::DebugStr) +      .emitInplaceString(""); +  DebugStrNextOffset++; + +  forEachOutputString( +      [&](StringDestinationKind Kind, const StringEntry *String) { +        switch (Kind) { +        case StringDestinationKind::DebugStr: { +          DwarfStringPoolEntryWithExtString *StringToEmit = +              DebugStrStrings.getExistingEntry(String); +          assert(StringToEmit->isIndexed()); + +          // Strings may be repeated. Use accumulated DebugStrNextOffset +          // to understand whether corresponding string is already emitted. +          // Skip string if its offset less than accumulated offset. +          if (StringToEmit->Offset >= DebugStrNextOffset) { +            DebugStrNextOffset = +                StringToEmit->Offset + StringToEmit->String.size() + 1; +            // Emit the string itself. +            CommonSections.getSectionDescriptor(DebugSectionKind::DebugStr) +                .emitInplaceString(StringToEmit->String); +          } +        } break; +        case StringDestinationKind::DebugLineStr: { +          DwarfStringPoolEntryWithExtString *StringToEmit = +              DebugLineStrStrings.getExistingEntry(String); +          assert(StringToEmit->isIndexed()); + +          // Strings may be repeated. Use accumulated DebugLineStrStrings +          // to understand whether corresponding string is already emitted. +          // Skip string if its offset less than accumulated offset. +          if (StringToEmit->Offset >= DebugLineStrNextOffset) { +            DebugLineStrNextOffset = +                StringToEmit->Offset + StringToEmit->String.size() + 1; +            // Emit the string itself. +            CommonSections.getSectionDescriptor(DebugSectionKind::DebugLineStr) +                .emitInplaceString(StringToEmit->String); +          } +        } break; +        } +      }); +} + +void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) { +  AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces; +  AccelTable<AppleAccelTableStaticOffsetData> AppleNames; +  AccelTable<AppleAccelTableStaticOffsetData> AppleObjC; +  AccelTable<AppleAccelTableStaticTypeData> AppleTypes; + +  forEachCompileAndTypeUnit([&](DwarfUnit *CU) { +    CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) { +      uint64_t OutOffset = Info.OutOffset; +      switch (Info.Type) { +      case DwarfUnit::AccelType::None: { +        llvm_unreachable("Unknown accelerator record"); +      } break; +      case DwarfUnit::AccelType::Namespace: { +        AppleNamespaces.addName( +            *DebugStrStrings.getExistingEntry(Info.String), +            CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset + +                OutOffset); +      } break; +      case DwarfUnit::AccelType::Name: { +        AppleNames.addName( +            *DebugStrStrings.getExistingEntry(Info.String), +            CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset + +                OutOffset); +      } break; +      case DwarfUnit::AccelType::ObjC: { +        AppleObjC.addName( +            *DebugStrStrings.getExistingEntry(Info.String), +            CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset + +                OutOffset); +      } break; +      case DwarfUnit::AccelType::Type: { +        AppleTypes.addName( +            *DebugStrStrings.getExistingEntry(Info.String), +            CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset + +                OutOffset, +            Info.Tag, +            Info.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation +                                         : 0, +            Info.QualifiedNameHash); +      } break; +      } +    }); +  }); + +  { +    // FIXME: we use AsmPrinter to emit accelerator sections. +    // It might be beneficial to directly emit accelerator data +    // to the raw_svector_ostream. +    SectionDescriptor &OutSection = +        CommonSections.getSectionDescriptor(DebugSectionKind::AppleNamespaces); +    DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, +                             OutSection.OS); +    if (Error Err = Emitter.init(TargetTriple, "__DWARF")) { +      consumeError(std::move(Err)); +      return; +    } + +    // Emit table. +    Emitter.emitAppleNamespaces(AppleNamespaces); +    Emitter.finish(); + +    // Set start offset and size for output section. +    OutSection.setSizesForSectionCreatedByAsmPrinter(); +  } + +  { +    // FIXME: we use AsmPrinter to emit accelerator sections. +    // It might be beneficial to directly emit accelerator data +    // to the raw_svector_ostream. +    SectionDescriptor &OutSection = +        CommonSections.getSectionDescriptor(DebugSectionKind::AppleNames); +    DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, +                             OutSection.OS); +    if (Error Err = Emitter.init(TargetTriple, "__DWARF")) { +      consumeError(std::move(Err)); +      return; +    } + +    // Emit table. +    Emitter.emitAppleNames(AppleNames); +    Emitter.finish(); + +    // Set start offset ans size for output section. +    OutSection.setSizesForSectionCreatedByAsmPrinter(); +  } + +  { +    // FIXME: we use AsmPrinter to emit accelerator sections. +    // It might be beneficial to directly emit accelerator data +    // to the raw_svector_ostream. +    SectionDescriptor &OutSection = +        CommonSections.getSectionDescriptor(DebugSectionKind::AppleObjC); +    DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, +                             OutSection.OS); +    if (Error Err = Emitter.init(TargetTriple, "__DWARF")) { +      consumeError(std::move(Err)); +      return; +    } + +    // Emit table. +    Emitter.emitAppleObjc(AppleObjC); +    Emitter.finish(); + +    // Set start offset ans size for output section. +    OutSection.setSizesForSectionCreatedByAsmPrinter(); +  } + +  { +    // FIXME: we use AsmPrinter to emit accelerator sections. +    // It might be beneficial to directly emit accelerator data +    // to the raw_svector_ostream. +    SectionDescriptor &OutSection = +        CommonSections.getSectionDescriptor(DebugSectionKind::AppleTypes); +    DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, +                             OutSection.OS); +    if (Error Err = Emitter.init(TargetTriple, "__DWARF")) { +      consumeError(std::move(Err)); +      return; +    } + +    // Emit table. +    Emitter.emitAppleTypes(AppleTypes); +    Emitter.finish(); + +    // Set start offset ans size for output section. +    OutSection.setSizesForSectionCreatedByAsmPrinter(); +  } +} + +void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) { +  std::unique_ptr<DWARF5AccelTable> DebugNames; + +  DebugNamesUnitsOffsets CompUnits; +  CompUnitIDToIdx CUidToIdx; + +  unsigned Id = 0; + +  forEachCompileAndTypeUnit([&](DwarfUnit *CU) { +    bool HasRecords = false; +    CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) { +      if (DebugNames.get() == nullptr) +        DebugNames = std::make_unique<DWARF5AccelTable>(); + +      HasRecords = true; +      switch (Info.Type) { +      case DwarfUnit::AccelType::Name: +      case DwarfUnit::AccelType::Namespace: +      case DwarfUnit::AccelType::Type: { +        DebugNames->addName(*DebugStrStrings.getExistingEntry(Info.String), +                            Info.OutOffset, Info.Tag, CU->getUniqueID()); +      } break; + +      default: +        break; // Nothing to do. +      }; +    }); + +    if (HasRecords) { +      CompUnits.push_back( +          CU->getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo) +              .StartOffset); +      CUidToIdx[CU->getUniqueID()] = Id++; +    } +  }); + +  if (DebugNames.get() != nullptr) { +    // FIXME: we use AsmPrinter to emit accelerator sections. +    // It might be beneficial to directly emit accelerator data +    // to the raw_svector_ostream. +    SectionDescriptor &OutSection = +        CommonSections.getSectionDescriptor(DebugSectionKind::DebugNames); +    DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, +                             OutSection.OS); +    if (Error Err = Emitter.init(TargetTriple, "__DWARF")) { +      consumeError(std::move(Err)); +      return; +    } + +    // Emit table. +    Emitter.emitDebugNames(*DebugNames, CompUnits, CUidToIdx); +    Emitter.finish(); + +    // Set start offset ans size for output section. +    OutSection.setSizesForSectionCreatedByAsmPrinter(); +  } +} + +void DWARFLinkerImpl::cleanupDataAfterDWARFOutputIsWritten() { +  GlobalData.getStringPool().clear(); +  DebugStrStrings.clear(); +  DebugLineStrStrings.clear(); +} + +void DWARFLinkerImpl::writeCompileUnitsToTheOutput() { +  bool HasAbbreviations = false; + +  // Enumerate all sections and store them into the final emitter. +  forEachObjectSectionsSet([&](OutputSections &Sections) { +    Sections.forEach([&](SectionDescriptor &OutSection) { +      if (!HasAbbreviations && !OutSection.getContents().empty() && +          OutSection.getKind() == DebugSectionKind::DebugAbbrev) +        HasAbbreviations = true; + +      // Emit section content. +      TheDwarfEmitter->emitSectionContents(OutSection.getContents(), +                                           OutSection.getName()); +      OutSection.clearSectionContent(); +    }); +  }); + +  if (!HasAbbreviations) { +    const SmallVector<std::unique_ptr<DIEAbbrev>> Abbreviations; +    TheDwarfEmitter->emitAbbrevs(Abbreviations, 3); +  } +} + +void DWARFLinkerImpl::writeCommonSectionsToTheOutput() { +  CommonSections.forEach([&](SectionDescriptor &OutSection) { +    // Emit section content. +    TheDwarfEmitter->emitSectionContents(OutSection.getContents(), +                                         OutSection.getName()); +    OutSection.clearSectionContent(); +  }); +}  | 
