Path: blob/main/contrib/llvm-project/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
35292 views
//=== DWARFLinker.cpp -----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/DWARFLinker/Classic/DWARFLinker.h"9#include "llvm/ADT/ArrayRef.h"10#include "llvm/ADT/BitVector.h"11#include "llvm/ADT/STLExtras.h"12#include "llvm/ADT/StringExtras.h"13#include "llvm/CodeGen/NonRelocatableStringpool.h"14#include "llvm/DWARFLinker/Classic/DWARFLinkerDeclContext.h"15#include "llvm/DWARFLinker/Classic/DWARFStreamer.h"16#include "llvm/DWARFLinker/Utils.h"17#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"18#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"19#include "llvm/DebugInfo/DWARF/DWARFContext.h"20#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"21#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"22#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"23#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"24#include "llvm/DebugInfo/DWARF/DWARFDie.h"25#include "llvm/DebugInfo/DWARF/DWARFExpression.h"26#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"27#include "llvm/DebugInfo/DWARF/DWARFSection.h"28#include "llvm/DebugInfo/DWARF/DWARFUnit.h"29#include "llvm/MC/MCDwarf.h"30#include "llvm/Support/DataExtractor.h"31#include "llvm/Support/Error.h"32#include "llvm/Support/ErrorHandling.h"33#include "llvm/Support/ErrorOr.h"34#include "llvm/Support/FormatVariadic.h"35#include "llvm/Support/LEB128.h"36#include "llvm/Support/Path.h"37#include "llvm/Support/ThreadPool.h"38#include <vector>3940namespace llvm {4142using namespace dwarf_linker;43using namespace dwarf_linker::classic;4445/// Hold the input and output of the debug info size in bytes.46struct DebugInfoSize {47uint64_t Input;48uint64_t Output;49};5051/// Compute the total size of the debug info.52static uint64_t getDebugInfoSize(DWARFContext &Dwarf) {53uint64_t Size = 0;54for (auto &Unit : Dwarf.compile_units()) {55Size += Unit->getLength();56}57return Size;58}5960/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our61/// CompileUnit object instead.62static CompileUnit *getUnitForOffset(const UnitListTy &Units, uint64_t Offset) {63auto CU = llvm::upper_bound(64Units, Offset, [](uint64_t LHS, const std::unique_ptr<CompileUnit> &RHS) {65return LHS < RHS->getOrigUnit().getNextUnitOffset();66});67return CU != Units.end() ? CU->get() : nullptr;68}6970/// Resolve the DIE attribute reference that has been extracted in \p RefValue.71/// The resulting DIE might be in another CompileUnit which is stored into \p72/// ReferencedCU. \returns null if resolving fails for any reason.73DWARFDie DWARFLinker::resolveDIEReference(const DWARFFile &File,74const UnitListTy &Units,75const DWARFFormValue &RefValue,76const DWARFDie &DIE,77CompileUnit *&RefCU) {78assert(RefValue.isFormClass(DWARFFormValue::FC_Reference));79uint64_t RefOffset;80if (std::optional<uint64_t> Off = RefValue.getAsRelativeReference()) {81RefOffset = RefValue.getUnit()->getOffset() + *Off;82} else if (Off = RefValue.getAsDebugInfoReference(); Off) {83RefOffset = *Off;84} else {85reportWarning("Unsupported reference type", File, &DIE);86return DWARFDie();87}88if ((RefCU = getUnitForOffset(Units, RefOffset)))89if (const auto RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) {90// In a file with broken references, an attribute might point to a NULL91// DIE.92if (!RefDie.isNULL())93return RefDie;94}9596reportWarning("could not find referenced DIE", File, &DIE);97return DWARFDie();98}99100/// \returns whether the passed \a Attr type might contain a DIE reference101/// suitable for ODR uniquing.102static bool isODRAttribute(uint16_t Attr) {103switch (Attr) {104default:105return false;106case dwarf::DW_AT_type:107case dwarf::DW_AT_containing_type:108case dwarf::DW_AT_specification:109case dwarf::DW_AT_abstract_origin:110case dwarf::DW_AT_import:111return true;112}113llvm_unreachable("Improper attribute.");114}115116static bool isTypeTag(uint16_t Tag) {117switch (Tag) {118case dwarf::DW_TAG_array_type:119case dwarf::DW_TAG_class_type:120case dwarf::DW_TAG_enumeration_type:121case dwarf::DW_TAG_pointer_type:122case dwarf::DW_TAG_reference_type:123case dwarf::DW_TAG_string_type:124case dwarf::DW_TAG_structure_type:125case dwarf::DW_TAG_subroutine_type:126case dwarf::DW_TAG_template_alias:127case dwarf::DW_TAG_typedef:128case dwarf::DW_TAG_union_type:129case dwarf::DW_TAG_ptr_to_member_type:130case dwarf::DW_TAG_set_type:131case dwarf::DW_TAG_subrange_type:132case dwarf::DW_TAG_base_type:133case dwarf::DW_TAG_const_type:134case dwarf::DW_TAG_constant:135case dwarf::DW_TAG_file_type:136case dwarf::DW_TAG_namelist:137case dwarf::DW_TAG_packed_type:138case dwarf::DW_TAG_volatile_type:139case dwarf::DW_TAG_restrict_type:140case dwarf::DW_TAG_atomic_type:141case dwarf::DW_TAG_interface_type:142case dwarf::DW_TAG_unspecified_type:143case dwarf::DW_TAG_shared_type:144case dwarf::DW_TAG_immutable_type:145return true;146default:147break;148}149return false;150}151152bool DWARFLinker::DIECloner::getDIENames(const DWARFDie &Die,153AttributesInfo &Info,154OffsetsStringPool &StringPool,155bool StripTemplate) {156// This function will be called on DIEs having low_pcs and157// ranges. As getting the name might be more expansive, filter out158// blocks directly.159if (Die.getTag() == dwarf::DW_TAG_lexical_block)160return false;161162if (!Info.MangledName)163if (const char *MangledName = Die.getLinkageName())164Info.MangledName = StringPool.getEntry(MangledName);165166if (!Info.Name)167if (const char *Name = Die.getShortName())168Info.Name = StringPool.getEntry(Name);169170if (!Info.MangledName)171Info.MangledName = Info.Name;172173if (StripTemplate && Info.Name && Info.MangledName != Info.Name) {174StringRef Name = Info.Name.getString();175if (std::optional<StringRef> StrippedName = StripTemplateParameters(Name))176Info.NameWithoutTemplate = StringPool.getEntry(*StrippedName);177}178179return Info.Name || Info.MangledName;180}181182/// Resolve the relative path to a build artifact referenced by DWARF by183/// applying DW_AT_comp_dir.184static void resolveRelativeObjectPath(SmallVectorImpl<char> &Buf, DWARFDie CU) {185sys::path::append(Buf, dwarf::toString(CU.find(dwarf::DW_AT_comp_dir), ""));186}187188/// Collect references to parseable Swift interfaces in imported189/// DW_TAG_module blocks.190static void analyzeImportedModule(191const DWARFDie &DIE, CompileUnit &CU,192DWARFLinkerBase::SwiftInterfacesMapTy *ParseableSwiftInterfaces,193std::function<void(const Twine &, const DWARFDie &)> ReportWarning) {194if (CU.getLanguage() != dwarf::DW_LANG_Swift)195return;196197if (!ParseableSwiftInterfaces)198return;199200StringRef Path = dwarf::toStringRef(DIE.find(dwarf::DW_AT_LLVM_include_path));201if (!Path.ends_with(".swiftinterface"))202return;203// Don't track interfaces that are part of the SDK.204StringRef SysRoot = dwarf::toStringRef(DIE.find(dwarf::DW_AT_LLVM_sysroot));205if (SysRoot.empty())206SysRoot = CU.getSysRoot();207if (!SysRoot.empty() && Path.starts_with(SysRoot))208return;209// Don't track interfaces that are part of the toolchain.210// For example: Swift, _Concurrency, ...211StringRef DeveloperDir = guessDeveloperDir(SysRoot);212if (!DeveloperDir.empty() && Path.starts_with(DeveloperDir))213return;214if (isInToolchainDir(Path))215return;216std::optional<const char *> Name =217dwarf::toString(DIE.find(dwarf::DW_AT_name));218if (!Name)219return;220auto &Entry = (*ParseableSwiftInterfaces)[*Name];221// The prepend path is applied later when copying.222DWARFDie CUDie = CU.getOrigUnit().getUnitDIE();223SmallString<128> ResolvedPath;224if (sys::path::is_relative(Path))225resolveRelativeObjectPath(ResolvedPath, CUDie);226sys::path::append(ResolvedPath, Path);227if (!Entry.empty() && Entry != ResolvedPath)228ReportWarning(Twine("Conflicting parseable interfaces for Swift Module ") +229*Name + ": " + Entry + " and " + Path,230DIE);231Entry = std::string(ResolvedPath);232}233234/// The distinct types of work performed by the work loop in235/// analyzeContextInfo.236enum class ContextWorklistItemType : uint8_t {237AnalyzeContextInfo,238UpdateChildPruning,239UpdatePruning,240};241242/// This class represents an item in the work list. The type defines what kind243/// of work needs to be performed when processing the current item. Everything244/// but the Type and Die fields are optional based on the type.245struct ContextWorklistItem {246DWARFDie Die;247unsigned ParentIdx;248union {249CompileUnit::DIEInfo *OtherInfo;250DeclContext *Context;251};252ContextWorklistItemType Type;253bool InImportedModule;254255ContextWorklistItem(DWARFDie Die, ContextWorklistItemType T,256CompileUnit::DIEInfo *OtherInfo = nullptr)257: Die(Die), ParentIdx(0), OtherInfo(OtherInfo), Type(T),258InImportedModule(false) {}259260ContextWorklistItem(DWARFDie Die, DeclContext *Context, unsigned ParentIdx,261bool InImportedModule)262: Die(Die), ParentIdx(ParentIdx), Context(Context),263Type(ContextWorklistItemType::AnalyzeContextInfo),264InImportedModule(InImportedModule) {}265};266267static bool updatePruning(const DWARFDie &Die, CompileUnit &CU,268uint64_t ModulesEndOffset) {269CompileUnit::DIEInfo &Info = CU.getInfo(Die);270271// Prune this DIE if it is either a forward declaration inside a272// DW_TAG_module or a DW_TAG_module that contains nothing but273// forward declarations.274Info.Prune &= (Die.getTag() == dwarf::DW_TAG_module) ||275(isTypeTag(Die.getTag()) &&276dwarf::toUnsigned(Die.find(dwarf::DW_AT_declaration), 0));277278// Only prune forward declarations inside a DW_TAG_module for which a279// definition exists elsewhere.280if (ModulesEndOffset == 0)281Info.Prune &= Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset();282else283Info.Prune &= Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset() > 0 &&284Info.Ctxt->getCanonicalDIEOffset() <= ModulesEndOffset;285286return Info.Prune;287}288289static void updateChildPruning(const DWARFDie &Die, CompileUnit &CU,290CompileUnit::DIEInfo &ChildInfo) {291CompileUnit::DIEInfo &Info = CU.getInfo(Die);292Info.Prune &= ChildInfo.Prune;293}294295/// Recursive helper to build the global DeclContext information and296/// gather the child->parent relationships in the original compile unit.297///298/// This function uses the same work list approach as lookForDIEsToKeep.299///300/// \return true when this DIE and all of its children are only301/// forward declarations to types defined in external clang modules302/// (i.e., forward declarations that are children of a DW_TAG_module).303static void analyzeContextInfo(304const DWARFDie &DIE, unsigned ParentIdx, CompileUnit &CU,305DeclContext *CurrentDeclContext, DeclContextTree &Contexts,306uint64_t ModulesEndOffset,307DWARFLinkerBase::SwiftInterfacesMapTy *ParseableSwiftInterfaces,308std::function<void(const Twine &, const DWARFDie &)> ReportWarning) {309// LIFO work list.310std::vector<ContextWorklistItem> Worklist;311Worklist.emplace_back(DIE, CurrentDeclContext, ParentIdx, false);312313while (!Worklist.empty()) {314ContextWorklistItem Current = Worklist.back();315Worklist.pop_back();316317switch (Current.Type) {318case ContextWorklistItemType::UpdatePruning:319updatePruning(Current.Die, CU, ModulesEndOffset);320continue;321case ContextWorklistItemType::UpdateChildPruning:322updateChildPruning(Current.Die, CU, *Current.OtherInfo);323continue;324case ContextWorklistItemType::AnalyzeContextInfo:325break;326}327328unsigned Idx = CU.getOrigUnit().getDIEIndex(Current.Die);329CompileUnit::DIEInfo &Info = CU.getInfo(Idx);330331// Clang imposes an ODR on modules(!) regardless of the language:332// "The module-id should consist of only a single identifier,333// which provides the name of the module being defined. Each334// module shall have a single definition."335//336// This does not extend to the types inside the modules:337// "[I]n C, this implies that if two structs are defined in338// different submodules with the same name, those two types are339// distinct types (but may be compatible types if their340// definitions match)."341//342// We treat non-C++ modules like namespaces for this reason.343if (Current.Die.getTag() == dwarf::DW_TAG_module &&344Current.ParentIdx == 0 &&345dwarf::toString(Current.Die.find(dwarf::DW_AT_name), "") !=346CU.getClangModuleName()) {347Current.InImportedModule = true;348analyzeImportedModule(Current.Die, CU, ParseableSwiftInterfaces,349ReportWarning);350}351352Info.ParentIdx = Current.ParentIdx;353Info.InModuleScope = CU.isClangModule() || Current.InImportedModule;354if (CU.hasODR() || Info.InModuleScope) {355if (Current.Context) {356auto PtrInvalidPair = Contexts.getChildDeclContext(357*Current.Context, Current.Die, CU, Info.InModuleScope);358Current.Context = PtrInvalidPair.getPointer();359Info.Ctxt =360PtrInvalidPair.getInt() ? nullptr : PtrInvalidPair.getPointer();361if (Info.Ctxt)362Info.Ctxt->setDefinedInClangModule(Info.InModuleScope);363} else364Info.Ctxt = Current.Context = nullptr;365}366367Info.Prune = Current.InImportedModule;368// Add children in reverse order to the worklist to effectively process369// them in order.370Worklist.emplace_back(Current.Die, ContextWorklistItemType::UpdatePruning);371for (auto Child : reverse(Current.Die.children())) {372CompileUnit::DIEInfo &ChildInfo = CU.getInfo(Child);373Worklist.emplace_back(374Current.Die, ContextWorklistItemType::UpdateChildPruning, &ChildInfo);375Worklist.emplace_back(Child, Current.Context, Idx,376Current.InImportedModule);377}378}379}380381static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) {382switch (Tag) {383default:384return false;385case dwarf::DW_TAG_class_type:386case dwarf::DW_TAG_common_block:387case dwarf::DW_TAG_lexical_block:388case dwarf::DW_TAG_structure_type:389case dwarf::DW_TAG_subprogram:390case dwarf::DW_TAG_subroutine_type:391case dwarf::DW_TAG_union_type:392return true;393}394llvm_unreachable("Invalid Tag");395}396397void DWARFLinker::cleanupAuxiliarryData(LinkContext &Context) {398Context.clear();399400for (DIEBlock *I : DIEBlocks)401I->~DIEBlock();402for (DIELoc *I : DIELocs)403I->~DIELoc();404405DIEBlocks.clear();406DIELocs.clear();407DIEAlloc.Reset();408}409410static bool isTlsAddressCode(uint8_t DW_OP_Code) {411return DW_OP_Code == dwarf::DW_OP_form_tls_address ||412DW_OP_Code == dwarf::DW_OP_GNU_push_tls_address;413}414415std::pair<bool, std::optional<int64_t>>416DWARFLinker::getVariableRelocAdjustment(AddressesMap &RelocMgr,417const DWARFDie &DIE) {418assert((DIE.getTag() == dwarf::DW_TAG_variable ||419DIE.getTag() == dwarf::DW_TAG_constant) &&420"Wrong type of input die");421422const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();423424// Check if DIE has DW_AT_location attribute.425DWARFUnit *U = DIE.getDwarfUnit();426std::optional<uint32_t> LocationIdx =427Abbrev->findAttributeIndex(dwarf::DW_AT_location);428if (!LocationIdx)429return std::make_pair(false, std::nullopt);430431// Get offset to the DW_AT_location attribute.432uint64_t AttrOffset =433Abbrev->getAttributeOffsetFromIndex(*LocationIdx, DIE.getOffset(), *U);434435// Get value of the DW_AT_location attribute.436std::optional<DWARFFormValue> LocationValue =437Abbrev->getAttributeValueFromOffset(*LocationIdx, AttrOffset, *U);438if (!LocationValue)439return std::make_pair(false, std::nullopt);440441// Check that DW_AT_location attribute is of 'exprloc' class.442// Handling value of location expressions for attributes of 'loclist'443// class is not implemented yet.444std::optional<ArrayRef<uint8_t>> Expr = LocationValue->getAsBlock();445if (!Expr)446return std::make_pair(false, std::nullopt);447448// Parse 'exprloc' expression.449DataExtractor Data(toStringRef(*Expr), U->getContext().isLittleEndian(),450U->getAddressByteSize());451DWARFExpression Expression(Data, U->getAddressByteSize(),452U->getFormParams().Format);453454bool HasLocationAddress = false;455uint64_t CurExprOffset = 0;456for (DWARFExpression::iterator It = Expression.begin();457It != Expression.end(); ++It) {458DWARFExpression::iterator NextIt = It;459++NextIt;460461const DWARFExpression::Operation &Op = *It;462switch (Op.getCode()) {463case dwarf::DW_OP_const2u:464case dwarf::DW_OP_const4u:465case dwarf::DW_OP_const8u:466case dwarf::DW_OP_const2s:467case dwarf::DW_OP_const4s:468case dwarf::DW_OP_const8s:469if (NextIt == Expression.end() || !isTlsAddressCode(NextIt->getCode()))470break;471[[fallthrough]];472case dwarf::DW_OP_addr: {473HasLocationAddress = true;474// Check relocation for the address.475if (std::optional<int64_t> RelocAdjustment =476RelocMgr.getExprOpAddressRelocAdjustment(477*U, Op, AttrOffset + CurExprOffset,478AttrOffset + Op.getEndOffset(), Options.Verbose))479return std::make_pair(HasLocationAddress, *RelocAdjustment);480} break;481case dwarf::DW_OP_constx:482case dwarf::DW_OP_addrx: {483HasLocationAddress = true;484if (std::optional<uint64_t> AddressOffset =485DIE.getDwarfUnit()->getIndexedAddressOffset(486Op.getRawOperand(0))) {487// Check relocation for the address.488if (std::optional<int64_t> RelocAdjustment =489RelocMgr.getExprOpAddressRelocAdjustment(490*U, Op, *AddressOffset,491*AddressOffset + DIE.getDwarfUnit()->getAddressByteSize(),492Options.Verbose))493return std::make_pair(HasLocationAddress, *RelocAdjustment);494}495} break;496default: {497// Nothing to do.498} break;499}500CurExprOffset = Op.getEndOffset();501}502503return std::make_pair(HasLocationAddress, std::nullopt);504}505506/// Check if a variable describing DIE should be kept.507/// \returns updated TraversalFlags.508unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr,509const DWARFDie &DIE,510CompileUnit::DIEInfo &MyInfo,511unsigned Flags) {512const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();513514// Global variables with constant value can always be kept.515if (!(Flags & TF_InFunctionScope) &&516Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {517MyInfo.InDebugMap = true;518return Flags | TF_Keep;519}520521// See if there is a relocation to a valid debug map entry inside this522// variable's location. The order is important here. We want to always check523// if the variable has a valid relocation, so that the DIEInfo is filled.524// However, we don't want a static variable in a function to force us to keep525// the enclosing function, unless requested explicitly.526std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =527getVariableRelocAdjustment(RelocMgr, DIE);528529if (LocExprAddrAndRelocAdjustment.first)530MyInfo.HasLocationExpressionAddr = true;531532if (!LocExprAddrAndRelocAdjustment.second)533return Flags;534535MyInfo.AddrAdjust = *LocExprAddrAndRelocAdjustment.second;536MyInfo.InDebugMap = true;537538if (((Flags & TF_InFunctionScope) &&539!LLVM_UNLIKELY(Options.KeepFunctionForStatic)))540return Flags;541542if (Options.Verbose) {543outs() << "Keeping variable DIE:";544DIDumpOptions DumpOpts;545DumpOpts.ChildRecurseDepth = 0;546DumpOpts.Verbose = Options.Verbose;547DIE.dump(outs(), 8 /* Indent */, DumpOpts);548}549550return Flags | TF_Keep;551}552553/// Check if a function describing DIE should be kept.554/// \returns updated TraversalFlags.555unsigned DWARFLinker::shouldKeepSubprogramDIE(556AddressesMap &RelocMgr, const DWARFDie &DIE, const DWARFFile &File,557CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags) {558Flags |= TF_InFunctionScope;559560auto LowPc = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc));561if (!LowPc)562return Flags;563564assert(LowPc && "low_pc attribute is not an address.");565std::optional<int64_t> RelocAdjustment =566RelocMgr.getSubprogramRelocAdjustment(DIE, Options.Verbose);567if (!RelocAdjustment)568return Flags;569570MyInfo.AddrAdjust = *RelocAdjustment;571MyInfo.InDebugMap = true;572573if (Options.Verbose) {574outs() << "Keeping subprogram DIE:";575DIDumpOptions DumpOpts;576DumpOpts.ChildRecurseDepth = 0;577DumpOpts.Verbose = Options.Verbose;578DIE.dump(outs(), 8 /* Indent */, DumpOpts);579}580581if (DIE.getTag() == dwarf::DW_TAG_label) {582if (Unit.hasLabelAt(*LowPc))583return Flags;584585DWARFUnit &OrigUnit = Unit.getOrigUnit();586// FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider labels587// that don't fall into the CU's aranges. This is wrong IMO. Debug info588// generation bugs aside, this is really wrong in the case of labels, where589// a label marking the end of a function will have a PC == CU's high_pc.590if (dwarf::toAddress(OrigUnit.getUnitDIE().find(dwarf::DW_AT_high_pc))591.value_or(UINT64_MAX) <= LowPc)592return Flags;593Unit.addLabelLowPc(*LowPc, MyInfo.AddrAdjust);594return Flags | TF_Keep;595}596597Flags |= TF_Keep;598599std::optional<uint64_t> HighPc = DIE.getHighPC(*LowPc);600if (!HighPc) {601reportWarning("Function without high_pc. Range will be discarded.\n", File,602&DIE);603return Flags;604}605if (*LowPc > *HighPc) {606reportWarning("low_pc greater than high_pc. Range will be discarded.\n",607File, &DIE);608return Flags;609}610611// Replace the debug map range with a more accurate one.612Unit.addFunctionRange(*LowPc, *HighPc, MyInfo.AddrAdjust);613return Flags;614}615616/// Check if a DIE should be kept.617/// \returns updated TraversalFlags.618unsigned DWARFLinker::shouldKeepDIE(AddressesMap &RelocMgr, const DWARFDie &DIE,619const DWARFFile &File, CompileUnit &Unit,620CompileUnit::DIEInfo &MyInfo,621unsigned Flags) {622switch (DIE.getTag()) {623case dwarf::DW_TAG_constant:624case dwarf::DW_TAG_variable:625return shouldKeepVariableDIE(RelocMgr, DIE, MyInfo, Flags);626case dwarf::DW_TAG_subprogram:627case dwarf::DW_TAG_label:628return shouldKeepSubprogramDIE(RelocMgr, DIE, File, Unit, MyInfo, Flags);629case dwarf::DW_TAG_base_type:630// DWARF Expressions may reference basic types, but scanning them631// is expensive. Basic types are tiny, so just keep all of them.632case dwarf::DW_TAG_imported_module:633case dwarf::DW_TAG_imported_declaration:634case dwarf::DW_TAG_imported_unit:635// We always want to keep these.636return Flags | TF_Keep;637default:638break;639}640641return Flags;642}643644/// Helper that updates the completeness of the current DIE based on the645/// completeness of one of its children. It depends on the incompleteness of646/// the children already being computed.647static void updateChildIncompleteness(const DWARFDie &Die, CompileUnit &CU,648CompileUnit::DIEInfo &ChildInfo) {649switch (Die.getTag()) {650case dwarf::DW_TAG_structure_type:651case dwarf::DW_TAG_class_type:652case dwarf::DW_TAG_union_type:653break;654default:655return;656}657658CompileUnit::DIEInfo &MyInfo = CU.getInfo(Die);659660if (ChildInfo.Incomplete || ChildInfo.Prune)661MyInfo.Incomplete = true;662}663664/// Helper that updates the completeness of the current DIE based on the665/// completeness of the DIEs it references. It depends on the incompleteness of666/// the referenced DIE already being computed.667static void updateRefIncompleteness(const DWARFDie &Die, CompileUnit &CU,668CompileUnit::DIEInfo &RefInfo) {669switch (Die.getTag()) {670case dwarf::DW_TAG_typedef:671case dwarf::DW_TAG_member:672case dwarf::DW_TAG_reference_type:673case dwarf::DW_TAG_ptr_to_member_type:674case dwarf::DW_TAG_pointer_type:675break;676default:677return;678}679680CompileUnit::DIEInfo &MyInfo = CU.getInfo(Die);681682if (MyInfo.Incomplete)683return;684685if (RefInfo.Incomplete)686MyInfo.Incomplete = true;687}688689/// Look at the children of the given DIE and decide whether they should be690/// kept.691void DWARFLinker::lookForChildDIEsToKeep(692const DWARFDie &Die, CompileUnit &CU, unsigned Flags,693SmallVectorImpl<WorklistItem> &Worklist) {694// The TF_ParentWalk flag tells us that we are currently walking up the695// parent chain of a required DIE, and we don't want to mark all the children696// of the parents as kept (consider for example a DW_TAG_namespace node in697// the parent chain). There are however a set of DIE types for which we want698// to ignore that directive and still walk their children.699if (dieNeedsChildrenToBeMeaningful(Die.getTag()))700Flags &= ~DWARFLinker::TF_ParentWalk;701702// We're finished if this DIE has no children or we're walking the parent703// chain.704if (!Die.hasChildren() || (Flags & DWARFLinker::TF_ParentWalk))705return;706707// Add children in reverse order to the worklist to effectively process them708// in order.709for (auto Child : reverse(Die.children())) {710// Add a worklist item before every child to calculate incompleteness right711// after the current child is processed.712CompileUnit::DIEInfo &ChildInfo = CU.getInfo(Child);713Worklist.emplace_back(Die, CU, WorklistItemType::UpdateChildIncompleteness,714&ChildInfo);715Worklist.emplace_back(Child, CU, Flags);716}717}718719static bool isODRCanonicalCandidate(const DWARFDie &Die, CompileUnit &CU) {720CompileUnit::DIEInfo &Info = CU.getInfo(Die);721722if (!Info.Ctxt || (Die.getTag() == dwarf::DW_TAG_namespace))723return false;724725if (!CU.hasODR() && !Info.InModuleScope)726return false;727728return !Info.Incomplete && Info.Ctxt != CU.getInfo(Info.ParentIdx).Ctxt;729}730731void DWARFLinker::markODRCanonicalDie(const DWARFDie &Die, CompileUnit &CU) {732CompileUnit::DIEInfo &Info = CU.getInfo(Die);733734Info.ODRMarkingDone = true;735if (Info.Keep && isODRCanonicalCandidate(Die, CU) &&736!Info.Ctxt->hasCanonicalDIE())737Info.Ctxt->setHasCanonicalDIE();738}739740/// Look at DIEs referenced by the given DIE and decide whether they should be741/// kept. All DIEs referenced though attributes should be kept.742void DWARFLinker::lookForRefDIEsToKeep(743const DWARFDie &Die, CompileUnit &CU, unsigned Flags,744const UnitListTy &Units, const DWARFFile &File,745SmallVectorImpl<WorklistItem> &Worklist) {746bool UseOdr = (Flags & DWARFLinker::TF_DependencyWalk)747? (Flags & DWARFLinker::TF_ODR)748: CU.hasODR();749DWARFUnit &Unit = CU.getOrigUnit();750DWARFDataExtractor Data = Unit.getDebugInfoExtractor();751const auto *Abbrev = Die.getAbbreviationDeclarationPtr();752uint64_t Offset = Die.getOffset() + getULEB128Size(Abbrev->getCode());753754SmallVector<std::pair<DWARFDie, CompileUnit &>, 4> ReferencedDIEs;755for (const auto &AttrSpec : Abbrev->attributes()) {756DWARFFormValue Val(AttrSpec.Form);757if (!Val.isFormClass(DWARFFormValue::FC_Reference) ||758AttrSpec.Attr == dwarf::DW_AT_sibling) {759DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,760Unit.getFormParams());761continue;762}763764Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);765CompileUnit *ReferencedCU;766if (auto RefDie =767resolveDIEReference(File, Units, Val, Die, ReferencedCU)) {768CompileUnit::DIEInfo &Info = ReferencedCU->getInfo(RefDie);769// If the referenced DIE has a DeclContext that has already been770// emitted, then do not keep the one in this CU. We'll link to771// the canonical DIE in cloneDieReferenceAttribute.772//773// FIXME: compatibility with dsymutil-classic. UseODR shouldn't774// be necessary and could be advantageously replaced by775// ReferencedCU->hasODR() && CU.hasODR().776//777// FIXME: compatibility with dsymutil-classic. There is no778// reason not to unique ref_addr references.779if (AttrSpec.Form != dwarf::DW_FORM_ref_addr &&780isODRAttribute(AttrSpec.Attr) && Info.Ctxt &&781Info.Ctxt->hasCanonicalDIE())782continue;783784// Keep a module forward declaration if there is no definition.785if (!(isODRAttribute(AttrSpec.Attr) && Info.Ctxt &&786Info.Ctxt->hasCanonicalDIE()))787Info.Prune = false;788ReferencedDIEs.emplace_back(RefDie, *ReferencedCU);789}790}791792unsigned ODRFlag = UseOdr ? DWARFLinker::TF_ODR : 0;793794// Add referenced DIEs in reverse order to the worklist to effectively795// process them in order.796for (auto &P : reverse(ReferencedDIEs)) {797// Add a worklist item before every child to calculate incompleteness right798// after the current child is processed.799CompileUnit::DIEInfo &Info = P.second.getInfo(P.first);800Worklist.emplace_back(Die, CU, WorklistItemType::UpdateRefIncompleteness,801&Info);802Worklist.emplace_back(P.first, P.second,803DWARFLinker::TF_Keep |804DWARFLinker::TF_DependencyWalk | ODRFlag);805}806}807808/// Look at the parent of the given DIE and decide whether they should be kept.809void DWARFLinker::lookForParentDIEsToKeep(810unsigned AncestorIdx, CompileUnit &CU, unsigned Flags,811SmallVectorImpl<WorklistItem> &Worklist) {812// Stop if we encounter an ancestor that's already marked as kept.813if (CU.getInfo(AncestorIdx).Keep)814return;815816DWARFUnit &Unit = CU.getOrigUnit();817DWARFDie ParentDIE = Unit.getDIEAtIndex(AncestorIdx);818Worklist.emplace_back(CU.getInfo(AncestorIdx).ParentIdx, CU, Flags);819Worklist.emplace_back(ParentDIE, CU, Flags);820}821822/// Recursively walk the \p DIE tree and look for DIEs to keep. Store that823/// information in \p CU's DIEInfo.824///825/// This function is the entry point of the DIE selection algorithm. It is826/// expected to walk the DIE tree in file order and (though the mediation of827/// its helper) call hasValidRelocation() on each DIE that might be a 'root828/// DIE' (See DwarfLinker class comment).829///830/// While walking the dependencies of root DIEs, this function is also called,831/// but during these dependency walks the file order is not respected. The832/// TF_DependencyWalk flag tells us which kind of traversal we are currently833/// doing.834///835/// The recursive algorithm is implemented iteratively as a work list because836/// very deep recursion could exhaust the stack for large projects. The work837/// list acts as a scheduler for different types of work that need to be838/// performed.839///840/// The recursive nature of the algorithm is simulated by running the "main"841/// algorithm (LookForDIEsToKeep) followed by either looking at more DIEs842/// (LookForChildDIEsToKeep, LookForRefDIEsToKeep, LookForParentDIEsToKeep) or843/// fixing up a computed property (UpdateChildIncompleteness,844/// UpdateRefIncompleteness).845///846/// The return value indicates whether the DIE is incomplete.847void DWARFLinker::lookForDIEsToKeep(AddressesMap &AddressesMap,848const UnitListTy &Units,849const DWARFDie &Die, const DWARFFile &File,850CompileUnit &Cu, unsigned Flags) {851// LIFO work list.852SmallVector<WorklistItem, 4> Worklist;853Worklist.emplace_back(Die, Cu, Flags);854855while (!Worklist.empty()) {856WorklistItem Current = Worklist.pop_back_val();857858// Look at the worklist type to decide what kind of work to perform.859switch (Current.Type) {860case WorklistItemType::UpdateChildIncompleteness:861updateChildIncompleteness(Current.Die, Current.CU, *Current.OtherInfo);862continue;863case WorklistItemType::UpdateRefIncompleteness:864updateRefIncompleteness(Current.Die, Current.CU, *Current.OtherInfo);865continue;866case WorklistItemType::LookForChildDIEsToKeep:867lookForChildDIEsToKeep(Current.Die, Current.CU, Current.Flags, Worklist);868continue;869case WorklistItemType::LookForRefDIEsToKeep:870lookForRefDIEsToKeep(Current.Die, Current.CU, Current.Flags, Units, File,871Worklist);872continue;873case WorklistItemType::LookForParentDIEsToKeep:874lookForParentDIEsToKeep(Current.AncestorIdx, Current.CU, Current.Flags,875Worklist);876continue;877case WorklistItemType::MarkODRCanonicalDie:878markODRCanonicalDie(Current.Die, Current.CU);879continue;880case WorklistItemType::LookForDIEsToKeep:881break;882}883884unsigned Idx = Current.CU.getOrigUnit().getDIEIndex(Current.Die);885CompileUnit::DIEInfo &MyInfo = Current.CU.getInfo(Idx);886887if (MyInfo.Prune) {888// We're walking the dependencies of a module forward declaration that was889// kept because there is no definition.890if (Current.Flags & TF_DependencyWalk)891MyInfo.Prune = false;892else893continue;894}895896// If the Keep flag is set, we are marking a required DIE's dependencies.897// If our target is already marked as kept, we're all set.898bool AlreadyKept = MyInfo.Keep;899if ((Current.Flags & TF_DependencyWalk) && AlreadyKept)900continue;901902if (!(Current.Flags & TF_DependencyWalk))903Current.Flags = shouldKeepDIE(AddressesMap, Current.Die, File, Current.CU,904MyInfo, Current.Flags);905906// We need to mark context for the canonical die in the end of normal907// traversing(not TF_DependencyWalk) or after normal traversing if die908// was not marked as kept.909if (!(Current.Flags & TF_DependencyWalk) ||910(MyInfo.ODRMarkingDone && !MyInfo.Keep)) {911if (Current.CU.hasODR() || MyInfo.InModuleScope)912Worklist.emplace_back(Current.Die, Current.CU,913WorklistItemType::MarkODRCanonicalDie);914}915916// Finish by looking for child DIEs. Because of the LIFO worklist we need917// to schedule that work before any subsequent items are added to the918// worklist.919Worklist.emplace_back(Current.Die, Current.CU, Current.Flags,920WorklistItemType::LookForChildDIEsToKeep);921922if (AlreadyKept || !(Current.Flags & TF_Keep))923continue;924925// If it is a newly kept DIE mark it as well as all its dependencies as926// kept.927MyInfo.Keep = true;928929// We're looking for incomplete types.930MyInfo.Incomplete =931Current.Die.getTag() != dwarf::DW_TAG_subprogram &&932Current.Die.getTag() != dwarf::DW_TAG_member &&933dwarf::toUnsigned(Current.Die.find(dwarf::DW_AT_declaration), 0);934935// After looking at the parent chain, look for referenced DIEs. Because of936// the LIFO worklist we need to schedule that work before any subsequent937// items are added to the worklist.938Worklist.emplace_back(Current.Die, Current.CU, Current.Flags,939WorklistItemType::LookForRefDIEsToKeep);940941bool UseOdr = (Current.Flags & TF_DependencyWalk) ? (Current.Flags & TF_ODR)942: Current.CU.hasODR();943unsigned ODRFlag = UseOdr ? TF_ODR : 0;944unsigned ParFlags = TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag;945946// Now schedule the parent walk.947Worklist.emplace_back(MyInfo.ParentIdx, Current.CU, ParFlags);948}949}950951#ifndef NDEBUG952/// A broken link in the keep chain. By recording both the parent and the child953/// we can show only broken links for DIEs with multiple children.954struct BrokenLink {955BrokenLink(DWARFDie Parent, DWARFDie Child) : Parent(Parent), Child(Child) {}956DWARFDie Parent;957DWARFDie Child;958};959960/// Verify the keep chain by looking for DIEs that are kept but who's parent961/// isn't.962static void verifyKeepChain(CompileUnit &CU) {963std::vector<DWARFDie> Worklist;964Worklist.push_back(CU.getOrigUnit().getUnitDIE());965966// List of broken links.967std::vector<BrokenLink> BrokenLinks;968969while (!Worklist.empty()) {970const DWARFDie Current = Worklist.back();971Worklist.pop_back();972973const bool CurrentDieIsKept = CU.getInfo(Current).Keep;974975for (DWARFDie Child : reverse(Current.children())) {976Worklist.push_back(Child);977978const bool ChildDieIsKept = CU.getInfo(Child).Keep;979if (!CurrentDieIsKept && ChildDieIsKept)980BrokenLinks.emplace_back(Current, Child);981}982}983984if (!BrokenLinks.empty()) {985for (BrokenLink Link : BrokenLinks) {986WithColor::error() << formatv(987"Found invalid link in keep chain between {0:x} and {1:x}\n",988Link.Parent.getOffset(), Link.Child.getOffset());989990errs() << "Parent:";991Link.Parent.dump(errs(), 0, {});992CU.getInfo(Link.Parent).dump();993994errs() << "Child:";995Link.Child.dump(errs(), 2, {});996CU.getInfo(Link.Child).dump();997}998report_fatal_error("invalid keep chain");999}1000}1001#endif10021003/// Assign an abbreviation number to \p Abbrev.1004///1005/// Our DIEs get freed after every DebugMapObject has been processed,1006/// thus the FoldingSet we use to unique DIEAbbrevs cannot refer to1007/// the instances hold by the DIEs. When we encounter an abbreviation1008/// that we don't know, we create a permanent copy of it.1009void DWARFLinker::assignAbbrev(DIEAbbrev &Abbrev) {1010// Check the set for priors.1011FoldingSetNodeID ID;1012Abbrev.Profile(ID);1013void *InsertToken;1014DIEAbbrev *InSet = AbbreviationsSet.FindNodeOrInsertPos(ID, InsertToken);10151016// If it's newly added.1017if (InSet) {1018// Assign existing abbreviation number.1019Abbrev.setNumber(InSet->getNumber());1020} else {1021// Add to abbreviation list.1022Abbreviations.push_back(1023std::make_unique<DIEAbbrev>(Abbrev.getTag(), Abbrev.hasChildren()));1024for (const auto &Attr : Abbrev.getData())1025Abbreviations.back()->AddAttribute(Attr);1026AbbreviationsSet.InsertNode(Abbreviations.back().get(), InsertToken);1027// Assign the unique abbreviation number.1028Abbrev.setNumber(Abbreviations.size());1029Abbreviations.back()->setNumber(Abbreviations.size());1030}1031}10321033unsigned DWARFLinker::DIECloner::cloneStringAttribute(DIE &Die,1034AttributeSpec AttrSpec,1035const DWARFFormValue &Val,1036const DWARFUnit &U,1037AttributesInfo &Info) {1038std::optional<const char *> String = dwarf::toString(Val);1039if (!String)1040return 0;1041DwarfStringPoolEntryRef StringEntry;1042if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {1043StringEntry = DebugLineStrPool.getEntry(*String);1044} else {1045StringEntry = DebugStrPool.getEntry(*String);10461047if (AttrSpec.Attr == dwarf::DW_AT_APPLE_origin) {1048Info.HasAppleOrigin = true;1049if (std::optional<StringRef> FileName =1050ObjFile.Addresses->getLibraryInstallName()) {1051StringEntry = DebugStrPool.getEntry(*FileName);1052}1053}10541055// Update attributes info.1056if (AttrSpec.Attr == dwarf::DW_AT_name)1057Info.Name = StringEntry;1058else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name ||1059AttrSpec.Attr == dwarf::DW_AT_linkage_name)1060Info.MangledName = StringEntry;1061if (U.getVersion() >= 5) {1062// Switch everything to DW_FORM_strx strings.1063auto StringOffsetIndex =1064StringOffsetPool.getValueIndex(StringEntry.getOffset());1065return Die1066.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),1067dwarf::DW_FORM_strx, DIEInteger(StringOffsetIndex))1068->sizeOf(U.getFormParams());1069}1070// Switch everything to out of line strings.1071AttrSpec.Form = dwarf::DW_FORM_strp;1072}1073Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), AttrSpec.Form,1074DIEInteger(StringEntry.getOffset()));1075return 4;1076}10771078unsigned DWARFLinker::DIECloner::cloneDieReferenceAttribute(1079DIE &Die, const DWARFDie &InputDIE, AttributeSpec AttrSpec,1080unsigned AttrSize, const DWARFFormValue &Val, const DWARFFile &File,1081CompileUnit &Unit) {1082const DWARFUnit &U = Unit.getOrigUnit();1083uint64_t Ref;1084if (std::optional<uint64_t> Off = Val.getAsRelativeReference())1085Ref = Val.getUnit()->getOffset() + *Off;1086else if (Off = Val.getAsDebugInfoReference(); Off)1087Ref = *Off;1088else1089return 0;10901091DIE *NewRefDie = nullptr;1092CompileUnit *RefUnit = nullptr;10931094DWARFDie RefDie =1095Linker.resolveDIEReference(File, CompileUnits, Val, InputDIE, RefUnit);10961097// If the referenced DIE is not found, drop the attribute.1098if (!RefDie || AttrSpec.Attr == dwarf::DW_AT_sibling)1099return 0;11001101CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(RefDie);11021103// If we already have emitted an equivalent DeclContext, just point1104// at it.1105if (isODRAttribute(AttrSpec.Attr) && RefInfo.Ctxt &&1106RefInfo.Ctxt->getCanonicalDIEOffset()) {1107assert(RefInfo.Ctxt->hasCanonicalDIE() &&1108"Offset to canonical die is set, but context is not marked");1109DIEInteger Attr(RefInfo.Ctxt->getCanonicalDIEOffset());1110Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),1111dwarf::DW_FORM_ref_addr, Attr);1112return U.getRefAddrByteSize();1113}11141115if (!RefInfo.Clone) {1116// We haven't cloned this DIE yet. Just create an empty one and1117// store it. It'll get really cloned when we process it.1118RefInfo.UnclonedReference = true;1119RefInfo.Clone = DIE::get(DIEAlloc, dwarf::Tag(RefDie.getTag()));1120}1121NewRefDie = RefInfo.Clone;11221123if (AttrSpec.Form == dwarf::DW_FORM_ref_addr ||1124(Unit.hasODR() && isODRAttribute(AttrSpec.Attr))) {1125// We cannot currently rely on a DIEEntry to emit ref_addr1126// references, because the implementation calls back to DwarfDebug1127// to find the unit offset. (We don't have a DwarfDebug)1128// FIXME: we should be able to design DIEEntry reliance on1129// DwarfDebug away.1130uint64_t Attr;1131if (Ref < InputDIE.getOffset() && !RefInfo.UnclonedReference) {1132// We have already cloned that DIE.1133uint32_t NewRefOffset =1134RefUnit->getStartOffset() + NewRefDie->getOffset();1135Attr = NewRefOffset;1136Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),1137dwarf::DW_FORM_ref_addr, DIEInteger(Attr));1138} else {1139// A forward reference. Note and fixup later.1140Attr = 0xBADDEF;1141Unit.noteForwardReference(1142NewRefDie, RefUnit, RefInfo.Ctxt,1143Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),1144dwarf::DW_FORM_ref_addr, DIEInteger(Attr)));1145}1146return U.getRefAddrByteSize();1147}11481149Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),1150dwarf::Form(AttrSpec.Form), DIEEntry(*NewRefDie));11511152return AttrSize;1153}11541155void DWARFLinker::DIECloner::cloneExpression(1156DataExtractor &Data, DWARFExpression Expression, const DWARFFile &File,1157CompileUnit &Unit, SmallVectorImpl<uint8_t> &OutputBuffer,1158int64_t AddrRelocAdjustment, bool IsLittleEndian) {1159using Encoding = DWARFExpression::Operation::Encoding;11601161uint8_t OrigAddressByteSize = Unit.getOrigUnit().getAddressByteSize();11621163uint64_t OpOffset = 0;1164for (auto &Op : Expression) {1165auto Desc = Op.getDescription();1166// DW_OP_const_type is variable-length and has 31167// operands. Thus far we only support 2.1168if ((Desc.Op.size() == 2 && Desc.Op[0] == Encoding::BaseTypeRef) ||1169(Desc.Op.size() == 2 && Desc.Op[1] == Encoding::BaseTypeRef &&1170Desc.Op[0] != Encoding::Size1))1171Linker.reportWarning("Unsupported DW_OP encoding.", File);11721173if ((Desc.Op.size() == 1 && Desc.Op[0] == Encoding::BaseTypeRef) ||1174(Desc.Op.size() == 2 && Desc.Op[1] == Encoding::BaseTypeRef &&1175Desc.Op[0] == Encoding::Size1)) {1176// This code assumes that the other non-typeref operand fits into 1 byte.1177assert(OpOffset < Op.getEndOffset());1178uint32_t ULEBsize = Op.getEndOffset() - OpOffset - 1;1179assert(ULEBsize <= 16);11801181// Copy over the operation.1182assert(!Op.getSubCode() && "SubOps not yet supported");1183OutputBuffer.push_back(Op.getCode());1184uint64_t RefOffset;1185if (Desc.Op.size() == 1) {1186RefOffset = Op.getRawOperand(0);1187} else {1188OutputBuffer.push_back(Op.getRawOperand(0));1189RefOffset = Op.getRawOperand(1);1190}1191uint32_t Offset = 0;1192// Look up the base type. For DW_OP_convert, the operand may be 0 to1193// instead indicate the generic type. The same holds for1194// DW_OP_reinterpret, which is currently not supported.1195if (RefOffset > 0 || Op.getCode() != dwarf::DW_OP_convert) {1196RefOffset += Unit.getOrigUnit().getOffset();1197auto RefDie = Unit.getOrigUnit().getDIEForOffset(RefOffset);1198CompileUnit::DIEInfo &Info = Unit.getInfo(RefDie);1199if (DIE *Clone = Info.Clone)1200Offset = Clone->getOffset();1201else1202Linker.reportWarning(1203"base type ref doesn't point to DW_TAG_base_type.", File);1204}1205uint8_t ULEB[16];1206unsigned RealSize = encodeULEB128(Offset, ULEB, ULEBsize);1207if (RealSize > ULEBsize) {1208// Emit the generic type as a fallback.1209RealSize = encodeULEB128(0, ULEB, ULEBsize);1210Linker.reportWarning("base type ref doesn't fit.", File);1211}1212assert(RealSize == ULEBsize && "padding failed");1213ArrayRef<uint8_t> ULEBbytes(ULEB, ULEBsize);1214OutputBuffer.append(ULEBbytes.begin(), ULEBbytes.end());1215} else if (!Linker.Options.Update && Op.getCode() == dwarf::DW_OP_addrx) {1216if (std::optional<object::SectionedAddress> SA =1217Unit.getOrigUnit().getAddrOffsetSectionItem(1218Op.getRawOperand(0))) {1219// DWARFLinker does not use addrx forms since it generates relocated1220// addresses. Replace DW_OP_addrx with DW_OP_addr here.1221// Argument of DW_OP_addrx should be relocated here as it is not1222// processed by applyValidRelocs.1223OutputBuffer.push_back(dwarf::DW_OP_addr);1224uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment;1225if (IsLittleEndian != sys::IsLittleEndianHost)1226sys::swapByteOrder(LinkedAddress);1227ArrayRef<uint8_t> AddressBytes(1228reinterpret_cast<const uint8_t *>(&LinkedAddress),1229OrigAddressByteSize);1230OutputBuffer.append(AddressBytes.begin(), AddressBytes.end());1231} else1232Linker.reportWarning("cannot read DW_OP_addrx operand.", File);1233} else if (!Linker.Options.Update && Op.getCode() == dwarf::DW_OP_constx) {1234if (std::optional<object::SectionedAddress> SA =1235Unit.getOrigUnit().getAddrOffsetSectionItem(1236Op.getRawOperand(0))) {1237// DWARFLinker does not use constx forms since it generates relocated1238// addresses. Replace DW_OP_constx with DW_OP_const[*]u here.1239// Argument of DW_OP_constx should be relocated here as it is not1240// processed by applyValidRelocs.1241std::optional<uint8_t> OutOperandKind;1242switch (OrigAddressByteSize) {1243case 4:1244OutOperandKind = dwarf::DW_OP_const4u;1245break;1246case 8:1247OutOperandKind = dwarf::DW_OP_const8u;1248break;1249default:1250Linker.reportWarning(1251formatv(("unsupported address size: {0}."), OrigAddressByteSize),1252File);1253break;1254}12551256if (OutOperandKind) {1257OutputBuffer.push_back(*OutOperandKind);1258uint64_t LinkedAddress = SA->Address + AddrRelocAdjustment;1259if (IsLittleEndian != sys::IsLittleEndianHost)1260sys::swapByteOrder(LinkedAddress);1261ArrayRef<uint8_t> AddressBytes(1262reinterpret_cast<const uint8_t *>(&LinkedAddress),1263OrigAddressByteSize);1264OutputBuffer.append(AddressBytes.begin(), AddressBytes.end());1265}1266} else1267Linker.reportWarning("cannot read DW_OP_constx operand.", File);1268} else {1269// Copy over everything else unmodified.1270StringRef Bytes = Data.getData().slice(OpOffset, Op.getEndOffset());1271OutputBuffer.append(Bytes.begin(), Bytes.end());1272}1273OpOffset = Op.getEndOffset();1274}1275}12761277unsigned DWARFLinker::DIECloner::cloneBlockAttribute(1278DIE &Die, const DWARFDie &InputDIE, const DWARFFile &File,1279CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val,1280bool IsLittleEndian) {1281DIEValueList *Attr;1282DIEValue Value;1283DIELoc *Loc = nullptr;1284DIEBlock *Block = nullptr;1285if (AttrSpec.Form == dwarf::DW_FORM_exprloc) {1286Loc = new (DIEAlloc) DIELoc;1287Linker.DIELocs.push_back(Loc);1288} else {1289Block = new (DIEAlloc) DIEBlock;1290Linker.DIEBlocks.push_back(Block);1291}1292Attr = Loc ? static_cast<DIEValueList *>(Loc)1293: static_cast<DIEValueList *>(Block);12941295DWARFUnit &OrigUnit = Unit.getOrigUnit();1296// If the block is a DWARF Expression, clone it into the temporary1297// buffer using cloneExpression(), otherwise copy the data directly.1298SmallVector<uint8_t, 32> Buffer;1299ArrayRef<uint8_t> Bytes = *Val.getAsBlock();1300if (DWARFAttribute::mayHaveLocationExpr(AttrSpec.Attr) &&1301(Val.isFormClass(DWARFFormValue::FC_Block) ||1302Val.isFormClass(DWARFFormValue::FC_Exprloc))) {1303DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()),1304IsLittleEndian, OrigUnit.getAddressByteSize());1305DWARFExpression Expr(Data, OrigUnit.getAddressByteSize(),1306OrigUnit.getFormParams().Format);1307cloneExpression(Data, Expr, File, Unit, Buffer,1308Unit.getInfo(InputDIE).AddrAdjust, IsLittleEndian);1309Bytes = Buffer;1310}1311for (auto Byte : Bytes)1312Attr->addValue(DIEAlloc, static_cast<dwarf::Attribute>(0),1313dwarf::DW_FORM_data1, DIEInteger(Byte));13141315// FIXME: If DIEBlock and DIELoc just reuses the Size field of1316// the DIE class, this "if" could be replaced by1317// Attr->setSize(Bytes.size()).1318if (Loc)1319Loc->setSize(Bytes.size());1320else1321Block->setSize(Bytes.size());13221323if (Loc)1324Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),1325dwarf::Form(AttrSpec.Form), Loc);1326else {1327// The expression location data might be updated and exceed the original1328// size. Check whether the new data fits into the original form.1329if ((AttrSpec.Form == dwarf::DW_FORM_block1 &&1330(Bytes.size() > UINT8_MAX)) ||1331(AttrSpec.Form == dwarf::DW_FORM_block2 &&1332(Bytes.size() > UINT16_MAX)) ||1333(AttrSpec.Form == dwarf::DW_FORM_block4 && (Bytes.size() > UINT32_MAX)))1334AttrSpec.Form = dwarf::DW_FORM_block;13351336Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),1337dwarf::Form(AttrSpec.Form), Block);1338}13391340return Die.addValue(DIEAlloc, Value)->sizeOf(OrigUnit.getFormParams());1341}13421343unsigned DWARFLinker::DIECloner::cloneAddressAttribute(1344DIE &Die, const DWARFDie &InputDIE, AttributeSpec AttrSpec,1345unsigned AttrSize, const DWARFFormValue &Val, const CompileUnit &Unit,1346AttributesInfo &Info) {1347if (AttrSpec.Attr == dwarf::DW_AT_low_pc)1348Info.HasLowPc = true;13491350if (LLVM_UNLIKELY(Linker.Options.Update)) {1351Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),1352dwarf::Form(AttrSpec.Form), DIEInteger(Val.getRawUValue()));1353return AttrSize;1354}13551356// Cloned Die may have address attributes relocated to a1357// totally unrelated value. This can happen:1358// - If high_pc is an address (Dwarf version == 2), then it might have been1359// relocated to a totally unrelated value (because the end address in the1360// object file might be start address of another function which got moved1361// independently by the linker).1362// - If address relocated in an inline_subprogram that happens at the1363// beginning of its inlining function.1364// To avoid above cases and to not apply relocation twice (in1365// applyValidRelocs and here), read address attribute from InputDIE and apply1366// Info.PCOffset here.13671368std::optional<DWARFFormValue> AddrAttribute = InputDIE.find(AttrSpec.Attr);1369if (!AddrAttribute)1370llvm_unreachable("Cann't find attribute.");13711372std::optional<uint64_t> Addr = AddrAttribute->getAsAddress();1373if (!Addr) {1374Linker.reportWarning("Cann't read address attribute value.", ObjFile);1375return 0;1376}13771378if (InputDIE.getTag() == dwarf::DW_TAG_compile_unit &&1379AttrSpec.Attr == dwarf::DW_AT_low_pc) {1380if (std::optional<uint64_t> LowPC = Unit.getLowPc())1381Addr = *LowPC;1382else1383return 0;1384} else if (InputDIE.getTag() == dwarf::DW_TAG_compile_unit &&1385AttrSpec.Attr == dwarf::DW_AT_high_pc) {1386if (uint64_t HighPc = Unit.getHighPc())1387Addr = HighPc;1388else1389return 0;1390} else {1391*Addr += Info.PCOffset;1392}13931394if (AttrSpec.Form == dwarf::DW_FORM_addr) {1395Die.addValue(DIEAlloc, static_cast<dwarf::Attribute>(AttrSpec.Attr),1396AttrSpec.Form, DIEInteger(*Addr));1397return Unit.getOrigUnit().getAddressByteSize();1398}13991400auto AddrIndex = AddrPool.getValueIndex(*Addr);14011402return Die1403.addValue(DIEAlloc, static_cast<dwarf::Attribute>(AttrSpec.Attr),1404dwarf::Form::DW_FORM_addrx, DIEInteger(AddrIndex))1405->sizeOf(Unit.getOrigUnit().getFormParams());1406}14071408unsigned DWARFLinker::DIECloner::cloneScalarAttribute(1409DIE &Die, const DWARFDie &InputDIE, const DWARFFile &File,1410CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val,1411unsigned AttrSize, AttributesInfo &Info) {1412uint64_t Value;14131414// Check for the offset to the macro table. If offset is incorrect then we1415// need to remove the attribute.1416if (AttrSpec.Attr == dwarf::DW_AT_macro_info) {1417if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {1418const llvm::DWARFDebugMacro *Macro = File.Dwarf->getDebugMacinfo();1419if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset))1420return 0;1421}1422}14231424if (AttrSpec.Attr == dwarf::DW_AT_macros) {1425if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {1426const llvm::DWARFDebugMacro *Macro = File.Dwarf->getDebugMacro();1427if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset))1428return 0;1429}1430}14311432if (AttrSpec.Attr == dwarf::DW_AT_str_offsets_base) {1433// DWARFLinker generates common .debug_str_offsets table used for all1434// compile units. The offset to the common .debug_str_offsets table is 8 on1435// DWARF32.1436Info.AttrStrOffsetBaseSeen = true;1437return Die1438.addValue(DIEAlloc, dwarf::DW_AT_str_offsets_base,1439dwarf::DW_FORM_sec_offset, DIEInteger(8))1440->sizeOf(Unit.getOrigUnit().getFormParams());1441}14421443if (LLVM_UNLIKELY(Linker.Options.Update)) {1444if (auto OptionalValue = Val.getAsUnsignedConstant())1445Value = *OptionalValue;1446else if (auto OptionalValue = Val.getAsSignedConstant())1447Value = *OptionalValue;1448else if (auto OptionalValue = Val.getAsSectionOffset())1449Value = *OptionalValue;1450else {1451Linker.reportWarning(1452"Unsupported scalar attribute form. Dropping attribute.", File,1453&InputDIE);1454return 0;1455}1456if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)1457Info.IsDeclaration = true;14581459if (AttrSpec.Form == dwarf::DW_FORM_loclistx)1460Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),1461dwarf::Form(AttrSpec.Form), DIELocList(Value));1462else1463Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),1464dwarf::Form(AttrSpec.Form), DIEInteger(Value));1465return AttrSize;1466}14671468[[maybe_unused]] dwarf::Form OriginalForm = AttrSpec.Form;1469if (AttrSpec.Form == dwarf::DW_FORM_rnglistx) {1470// DWARFLinker does not generate .debug_addr table. Thus we need to change1471// all "addrx" related forms to "addr" version. Change DW_FORM_rnglistx1472// to DW_FORM_sec_offset here.1473std::optional<uint64_t> Index = Val.getAsSectionOffset();1474if (!Index) {1475Linker.reportWarning("Cannot read the attribute. Dropping.", File,1476&InputDIE);1477return 0;1478}1479std::optional<uint64_t> Offset =1480Unit.getOrigUnit().getRnglistOffset(*Index);1481if (!Offset) {1482Linker.reportWarning("Cannot read the attribute. Dropping.", File,1483&InputDIE);1484return 0;1485}14861487Value = *Offset;1488AttrSpec.Form = dwarf::DW_FORM_sec_offset;1489AttrSize = Unit.getOrigUnit().getFormParams().getDwarfOffsetByteSize();1490} else if (AttrSpec.Form == dwarf::DW_FORM_loclistx) {1491// DWARFLinker does not generate .debug_addr table. Thus we need to change1492// all "addrx" related forms to "addr" version. Change DW_FORM_loclistx1493// to DW_FORM_sec_offset here.1494std::optional<uint64_t> Index = Val.getAsSectionOffset();1495if (!Index) {1496Linker.reportWarning("Cannot read the attribute. Dropping.", File,1497&InputDIE);1498return 0;1499}1500std::optional<uint64_t> Offset =1501Unit.getOrigUnit().getLoclistOffset(*Index);1502if (!Offset) {1503Linker.reportWarning("Cannot read the attribute. Dropping.", File,1504&InputDIE);1505return 0;1506}15071508Value = *Offset;1509AttrSpec.Form = dwarf::DW_FORM_sec_offset;1510AttrSize = Unit.getOrigUnit().getFormParams().getDwarfOffsetByteSize();1511} else if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&1512Die.getTag() == dwarf::DW_TAG_compile_unit) {1513std::optional<uint64_t> LowPC = Unit.getLowPc();1514if (!LowPC)1515return 0;1516// Dwarf >= 4 high_pc is an size, not an address.1517Value = Unit.getHighPc() - *LowPC;1518} else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)1519Value = *Val.getAsSectionOffset();1520else if (AttrSpec.Form == dwarf::DW_FORM_sdata)1521Value = *Val.getAsSignedConstant();1522else if (auto OptionalValue = Val.getAsUnsignedConstant())1523Value = *OptionalValue;1524else {1525Linker.reportWarning(1526"Unsupported scalar attribute form. Dropping attribute.", File,1527&InputDIE);1528return 0;1529}15301531DIE::value_iterator Patch =1532Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),1533dwarf::Form(AttrSpec.Form), DIEInteger(Value));1534if (AttrSpec.Attr == dwarf::DW_AT_ranges ||1535AttrSpec.Attr == dwarf::DW_AT_start_scope) {1536Unit.noteRangeAttribute(Die, Patch);1537Info.HasRanges = true;1538} else if (DWARFAttribute::mayHaveLocationList(AttrSpec.Attr) &&1539dwarf::doesFormBelongToClass(AttrSpec.Form,1540DWARFFormValue::FC_SectionOffset,1541Unit.getOrigUnit().getVersion())) {15421543CompileUnit::DIEInfo &LocationDieInfo = Unit.getInfo(InputDIE);1544Unit.noteLocationAttribute({Patch, LocationDieInfo.InDebugMap1545? LocationDieInfo.AddrAdjust1546: Info.PCOffset});1547} else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)1548Info.IsDeclaration = true;15491550// check that all dwarf::DW_FORM_rnglistx are handled previously.1551assert((Info.HasRanges || (OriginalForm != dwarf::DW_FORM_rnglistx)) &&1552"Unhandled DW_FORM_rnglistx attribute");15531554return AttrSize;1555}15561557/// Clone \p InputDIE's attribute described by \p AttrSpec with1558/// value \p Val, and add it to \p Die.1559/// \returns the size of the cloned attribute.1560unsigned DWARFLinker::DIECloner::cloneAttribute(1561DIE &Die, const DWARFDie &InputDIE, const DWARFFile &File,1562CompileUnit &Unit, const DWARFFormValue &Val, const AttributeSpec AttrSpec,1563unsigned AttrSize, AttributesInfo &Info, bool IsLittleEndian) {1564const DWARFUnit &U = Unit.getOrigUnit();15651566switch (AttrSpec.Form) {1567case dwarf::DW_FORM_strp:1568case dwarf::DW_FORM_line_strp:1569case dwarf::DW_FORM_string:1570case dwarf::DW_FORM_strx:1571case dwarf::DW_FORM_strx1:1572case dwarf::DW_FORM_strx2:1573case dwarf::DW_FORM_strx3:1574case dwarf::DW_FORM_strx4:1575return cloneStringAttribute(Die, AttrSpec, Val, U, Info);1576case dwarf::DW_FORM_ref_addr:1577case dwarf::DW_FORM_ref1:1578case dwarf::DW_FORM_ref2:1579case dwarf::DW_FORM_ref4:1580case dwarf::DW_FORM_ref8:1581return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val,1582File, Unit);1583case dwarf::DW_FORM_block:1584case dwarf::DW_FORM_block1:1585case dwarf::DW_FORM_block2:1586case dwarf::DW_FORM_block4:1587case dwarf::DW_FORM_exprloc:1588return cloneBlockAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,1589IsLittleEndian);1590case dwarf::DW_FORM_addr:1591case dwarf::DW_FORM_addrx:1592case dwarf::DW_FORM_addrx1:1593case dwarf::DW_FORM_addrx2:1594case dwarf::DW_FORM_addrx3:1595case dwarf::DW_FORM_addrx4:1596return cloneAddressAttribute(Die, InputDIE, AttrSpec, AttrSize, Val, Unit,1597Info);1598case dwarf::DW_FORM_data1:1599case dwarf::DW_FORM_data2:1600case dwarf::DW_FORM_data4:1601case dwarf::DW_FORM_data8:1602case dwarf::DW_FORM_udata:1603case dwarf::DW_FORM_sdata:1604case dwarf::DW_FORM_sec_offset:1605case dwarf::DW_FORM_flag:1606case dwarf::DW_FORM_flag_present:1607case dwarf::DW_FORM_rnglistx:1608case dwarf::DW_FORM_loclistx:1609case dwarf::DW_FORM_implicit_const:1610return cloneScalarAttribute(Die, InputDIE, File, Unit, AttrSpec, Val,1611AttrSize, Info);1612default:1613Linker.reportWarning("Unsupported attribute form " +1614dwarf::FormEncodingString(AttrSpec.Form) +1615" in cloneAttribute. Dropping.",1616File, &InputDIE);1617}16181619return 0;1620}16211622void DWARFLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit,1623const DIE *Die,1624DwarfStringPoolEntryRef Name,1625OffsetsStringPool &StringPool,1626bool SkipPubSection) {1627std::optional<ObjCSelectorNames> Names =1628getObjCNamesIfSelector(Name.getString());1629if (!Names)1630return;1631Unit.addNameAccelerator(Die, StringPool.getEntry(Names->Selector),1632SkipPubSection);1633Unit.addObjCAccelerator(Die, StringPool.getEntry(Names->ClassName),1634SkipPubSection);1635if (Names->ClassNameNoCategory)1636Unit.addObjCAccelerator(1637Die, StringPool.getEntry(*Names->ClassNameNoCategory), SkipPubSection);1638if (Names->MethodNameNoCategory)1639Unit.addNameAccelerator(1640Die, StringPool.getEntry(*Names->MethodNameNoCategory), SkipPubSection);1641}16421643static bool1644shouldSkipAttribute(bool Update,1645DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,1646bool SkipPC) {1647switch (AttrSpec.Attr) {1648default:1649return false;1650case dwarf::DW_AT_low_pc:1651case dwarf::DW_AT_high_pc:1652case dwarf::DW_AT_ranges:1653return !Update && SkipPC;1654case dwarf::DW_AT_rnglists_base:1655// In case !Update the .debug_addr table is not generated/preserved.1656// Thus instead of DW_FORM_rnglistx the DW_FORM_sec_offset is used.1657// Since DW_AT_rnglists_base is used for only DW_FORM_rnglistx the1658// DW_AT_rnglists_base is removed.1659return !Update;1660case dwarf::DW_AT_loclists_base:1661// In case !Update the .debug_addr table is not generated/preserved.1662// Thus instead of DW_FORM_loclistx the DW_FORM_sec_offset is used.1663// Since DW_AT_loclists_base is used for only DW_FORM_loclistx the1664// DW_AT_loclists_base is removed.1665return !Update;1666case dwarf::DW_AT_location:1667case dwarf::DW_AT_frame_base:1668return !Update && SkipPC;1669}1670}16711672struct AttributeLinkedOffsetFixup {1673int64_t LinkedOffsetFixupVal;1674uint64_t InputAttrStartOffset;1675uint64_t InputAttrEndOffset;1676};16771678DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,1679const DWARFFile &File, CompileUnit &Unit,1680int64_t PCOffset, uint32_t OutOffset,1681unsigned Flags, bool IsLittleEndian,1682DIE *Die) {1683DWARFUnit &U = Unit.getOrigUnit();1684unsigned Idx = U.getDIEIndex(InputDIE);1685CompileUnit::DIEInfo &Info = Unit.getInfo(Idx);16861687// Should the DIE appear in the output?1688if (!Unit.getInfo(Idx).Keep)1689return nullptr;16901691uint64_t Offset = InputDIE.getOffset();1692assert(!(Die && Info.Clone) && "Can't supply a DIE and a cloned DIE");1693if (!Die) {1694// The DIE might have been already created by a forward reference1695// (see cloneDieReferenceAttribute()).1696if (!Info.Clone)1697Info.Clone = DIE::get(DIEAlloc, dwarf::Tag(InputDIE.getTag()));1698Die = Info.Clone;1699}17001701assert(Die->getTag() == InputDIE.getTag());1702Die->setOffset(OutOffset);1703if (isODRCanonicalCandidate(InputDIE, Unit) && Info.Ctxt &&1704(Info.Ctxt->getCanonicalDIEOffset() == 0)) {1705if (!Info.Ctxt->hasCanonicalDIE())1706Info.Ctxt->setHasCanonicalDIE();1707// We are about to emit a DIE that is the root of its own valid1708// DeclContext tree. Make the current offset the canonical offset1709// for this context.1710Info.Ctxt->setCanonicalDIEOffset(OutOffset + Unit.getStartOffset());1711}17121713// Extract and clone every attribute.1714DWARFDataExtractor Data = U.getDebugInfoExtractor();1715// Point to the next DIE (generally there is always at least a NULL1716// entry after the current one). If this is a lone1717// DW_TAG_compile_unit without any children, point to the next unit.1718uint64_t NextOffset = (Idx + 1 < U.getNumDIEs())1719? U.getDIEAtIndex(Idx + 1).getOffset()1720: U.getNextUnitOffset();1721AttributesInfo AttrInfo;17221723// We could copy the data only if we need to apply a relocation to it. After1724// testing, it seems there is no performance downside to doing the copy1725// unconditionally, and it makes the code simpler.1726SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset));1727Data =1728DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());17291730// Modify the copy with relocated addresses.1731ObjFile.Addresses->applyValidRelocs(DIECopy, Offset, Data.isLittleEndian());17321733// Reset the Offset to 0 as we will be working on the local copy of1734// the data.1735Offset = 0;17361737const auto *Abbrev = InputDIE.getAbbreviationDeclarationPtr();1738Offset += getULEB128Size(Abbrev->getCode());17391740// We are entering a subprogram. Get and propagate the PCOffset.1741if (Die->getTag() == dwarf::DW_TAG_subprogram)1742PCOffset = Info.AddrAdjust;1743AttrInfo.PCOffset = PCOffset;17441745if (Abbrev->getTag() == dwarf::DW_TAG_subprogram) {1746Flags |= TF_InFunctionScope;1747if (!Info.InDebugMap && LLVM_LIKELY(!Update))1748Flags |= TF_SkipPC;1749} else if (Abbrev->getTag() == dwarf::DW_TAG_variable) {1750// Function-local globals could be in the debug map even when the function1751// is not, e.g., inlined functions.1752if ((Flags & TF_InFunctionScope) && Info.InDebugMap)1753Flags &= ~TF_SkipPC;1754// Location expressions referencing an address which is not in debug map1755// should be deleted.1756else if (!Info.InDebugMap && Info.HasLocationExpressionAddr &&1757LLVM_LIKELY(!Update))1758Flags |= TF_SkipPC;1759}17601761std::optional<StringRef> LibraryInstallName =1762ObjFile.Addresses->getLibraryInstallName();1763SmallVector<AttributeLinkedOffsetFixup> AttributesFixups;1764for (const auto &AttrSpec : Abbrev->attributes()) {1765if (shouldSkipAttribute(Update, AttrSpec, Flags & TF_SkipPC)) {1766DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,1767U.getFormParams());1768continue;1769}17701771AttributeLinkedOffsetFixup CurAttrFixup;1772CurAttrFixup.InputAttrStartOffset = InputDIE.getOffset() + Offset;1773CurAttrFixup.LinkedOffsetFixupVal =1774Unit.getStartOffset() + OutOffset - CurAttrFixup.InputAttrStartOffset;17751776DWARFFormValue Val = AttrSpec.getFormValue();1777uint64_t AttrSize = Offset;1778Val.extractValue(Data, &Offset, U.getFormParams(), &U);1779CurAttrFixup.InputAttrEndOffset = InputDIE.getOffset() + Offset;1780AttrSize = Offset - AttrSize;17811782uint64_t FinalAttrSize =1783cloneAttribute(*Die, InputDIE, File, Unit, Val, AttrSpec, AttrSize,1784AttrInfo, IsLittleEndian);1785if (FinalAttrSize != 0 && ObjFile.Addresses->needToSaveValidRelocs())1786AttributesFixups.push_back(CurAttrFixup);17871788OutOffset += FinalAttrSize;1789}17901791uint16_t Tag = InputDIE.getTag();1792// Add the DW_AT_APPLE_origin attribute to Compile Unit die if we have1793// an install name and the DWARF doesn't have the attribute yet.1794const bool NeedsAppleOrigin = (Tag == dwarf::DW_TAG_compile_unit) &&1795LibraryInstallName.has_value() &&1796!AttrInfo.HasAppleOrigin;1797if (NeedsAppleOrigin) {1798auto StringEntry = DebugStrPool.getEntry(LibraryInstallName.value());1799Die->addValue(DIEAlloc, dwarf::Attribute(dwarf::DW_AT_APPLE_origin),1800dwarf::DW_FORM_strp, DIEInteger(StringEntry.getOffset()));1801AttrInfo.Name = StringEntry;1802OutOffset += 4;1803}18041805// Look for accelerator entries.1806// FIXME: This is slightly wrong. An inline_subroutine without a1807// low_pc, but with AT_ranges might be interesting to get into the1808// accelerator tables too. For now stick with dsymutil's behavior.1809if ((Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&1810Tag != dwarf::DW_TAG_compile_unit &&1811getDIENames(InputDIE, AttrInfo, DebugStrPool,1812Tag != dwarf::DW_TAG_inlined_subroutine)) {1813if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)1814Unit.addNameAccelerator(Die, AttrInfo.MangledName,1815Tag == dwarf::DW_TAG_inlined_subroutine);1816if (AttrInfo.Name) {1817if (AttrInfo.NameWithoutTemplate)1818Unit.addNameAccelerator(Die, AttrInfo.NameWithoutTemplate,1819/* SkipPubSection */ true);1820Unit.addNameAccelerator(Die, AttrInfo.Name,1821Tag == dwarf::DW_TAG_inlined_subroutine);1822}1823if (AttrInfo.Name)1824addObjCAccelerator(Unit, Die, AttrInfo.Name, DebugStrPool,1825/* SkipPubSection =*/true);18261827} else if (Tag == dwarf::DW_TAG_namespace) {1828if (!AttrInfo.Name)1829AttrInfo.Name = DebugStrPool.getEntry("(anonymous namespace)");1830Unit.addNamespaceAccelerator(Die, AttrInfo.Name);1831} else if (Tag == dwarf::DW_TAG_imported_declaration && AttrInfo.Name) {1832Unit.addNamespaceAccelerator(Die, AttrInfo.Name);1833} else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration &&1834getDIENames(InputDIE, AttrInfo, DebugStrPool) && AttrInfo.Name &&1835AttrInfo.Name.getString()[0]) {1836uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit, File);1837uint64_t RuntimeLang =1838dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))1839.value_or(0);1840bool ObjCClassIsImplementation =1841(RuntimeLang == dwarf::DW_LANG_ObjC ||1842RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&1843dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))1844.value_or(0);1845Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation,1846Hash);1847}18481849// Determine whether there are any children that we want to keep.1850bool HasChildren = false;1851for (auto Child : InputDIE.children()) {1852unsigned Idx = U.getDIEIndex(Child);1853if (Unit.getInfo(Idx).Keep) {1854HasChildren = true;1855break;1856}1857}18581859if (Unit.getOrigUnit().getVersion() >= 5 && !AttrInfo.AttrStrOffsetBaseSeen &&1860Die->getTag() == dwarf::DW_TAG_compile_unit) {1861// No DW_AT_str_offsets_base seen, add it to the DIE.1862Die->addValue(DIEAlloc, dwarf::DW_AT_str_offsets_base,1863dwarf::DW_FORM_sec_offset, DIEInteger(8));1864OutOffset += 4;1865}18661867DIEAbbrev NewAbbrev = Die->generateAbbrev();1868if (HasChildren)1869NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);1870// Assign a permanent abbrev number1871Linker.assignAbbrev(NewAbbrev);1872Die->setAbbrevNumber(NewAbbrev.getNumber());18731874uint64_t AbbrevNumberSize = getULEB128Size(Die->getAbbrevNumber());18751876// Add the size of the abbreviation number to the output offset.1877OutOffset += AbbrevNumberSize;18781879// Update fixups with the size of the abbreviation number1880for (AttributeLinkedOffsetFixup &F : AttributesFixups)1881F.LinkedOffsetFixupVal += AbbrevNumberSize;18821883for (AttributeLinkedOffsetFixup &F : AttributesFixups)1884ObjFile.Addresses->updateAndSaveValidRelocs(1885Unit.getOrigUnit().getVersion() >= 5, Unit.getOrigUnit().getOffset(),1886F.LinkedOffsetFixupVal, F.InputAttrStartOffset, F.InputAttrEndOffset);18871888if (!HasChildren) {1889// Update our size.1890Die->setSize(OutOffset - Die->getOffset());1891return Die;1892}18931894// Recursively clone children.1895for (auto Child : InputDIE.children()) {1896if (DIE *Clone = cloneDIE(Child, File, Unit, PCOffset, OutOffset, Flags,1897IsLittleEndian)) {1898Die->addChild(Clone);1899OutOffset = Clone->getOffset() + Clone->getSize();1900}1901}19021903// Account for the end of children marker.1904OutOffset += sizeof(int8_t);1905// Update our size.1906Die->setSize(OutOffset - Die->getOffset());1907return Die;1908}19091910/// Patch the input object file relevant debug_ranges or debug_rnglists1911/// entries and emit them in the output file. Update the relevant attributes1912/// to point at the new entries.1913void DWARFLinker::generateUnitRanges(CompileUnit &Unit, const DWARFFile &File,1914DebugDieValuePool &AddrPool) const {1915if (LLVM_UNLIKELY(Options.Update))1916return;19171918const auto &FunctionRanges = Unit.getFunctionRanges();19191920// Build set of linked address ranges for unit function ranges.1921AddressRanges LinkedFunctionRanges;1922for (const AddressRangeValuePair &Range : FunctionRanges)1923LinkedFunctionRanges.insert(1924{Range.Range.start() + Range.Value, Range.Range.end() + Range.Value});19251926// Emit LinkedFunctionRanges into .debug_aranges1927if (!LinkedFunctionRanges.empty())1928TheDwarfEmitter->emitDwarfDebugArangesTable(Unit, LinkedFunctionRanges);19291930RngListAttributesTy AllRngListAttributes = Unit.getRangesAttributes();1931std::optional<PatchLocation> UnitRngListAttribute =1932Unit.getUnitRangesAttribute();19331934if (!AllRngListAttributes.empty() || UnitRngListAttribute) {1935std::optional<AddressRangeValuePair> CachedRange;1936MCSymbol *EndLabel = TheDwarfEmitter->emitDwarfDebugRangeListHeader(Unit);19371938// Read original address ranges, apply relocation value, emit linked address1939// ranges.1940for (PatchLocation &AttributePatch : AllRngListAttributes) {1941// Get ranges from the source DWARF corresponding to the current1942// attribute.1943AddressRanges LinkedRanges;1944if (Expected<DWARFAddressRangesVector> OriginalRanges =1945Unit.getOrigUnit().findRnglistFromOffset(AttributePatch.get())) {1946// Apply relocation adjustment.1947for (const auto &Range : *OriginalRanges) {1948if (!CachedRange || !CachedRange->Range.contains(Range.LowPC))1949CachedRange = FunctionRanges.getRangeThatContains(Range.LowPC);19501951// All range entries should lie in the function range.1952if (!CachedRange) {1953reportWarning("inconsistent range data.", File);1954continue;1955}19561957// Store range for emiting.1958LinkedRanges.insert({Range.LowPC + CachedRange->Value,1959Range.HighPC + CachedRange->Value});1960}1961} else {1962llvm::consumeError(OriginalRanges.takeError());1963reportWarning("invalid range list ignored.", File);1964}19651966// Emit linked ranges.1967TheDwarfEmitter->emitDwarfDebugRangeListFragment(1968Unit, LinkedRanges, AttributePatch, AddrPool);1969}19701971// Emit ranges for Unit AT_ranges attribute.1972if (UnitRngListAttribute.has_value())1973TheDwarfEmitter->emitDwarfDebugRangeListFragment(1974Unit, LinkedFunctionRanges, *UnitRngListAttribute, AddrPool);19751976// Emit ranges footer.1977TheDwarfEmitter->emitDwarfDebugRangeListFooter(Unit, EndLabel);1978}1979}19801981void DWARFLinker::DIECloner::generateUnitLocations(1982CompileUnit &Unit, const DWARFFile &File,1983ExpressionHandlerRef ExprHandler) {1984if (LLVM_UNLIKELY(Linker.Options.Update))1985return;19861987const LocListAttributesTy &AllLocListAttributes =1988Unit.getLocationAttributes();19891990if (AllLocListAttributes.empty())1991return;19921993// Emit locations list table header.1994MCSymbol *EndLabel = Emitter->emitDwarfDebugLocListHeader(Unit);19951996for (auto &CurLocAttr : AllLocListAttributes) {1997// Get location expressions vector corresponding to the current attribute1998// from the source DWARF.1999Expected<DWARFLocationExpressionsVector> OriginalLocations =2000Unit.getOrigUnit().findLoclistFromOffset(CurLocAttr.get());20012002if (!OriginalLocations) {2003llvm::consumeError(OriginalLocations.takeError());2004Linker.reportWarning("Invalid location attribute ignored.", File);2005continue;2006}20072008DWARFLocationExpressionsVector LinkedLocationExpressions;2009for (DWARFLocationExpression &CurExpression : *OriginalLocations) {2010DWARFLocationExpression LinkedExpression;20112012if (CurExpression.Range) {2013// Relocate address range.2014LinkedExpression.Range = {2015CurExpression.Range->LowPC + CurLocAttr.RelocAdjustment,2016CurExpression.Range->HighPC + CurLocAttr.RelocAdjustment};2017}20182019// Clone expression.2020LinkedExpression.Expr.reserve(CurExpression.Expr.size());2021ExprHandler(CurExpression.Expr, LinkedExpression.Expr,2022CurLocAttr.RelocAdjustment);20232024LinkedLocationExpressions.push_back(LinkedExpression);2025}20262027// Emit locations list table fragment corresponding to the CurLocAttr.2028Emitter->emitDwarfDebugLocListFragment(Unit, LinkedLocationExpressions,2029CurLocAttr, AddrPool);2030}20312032// Emit locations list table footer.2033Emitter->emitDwarfDebugLocListFooter(Unit, EndLabel);2034}20352036static void patchAddrBase(DIE &Die, DIEInteger Offset) {2037for (auto &V : Die.values())2038if (V.getAttribute() == dwarf::DW_AT_addr_base) {2039V = DIEValue(V.getAttribute(), V.getForm(), Offset);2040return;2041}20422043llvm_unreachable("Didn't find a DW_AT_addr_base in cloned DIE!");2044}20452046void DWARFLinker::DIECloner::emitDebugAddrSection(2047CompileUnit &Unit, const uint16_t DwarfVersion) const {20482049if (LLVM_UNLIKELY(Linker.Options.Update))2050return;20512052if (DwarfVersion < 5)2053return;20542055if (AddrPool.getValues().empty())2056return;20572058MCSymbol *EndLabel = Emitter->emitDwarfDebugAddrsHeader(Unit);2059patchAddrBase(*Unit.getOutputUnitDIE(),2060DIEInteger(Emitter->getDebugAddrSectionSize()));2061Emitter->emitDwarfDebugAddrs(AddrPool.getValues(),2062Unit.getOrigUnit().getAddressByteSize());2063Emitter->emitDwarfDebugAddrsFooter(Unit, EndLabel);2064}20652066/// Insert the new line info sequence \p Seq into the current2067/// set of already linked line info \p Rows.2068static void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,2069std::vector<DWARFDebugLine::Row> &Rows) {2070if (Seq.empty())2071return;20722073if (!Rows.empty() && Rows.back().Address < Seq.front().Address) {2074llvm::append_range(Rows, Seq);2075Seq.clear();2076return;2077}20782079object::SectionedAddress Front = Seq.front().Address;2080auto InsertPoint = partition_point(2081Rows, [=](const DWARFDebugLine::Row &O) { return O.Address < Front; });20822083// FIXME: this only removes the unneeded end_sequence if the2084// sequences have been inserted in order. Using a global sort like2085// described in generateLineTableForUnit() and delaying the end_sequene2086// elimination to emitLineTableForUnit() we can get rid of all of them.2087if (InsertPoint != Rows.end() && InsertPoint->Address == Front &&2088InsertPoint->EndSequence) {2089*InsertPoint = Seq.front();2090Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end());2091} else {2092Rows.insert(InsertPoint, Seq.begin(), Seq.end());2093}20942095Seq.clear();2096}20972098static void patchStmtList(DIE &Die, DIEInteger Offset) {2099for (auto &V : Die.values())2100if (V.getAttribute() == dwarf::DW_AT_stmt_list) {2101V = DIEValue(V.getAttribute(), V.getForm(), Offset);2102return;2103}21042105llvm_unreachable("Didn't find DW_AT_stmt_list in cloned DIE!");2106}21072108void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {2109DWARFUnit &OrigUnit = Unit.getOrigUnit();2110DWARFDie OrigUnitDie = OrigUnit.getUnitDIE();21112112if (std::optional<uint64_t> MacroAttr =2113dwarf::toSectionOffset(OrigUnitDie.find(dwarf::DW_AT_macros))) {2114UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));2115return;2116}21172118if (std::optional<uint64_t> MacroAttr =2119dwarf::toSectionOffset(OrigUnitDie.find(dwarf::DW_AT_macro_info))) {2120UnitMacroMap.insert(std::make_pair(*MacroAttr, &Unit));2121return;2122}2123}21242125void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {2126if (LLVM_UNLIKELY(Emitter == nullptr))2127return;21282129// Check whether DW_AT_stmt_list attribute is presented.2130DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();2131auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list));2132if (!StmtList)2133return;21342135// Update the cloned DW_AT_stmt_list with the correct debug_line offset.2136if (auto *OutputDIE = Unit.getOutputUnitDIE())2137patchStmtList(*OutputDIE, DIEInteger(Emitter->getLineSectionSize()));21382139if (const DWARFDebugLine::LineTable *LT =2140ObjFile.Dwarf->getLineTableForUnit(&Unit.getOrigUnit())) {21412142DWARFDebugLine::LineTable LineTable;21432144// Set Line Table header.2145LineTable.Prologue = LT->Prologue;21462147// Set Line Table Rows.2148if (Linker.Options.Update) {2149LineTable.Rows = LT->Rows;2150// If all the line table contains is a DW_LNE_end_sequence, clear the line2151// table rows, it will be inserted again in the DWARFStreamer.2152if (LineTable.Rows.size() == 1 && LineTable.Rows[0].EndSequence)2153LineTable.Rows.clear();21542155LineTable.Sequences = LT->Sequences;2156} else {2157// This vector is the output line table.2158std::vector<DWARFDebugLine::Row> NewRows;2159NewRows.reserve(LT->Rows.size());21602161// Current sequence of rows being extracted, before being inserted2162// in NewRows.2163std::vector<DWARFDebugLine::Row> Seq;21642165const auto &FunctionRanges = Unit.getFunctionRanges();2166std::optional<AddressRangeValuePair> CurrRange;21672168// FIXME: This logic is meant to generate exactly the same output as2169// Darwin's classic dsymutil. There is a nicer way to implement this2170// by simply putting all the relocated line info in NewRows and simply2171// sorting NewRows before passing it to emitLineTableForUnit. This2172// should be correct as sequences for a function should stay2173// together in the sorted output. There are a few corner cases that2174// look suspicious though, and that required to implement the logic2175// this way. Revisit that once initial validation is finished.21762177// Iterate over the object file line info and extract the sequences2178// that correspond to linked functions.2179for (DWARFDebugLine::Row Row : LT->Rows) {2180// Check whether we stepped out of the range. The range is2181// half-open, but consider accept the end address of the range if2182// it is marked as end_sequence in the input (because in that2183// case, the relocation offset is accurate and that entry won't2184// serve as the start of another function).2185if (!CurrRange || !CurrRange->Range.contains(Row.Address.Address)) {2186// We just stepped out of a known range. Insert a end_sequence2187// corresponding to the end of the range.2188uint64_t StopAddress =2189CurrRange ? CurrRange->Range.end() + CurrRange->Value : -1ULL;2190CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);2191if (StopAddress != -1ULL && !Seq.empty()) {2192// Insert end sequence row with the computed end address, but2193// the same line as the previous one.2194auto NextLine = Seq.back();2195NextLine.Address.Address = StopAddress;2196NextLine.EndSequence = 1;2197NextLine.PrologueEnd = 0;2198NextLine.BasicBlock = 0;2199NextLine.EpilogueBegin = 0;2200Seq.push_back(NextLine);2201insertLineSequence(Seq, NewRows);2202}22032204if (!CurrRange)2205continue;2206}22072208// Ignore empty sequences.2209if (Row.EndSequence && Seq.empty())2210continue;22112212// Relocate row address and add it to the current sequence.2213Row.Address.Address += CurrRange->Value;2214Seq.emplace_back(Row);22152216if (Row.EndSequence)2217insertLineSequence(Seq, NewRows);2218}22192220LineTable.Rows = std::move(NewRows);2221}22222223Emitter->emitLineTableForUnit(LineTable, Unit, DebugStrPool,2224DebugLineStrPool);2225} else2226Linker.reportWarning("Cann't load line table.", ObjFile);2227}22282229void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {2230for (AccelTableKind AccelTableKind : Options.AccelTables) {2231switch (AccelTableKind) {2232case AccelTableKind::Apple: {2233// Add namespaces.2234for (const auto &Namespace : Unit.getNamespaces())2235AppleNamespaces.addName(Namespace.Name, Namespace.Die->getOffset() +2236Unit.getStartOffset());2237// Add names.2238for (const auto &Pubname : Unit.getPubnames())2239AppleNames.addName(Pubname.Name,2240Pubname.Die->getOffset() + Unit.getStartOffset());2241// Add types.2242for (const auto &Pubtype : Unit.getPubtypes())2243AppleTypes.addName(2244Pubtype.Name, Pubtype.Die->getOffset() + Unit.getStartOffset(),2245Pubtype.Die->getTag(),2246Pubtype.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation2247: 0,2248Pubtype.QualifiedNameHash);2249// Add ObjC names.2250for (const auto &ObjC : Unit.getObjC())2251AppleObjc.addName(ObjC.Name,2252ObjC.Die->getOffset() + Unit.getStartOffset());2253} break;2254case AccelTableKind::Pub: {2255TheDwarfEmitter->emitPubNamesForUnit(Unit);2256TheDwarfEmitter->emitPubTypesForUnit(Unit);2257} break;2258case AccelTableKind::DebugNames: {2259for (const auto &Namespace : Unit.getNamespaces())2260DebugNames.addName(2261Namespace.Name, Namespace.Die->getOffset(),2262DWARF5AccelTableData::getDefiningParentDieOffset(*Namespace.Die),2263Namespace.Die->getTag(), Unit.getUniqueID(),2264Unit.getTag() == dwarf::DW_TAG_type_unit);2265for (const auto &Pubname : Unit.getPubnames())2266DebugNames.addName(2267Pubname.Name, Pubname.Die->getOffset(),2268DWARF5AccelTableData::getDefiningParentDieOffset(*Pubname.Die),2269Pubname.Die->getTag(), Unit.getUniqueID(),2270Unit.getTag() == dwarf::DW_TAG_type_unit);2271for (const auto &Pubtype : Unit.getPubtypes())2272DebugNames.addName(2273Pubtype.Name, Pubtype.Die->getOffset(),2274DWARF5AccelTableData::getDefiningParentDieOffset(*Pubtype.Die),2275Pubtype.Die->getTag(), Unit.getUniqueID(),2276Unit.getTag() == dwarf::DW_TAG_type_unit);2277} break;2278}2279}2280}22812282/// Read the frame info stored in the object, and emit the2283/// patched frame descriptions for the resulting file.2284///2285/// This is actually pretty easy as the data of the CIEs and FDEs can2286/// be considered as black boxes and moved as is. The only thing to do2287/// is to patch the addresses in the headers.2288void DWARFLinker::patchFrameInfoForObject(LinkContext &Context) {2289DWARFContext &OrigDwarf = *Context.File.Dwarf;2290unsigned SrcAddrSize = OrigDwarf.getDWARFObj().getAddressSize();22912292StringRef FrameData = OrigDwarf.getDWARFObj().getFrameSection().Data;2293if (FrameData.empty())2294return;22952296RangesTy AllUnitsRanges;2297for (std::unique_ptr<CompileUnit> &Unit : Context.CompileUnits) {2298for (auto CurRange : Unit->getFunctionRanges())2299AllUnitsRanges.insert(CurRange.Range, CurRange.Value);2300}23012302DataExtractor Data(FrameData, OrigDwarf.isLittleEndian(), 0);2303uint64_t InputOffset = 0;23042305// Store the data of the CIEs defined in this object, keyed by their2306// offsets.2307DenseMap<uint64_t, StringRef> LocalCIES;23082309while (Data.isValidOffset(InputOffset)) {2310uint64_t EntryOffset = InputOffset;2311uint32_t InitialLength = Data.getU32(&InputOffset);2312if (InitialLength == 0xFFFFFFFF)2313return reportWarning("Dwarf64 bits no supported", Context.File);23142315uint32_t CIEId = Data.getU32(&InputOffset);2316if (CIEId == 0xFFFFFFFF) {2317// This is a CIE, store it.2318StringRef CIEData = FrameData.substr(EntryOffset, InitialLength + 4);2319LocalCIES[EntryOffset] = CIEData;2320// The -4 is to account for the CIEId we just read.2321InputOffset += InitialLength - 4;2322continue;2323}23242325uint64_t Loc = Data.getUnsigned(&InputOffset, SrcAddrSize);23262327// Some compilers seem to emit frame info that doesn't start at2328// the function entry point, thus we can't just lookup the address2329// in the debug map. Use the AddressInfo's range map to see if the FDE2330// describes something that we can relocate.2331std::optional<AddressRangeValuePair> Range =2332AllUnitsRanges.getRangeThatContains(Loc);2333if (!Range) {2334// The +4 is to account for the size of the InitialLength field itself.2335InputOffset = EntryOffset + InitialLength + 4;2336continue;2337}23382339// This is an FDE, and we have a mapping.2340// Have we already emitted a corresponding CIE?2341StringRef CIEData = LocalCIES[CIEId];2342if (CIEData.empty())2343return reportWarning("Inconsistent debug_frame content. Dropping.",2344Context.File);23452346// Look if we already emitted a CIE that corresponds to the2347// referenced one (the CIE data is the key of that lookup).2348auto IteratorInserted = EmittedCIEs.insert(2349std::make_pair(CIEData, TheDwarfEmitter->getFrameSectionSize()));2350// If there is no CIE yet for this ID, emit it.2351if (IteratorInserted.second) {2352LastCIEOffset = TheDwarfEmitter->getFrameSectionSize();2353IteratorInserted.first->getValue() = LastCIEOffset;2354TheDwarfEmitter->emitCIE(CIEData);2355}23562357// Emit the FDE with updated address and CIE pointer.2358// (4 + AddrSize) is the size of the CIEId + initial_location2359// fields that will get reconstructed by emitFDE().2360unsigned FDERemainingBytes = InitialLength - (4 + SrcAddrSize);2361TheDwarfEmitter->emitFDE(IteratorInserted.first->getValue(), SrcAddrSize,2362Loc + Range->Value,2363FrameData.substr(InputOffset, FDERemainingBytes));2364InputOffset += FDERemainingBytes;2365}2366}23672368uint32_t DWARFLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE,2369CompileUnit &U,2370const DWARFFile &File,2371int ChildRecurseDepth) {2372const char *Name = nullptr;2373DWARFUnit *OrigUnit = &U.getOrigUnit();2374CompileUnit *CU = &U;2375std::optional<DWARFFormValue> Ref;23762377while (true) {2378if (const char *CurrentName = DIE.getName(DINameKind::ShortName))2379Name = CurrentName;23802381if (!(Ref = DIE.find(dwarf::DW_AT_specification)) &&2382!(Ref = DIE.find(dwarf::DW_AT_abstract_origin)))2383break;23842385if (!Ref->isFormClass(DWARFFormValue::FC_Reference))2386break;23872388CompileUnit *RefCU;2389if (auto RefDIE =2390Linker.resolveDIEReference(File, CompileUnits, *Ref, DIE, RefCU)) {2391CU = RefCU;2392OrigUnit = &RefCU->getOrigUnit();2393DIE = RefDIE;2394}2395}23962397unsigned Idx = OrigUnit->getDIEIndex(DIE);2398if (!Name && DIE.getTag() == dwarf::DW_TAG_namespace)2399Name = "(anonymous namespace)";24002401if (CU->getInfo(Idx).ParentIdx == 0 ||2402// FIXME: dsymutil-classic compatibility. Ignore modules.2403CU->getOrigUnit().getDIEAtIndex(CU->getInfo(Idx).ParentIdx).getTag() ==2404dwarf::DW_TAG_module)2405return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::"));24062407DWARFDie Die = OrigUnit->getDIEAtIndex(CU->getInfo(Idx).ParentIdx);2408return djbHash(2409(Name ? Name : ""),2410djbHash((Name ? "::" : ""),2411hashFullyQualifiedName(Die, *CU, File, ++ChildRecurseDepth)));2412}24132414static uint64_t getDwoId(const DWARFDie &CUDie) {2415auto DwoId = dwarf::toUnsigned(2416CUDie.find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id}));2417if (DwoId)2418return *DwoId;2419return 0;2420}24212422static std::string2423remapPath(StringRef Path,2424const DWARFLinkerBase::ObjectPrefixMapTy &ObjectPrefixMap) {2425if (ObjectPrefixMap.empty())2426return Path.str();24272428SmallString<256> p = Path;2429for (const auto &Entry : ObjectPrefixMap)2430if (llvm::sys::path::replace_path_prefix(p, Entry.first, Entry.second))2431break;2432return p.str().str();2433}24342435static std::string2436getPCMFile(const DWARFDie &CUDie,2437const DWARFLinkerBase::ObjectPrefixMapTy *ObjectPrefixMap) {2438std::string PCMFile = dwarf::toString(2439CUDie.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), "");24402441if (PCMFile.empty())2442return PCMFile;24432444if (ObjectPrefixMap)2445PCMFile = remapPath(PCMFile, *ObjectPrefixMap);24462447return PCMFile;2448}24492450std::pair<bool, bool> DWARFLinker::isClangModuleRef(const DWARFDie &CUDie,2451std::string &PCMFile,2452LinkContext &Context,2453unsigned Indent,2454bool Quiet) {2455if (PCMFile.empty())2456return std::make_pair(false, false);24572458// Clang module DWARF skeleton CUs abuse this for the path to the module.2459uint64_t DwoId = getDwoId(CUDie);24602461std::string Name = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");2462if (Name.empty()) {2463if (!Quiet)2464reportWarning("Anonymous module skeleton CU for " + PCMFile,2465Context.File);2466return std::make_pair(true, true);2467}24682469if (!Quiet && Options.Verbose) {2470outs().indent(Indent);2471outs() << "Found clang module reference " << PCMFile;2472}24732474auto Cached = ClangModules.find(PCMFile);2475if (Cached != ClangModules.end()) {2476// FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is2477// fixed in clang, only warn about DWO_id mismatches in verbose mode.2478// ASTFileSignatures will change randomly when a module is rebuilt.2479if (!Quiet && Options.Verbose && (Cached->second != DwoId))2480reportWarning(Twine("hash mismatch: this object file was built against a "2481"different version of the module ") +2482PCMFile,2483Context.File);2484if (!Quiet && Options.Verbose)2485outs() << " [cached].\n";2486return std::make_pair(true, true);2487}24882489return std::make_pair(true, false);2490}24912492bool DWARFLinker::registerModuleReference(const DWARFDie &CUDie,2493LinkContext &Context,2494ObjFileLoaderTy Loader,2495CompileUnitHandlerTy OnCUDieLoaded,2496unsigned Indent) {2497std::string PCMFile = getPCMFile(CUDie, Options.ObjectPrefixMap);2498std::pair<bool, bool> IsClangModuleRef =2499isClangModuleRef(CUDie, PCMFile, Context, Indent, false);25002501if (!IsClangModuleRef.first)2502return false;25032504if (IsClangModuleRef.second)2505return true;25062507if (Options.Verbose)2508outs() << " ...\n";25092510// Cyclic dependencies are disallowed by Clang, but we still2511// shouldn't run into an infinite loop, so mark it as processed now.2512ClangModules.insert({PCMFile, getDwoId(CUDie)});25132514if (Error E = loadClangModule(Loader, CUDie, PCMFile, Context, OnCUDieLoaded,2515Indent + 2)) {2516consumeError(std::move(E));2517return false;2518}2519return true;2520}25212522Error DWARFLinker::loadClangModule(2523ObjFileLoaderTy Loader, const DWARFDie &CUDie, const std::string &PCMFile,2524LinkContext &Context, CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) {25252526uint64_t DwoId = getDwoId(CUDie);2527std::string ModuleName = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");25282529/// Using a SmallString<0> because loadClangModule() is recursive.2530SmallString<0> Path(Options.PrependPath);2531if (sys::path::is_relative(PCMFile))2532resolveRelativeObjectPath(Path, CUDie);2533sys::path::append(Path, PCMFile);2534// Don't use the cached binary holder because we have no thread-safety2535// guarantee and the lifetime is limited.25362537if (Loader == nullptr) {2538reportError("Could not load clang module: loader is not specified.\n",2539Context.File);2540return Error::success();2541}25422543auto ErrOrObj = Loader(Context.File.FileName, Path);2544if (!ErrOrObj)2545return Error::success();25462547std::unique_ptr<CompileUnit> Unit;2548for (const auto &CU : ErrOrObj->Dwarf->compile_units()) {2549OnCUDieLoaded(*CU);2550// Recursively get all modules imported by this one.2551auto ChildCUDie = CU->getUnitDIE();2552if (!ChildCUDie)2553continue;2554if (!registerModuleReference(ChildCUDie, Context, Loader, OnCUDieLoaded,2555Indent)) {2556if (Unit) {2557std::string Err =2558(PCMFile +2559": Clang modules are expected to have exactly 1 compile unit.\n");2560reportError(Err, Context.File);2561return make_error<StringError>(Err, inconvertibleErrorCode());2562}2563// FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is2564// fixed in clang, only warn about DWO_id mismatches in verbose mode.2565// ASTFileSignatures will change randomly when a module is rebuilt.2566uint64_t PCMDwoId = getDwoId(ChildCUDie);2567if (PCMDwoId != DwoId) {2568if (Options.Verbose)2569reportWarning(2570Twine("hash mismatch: this object file was built against a "2571"different version of the module ") +2572PCMFile,2573Context.File);2574// Update the cache entry with the DwoId of the module loaded from disk.2575ClangModules[PCMFile] = PCMDwoId;2576}25772578// Add this module.2579Unit = std::make_unique<CompileUnit>(*CU, UniqueUnitID++, !Options.NoODR,2580ModuleName);2581}2582}25832584if (Unit)2585Context.ModuleUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)});25862587return Error::success();2588}25892590uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(2591DWARFContext &DwarfContext, const DWARFFile &File, bool IsLittleEndian) {2592uint64_t OutputDebugInfoSize =2593(Emitter == nullptr) ? 0 : Emitter->getDebugInfoSectionSize();2594const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;25952596for (auto &CurrentUnit : CompileUnits) {2597const uint16_t DwarfVersion = CurrentUnit->getOrigUnit().getVersion();2598const uint32_t UnitHeaderSize = DwarfVersion >= 5 ? 12 : 11;2599auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();2600CurrentUnit->setStartOffset(OutputDebugInfoSize);2601if (!InputDIE) {2602OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);2603continue;2604}2605if (CurrentUnit->getInfo(0).Keep) {2606// Clone the InputDIE into your Unit DIE in our compile unit since it2607// already has a DIE inside of it.2608CurrentUnit->createOutputDIE();2609rememberUnitForMacroOffset(*CurrentUnit);2610cloneDIE(InputDIE, File, *CurrentUnit, 0 /* PC offset */, UnitHeaderSize,26110, IsLittleEndian, CurrentUnit->getOutputUnitDIE());2612}26132614OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);26152616if (Emitter != nullptr) {26172618generateLineTableForUnit(*CurrentUnit);26192620Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);26212622if (LLVM_UNLIKELY(Linker.Options.Update))2623continue;26242625Linker.generateUnitRanges(*CurrentUnit, File, AddrPool);26262627auto ProcessExpr = [&](SmallVectorImpl<uint8_t> &SrcBytes,2628SmallVectorImpl<uint8_t> &OutBytes,2629int64_t RelocAdjustment) {2630DWARFUnit &OrigUnit = CurrentUnit->getOrigUnit();2631DataExtractor Data(SrcBytes, IsLittleEndian,2632OrigUnit.getAddressByteSize());2633cloneExpression(Data,2634DWARFExpression(Data, OrigUnit.getAddressByteSize(),2635OrigUnit.getFormParams().Format),2636File, *CurrentUnit, OutBytes, RelocAdjustment,2637IsLittleEndian);2638};2639generateUnitLocations(*CurrentUnit, File, ProcessExpr);2640emitDebugAddrSection(*CurrentUnit, DwarfVersion);2641}2642AddrPool.clear();2643}26442645if (Emitter != nullptr) {2646assert(Emitter);2647// Emit macro tables.2648Emitter->emitMacroTables(File.Dwarf.get(), UnitMacroMap, DebugStrPool);26492650// Emit all the compile unit's debug information.2651for (auto &CurrentUnit : CompileUnits) {2652CurrentUnit->fixupForwardReferences();26532654if (!CurrentUnit->getOutputUnitDIE())2655continue;26562657unsigned DwarfVersion = CurrentUnit->getOrigUnit().getVersion();26582659assert(Emitter->getDebugInfoSectionSize() ==2660CurrentUnit->getStartOffset());2661Emitter->emitCompileUnitHeader(*CurrentUnit, DwarfVersion);2662Emitter->emitDIE(*CurrentUnit->getOutputUnitDIE());2663assert(Emitter->getDebugInfoSectionSize() ==2664CurrentUnit->computeNextUnitOffset(DwarfVersion));2665}2666}26672668return OutputDebugInfoSize - StartOutputDebugInfoSize;2669}26702671void DWARFLinker::copyInvariantDebugSection(DWARFContext &Dwarf) {2672TheDwarfEmitter->emitSectionContents(Dwarf.getDWARFObj().getLocSection().Data,2673DebugSectionKind::DebugLoc);2674TheDwarfEmitter->emitSectionContents(2675Dwarf.getDWARFObj().getRangesSection().Data,2676DebugSectionKind::DebugRange);2677TheDwarfEmitter->emitSectionContents(2678Dwarf.getDWARFObj().getFrameSection().Data, DebugSectionKind::DebugFrame);2679TheDwarfEmitter->emitSectionContents(Dwarf.getDWARFObj().getArangesSection(),2680DebugSectionKind::DebugARanges);2681TheDwarfEmitter->emitSectionContents(2682Dwarf.getDWARFObj().getAddrSection().Data, DebugSectionKind::DebugAddr);2683TheDwarfEmitter->emitSectionContents(2684Dwarf.getDWARFObj().getRnglistsSection().Data,2685DebugSectionKind::DebugRngLists);2686TheDwarfEmitter->emitSectionContents(2687Dwarf.getDWARFObj().getLoclistsSection().Data,2688DebugSectionKind::DebugLocLists);2689}26902691void DWARFLinker::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader,2692CompileUnitHandlerTy OnCUDieLoaded) {2693ObjectContexts.emplace_back(LinkContext(File));26942695if (ObjectContexts.back().File.Dwarf) {2696for (const std::unique_ptr<DWARFUnit> &CU :2697ObjectContexts.back().File.Dwarf->compile_units()) {2698DWARFDie CUDie = CU->getUnitDIE();26992700if (!CUDie)2701continue;27022703OnCUDieLoaded(*CU);27042705if (!LLVM_UNLIKELY(Options.Update))2706registerModuleReference(CUDie, ObjectContexts.back(), Loader,2707OnCUDieLoaded);2708}2709}2710}27112712Error DWARFLinker::link() {2713assert((Options.TargetDWARFVersion != 0) &&2714"TargetDWARFVersion should be set");27152716// First populate the data structure we need for each iteration of the2717// parallel loop.2718unsigned NumObjects = ObjectContexts.size();27192720// This Dwarf string pool which is used for emission. It must be used2721// serially as the order of calling getStringOffset matters for2722// reproducibility.2723OffsetsStringPool DebugStrPool(true);2724OffsetsStringPool DebugLineStrPool(false);2725DebugDieValuePool StringOffsetPool;27262727// ODR Contexts for the optimize.2728DeclContextTree ODRContexts;27292730for (LinkContext &OptContext : ObjectContexts) {2731if (Options.Verbose)2732outs() << "DEBUG MAP OBJECT: " << OptContext.File.FileName << "\n";27332734if (!OptContext.File.Dwarf)2735continue;27362737if (Options.VerifyInputDWARF)2738verifyInput(OptContext.File);27392740// Look for relocations that correspond to address map entries.27412742// there was findvalidrelocations previously ... probably we need to gather2743// info here2744if (LLVM_LIKELY(!Options.Update) &&2745!OptContext.File.Addresses->hasValidRelocs()) {2746if (Options.Verbose)2747outs() << "No valid relocations found. Skipping.\n";27482749// Set "Skip" flag as a signal to other loops that we should not2750// process this iteration.2751OptContext.Skip = true;2752continue;2753}27542755// Setup access to the debug info.2756if (!OptContext.File.Dwarf)2757continue;27582759// Check whether type units are presented.2760if (!OptContext.File.Dwarf->types_section_units().empty()) {2761reportWarning("type units are not currently supported: file will "2762"be skipped",2763OptContext.File);2764OptContext.Skip = true;2765continue;2766}27672768// Clone all the clang modules with requires extracting the DIE units. We2769// don't need the full debug info until the Analyze phase.2770OptContext.CompileUnits.reserve(2771OptContext.File.Dwarf->getNumCompileUnits());2772for (const auto &CU : OptContext.File.Dwarf->compile_units()) {2773auto CUDie = CU->getUnitDIE(/*ExtractUnitDIEOnly=*/true);2774if (Options.Verbose) {2775outs() << "Input compilation unit:";2776DIDumpOptions DumpOpts;2777DumpOpts.ChildRecurseDepth = 0;2778DumpOpts.Verbose = Options.Verbose;2779CUDie.dump(outs(), 0, DumpOpts);2780}2781}27822783for (auto &CU : OptContext.ModuleUnits) {2784if (Error Err = cloneModuleUnit(OptContext, CU, ODRContexts, DebugStrPool,2785DebugLineStrPool, StringOffsetPool))2786reportWarning(toString(std::move(Err)), CU.File);2787}2788}27892790// At this point we know how much data we have emitted. We use this value to2791// compare canonical DIE offsets in analyzeContextInfo to see if a definition2792// is already emitted, without being affected by canonical die offsets set2793// later. This prevents undeterminism when analyze and clone execute2794// concurrently, as clone set the canonical DIE offset and analyze reads it.2795const uint64_t ModulesEndOffset =2796(TheDwarfEmitter == nullptr) ? 02797: TheDwarfEmitter->getDebugInfoSectionSize();27982799// These variables manage the list of processed object files.2800// The mutex and condition variable are to ensure that this is thread safe.2801std::mutex ProcessedFilesMutex;2802std::condition_variable ProcessedFilesConditionVariable;2803BitVector ProcessedFiles(NumObjects, false);28042805// Analyzing the context info is particularly expensive so it is executed in2806// parallel with emitting the previous compile unit.2807auto AnalyzeLambda = [&](size_t I) {2808auto &Context = ObjectContexts[I];28092810if (Context.Skip || !Context.File.Dwarf)2811return;28122813for (const auto &CU : Context.File.Dwarf->compile_units()) {2814// Previously we only extracted the unit DIEs. We need the full debug info2815// now.2816auto CUDie = CU->getUnitDIE(/*ExtractUnitDIEOnly=*/false);2817std::string PCMFile = getPCMFile(CUDie, Options.ObjectPrefixMap);28182819if (!CUDie || LLVM_UNLIKELY(Options.Update) ||2820!isClangModuleRef(CUDie, PCMFile, Context, 0, true).first) {2821Context.CompileUnits.push_back(std::make_unique<CompileUnit>(2822*CU, UniqueUnitID++, !Options.NoODR && !Options.Update, ""));2823}2824}28252826// Now build the DIE parent links that we will use during the next phase.2827for (auto &CurrentUnit : Context.CompileUnits) {2828auto CUDie = CurrentUnit->getOrigUnit().getUnitDIE();2829if (!CUDie)2830continue;2831analyzeContextInfo(CurrentUnit->getOrigUnit().getUnitDIE(), 0,2832*CurrentUnit, &ODRContexts.getRoot(), ODRContexts,2833ModulesEndOffset, Options.ParseableSwiftInterfaces,2834[&](const Twine &Warning, const DWARFDie &DIE) {2835reportWarning(Warning, Context.File, &DIE);2836});2837}2838};28392840// For each object file map how many bytes were emitted.2841StringMap<DebugInfoSize> SizeByObject;28422843// And then the remaining work in serial again.2844// Note, although this loop runs in serial, it can run in parallel with2845// the analyzeContextInfo loop so long as we process files with indices >=2846// than those processed by analyzeContextInfo.2847auto CloneLambda = [&](size_t I) {2848auto &OptContext = ObjectContexts[I];2849if (OptContext.Skip || !OptContext.File.Dwarf)2850return;28512852// Then mark all the DIEs that need to be present in the generated output2853// and collect some information about them.2854// Note that this loop can not be merged with the previous one because2855// cross-cu references require the ParentIdx to be setup for every CU in2856// the object file before calling this.2857if (LLVM_UNLIKELY(Options.Update)) {2858for (auto &CurrentUnit : OptContext.CompileUnits)2859CurrentUnit->markEverythingAsKept();2860copyInvariantDebugSection(*OptContext.File.Dwarf);2861} else {2862for (auto &CurrentUnit : OptContext.CompileUnits) {2863lookForDIEsToKeep(*OptContext.File.Addresses, OptContext.CompileUnits,2864CurrentUnit->getOrigUnit().getUnitDIE(),2865OptContext.File, *CurrentUnit, 0);2866#ifndef NDEBUG2867verifyKeepChain(*CurrentUnit);2868#endif2869}2870}28712872// The calls to applyValidRelocs inside cloneDIE will walk the reloc2873// array again (in the same way findValidRelocsInDebugInfo() did). We2874// need to reset the NextValidReloc index to the beginning.2875if (OptContext.File.Addresses->hasValidRelocs() ||2876LLVM_UNLIKELY(Options.Update)) {2877SizeByObject[OptContext.File.FileName].Input =2878getDebugInfoSize(*OptContext.File.Dwarf);2879SizeByObject[OptContext.File.FileName].Output =2880DIECloner(*this, TheDwarfEmitter, OptContext.File, DIEAlloc,2881OptContext.CompileUnits, Options.Update, DebugStrPool,2882DebugLineStrPool, StringOffsetPool)2883.cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,2884OptContext.File.Dwarf->isLittleEndian());2885}2886if ((TheDwarfEmitter != nullptr) && !OptContext.CompileUnits.empty() &&2887LLVM_LIKELY(!Options.Update))2888patchFrameInfoForObject(OptContext);28892890// Clean-up before starting working on the next object.2891cleanupAuxiliarryData(OptContext);2892};28932894auto EmitLambda = [&]() {2895// Emit everything that's global.2896if (TheDwarfEmitter != nullptr) {2897TheDwarfEmitter->emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);2898TheDwarfEmitter->emitStrings(DebugStrPool);2899TheDwarfEmitter->emitStringOffsets(StringOffsetPool.getValues(),2900Options.TargetDWARFVersion);2901TheDwarfEmitter->emitLineStrings(DebugLineStrPool);2902for (AccelTableKind TableKind : Options.AccelTables) {2903switch (TableKind) {2904case AccelTableKind::Apple:2905TheDwarfEmitter->emitAppleNamespaces(AppleNamespaces);2906TheDwarfEmitter->emitAppleNames(AppleNames);2907TheDwarfEmitter->emitAppleTypes(AppleTypes);2908TheDwarfEmitter->emitAppleObjc(AppleObjc);2909break;2910case AccelTableKind::Pub:2911// Already emitted by emitAcceleratorEntriesForUnit.2912// Already emitted by emitAcceleratorEntriesForUnit.2913break;2914case AccelTableKind::DebugNames:2915TheDwarfEmitter->emitDebugNames(DebugNames);2916break;2917}2918}2919}2920};29212922auto AnalyzeAll = [&]() {2923for (unsigned I = 0, E = NumObjects; I != E; ++I) {2924AnalyzeLambda(I);29252926std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);2927ProcessedFiles.set(I);2928ProcessedFilesConditionVariable.notify_one();2929}2930};29312932auto CloneAll = [&]() {2933for (unsigned I = 0, E = NumObjects; I != E; ++I) {2934{2935std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);2936if (!ProcessedFiles[I]) {2937ProcessedFilesConditionVariable.wait(2938LockGuard, [&]() { return ProcessedFiles[I]; });2939}2940}29412942CloneLambda(I);2943}2944EmitLambda();2945};29462947// To limit memory usage in the single threaded case, analyze and clone are2948// run sequentially so the OptContext is freed after processing each object2949// in endDebugObject.2950if (Options.Threads == 1) {2951for (unsigned I = 0, E = NumObjects; I != E; ++I) {2952AnalyzeLambda(I);2953CloneLambda(I);2954}2955EmitLambda();2956} else {2957DefaultThreadPool Pool(hardware_concurrency(2));2958Pool.async(AnalyzeAll);2959Pool.async(CloneAll);2960Pool.wait();2961}29622963if (Options.Statistics) {2964// Create a vector sorted in descending order by output size.2965std::vector<std::pair<StringRef, DebugInfoSize>> Sorted;2966for (auto &E : SizeByObject)2967Sorted.emplace_back(E.first(), E.second);2968llvm::sort(Sorted, [](auto &LHS, auto &RHS) {2969return LHS.second.Output > RHS.second.Output;2970});29712972auto ComputePercentange = [](int64_t Input, int64_t Output) -> float {2973const float Difference = Output - Input;2974const float Sum = Input + Output;2975if (Sum == 0)2976return 0;2977return (Difference / (Sum / 2));2978};29792980int64_t InputTotal = 0;2981int64_t OutputTotal = 0;2982const char *FormatStr = "{0,-45} {1,10}b {2,10}b {3,8:P}\n";29832984// Print header.2985outs() << ".debug_info section size (in bytes)\n";2986outs() << "----------------------------------------------------------------"2987"---------------\n";2988outs() << "Filename Object "2989" dSYM Change\n";2990outs() << "----------------------------------------------------------------"2991"---------------\n";29922993// Print body.2994for (auto &E : Sorted) {2995InputTotal += E.second.Input;2996OutputTotal += E.second.Output;2997llvm::outs() << formatv(2998FormatStr, sys::path::filename(E.first).take_back(45), E.second.Input,2999E.second.Output, ComputePercentange(E.second.Input, E.second.Output));3000}3001// Print total and footer.3002outs() << "----------------------------------------------------------------"3003"---------------\n";3004llvm::outs() << formatv(FormatStr, "Total", InputTotal, OutputTotal,3005ComputePercentange(InputTotal, OutputTotal));3006outs() << "----------------------------------------------------------------"3007"---------------\n\n";3008}30093010return Error::success();3011}30123013Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,3014DeclContextTree &ODRContexts,3015OffsetsStringPool &DebugStrPool,3016OffsetsStringPool &DebugLineStrPool,3017DebugDieValuePool &StringOffsetPool,3018unsigned Indent) {3019assert(Unit.Unit.get() != nullptr);30203021if (!Unit.Unit->getOrigUnit().getUnitDIE().hasChildren())3022return Error::success();30233024if (Options.Verbose) {3025outs().indent(Indent);3026outs() << "cloning .debug_info from " << Unit.File.FileName << "\n";3027}30283029// Analyze context for the module.3030analyzeContextInfo(Unit.Unit->getOrigUnit().getUnitDIE(), 0, *(Unit.Unit),3031&ODRContexts.getRoot(), ODRContexts, 0,3032Options.ParseableSwiftInterfaces,3033[&](const Twine &Warning, const DWARFDie &DIE) {3034reportWarning(Warning, Context.File, &DIE);3035});3036// Keep everything.3037Unit.Unit->markEverythingAsKept();30383039// Clone unit.3040UnitListTy CompileUnits;3041CompileUnits.emplace_back(std::move(Unit.Unit));3042assert(TheDwarfEmitter);3043DIECloner(*this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits,3044Options.Update, DebugStrPool, DebugLineStrPool, StringOffsetPool)3045.cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,3046Unit.File.Dwarf->isLittleEndian());3047return Error::success();3048}30493050void DWARFLinker::verifyInput(const DWARFFile &File) {3051assert(File.Dwarf);30523053std::string Buffer;3054raw_string_ostream OS(Buffer);3055DIDumpOptions DumpOpts;3056if (!File.Dwarf->verify(OS, DumpOpts.noImplicitRecursion())) {3057if (Options.InputVerificationHandler)3058Options.InputVerificationHandler(File, OS.str());3059}3060}30613062} // namespace llvm306330643065