Path: blob/main/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.cpp
35291 views
//=== DependencyTracker.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 "DependencyTracker.h"9#include "llvm/Support/FormatVariadic.h"1011using namespace llvm;12using namespace dwarf_linker;13using namespace dwarf_linker::parallel;1415/// A broken link in the keep chain. By recording both the parent and the child16/// we can show only broken links for DIEs with multiple children.17struct BrokenLink {18BrokenLink(DWARFDie Parent, DWARFDie Child, const char *Message)19: Parent(Parent), Child(Child), Message(Message) {}20DWARFDie Parent;21DWARFDie Child;22std::string Message;23};2425/// Verify the keep chain by looking for DIEs that are kept but who's parent26/// isn't.27void DependencyTracker::verifyKeepChain() {28#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)29SmallVector<DWARFDie> Worklist;30Worklist.push_back(CU.getOrigUnit().getUnitDIE());3132// List of broken links.33SmallVector<BrokenLink> BrokenLinks;3435while (!Worklist.empty()) {36const DWARFDie Current = Worklist.back();37Worklist.pop_back();3839if (!Current.isValid())40continue;4142CompileUnit::DIEInfo &CurrentInfo =43CU.getDIEInfo(Current.getDebugInfoEntry());44const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf();45const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable();4647for (DWARFDie Child : reverse(Current.children())) {48Worklist.push_back(Child);4950CompileUnit::DIEInfo &ChildInfo =51CU.getDIEInfo(Child.getDebugInfoEntry());52const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf();53const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable();5455if (!ParentPlainDieIsKept && ChildPlainDieIsKept)56BrokenLinks.emplace_back(Current, Child,57"Found invalid link in keep chain");5859if (Child.getTag() == dwarf::DW_TAG_subprogram) {60if (!ChildInfo.getKeep() && isLiveSubprogramEntry(UnitEntryPairTy(61&CU, Child.getDebugInfoEntry()))) {62BrokenLinks.emplace_back(Current, Child,63"Live subprogram is not marked as kept");64}65}6667if (!ChildInfo.getODRAvailable()) {68assert(!ChildTypeDieIsKept);69continue;70}7172if (!ParentTypeDieIsKept && ChildTypeDieIsKept)73BrokenLinks.emplace_back(Current, Child,74"Found invalid link in keep chain");7576if (CurrentInfo.getIsInAnonNamespaceScope() &&77ChildInfo.needToPlaceInTypeTable()) {78BrokenLinks.emplace_back(Current, Child,79"Found invalid placement marking for member "80"of anonymous namespace");81}82}83}8485if (!BrokenLinks.empty()) {86for (BrokenLink Link : BrokenLinks) {87errs() << "\n=================================\n";88WithColor::error() << formatv("{0} between {1:x} and {2:x}", Link.Message,89Link.Parent.getOffset(),90Link.Child.getOffset());9192errs() << "\nParent:";93Link.Parent.dump(errs(), 0, {});94errs() << "\n";95CU.getDIEInfo(Link.Parent).dump();9697errs() << "\nChild:";98Link.Child.dump(errs(), 2, {});99errs() << "\n";100CU.getDIEInfo(Link.Child).dump();101}102report_fatal_error("invalid keep chain");103}104#endif105}106107bool DependencyTracker::resolveDependenciesAndMarkLiveness(108bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {109RootEntriesWorkList.clear();110111// Search for live root DIEs.112CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));113CUInfo.setPlacement(CompileUnit::PlainDwarf);114collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},115std::nullopt, false);116117// Mark live DIEs as kept.118return markCollectedLiveRootsAsKept(InterCUProcessingStarted,119HasNewInterconnectedCUs);120}121122void DependencyTracker::addActionToRootEntriesWorkList(123LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,124std::optional<UnitEntryPairTy> ReferencedBy) {125if (ReferencedBy) {126RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy);127return;128}129130RootEntriesWorkList.emplace_back(Action, Entry);131}132133void DependencyTracker::collectRootsToKeep(134const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,135bool IsLiveParent) {136for (const DWARFDebugInfoEntry *CurChild =137Entry.CU->getFirstChildEntry(Entry.DieEntry);138CurChild && CurChild->getAbbreviationDeclarationPtr();139CurChild = Entry.CU->getSiblingEntry(CurChild)) {140UnitEntryPairTy ChildEntry(Entry.CU, CurChild);141CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild);142143bool IsLiveChild = false;144145switch (CurChild->getTag()) {146case dwarf::DW_TAG_label: {147IsLiveChild = isLiveSubprogramEntry(ChildEntry);148149// Keep label referencing live address.150// Keep label which is child of live parent entry.151if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {152addActionToRootEntriesWorkList(153LiveRootWorklistActionTy::MarkLiveEntryRec, ChildEntry,154ReferencedBy);155}156} break;157case dwarf::DW_TAG_subprogram: {158IsLiveChild = isLiveSubprogramEntry(ChildEntry);159160// Keep subprogram referencing live address.161if (IsLiveChild) {162// If subprogram is in module scope and this module allows ODR163// deduplication set "TypeTable" placement, otherwise set "" placement164LiveRootWorklistActionTy Action =165(ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())166? LiveRootWorklistActionTy::MarkTypeEntryRec167: LiveRootWorklistActionTy::MarkLiveEntryRec;168169addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);170}171} break;172case dwarf::DW_TAG_constant:173case dwarf::DW_TAG_variable: {174IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);175176// Keep variable referencing live address.177if (IsLiveChild) {178// If variable is in module scope and this module allows ODR179// deduplication set "TypeTable" placement, otherwise set "" placement180181LiveRootWorklistActionTy Action =182(ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())183? LiveRootWorklistActionTy::MarkTypeEntryRec184: LiveRootWorklistActionTy::MarkLiveEntryRec;185186addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);187}188} break;189case dwarf::DW_TAG_base_type: {190// Always keep base types.191addActionToRootEntriesWorkList(192LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,193ReferencedBy);194} break;195case dwarf::DW_TAG_imported_module:196case dwarf::DW_TAG_imported_declaration:197case dwarf::DW_TAG_imported_unit: {198// Always keep DIEs having DW_AT_import attribute.199if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {200addActionToRootEntriesWorkList(201LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,202ReferencedBy);203break;204}205206addActionToRootEntriesWorkList(207LiveRootWorklistActionTy::MarkSingleTypeEntry, ChildEntry,208ReferencedBy);209} break;210case dwarf::DW_TAG_type_unit:211case dwarf::DW_TAG_partial_unit:212case dwarf::DW_TAG_compile_unit: {213llvm_unreachable("Called for incorrect DIE");214} break;215default:216// Nothing to do.217break;218}219220collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);221}222}223224bool DependencyTracker::markCollectedLiveRootsAsKept(225bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {226bool Res = true;227228// Mark roots as kept.229while (!RootEntriesWorkList.empty()) {230LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();231232if (markDIEEntryAsKeptRec(Root.getAction(), Root.getRootEntry(),233Root.getRootEntry(), InterCUProcessingStarted,234HasNewInterconnectedCUs)) {235if (Root.hasReferencedByOtherEntry())236Dependencies.push_back(Root);237} else238Res = false;239}240241return Res;242}243244bool DependencyTracker::updateDependenciesCompleteness() {245bool HasNewDependency = false;246for (LiveRootWorklistItemTy &Root : Dependencies) {247assert(Root.hasReferencedByOtherEntry() &&248"Root entry without dependency inside the dependencies list");249250UnitEntryPairTy RootEntry = Root.getRootEntry();251CompileUnit::DIEInfo &RootInfo =252RootEntry.CU->getDIEInfo(RootEntry.DieEntry);253254UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();255CompileUnit::DIEInfo &ReferencedByInfo =256ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);257258if (!RootInfo.needToPlaceInTypeTable() &&259ReferencedByInfo.needToPlaceInTypeTable()) {260HasNewDependency = true;261setPlainDwarfPlacementRec(ReferencedByEntry);262263// FIXME: we probably need to update getKeepTypeChildren status for264// parents of *Root.ReferencedBy.265}266}267268return HasNewDependency;269}270271void DependencyTracker::setPlainDwarfPlacementRec(272const UnitEntryPairTy &Entry) {273CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);274if (Info.getPlacement() == CompileUnit::PlainDwarf &&275!Info.getKeepTypeChildren())276return;277278Info.setPlacement(CompileUnit::PlainDwarf);279Info.unsetKeepTypeChildren();280markParentsAsKeepingChildren(Entry);281282for (const DWARFDebugInfoEntry *CurChild =283Entry.CU->getFirstChildEntry(Entry.DieEntry);284CurChild && CurChild->getAbbreviationDeclarationPtr();285CurChild = Entry.CU->getSiblingEntry(CurChild))286setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});287}288289static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {290switch (Entry->getTag()) {291case dwarf::DW_TAG_compile_unit:292case dwarf::DW_TAG_module:293case dwarf::DW_TAG_namespace:294return true;295296default:297return false;298}299}300301bool isAlreadyMarked(const CompileUnit::DIEInfo &Info,302CompileUnit::DieOutputPlacement NewPlacement) {303if (!Info.getKeep())304return false;305306switch (NewPlacement) {307case CompileUnit::TypeTable:308return Info.needToPlaceInTypeTable();309310case CompileUnit::PlainDwarf:311return Info.needToKeepInPlainDwarf();312313case CompileUnit::Both:314return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();315316case CompileUnit::NotSet:317llvm_unreachable("Unset placement type is specified.");318};319320llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");321}322323bool isAlreadyMarked(const UnitEntryPairTy &Entry,324CompileUnit::DieOutputPlacement NewPlacement) {325return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);326}327328void DependencyTracker::markParentsAsKeepingChildren(329const UnitEntryPairTy &Entry) {330if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)331return;332333CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);334bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();335bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();336337bool AreTypeParentsDone = !NeedKeepTypeChildren;338bool ArePlainParentsDone = !NeedKeepPlainChildren;339340// Mark parents as 'Keep*Children'.341std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();342while (ParentIdx) {343const DWARFDebugInfoEntry *ParentEntry =344Entry.CU->getDebugInfoEntry(*ParentIdx);345CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);346347if (!AreTypeParentsDone && NeedKeepTypeChildren) {348if (ParentInfo.getKeepTypeChildren())349AreTypeParentsDone = true;350else {351bool AddToWorklist = !isAlreadyMarked(352ParentInfo, CompileUnit::DieOutputPlacement::TypeTable);353ParentInfo.setKeepTypeChildren();354if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {355addActionToRootEntriesWorkList(356LiveRootWorklistActionTy::MarkTypeChildrenRec,357UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);358}359}360}361362if (!ArePlainParentsDone && NeedKeepPlainChildren) {363if (ParentInfo.getKeepPlainChildren())364ArePlainParentsDone = true;365else {366bool AddToWorklist = !isAlreadyMarked(367ParentInfo, CompileUnit::DieOutputPlacement::PlainDwarf);368ParentInfo.setKeepPlainChildren();369if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {370addActionToRootEntriesWorkList(371LiveRootWorklistActionTy::MarkLiveChildrenRec,372UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);373}374}375}376377if (AreTypeParentsDone && ArePlainParentsDone)378break;379380ParentIdx = ParentEntry->getParentIdx();381}382}383384// This function tries to set specified \p Placement for the \p Entry.385// Depending on the concrete entry, the placement could be:386// a) changed to another.387// b) joined with current entry placement.388// c) set as requested.389static CompileUnit::DieOutputPlacement390getFinalPlacementForEntry(const UnitEntryPairTy &Entry,391CompileUnit::DieOutputPlacement Placement) {392assert((Placement != CompileUnit::NotSet) && "Placement is not set");393CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);394395if (!EntryInfo.getODRAvailable())396return CompileUnit::PlainDwarf;397398if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {399// Do not put variable into the "TypeTable" and "PlainDwarf" at the same400// time.401if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||402EntryInfo.getPlacement() == CompileUnit::Both)403return CompileUnit::PlainDwarf;404405if (Placement == CompileUnit::PlainDwarf || Placement == CompileUnit::Both)406return CompileUnit::PlainDwarf;407}408409switch (EntryInfo.getPlacement()) {410case CompileUnit::NotSet:411return Placement;412413case CompileUnit::TypeTable:414return Placement == CompileUnit::PlainDwarf ? CompileUnit::Both : Placement;415416case CompileUnit::PlainDwarf:417return Placement == CompileUnit::TypeTable ? CompileUnit::Both : Placement;418419case CompileUnit::Both:420return CompileUnit::Both;421};422423llvm_unreachable("Unknown placement type.");424return Placement;425}426427bool DependencyTracker::markDIEEntryAsKeptRec(428LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,429const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,430std::atomic<bool> &HasNewInterconnectedCUs) {431if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)432return true;433434CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);435436// Calculate final placement placement.437CompileUnit::DieOutputPlacement Placement = getFinalPlacementForEntry(438Entry,439isLiveAction(Action) ? CompileUnit::PlainDwarf : CompileUnit::TypeTable);440assert((Info.getODRAvailable() || isLiveAction(Action) ||441Placement == CompileUnit::PlainDwarf) &&442"Wrong kind of placement for ODR unavailable entry");443444if (!isChildrenAction(Action))445if (isAlreadyMarked(Entry, Placement))446return true;447448// Mark current DIE as kept.449Info.setKeep();450Info.setPlacement(Placement);451452// Set keep children property for parents.453markParentsAsKeepingChildren(Entry);454455UnitEntryPairTy FinalRootEntry =456Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;457458// Analyse referenced DIEs.459bool Res = true;460if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,461InterCUProcessingStarted,462HasNewInterconnectedCUs))463Res = false;464465// Return if we do not need to process children.466if (isSingleAction(Action))467return Res;468469// Process children.470// Check for subprograms special case.471if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&472Info.getODRAvailable()) {473// Subprograms is a special case. As it can be root for type DIEs474// and itself may be subject to move into the artificial type unit.475// a) Non removable children(like DW_TAG_formal_parameter) should always476// be cloned. They are placed into the "PlainDwarf" and into the477// "TypeTable".478// b) ODR deduplication candidates(type DIEs) children should not be put479// into the "PlainDwarf".480// c) Children keeping addresses and locations(like DW_TAG_call_site)481// should not be put into the "TypeTable".482for (const DWARFDebugInfoEntry *CurChild =483Entry.CU->getFirstChildEntry(Entry.DieEntry);484CurChild && CurChild->getAbbreviationDeclarationPtr();485CurChild = Entry.CU->getSiblingEntry(CurChild)) {486CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);487488switch (CurChild->getTag()) {489case dwarf::DW_TAG_variable:490case dwarf::DW_TAG_constant:491case dwarf::DW_TAG_subprogram:492case dwarf::DW_TAG_label: {493if (ChildInfo.getHasAnAddress())494continue;495} break;496497// Entries having following tags could not be removed from the subprogram.498case dwarf::DW_TAG_lexical_block:499case dwarf::DW_TAG_friend:500case dwarf::DW_TAG_inheritance:501case dwarf::DW_TAG_formal_parameter:502case dwarf::DW_TAG_unspecified_parameters:503case dwarf::DW_TAG_template_type_parameter:504case dwarf::DW_TAG_template_value_parameter:505case dwarf::DW_TAG_GNU_template_parameter_pack:506case dwarf::DW_TAG_GNU_formal_parameter_pack:507case dwarf::DW_TAG_GNU_template_template_param:508case dwarf::DW_TAG_thrown_type: {509// Go to the default child handling.510} break;511512default: {513bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);514515// Skip child marked to be copied into the artificial type unit.516if (isLiveAction(Action) && ChildIsTypeTableCandidate)517continue;518519// Skip child marked to be copied into the plain unit.520if (isTypeAction(Action) && !ChildIsTypeTableCandidate)521continue;522523// Go to the default child handling.524} break;525}526527if (!markDIEEntryAsKeptRec(528Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},529InterCUProcessingStarted, HasNewInterconnectedCUs))530Res = false;531}532533return Res;534}535536// Recursively process children.537for (const DWARFDebugInfoEntry *CurChild =538Entry.CU->getFirstChildEntry(Entry.DieEntry);539CurChild && CurChild->getAbbreviationDeclarationPtr();540CurChild = Entry.CU->getSiblingEntry(CurChild)) {541CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);542switch (CurChild->getTag()) {543case dwarf::DW_TAG_variable:544case dwarf::DW_TAG_constant:545case dwarf::DW_TAG_subprogram:546case dwarf::DW_TAG_label: {547if (ChildInfo.getHasAnAddress())548continue;549} break;550default:551break; // Nothing to do.552};553554if (!markDIEEntryAsKeptRec(555Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},556InterCUProcessingStarted, HasNewInterconnectedCUs))557Res = false;558}559560return Res;561}562563bool DependencyTracker::isTypeTableCandidate(564const DWARFDebugInfoEntry *DIEEntry) {565switch (DIEEntry->getTag()) {566default:567return false;568569case dwarf::DW_TAG_imported_module:570case dwarf::DW_TAG_imported_declaration:571case dwarf::DW_TAG_imported_unit:572case dwarf::DW_TAG_array_type:573case dwarf::DW_TAG_class_type:574case dwarf::DW_TAG_enumeration_type:575case dwarf::DW_TAG_pointer_type:576case dwarf::DW_TAG_reference_type:577case dwarf::DW_TAG_string_type:578case dwarf::DW_TAG_structure_type:579case dwarf::DW_TAG_subroutine_type:580case dwarf::DW_TAG_typedef:581case dwarf::DW_TAG_union_type:582case dwarf::DW_TAG_variant:583case dwarf::DW_TAG_module:584case dwarf::DW_TAG_ptr_to_member_type:585case dwarf::DW_TAG_set_type:586case dwarf::DW_TAG_subrange_type:587case dwarf::DW_TAG_base_type:588case dwarf::DW_TAG_const_type:589case dwarf::DW_TAG_enumerator:590case dwarf::DW_TAG_file_type:591case dwarf::DW_TAG_packed_type:592case dwarf::DW_TAG_thrown_type:593case dwarf::DW_TAG_volatile_type:594case dwarf::DW_TAG_dwarf_procedure:595case dwarf::DW_TAG_restrict_type:596case dwarf::DW_TAG_interface_type:597case dwarf::DW_TAG_namespace:598case dwarf::DW_TAG_unspecified_type:599case dwarf::DW_TAG_shared_type:600case dwarf::DW_TAG_rvalue_reference_type:601case dwarf::DW_TAG_coarray_type:602case dwarf::DW_TAG_dynamic_type:603case dwarf::DW_TAG_atomic_type:604case dwarf::DW_TAG_immutable_type:605case dwarf::DW_TAG_function_template:606case dwarf::DW_TAG_class_template:607return true;608}609}610611bool DependencyTracker::maybeAddReferencedRoots(612LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,613const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,614std::atomic<bool> &HasNewInterconnectedCUs) {615const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();616if (Abbrev == nullptr)617return true;618619DWARFUnit &Unit = Entry.CU->getOrigUnit();620DWARFDataExtractor Data = Unit.getDebugInfoExtractor();621uint64_t Offset =622Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());623624// For each DIE attribute...625for (const auto &AttrSpec : Abbrev->attributes()) {626DWARFFormValue Val(AttrSpec.Form);627if (!Val.isFormClass(DWARFFormValue::FC_Reference) ||628AttrSpec.Attr == dwarf::DW_AT_sibling) {629DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,630Unit.getFormParams());631continue;632}633Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);634635// Resolve reference.636std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(637Val, InterCUProcessingStarted638? ResolveInterCUReferencesMode::Resolve639: ResolveInterCUReferencesMode::AvoidResolving);640if (!RefDie) {641Entry.CU->warn("cann't find referenced DIE", Entry.DieEntry);642continue;643}644645if (!RefDie->DieEntry) {646// Delay resolving reference.647RefDie->CU->setInterconnectedCU();648Entry.CU->setInterconnectedCU();649HasNewInterconnectedCUs = true;650return false;651}652653assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||654InterCUProcessingStarted) &&655"Inter-CU reference while inter-CU processing is not started");656657CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);658if (!RefInfo.getODRAvailable())659Action = LiveRootWorklistActionTy::MarkLiveEntryRec;660else if (RefInfo.getODRAvailable() &&661llvm::is_contained(getODRAttributes(), AttrSpec.Attr))662// Note: getODRAttributes does not include DW_AT_containing_type.663// It should be OK as we do getRootForSpecifiedEntry(). So any containing664// type would be found as the root for the entry.665Action = LiveRootWorklistActionTy::MarkTypeEntryRec;666else if (isLiveAction(Action))667Action = LiveRootWorklistActionTy::MarkLiveEntryRec;668else669Action = LiveRootWorklistActionTy::MarkTypeEntryRec;670671if (AttrSpec.Attr == dwarf::DW_AT_import) {672if (isNamespaceLikeEntry(RefDie->DieEntry)) {673addActionToRootEntriesWorkList(674isTypeAction(Action)675? LiveRootWorklistActionTy::MarkSingleTypeEntry676: LiveRootWorklistActionTy::MarkSingleLiveEntry,677*RefDie, RootEntry);678continue;679}680681addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);682continue;683}684685UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);686addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);687}688689return true;690}691692UnitEntryPairTy693DependencyTracker::getRootForSpecifiedEntry(UnitEntryPairTy Entry) {694UnitEntryPairTy Result = Entry;695696do {697switch (Entry.DieEntry->getTag()) {698case dwarf::DW_TAG_subprogram:699case dwarf::DW_TAG_label:700case dwarf::DW_TAG_variable:701case dwarf::DW_TAG_constant: {702return Result;703} break;704705default: {706// Nothing to do.707}708}709710std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();711if (!ParentIdx)712return Result;713714const DWARFDebugInfoEntry *ParentEntry =715Result.CU->getDebugInfoEntry(*ParentIdx);716if (isNamespaceLikeEntry(ParentEntry))717break;718Result.DieEntry = ParentEntry;719} while (true);720721return Result;722}723724bool DependencyTracker::isLiveVariableEntry(const UnitEntryPairTy &Entry,725bool IsLiveParent) {726DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);727CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);728729if (Info.getTrackLiveness()) {730const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();731732if (!Info.getIsInFunctionScope() &&733Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {734// Global variables with constant value can always be kept.735} else {736// See if there is a relocation to a valid debug map entry inside this737// variable's location. The order is important here. We want to always738// check if the variable has a location expression address. However, we739// don't want a static variable in a function to force us to keep the740// enclosing function, unless requested explicitly.741std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =742Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(743DIE, Entry.CU->getGlobalData().getOptions().Verbose);744745if (LocExprAddrAndRelocAdjustment.first)746Info.setHasAnAddress();747748if (!LocExprAddrAndRelocAdjustment.second)749return false;750751if (!IsLiveParent && Info.getIsInFunctionScope() &&752!Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)753return false;754}755}756Info.setHasAnAddress();757758if (Entry.CU->getGlobalData().getOptions().Verbose) {759outs() << "Keeping variable DIE:";760DIDumpOptions DumpOpts;761DumpOpts.ChildRecurseDepth = 0;762DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;763DIE.dump(outs(), 8 /* Indent */, DumpOpts);764}765766return true;767}768769bool DependencyTracker::isLiveSubprogramEntry(const UnitEntryPairTy &Entry) {770DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);771CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);772std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);773774std::optional<uint64_t> LowPc;775std::optional<uint64_t> HighPc;776std::optional<int64_t> RelocAdjustment;777if (Info.getTrackLiveness()) {778LowPc = dwarf::toAddress(LowPCVal);779if (!LowPc)780return false;781782Info.setHasAnAddress();783784RelocAdjustment =785Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(786DIE, Entry.CU->getGlobalData().getOptions().Verbose);787if (!RelocAdjustment)788return false;789790if (DIE.getTag() == dwarf::DW_TAG_subprogram) {791// Validate subprogram address range.792793HighPc = DIE.getHighPC(*LowPc);794if (!HighPc) {795Entry.CU->warn("function without high_pc. Range will be discarded.",796&DIE);797return false;798}799800if (*LowPc > *HighPc) {801Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",802&DIE);803return false;804}805} else if (DIE.getTag() == dwarf::DW_TAG_label) {806if (Entry.CU->hasLabelAt(*LowPc))807return false;808809// FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider810// labels that don't fall into the CU's aranges. This is wrong IMO. Debug811// info generation bugs aside, this is really wrong in the case of labels,812// where a label marking the end of a function will have a PC == CU's813// high_pc.814if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))815.value_or(UINT64_MAX) <= LowPc)816return false;817818Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);819}820} else821Info.setHasAnAddress();822823if (Entry.CU->getGlobalData().getOptions().Verbose) {824outs() << "Keeping subprogram DIE:";825DIDumpOptions DumpOpts;826DumpOpts.ChildRecurseDepth = 0;827DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;828DIE.dump(outs(), 8 /* Indent */, DumpOpts);829}830831if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)832return true;833834Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);835return true;836}837838839