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