11db9f3b2SDimitry Andric //=== DependencyTracker.cpp -----------------------------------------------===//
21db9f3b2SDimitry Andric //
31db9f3b2SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41db9f3b2SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
51db9f3b2SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61db9f3b2SDimitry Andric //
71db9f3b2SDimitry Andric //===----------------------------------------------------------------------===//
81db9f3b2SDimitry Andric
91db9f3b2SDimitry Andric #include "DependencyTracker.h"
101db9f3b2SDimitry Andric #include "llvm/Support/FormatVariadic.h"
111db9f3b2SDimitry Andric
121db9f3b2SDimitry Andric using namespace llvm;
131db9f3b2SDimitry Andric using namespace dwarf_linker;
141db9f3b2SDimitry Andric using namespace dwarf_linker::parallel;
151db9f3b2SDimitry Andric
161db9f3b2SDimitry Andric /// A broken link in the keep chain. By recording both the parent and the child
171db9f3b2SDimitry Andric /// we can show only broken links for DIEs with multiple children.
181db9f3b2SDimitry Andric struct BrokenLink {
BrokenLinkBrokenLink191db9f3b2SDimitry Andric BrokenLink(DWARFDie Parent, DWARFDie Child, const char *Message)
201db9f3b2SDimitry Andric : Parent(Parent), Child(Child), Message(Message) {}
211db9f3b2SDimitry Andric DWARFDie Parent;
221db9f3b2SDimitry Andric DWARFDie Child;
231db9f3b2SDimitry Andric std::string Message;
241db9f3b2SDimitry Andric };
251db9f3b2SDimitry Andric
261db9f3b2SDimitry Andric /// Verify the keep chain by looking for DIEs that are kept but who's parent
271db9f3b2SDimitry Andric /// isn't.
verifyKeepChain()281db9f3b2SDimitry Andric void DependencyTracker::verifyKeepChain() {
291db9f3b2SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
301db9f3b2SDimitry Andric SmallVector<DWARFDie> Worklist;
311db9f3b2SDimitry Andric Worklist.push_back(CU.getOrigUnit().getUnitDIE());
321db9f3b2SDimitry Andric
331db9f3b2SDimitry Andric // List of broken links.
341db9f3b2SDimitry Andric SmallVector<BrokenLink> BrokenLinks;
351db9f3b2SDimitry Andric
361db9f3b2SDimitry Andric while (!Worklist.empty()) {
371db9f3b2SDimitry Andric const DWARFDie Current = Worklist.back();
381db9f3b2SDimitry Andric Worklist.pop_back();
391db9f3b2SDimitry Andric
401db9f3b2SDimitry Andric if (!Current.isValid())
411db9f3b2SDimitry Andric continue;
421db9f3b2SDimitry Andric
431db9f3b2SDimitry Andric CompileUnit::DIEInfo &CurrentInfo =
441db9f3b2SDimitry Andric CU.getDIEInfo(Current.getDebugInfoEntry());
451db9f3b2SDimitry Andric const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf();
461db9f3b2SDimitry Andric const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable();
471db9f3b2SDimitry Andric
481db9f3b2SDimitry Andric for (DWARFDie Child : reverse(Current.children())) {
491db9f3b2SDimitry Andric Worklist.push_back(Child);
501db9f3b2SDimitry Andric
511db9f3b2SDimitry Andric CompileUnit::DIEInfo &ChildInfo =
521db9f3b2SDimitry Andric CU.getDIEInfo(Child.getDebugInfoEntry());
531db9f3b2SDimitry Andric const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf();
541db9f3b2SDimitry Andric const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable();
551db9f3b2SDimitry Andric
561db9f3b2SDimitry Andric if (!ParentPlainDieIsKept && ChildPlainDieIsKept)
571db9f3b2SDimitry Andric BrokenLinks.emplace_back(Current, Child,
581db9f3b2SDimitry Andric "Found invalid link in keep chain");
591db9f3b2SDimitry Andric
601db9f3b2SDimitry Andric if (Child.getTag() == dwarf::DW_TAG_subprogram) {
611db9f3b2SDimitry Andric if (!ChildInfo.getKeep() && isLiveSubprogramEntry(UnitEntryPairTy(
621db9f3b2SDimitry Andric &CU, Child.getDebugInfoEntry()))) {
631db9f3b2SDimitry Andric BrokenLinks.emplace_back(Current, Child,
641db9f3b2SDimitry Andric "Live subprogram is not marked as kept");
651db9f3b2SDimitry Andric }
661db9f3b2SDimitry Andric }
671db9f3b2SDimitry Andric
681db9f3b2SDimitry Andric if (!ChildInfo.getODRAvailable()) {
691db9f3b2SDimitry Andric assert(!ChildTypeDieIsKept);
701db9f3b2SDimitry Andric continue;
711db9f3b2SDimitry Andric }
721db9f3b2SDimitry Andric
731db9f3b2SDimitry Andric if (!ParentTypeDieIsKept && ChildTypeDieIsKept)
741db9f3b2SDimitry Andric BrokenLinks.emplace_back(Current, Child,
751db9f3b2SDimitry Andric "Found invalid link in keep chain");
761db9f3b2SDimitry Andric
771db9f3b2SDimitry Andric if (CurrentInfo.getIsInAnonNamespaceScope() &&
781db9f3b2SDimitry Andric ChildInfo.needToPlaceInTypeTable()) {
791db9f3b2SDimitry Andric BrokenLinks.emplace_back(Current, Child,
801db9f3b2SDimitry Andric "Found invalid placement marking for member "
811db9f3b2SDimitry Andric "of anonymous namespace");
821db9f3b2SDimitry Andric }
831db9f3b2SDimitry Andric }
841db9f3b2SDimitry Andric }
851db9f3b2SDimitry Andric
861db9f3b2SDimitry Andric if (!BrokenLinks.empty()) {
871db9f3b2SDimitry Andric for (BrokenLink Link : BrokenLinks) {
881db9f3b2SDimitry Andric errs() << "\n=================================\n";
891db9f3b2SDimitry Andric WithColor::error() << formatv("{0} between {1:x} and {2:x}", Link.Message,
901db9f3b2SDimitry Andric Link.Parent.getOffset(),
911db9f3b2SDimitry Andric Link.Child.getOffset());
921db9f3b2SDimitry Andric
931db9f3b2SDimitry Andric errs() << "\nParent:";
941db9f3b2SDimitry Andric Link.Parent.dump(errs(), 0, {});
951db9f3b2SDimitry Andric errs() << "\n";
961db9f3b2SDimitry Andric CU.getDIEInfo(Link.Parent).dump();
971db9f3b2SDimitry Andric
981db9f3b2SDimitry Andric errs() << "\nChild:";
991db9f3b2SDimitry Andric Link.Child.dump(errs(), 2, {});
1001db9f3b2SDimitry Andric errs() << "\n";
1011db9f3b2SDimitry Andric CU.getDIEInfo(Link.Child).dump();
1021db9f3b2SDimitry Andric }
1031db9f3b2SDimitry Andric report_fatal_error("invalid keep chain");
1041db9f3b2SDimitry Andric }
1051db9f3b2SDimitry Andric #endif
1061db9f3b2SDimitry Andric }
1071db9f3b2SDimitry Andric
resolveDependenciesAndMarkLiveness(bool InterCUProcessingStarted,std::atomic<bool> & HasNewInterconnectedCUs)1081db9f3b2SDimitry Andric bool DependencyTracker::resolveDependenciesAndMarkLiveness(
1091db9f3b2SDimitry Andric bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
1101db9f3b2SDimitry Andric RootEntriesWorkList.clear();
1111db9f3b2SDimitry Andric
1121db9f3b2SDimitry Andric // Search for live root DIEs.
1131db9f3b2SDimitry Andric CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));
1141db9f3b2SDimitry Andric CUInfo.setPlacement(CompileUnit::PlainDwarf);
1151db9f3b2SDimitry Andric collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},
1161db9f3b2SDimitry Andric std::nullopt, false);
1171db9f3b2SDimitry Andric
1181db9f3b2SDimitry Andric // Mark live DIEs as kept.
1191db9f3b2SDimitry Andric return markCollectedLiveRootsAsKept(InterCUProcessingStarted,
1201db9f3b2SDimitry Andric HasNewInterconnectedCUs);
1211db9f3b2SDimitry Andric }
1221db9f3b2SDimitry Andric
addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action,const UnitEntryPairTy & Entry,std::optional<UnitEntryPairTy> ReferencedBy)1231db9f3b2SDimitry Andric void DependencyTracker::addActionToRootEntriesWorkList(
1241db9f3b2SDimitry Andric LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
1251db9f3b2SDimitry Andric std::optional<UnitEntryPairTy> ReferencedBy) {
1261db9f3b2SDimitry Andric if (ReferencedBy) {
1271db9f3b2SDimitry Andric RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy);
1281db9f3b2SDimitry Andric return;
1291db9f3b2SDimitry Andric }
1301db9f3b2SDimitry Andric
1311db9f3b2SDimitry Andric RootEntriesWorkList.emplace_back(Action, Entry);
1321db9f3b2SDimitry Andric }
1331db9f3b2SDimitry Andric
collectRootsToKeep(const UnitEntryPairTy & Entry,std::optional<UnitEntryPairTy> ReferencedBy,bool IsLiveParent)1341db9f3b2SDimitry Andric void DependencyTracker::collectRootsToKeep(
1351db9f3b2SDimitry Andric const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,
1361db9f3b2SDimitry Andric bool IsLiveParent) {
1371db9f3b2SDimitry Andric for (const DWARFDebugInfoEntry *CurChild =
1381db9f3b2SDimitry Andric Entry.CU->getFirstChildEntry(Entry.DieEntry);
1391db9f3b2SDimitry Andric CurChild && CurChild->getAbbreviationDeclarationPtr();
1401db9f3b2SDimitry Andric CurChild = Entry.CU->getSiblingEntry(CurChild)) {
1411db9f3b2SDimitry Andric UnitEntryPairTy ChildEntry(Entry.CU, CurChild);
1421db9f3b2SDimitry Andric CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild);
1431db9f3b2SDimitry Andric
1441db9f3b2SDimitry Andric bool IsLiveChild = false;
1451db9f3b2SDimitry Andric
1461db9f3b2SDimitry Andric switch (CurChild->getTag()) {
1471db9f3b2SDimitry Andric case dwarf::DW_TAG_label: {
1481db9f3b2SDimitry Andric IsLiveChild = isLiveSubprogramEntry(ChildEntry);
1491db9f3b2SDimitry Andric
1501db9f3b2SDimitry Andric // Keep label referencing live address.
1511db9f3b2SDimitry Andric // Keep label which is child of live parent entry.
1521db9f3b2SDimitry Andric if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
1531db9f3b2SDimitry Andric addActionToRootEntriesWorkList(
1541db9f3b2SDimitry Andric LiveRootWorklistActionTy::MarkLiveEntryRec, ChildEntry,
1551db9f3b2SDimitry Andric ReferencedBy);
1561db9f3b2SDimitry Andric }
1571db9f3b2SDimitry Andric } break;
1581db9f3b2SDimitry Andric case dwarf::DW_TAG_subprogram: {
1591db9f3b2SDimitry Andric IsLiveChild = isLiveSubprogramEntry(ChildEntry);
1601db9f3b2SDimitry Andric
1611db9f3b2SDimitry Andric // Keep subprogram referencing live address.
1621db9f3b2SDimitry Andric if (IsLiveChild) {
1631db9f3b2SDimitry Andric // If subprogram is in module scope and this module allows ODR
1641db9f3b2SDimitry Andric // deduplication set "TypeTable" placement, otherwise set "" placement
1651db9f3b2SDimitry Andric LiveRootWorklistActionTy Action =
1661db9f3b2SDimitry Andric (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
1671db9f3b2SDimitry Andric ? LiveRootWorklistActionTy::MarkTypeEntryRec
1681db9f3b2SDimitry Andric : LiveRootWorklistActionTy::MarkLiveEntryRec;
1691db9f3b2SDimitry Andric
1701db9f3b2SDimitry Andric addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
1711db9f3b2SDimitry Andric }
1721db9f3b2SDimitry Andric } break;
1731db9f3b2SDimitry Andric case dwarf::DW_TAG_constant:
1741db9f3b2SDimitry Andric case dwarf::DW_TAG_variable: {
1751db9f3b2SDimitry Andric IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);
1761db9f3b2SDimitry Andric
1771db9f3b2SDimitry Andric // Keep variable referencing live address.
1781db9f3b2SDimitry Andric if (IsLiveChild) {
1791db9f3b2SDimitry Andric // If variable is in module scope and this module allows ODR
1801db9f3b2SDimitry Andric // deduplication set "TypeTable" placement, otherwise set "" placement
1811db9f3b2SDimitry Andric
1821db9f3b2SDimitry Andric LiveRootWorklistActionTy Action =
1831db9f3b2SDimitry Andric (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
1841db9f3b2SDimitry Andric ? LiveRootWorklistActionTy::MarkTypeEntryRec
1851db9f3b2SDimitry Andric : LiveRootWorklistActionTy::MarkLiveEntryRec;
1861db9f3b2SDimitry Andric
1871db9f3b2SDimitry Andric addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
1881db9f3b2SDimitry Andric }
1891db9f3b2SDimitry Andric } break;
1901db9f3b2SDimitry Andric case dwarf::DW_TAG_base_type: {
1911db9f3b2SDimitry Andric // Always keep base types.
1921db9f3b2SDimitry Andric addActionToRootEntriesWorkList(
1931db9f3b2SDimitry Andric LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
1941db9f3b2SDimitry Andric ReferencedBy);
1951db9f3b2SDimitry Andric } break;
1961db9f3b2SDimitry Andric case dwarf::DW_TAG_imported_module:
1971db9f3b2SDimitry Andric case dwarf::DW_TAG_imported_declaration:
1981db9f3b2SDimitry Andric case dwarf::DW_TAG_imported_unit: {
1991db9f3b2SDimitry Andric // Always keep DIEs having DW_AT_import attribute.
2001db9f3b2SDimitry Andric if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
2011db9f3b2SDimitry Andric addActionToRootEntriesWorkList(
2021db9f3b2SDimitry Andric LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
2031db9f3b2SDimitry Andric ReferencedBy);
2041db9f3b2SDimitry Andric break;
2051db9f3b2SDimitry Andric }
2061db9f3b2SDimitry Andric
2071db9f3b2SDimitry Andric addActionToRootEntriesWorkList(
2081db9f3b2SDimitry Andric LiveRootWorklistActionTy::MarkSingleTypeEntry, ChildEntry,
2091db9f3b2SDimitry Andric ReferencedBy);
2101db9f3b2SDimitry Andric } break;
2111db9f3b2SDimitry Andric case dwarf::DW_TAG_type_unit:
2121db9f3b2SDimitry Andric case dwarf::DW_TAG_partial_unit:
2131db9f3b2SDimitry Andric case dwarf::DW_TAG_compile_unit: {
2141db9f3b2SDimitry Andric llvm_unreachable("Called for incorrect DIE");
2151db9f3b2SDimitry Andric } break;
2161db9f3b2SDimitry Andric default:
2171db9f3b2SDimitry Andric // Nothing to do.
2181db9f3b2SDimitry Andric break;
2191db9f3b2SDimitry Andric }
2201db9f3b2SDimitry Andric
2211db9f3b2SDimitry Andric collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
2221db9f3b2SDimitry Andric }
2231db9f3b2SDimitry Andric }
2241db9f3b2SDimitry Andric
markCollectedLiveRootsAsKept(bool InterCUProcessingStarted,std::atomic<bool> & HasNewInterconnectedCUs)2251db9f3b2SDimitry Andric bool DependencyTracker::markCollectedLiveRootsAsKept(
2261db9f3b2SDimitry Andric bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
2271db9f3b2SDimitry Andric bool Res = true;
2281db9f3b2SDimitry Andric
2291db9f3b2SDimitry Andric // Mark roots as kept.
2301db9f3b2SDimitry Andric while (!RootEntriesWorkList.empty()) {
2311db9f3b2SDimitry Andric LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();
2321db9f3b2SDimitry Andric
2331db9f3b2SDimitry Andric if (markDIEEntryAsKeptRec(Root.getAction(), Root.getRootEntry(),
2341db9f3b2SDimitry Andric Root.getRootEntry(), InterCUProcessingStarted,
2351db9f3b2SDimitry Andric HasNewInterconnectedCUs)) {
2361db9f3b2SDimitry Andric if (Root.hasReferencedByOtherEntry())
2371db9f3b2SDimitry Andric Dependencies.push_back(Root);
2381db9f3b2SDimitry Andric } else
2391db9f3b2SDimitry Andric Res = false;
2401db9f3b2SDimitry Andric }
2411db9f3b2SDimitry Andric
2421db9f3b2SDimitry Andric return Res;
2431db9f3b2SDimitry Andric }
2441db9f3b2SDimitry Andric
updateDependenciesCompleteness()2451db9f3b2SDimitry Andric bool DependencyTracker::updateDependenciesCompleteness() {
2461db9f3b2SDimitry Andric bool HasNewDependency = false;
2471db9f3b2SDimitry Andric for (LiveRootWorklistItemTy &Root : Dependencies) {
2481db9f3b2SDimitry Andric assert(Root.hasReferencedByOtherEntry() &&
2491db9f3b2SDimitry Andric "Root entry without dependency inside the dependencies list");
2501db9f3b2SDimitry Andric
2511db9f3b2SDimitry Andric UnitEntryPairTy RootEntry = Root.getRootEntry();
2521db9f3b2SDimitry Andric CompileUnit::DIEInfo &RootInfo =
2531db9f3b2SDimitry Andric RootEntry.CU->getDIEInfo(RootEntry.DieEntry);
2541db9f3b2SDimitry Andric
2551db9f3b2SDimitry Andric UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
2561db9f3b2SDimitry Andric CompileUnit::DIEInfo &ReferencedByInfo =
2571db9f3b2SDimitry Andric ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
2581db9f3b2SDimitry Andric
2591db9f3b2SDimitry Andric if (!RootInfo.needToPlaceInTypeTable() &&
2601db9f3b2SDimitry Andric ReferencedByInfo.needToPlaceInTypeTable()) {
2611db9f3b2SDimitry Andric HasNewDependency = true;
2621db9f3b2SDimitry Andric setPlainDwarfPlacementRec(ReferencedByEntry);
2631db9f3b2SDimitry Andric
2641db9f3b2SDimitry Andric // FIXME: we probably need to update getKeepTypeChildren status for
2651db9f3b2SDimitry Andric // parents of *Root.ReferencedBy.
2661db9f3b2SDimitry Andric }
2671db9f3b2SDimitry Andric }
2681db9f3b2SDimitry Andric
2691db9f3b2SDimitry Andric return HasNewDependency;
2701db9f3b2SDimitry Andric }
2711db9f3b2SDimitry Andric
setPlainDwarfPlacementRec(const UnitEntryPairTy & Entry)2721db9f3b2SDimitry Andric void DependencyTracker::setPlainDwarfPlacementRec(
2731db9f3b2SDimitry Andric const UnitEntryPairTy &Entry) {
2741db9f3b2SDimitry Andric CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
2751db9f3b2SDimitry Andric if (Info.getPlacement() == CompileUnit::PlainDwarf &&
2761db9f3b2SDimitry Andric !Info.getKeepTypeChildren())
2771db9f3b2SDimitry Andric return;
2781db9f3b2SDimitry Andric
2791db9f3b2SDimitry Andric Info.setPlacement(CompileUnit::PlainDwarf);
2801db9f3b2SDimitry Andric Info.unsetKeepTypeChildren();
2811db9f3b2SDimitry Andric markParentsAsKeepingChildren(Entry);
2821db9f3b2SDimitry Andric
2831db9f3b2SDimitry Andric for (const DWARFDebugInfoEntry *CurChild =
2841db9f3b2SDimitry Andric Entry.CU->getFirstChildEntry(Entry.DieEntry);
2851db9f3b2SDimitry Andric CurChild && CurChild->getAbbreviationDeclarationPtr();
2861db9f3b2SDimitry Andric CurChild = Entry.CU->getSiblingEntry(CurChild))
2871db9f3b2SDimitry Andric setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});
2881db9f3b2SDimitry Andric }
2891db9f3b2SDimitry Andric
isNamespaceLikeEntry(const DWARFDebugInfoEntry * Entry)2901db9f3b2SDimitry Andric static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {
2911db9f3b2SDimitry Andric switch (Entry->getTag()) {
2921db9f3b2SDimitry Andric case dwarf::DW_TAG_compile_unit:
2931db9f3b2SDimitry Andric case dwarf::DW_TAG_module:
2941db9f3b2SDimitry Andric case dwarf::DW_TAG_namespace:
2951db9f3b2SDimitry Andric return true;
2961db9f3b2SDimitry Andric
2971db9f3b2SDimitry Andric default:
2981db9f3b2SDimitry Andric return false;
2991db9f3b2SDimitry Andric }
3001db9f3b2SDimitry Andric }
3011db9f3b2SDimitry Andric
isAlreadyMarked(const CompileUnit::DIEInfo & Info,CompileUnit::DieOutputPlacement NewPlacement)3021db9f3b2SDimitry Andric bool isAlreadyMarked(const CompileUnit::DIEInfo &Info,
3031db9f3b2SDimitry Andric CompileUnit::DieOutputPlacement NewPlacement) {
3041db9f3b2SDimitry Andric if (!Info.getKeep())
3051db9f3b2SDimitry Andric return false;
3061db9f3b2SDimitry Andric
3071db9f3b2SDimitry Andric switch (NewPlacement) {
3081db9f3b2SDimitry Andric case CompileUnit::TypeTable:
3091db9f3b2SDimitry Andric return Info.needToPlaceInTypeTable();
3101db9f3b2SDimitry Andric
3111db9f3b2SDimitry Andric case CompileUnit::PlainDwarf:
3121db9f3b2SDimitry Andric return Info.needToKeepInPlainDwarf();
3131db9f3b2SDimitry Andric
3141db9f3b2SDimitry Andric case CompileUnit::Both:
3151db9f3b2SDimitry Andric return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
3161db9f3b2SDimitry Andric
3171db9f3b2SDimitry Andric case CompileUnit::NotSet:
3181db9f3b2SDimitry Andric llvm_unreachable("Unset placement type is specified.");
3191db9f3b2SDimitry Andric };
3201db9f3b2SDimitry Andric
3211db9f3b2SDimitry Andric llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");
3221db9f3b2SDimitry Andric }
3231db9f3b2SDimitry Andric
isAlreadyMarked(const UnitEntryPairTy & Entry,CompileUnit::DieOutputPlacement NewPlacement)3241db9f3b2SDimitry Andric bool isAlreadyMarked(const UnitEntryPairTy &Entry,
3251db9f3b2SDimitry Andric CompileUnit::DieOutputPlacement NewPlacement) {
3261db9f3b2SDimitry Andric return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
3271db9f3b2SDimitry Andric }
3281db9f3b2SDimitry Andric
markParentsAsKeepingChildren(const UnitEntryPairTy & Entry)3291db9f3b2SDimitry Andric void DependencyTracker::markParentsAsKeepingChildren(
3301db9f3b2SDimitry Andric const UnitEntryPairTy &Entry) {
3311db9f3b2SDimitry Andric if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
3321db9f3b2SDimitry Andric return;
3331db9f3b2SDimitry Andric
3341db9f3b2SDimitry Andric CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
3351db9f3b2SDimitry Andric bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
3361db9f3b2SDimitry Andric bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
3371db9f3b2SDimitry Andric
3381db9f3b2SDimitry Andric bool AreTypeParentsDone = !NeedKeepTypeChildren;
3391db9f3b2SDimitry Andric bool ArePlainParentsDone = !NeedKeepPlainChildren;
3401db9f3b2SDimitry Andric
3411db9f3b2SDimitry Andric // Mark parents as 'Keep*Children'.
3421db9f3b2SDimitry Andric std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
3431db9f3b2SDimitry Andric while (ParentIdx) {
3441db9f3b2SDimitry Andric const DWARFDebugInfoEntry *ParentEntry =
3451db9f3b2SDimitry Andric Entry.CU->getDebugInfoEntry(*ParentIdx);
3461db9f3b2SDimitry Andric CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);
3471db9f3b2SDimitry Andric
3481db9f3b2SDimitry Andric if (!AreTypeParentsDone && NeedKeepTypeChildren) {
3491db9f3b2SDimitry Andric if (ParentInfo.getKeepTypeChildren())
3501db9f3b2SDimitry Andric AreTypeParentsDone = true;
3511db9f3b2SDimitry Andric else {
3521db9f3b2SDimitry Andric bool AddToWorklist = !isAlreadyMarked(
3531db9f3b2SDimitry Andric ParentInfo, CompileUnit::DieOutputPlacement::TypeTable);
3541db9f3b2SDimitry Andric ParentInfo.setKeepTypeChildren();
3551db9f3b2SDimitry Andric if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
3561db9f3b2SDimitry Andric addActionToRootEntriesWorkList(
3571db9f3b2SDimitry Andric LiveRootWorklistActionTy::MarkTypeChildrenRec,
3581db9f3b2SDimitry Andric UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
3591db9f3b2SDimitry Andric }
3601db9f3b2SDimitry Andric }
3611db9f3b2SDimitry Andric }
3621db9f3b2SDimitry Andric
3631db9f3b2SDimitry Andric if (!ArePlainParentsDone && NeedKeepPlainChildren) {
3641db9f3b2SDimitry Andric if (ParentInfo.getKeepPlainChildren())
3651db9f3b2SDimitry Andric ArePlainParentsDone = true;
3661db9f3b2SDimitry Andric else {
3671db9f3b2SDimitry Andric bool AddToWorklist = !isAlreadyMarked(
3681db9f3b2SDimitry Andric ParentInfo, CompileUnit::DieOutputPlacement::PlainDwarf);
3691db9f3b2SDimitry Andric ParentInfo.setKeepPlainChildren();
3701db9f3b2SDimitry Andric if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
3711db9f3b2SDimitry Andric addActionToRootEntriesWorkList(
3721db9f3b2SDimitry Andric LiveRootWorklistActionTy::MarkLiveChildrenRec,
3731db9f3b2SDimitry Andric UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
3741db9f3b2SDimitry Andric }
3751db9f3b2SDimitry Andric }
3761db9f3b2SDimitry Andric }
3771db9f3b2SDimitry Andric
3781db9f3b2SDimitry Andric if (AreTypeParentsDone && ArePlainParentsDone)
3791db9f3b2SDimitry Andric break;
3801db9f3b2SDimitry Andric
3811db9f3b2SDimitry Andric ParentIdx = ParentEntry->getParentIdx();
3821db9f3b2SDimitry Andric }
3831db9f3b2SDimitry Andric }
3841db9f3b2SDimitry Andric
3851db9f3b2SDimitry Andric // This function tries to set specified \p Placement for the \p Entry.
3861db9f3b2SDimitry Andric // Depending on the concrete entry, the placement could be:
3871db9f3b2SDimitry Andric // a) changed to another.
3881db9f3b2SDimitry Andric // b) joined with current entry placement.
3891db9f3b2SDimitry Andric // c) set as requested.
3901db9f3b2SDimitry Andric static CompileUnit::DieOutputPlacement
getFinalPlacementForEntry(const UnitEntryPairTy & Entry,CompileUnit::DieOutputPlacement Placement)3911db9f3b2SDimitry Andric getFinalPlacementForEntry(const UnitEntryPairTy &Entry,
3921db9f3b2SDimitry Andric CompileUnit::DieOutputPlacement Placement) {
3931db9f3b2SDimitry Andric assert((Placement != CompileUnit::NotSet) && "Placement is not set");
3941db9f3b2SDimitry Andric CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
3951db9f3b2SDimitry Andric
3961db9f3b2SDimitry Andric if (!EntryInfo.getODRAvailable())
3971db9f3b2SDimitry Andric return CompileUnit::PlainDwarf;
3981db9f3b2SDimitry Andric
3991db9f3b2SDimitry Andric if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
4001db9f3b2SDimitry Andric // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
4011db9f3b2SDimitry Andric // time.
4021db9f3b2SDimitry Andric if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||
4031db9f3b2SDimitry Andric EntryInfo.getPlacement() == CompileUnit::Both)
4041db9f3b2SDimitry Andric return CompileUnit::PlainDwarf;
4051db9f3b2SDimitry Andric
4061db9f3b2SDimitry Andric if (Placement == CompileUnit::PlainDwarf || Placement == CompileUnit::Both)
4071db9f3b2SDimitry Andric return CompileUnit::PlainDwarf;
4081db9f3b2SDimitry Andric }
4091db9f3b2SDimitry Andric
4101db9f3b2SDimitry Andric switch (EntryInfo.getPlacement()) {
4111db9f3b2SDimitry Andric case CompileUnit::NotSet:
4121db9f3b2SDimitry Andric return Placement;
4131db9f3b2SDimitry Andric
4141db9f3b2SDimitry Andric case CompileUnit::TypeTable:
4151db9f3b2SDimitry Andric return Placement == CompileUnit::PlainDwarf ? CompileUnit::Both : Placement;
4161db9f3b2SDimitry Andric
4171db9f3b2SDimitry Andric case CompileUnit::PlainDwarf:
4181db9f3b2SDimitry Andric return Placement == CompileUnit::TypeTable ? CompileUnit::Both : Placement;
4191db9f3b2SDimitry Andric
4201db9f3b2SDimitry Andric case CompileUnit::Both:
4211db9f3b2SDimitry Andric return CompileUnit::Both;
4221db9f3b2SDimitry Andric };
4231db9f3b2SDimitry Andric
4241db9f3b2SDimitry Andric llvm_unreachable("Unknown placement type.");
4251db9f3b2SDimitry Andric return Placement;
4261db9f3b2SDimitry Andric }
4271db9f3b2SDimitry Andric
markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action,const UnitEntryPairTy & RootEntry,const UnitEntryPairTy & Entry,bool InterCUProcessingStarted,std::atomic<bool> & HasNewInterconnectedCUs)4281db9f3b2SDimitry Andric bool DependencyTracker::markDIEEntryAsKeptRec(
4291db9f3b2SDimitry Andric LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
4301db9f3b2SDimitry Andric const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
4311db9f3b2SDimitry Andric std::atomic<bool> &HasNewInterconnectedCUs) {
4321db9f3b2SDimitry Andric if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
4331db9f3b2SDimitry Andric return true;
4341db9f3b2SDimitry Andric
4351db9f3b2SDimitry Andric CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
4361db9f3b2SDimitry Andric
4371db9f3b2SDimitry Andric // Calculate final placement placement.
4381db9f3b2SDimitry Andric CompileUnit::DieOutputPlacement Placement = getFinalPlacementForEntry(
4391db9f3b2SDimitry Andric Entry,
4401db9f3b2SDimitry Andric isLiveAction(Action) ? CompileUnit::PlainDwarf : CompileUnit::TypeTable);
4411db9f3b2SDimitry Andric assert((Info.getODRAvailable() || isLiveAction(Action) ||
4421db9f3b2SDimitry Andric Placement == CompileUnit::PlainDwarf) &&
4431db9f3b2SDimitry Andric "Wrong kind of placement for ODR unavailable entry");
4441db9f3b2SDimitry Andric
4451db9f3b2SDimitry Andric if (!isChildrenAction(Action))
4461db9f3b2SDimitry Andric if (isAlreadyMarked(Entry, Placement))
4471db9f3b2SDimitry Andric return true;
4481db9f3b2SDimitry Andric
4491db9f3b2SDimitry Andric // Mark current DIE as kept.
4501db9f3b2SDimitry Andric Info.setKeep();
4511db9f3b2SDimitry Andric Info.setPlacement(Placement);
4521db9f3b2SDimitry Andric
4531db9f3b2SDimitry Andric // Set keep children property for parents.
4541db9f3b2SDimitry Andric markParentsAsKeepingChildren(Entry);
4551db9f3b2SDimitry Andric
4561db9f3b2SDimitry Andric UnitEntryPairTy FinalRootEntry =
4571db9f3b2SDimitry Andric Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
4581db9f3b2SDimitry Andric
4591db9f3b2SDimitry Andric // Analyse referenced DIEs.
4601db9f3b2SDimitry Andric bool Res = true;
4611db9f3b2SDimitry Andric if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
4621db9f3b2SDimitry Andric InterCUProcessingStarted,
4631db9f3b2SDimitry Andric HasNewInterconnectedCUs))
4641db9f3b2SDimitry Andric Res = false;
4651db9f3b2SDimitry Andric
4661db9f3b2SDimitry Andric // Return if we do not need to process children.
4671db9f3b2SDimitry Andric if (isSingleAction(Action))
4681db9f3b2SDimitry Andric return Res;
4691db9f3b2SDimitry Andric
4701db9f3b2SDimitry Andric // Process children.
4711db9f3b2SDimitry Andric // Check for subprograms special case.
4721db9f3b2SDimitry Andric if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
4731db9f3b2SDimitry Andric Info.getODRAvailable()) {
4741db9f3b2SDimitry Andric // Subprograms is a special case. As it can be root for type DIEs
4751db9f3b2SDimitry Andric // and itself may be subject to move into the artificial type unit.
4761db9f3b2SDimitry Andric // a) Non removable children(like DW_TAG_formal_parameter) should always
4771db9f3b2SDimitry Andric // be cloned. They are placed into the "PlainDwarf" and into the
4781db9f3b2SDimitry Andric // "TypeTable".
4791db9f3b2SDimitry Andric // b) ODR deduplication candidates(type DIEs) children should not be put
4801db9f3b2SDimitry Andric // into the "PlainDwarf".
4811db9f3b2SDimitry Andric // c) Children keeping addresses and locations(like DW_TAG_call_site)
4821db9f3b2SDimitry Andric // should not be put into the "TypeTable".
4831db9f3b2SDimitry Andric for (const DWARFDebugInfoEntry *CurChild =
4841db9f3b2SDimitry Andric Entry.CU->getFirstChildEntry(Entry.DieEntry);
4851db9f3b2SDimitry Andric CurChild && CurChild->getAbbreviationDeclarationPtr();
4861db9f3b2SDimitry Andric CurChild = Entry.CU->getSiblingEntry(CurChild)) {
4871db9f3b2SDimitry Andric CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
4881db9f3b2SDimitry Andric
4891db9f3b2SDimitry Andric switch (CurChild->getTag()) {
4901db9f3b2SDimitry Andric case dwarf::DW_TAG_variable:
4911db9f3b2SDimitry Andric case dwarf::DW_TAG_constant:
4921db9f3b2SDimitry Andric case dwarf::DW_TAG_subprogram:
4931db9f3b2SDimitry Andric case dwarf::DW_TAG_label: {
4941db9f3b2SDimitry Andric if (ChildInfo.getHasAnAddress())
4951db9f3b2SDimitry Andric continue;
4961db9f3b2SDimitry Andric } break;
4971db9f3b2SDimitry Andric
4981db9f3b2SDimitry Andric // Entries having following tags could not be removed from the subprogram.
4991db9f3b2SDimitry Andric case dwarf::DW_TAG_lexical_block:
5001db9f3b2SDimitry Andric case dwarf::DW_TAG_friend:
5011db9f3b2SDimitry Andric case dwarf::DW_TAG_inheritance:
5021db9f3b2SDimitry Andric case dwarf::DW_TAG_formal_parameter:
5031db9f3b2SDimitry Andric case dwarf::DW_TAG_unspecified_parameters:
5041db9f3b2SDimitry Andric case dwarf::DW_TAG_template_type_parameter:
5051db9f3b2SDimitry Andric case dwarf::DW_TAG_template_value_parameter:
5061db9f3b2SDimitry Andric case dwarf::DW_TAG_GNU_template_parameter_pack:
5071db9f3b2SDimitry Andric case dwarf::DW_TAG_GNU_formal_parameter_pack:
5081db9f3b2SDimitry Andric case dwarf::DW_TAG_GNU_template_template_param:
5091db9f3b2SDimitry Andric case dwarf::DW_TAG_thrown_type: {
5101db9f3b2SDimitry Andric // Go to the default child handling.
5111db9f3b2SDimitry Andric } break;
5121db9f3b2SDimitry Andric
5131db9f3b2SDimitry Andric default: {
5141db9f3b2SDimitry Andric bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
5151db9f3b2SDimitry Andric
5161db9f3b2SDimitry Andric // Skip child marked to be copied into the artificial type unit.
5171db9f3b2SDimitry Andric if (isLiveAction(Action) && ChildIsTypeTableCandidate)
5181db9f3b2SDimitry Andric continue;
5191db9f3b2SDimitry Andric
5201db9f3b2SDimitry Andric // Skip child marked to be copied into the plain unit.
5211db9f3b2SDimitry Andric if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
5221db9f3b2SDimitry Andric continue;
5231db9f3b2SDimitry Andric
5241db9f3b2SDimitry Andric // Go to the default child handling.
5251db9f3b2SDimitry Andric } break;
5261db9f3b2SDimitry Andric }
5271db9f3b2SDimitry Andric
5281db9f3b2SDimitry Andric if (!markDIEEntryAsKeptRec(
5291db9f3b2SDimitry Andric Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
5301db9f3b2SDimitry Andric InterCUProcessingStarted, HasNewInterconnectedCUs))
5311db9f3b2SDimitry Andric Res = false;
5321db9f3b2SDimitry Andric }
5331db9f3b2SDimitry Andric
5341db9f3b2SDimitry Andric return Res;
5351db9f3b2SDimitry Andric }
5361db9f3b2SDimitry Andric
5371db9f3b2SDimitry Andric // Recursively process children.
5381db9f3b2SDimitry Andric for (const DWARFDebugInfoEntry *CurChild =
5391db9f3b2SDimitry Andric Entry.CU->getFirstChildEntry(Entry.DieEntry);
5401db9f3b2SDimitry Andric CurChild && CurChild->getAbbreviationDeclarationPtr();
5411db9f3b2SDimitry Andric CurChild = Entry.CU->getSiblingEntry(CurChild)) {
5421db9f3b2SDimitry Andric CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
5431db9f3b2SDimitry Andric switch (CurChild->getTag()) {
5441db9f3b2SDimitry Andric case dwarf::DW_TAG_variable:
5451db9f3b2SDimitry Andric case dwarf::DW_TAG_constant:
5461db9f3b2SDimitry Andric case dwarf::DW_TAG_subprogram:
5471db9f3b2SDimitry Andric case dwarf::DW_TAG_label: {
5481db9f3b2SDimitry Andric if (ChildInfo.getHasAnAddress())
5491db9f3b2SDimitry Andric continue;
5501db9f3b2SDimitry Andric } break;
5511db9f3b2SDimitry Andric default:
5521db9f3b2SDimitry Andric break; // Nothing to do.
5531db9f3b2SDimitry Andric };
5541db9f3b2SDimitry Andric
5551db9f3b2SDimitry Andric if (!markDIEEntryAsKeptRec(
5561db9f3b2SDimitry Andric Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
5571db9f3b2SDimitry Andric InterCUProcessingStarted, HasNewInterconnectedCUs))
5581db9f3b2SDimitry Andric Res = false;
5591db9f3b2SDimitry Andric }
5601db9f3b2SDimitry Andric
5611db9f3b2SDimitry Andric return Res;
5621db9f3b2SDimitry Andric }
5631db9f3b2SDimitry Andric
isTypeTableCandidate(const DWARFDebugInfoEntry * DIEEntry)5641db9f3b2SDimitry Andric bool DependencyTracker::isTypeTableCandidate(
5651db9f3b2SDimitry Andric const DWARFDebugInfoEntry *DIEEntry) {
5661db9f3b2SDimitry Andric switch (DIEEntry->getTag()) {
5671db9f3b2SDimitry Andric default:
5681db9f3b2SDimitry Andric return false;
5691db9f3b2SDimitry Andric
5701db9f3b2SDimitry Andric case dwarf::DW_TAG_imported_module:
5711db9f3b2SDimitry Andric case dwarf::DW_TAG_imported_declaration:
5721db9f3b2SDimitry Andric case dwarf::DW_TAG_imported_unit:
5731db9f3b2SDimitry Andric case dwarf::DW_TAG_array_type:
5741db9f3b2SDimitry Andric case dwarf::DW_TAG_class_type:
5751db9f3b2SDimitry Andric case dwarf::DW_TAG_enumeration_type:
5761db9f3b2SDimitry Andric case dwarf::DW_TAG_pointer_type:
5771db9f3b2SDimitry Andric case dwarf::DW_TAG_reference_type:
5781db9f3b2SDimitry Andric case dwarf::DW_TAG_string_type:
5791db9f3b2SDimitry Andric case dwarf::DW_TAG_structure_type:
5801db9f3b2SDimitry Andric case dwarf::DW_TAG_subroutine_type:
5811db9f3b2SDimitry Andric case dwarf::DW_TAG_typedef:
5821db9f3b2SDimitry Andric case dwarf::DW_TAG_union_type:
5831db9f3b2SDimitry Andric case dwarf::DW_TAG_variant:
5841db9f3b2SDimitry Andric case dwarf::DW_TAG_module:
5851db9f3b2SDimitry Andric case dwarf::DW_TAG_ptr_to_member_type:
5861db9f3b2SDimitry Andric case dwarf::DW_TAG_set_type:
5871db9f3b2SDimitry Andric case dwarf::DW_TAG_subrange_type:
5881db9f3b2SDimitry Andric case dwarf::DW_TAG_base_type:
5891db9f3b2SDimitry Andric case dwarf::DW_TAG_const_type:
5901db9f3b2SDimitry Andric case dwarf::DW_TAG_enumerator:
5911db9f3b2SDimitry Andric case dwarf::DW_TAG_file_type:
5921db9f3b2SDimitry Andric case dwarf::DW_TAG_packed_type:
5931db9f3b2SDimitry Andric case dwarf::DW_TAG_thrown_type:
5941db9f3b2SDimitry Andric case dwarf::DW_TAG_volatile_type:
5951db9f3b2SDimitry Andric case dwarf::DW_TAG_dwarf_procedure:
5961db9f3b2SDimitry Andric case dwarf::DW_TAG_restrict_type:
5971db9f3b2SDimitry Andric case dwarf::DW_TAG_interface_type:
5981db9f3b2SDimitry Andric case dwarf::DW_TAG_namespace:
5991db9f3b2SDimitry Andric case dwarf::DW_TAG_unspecified_type:
6001db9f3b2SDimitry Andric case dwarf::DW_TAG_shared_type:
6011db9f3b2SDimitry Andric case dwarf::DW_TAG_rvalue_reference_type:
6021db9f3b2SDimitry Andric case dwarf::DW_TAG_coarray_type:
6031db9f3b2SDimitry Andric case dwarf::DW_TAG_dynamic_type:
6041db9f3b2SDimitry Andric case dwarf::DW_TAG_atomic_type:
6051db9f3b2SDimitry Andric case dwarf::DW_TAG_immutable_type:
6061db9f3b2SDimitry Andric case dwarf::DW_TAG_function_template:
6071db9f3b2SDimitry Andric case dwarf::DW_TAG_class_template:
6081db9f3b2SDimitry Andric return true;
6091db9f3b2SDimitry Andric }
6101db9f3b2SDimitry Andric }
6111db9f3b2SDimitry Andric
maybeAddReferencedRoots(LiveRootWorklistActionTy Action,const UnitEntryPairTy & RootEntry,const UnitEntryPairTy & Entry,bool InterCUProcessingStarted,std::atomic<bool> & HasNewInterconnectedCUs)6121db9f3b2SDimitry Andric bool DependencyTracker::maybeAddReferencedRoots(
6131db9f3b2SDimitry Andric LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
6141db9f3b2SDimitry Andric const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
6151db9f3b2SDimitry Andric std::atomic<bool> &HasNewInterconnectedCUs) {
6161db9f3b2SDimitry Andric const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
6171db9f3b2SDimitry Andric if (Abbrev == nullptr)
6181db9f3b2SDimitry Andric return true;
6191db9f3b2SDimitry Andric
6201db9f3b2SDimitry Andric DWARFUnit &Unit = Entry.CU->getOrigUnit();
6211db9f3b2SDimitry Andric DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
6221db9f3b2SDimitry Andric uint64_t Offset =
6231db9f3b2SDimitry Andric Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
6241db9f3b2SDimitry Andric
6251db9f3b2SDimitry Andric // For each DIE attribute...
6261db9f3b2SDimitry Andric for (const auto &AttrSpec : Abbrev->attributes()) {
6271db9f3b2SDimitry Andric DWARFFormValue Val(AttrSpec.Form);
6281db9f3b2SDimitry Andric if (!Val.isFormClass(DWARFFormValue::FC_Reference) ||
6291db9f3b2SDimitry Andric AttrSpec.Attr == dwarf::DW_AT_sibling) {
6301db9f3b2SDimitry Andric DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
6311db9f3b2SDimitry Andric Unit.getFormParams());
6321db9f3b2SDimitry Andric continue;
6331db9f3b2SDimitry Andric }
6341db9f3b2SDimitry Andric Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
6351db9f3b2SDimitry Andric
6361db9f3b2SDimitry Andric // Resolve reference.
6371db9f3b2SDimitry Andric std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
6381db9f3b2SDimitry Andric Val, InterCUProcessingStarted
6391db9f3b2SDimitry Andric ? ResolveInterCUReferencesMode::Resolve
6401db9f3b2SDimitry Andric : ResolveInterCUReferencesMode::AvoidResolving);
6411db9f3b2SDimitry Andric if (!RefDie) {
6421db9f3b2SDimitry Andric Entry.CU->warn("cann't find referenced DIE", Entry.DieEntry);
6431db9f3b2SDimitry Andric continue;
6441db9f3b2SDimitry Andric }
6451db9f3b2SDimitry Andric
6461db9f3b2SDimitry Andric if (!RefDie->DieEntry) {
6471db9f3b2SDimitry Andric // Delay resolving reference.
6481db9f3b2SDimitry Andric RefDie->CU->setInterconnectedCU();
6491db9f3b2SDimitry Andric Entry.CU->setInterconnectedCU();
6501db9f3b2SDimitry Andric HasNewInterconnectedCUs = true;
6511db9f3b2SDimitry Andric return false;
6521db9f3b2SDimitry Andric }
6531db9f3b2SDimitry Andric
6541db9f3b2SDimitry Andric assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
6551db9f3b2SDimitry Andric InterCUProcessingStarted) &&
6561db9f3b2SDimitry Andric "Inter-CU reference while inter-CU processing is not started");
6571db9f3b2SDimitry Andric
6581db9f3b2SDimitry Andric CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
6591db9f3b2SDimitry Andric if (!RefInfo.getODRAvailable())
6601db9f3b2SDimitry Andric Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
6611db9f3b2SDimitry Andric else if (RefInfo.getODRAvailable() &&
6621db9f3b2SDimitry Andric llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
6631db9f3b2SDimitry Andric // Note: getODRAttributes does not include DW_AT_containing_type.
6641db9f3b2SDimitry Andric // It should be OK as we do getRootForSpecifiedEntry(). So any containing
6651db9f3b2SDimitry Andric // type would be found as the root for the entry.
6661db9f3b2SDimitry Andric Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
6671db9f3b2SDimitry Andric else if (isLiveAction(Action))
6681db9f3b2SDimitry Andric Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
6691db9f3b2SDimitry Andric else
6701db9f3b2SDimitry Andric Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
6711db9f3b2SDimitry Andric
6721db9f3b2SDimitry Andric if (AttrSpec.Attr == dwarf::DW_AT_import) {
6731db9f3b2SDimitry Andric if (isNamespaceLikeEntry(RefDie->DieEntry)) {
6741db9f3b2SDimitry Andric addActionToRootEntriesWorkList(
6751db9f3b2SDimitry Andric isTypeAction(Action)
6761db9f3b2SDimitry Andric ? LiveRootWorklistActionTy::MarkSingleTypeEntry
6771db9f3b2SDimitry Andric : LiveRootWorklistActionTy::MarkSingleLiveEntry,
6781db9f3b2SDimitry Andric *RefDie, RootEntry);
6791db9f3b2SDimitry Andric continue;
6801db9f3b2SDimitry Andric }
6811db9f3b2SDimitry Andric
6821db9f3b2SDimitry Andric addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);
6831db9f3b2SDimitry Andric continue;
6841db9f3b2SDimitry Andric }
6851db9f3b2SDimitry Andric
6861db9f3b2SDimitry Andric UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
6871db9f3b2SDimitry Andric addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);
6881db9f3b2SDimitry Andric }
6891db9f3b2SDimitry Andric
6901db9f3b2SDimitry Andric return true;
6911db9f3b2SDimitry Andric }
6921db9f3b2SDimitry Andric
6931db9f3b2SDimitry Andric UnitEntryPairTy
getRootForSpecifiedEntry(UnitEntryPairTy Entry)6941db9f3b2SDimitry Andric DependencyTracker::getRootForSpecifiedEntry(UnitEntryPairTy Entry) {
6951db9f3b2SDimitry Andric UnitEntryPairTy Result = Entry;
6961db9f3b2SDimitry Andric
6971db9f3b2SDimitry Andric do {
6981db9f3b2SDimitry Andric switch (Entry.DieEntry->getTag()) {
6991db9f3b2SDimitry Andric case dwarf::DW_TAG_subprogram:
7001db9f3b2SDimitry Andric case dwarf::DW_TAG_label:
7011db9f3b2SDimitry Andric case dwarf::DW_TAG_variable:
7021db9f3b2SDimitry Andric case dwarf::DW_TAG_constant: {
7031db9f3b2SDimitry Andric return Result;
7041db9f3b2SDimitry Andric } break;
7051db9f3b2SDimitry Andric
7061db9f3b2SDimitry Andric default: {
7071db9f3b2SDimitry Andric // Nothing to do.
7081db9f3b2SDimitry Andric }
7091db9f3b2SDimitry Andric }
7101db9f3b2SDimitry Andric
7111db9f3b2SDimitry Andric std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
7121db9f3b2SDimitry Andric if (!ParentIdx)
7131db9f3b2SDimitry Andric return Result;
7141db9f3b2SDimitry Andric
7151db9f3b2SDimitry Andric const DWARFDebugInfoEntry *ParentEntry =
7161db9f3b2SDimitry Andric Result.CU->getDebugInfoEntry(*ParentIdx);
7171db9f3b2SDimitry Andric if (isNamespaceLikeEntry(ParentEntry))
7181db9f3b2SDimitry Andric break;
7191db9f3b2SDimitry Andric Result.DieEntry = ParentEntry;
7201db9f3b2SDimitry Andric } while (true);
7211db9f3b2SDimitry Andric
7221db9f3b2SDimitry Andric return Result;
7231db9f3b2SDimitry Andric }
7241db9f3b2SDimitry Andric
isLiveVariableEntry(const UnitEntryPairTy & Entry,bool IsLiveParent)7251db9f3b2SDimitry Andric bool DependencyTracker::isLiveVariableEntry(const UnitEntryPairTy &Entry,
7261db9f3b2SDimitry Andric bool IsLiveParent) {
7271db9f3b2SDimitry Andric DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
7281db9f3b2SDimitry Andric CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
7291db9f3b2SDimitry Andric
7301db9f3b2SDimitry Andric if (Info.getTrackLiveness()) {
7311db9f3b2SDimitry Andric const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
7321db9f3b2SDimitry Andric
7331db9f3b2SDimitry Andric if (!Info.getIsInFunctionScope() &&
7341db9f3b2SDimitry Andric Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
7351db9f3b2SDimitry Andric // Global variables with constant value can always be kept.
7361db9f3b2SDimitry Andric } else {
7371db9f3b2SDimitry Andric // See if there is a relocation to a valid debug map entry inside this
7381db9f3b2SDimitry Andric // variable's location. The order is important here. We want to always
7391db9f3b2SDimitry Andric // check if the variable has a location expression address. However, we
7401db9f3b2SDimitry Andric // don't want a static variable in a function to force us to keep the
7411db9f3b2SDimitry Andric // enclosing function, unless requested explicitly.
7421db9f3b2SDimitry Andric std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
7431db9f3b2SDimitry Andric Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
744*7a6dacacSDimitry Andric DIE, Entry.CU->getGlobalData().getOptions().Verbose);
7451db9f3b2SDimitry Andric
7461db9f3b2SDimitry Andric if (LocExprAddrAndRelocAdjustment.first)
7471db9f3b2SDimitry Andric Info.setHasAnAddress();
7481db9f3b2SDimitry Andric
7491db9f3b2SDimitry Andric if (!LocExprAddrAndRelocAdjustment.second)
7501db9f3b2SDimitry Andric return false;
7511db9f3b2SDimitry Andric
7521db9f3b2SDimitry Andric if (!IsLiveParent && Info.getIsInFunctionScope() &&
7531db9f3b2SDimitry Andric !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
7541db9f3b2SDimitry Andric return false;
7551db9f3b2SDimitry Andric }
7561db9f3b2SDimitry Andric }
7571db9f3b2SDimitry Andric Info.setHasAnAddress();
7581db9f3b2SDimitry Andric
7591db9f3b2SDimitry Andric if (Entry.CU->getGlobalData().getOptions().Verbose) {
7601db9f3b2SDimitry Andric outs() << "Keeping variable DIE:";
7611db9f3b2SDimitry Andric DIDumpOptions DumpOpts;
7621db9f3b2SDimitry Andric DumpOpts.ChildRecurseDepth = 0;
7631db9f3b2SDimitry Andric DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
7641db9f3b2SDimitry Andric DIE.dump(outs(), 8 /* Indent */, DumpOpts);
7651db9f3b2SDimitry Andric }
7661db9f3b2SDimitry Andric
7671db9f3b2SDimitry Andric return true;
7681db9f3b2SDimitry Andric }
7691db9f3b2SDimitry Andric
isLiveSubprogramEntry(const UnitEntryPairTy & Entry)7701db9f3b2SDimitry Andric bool DependencyTracker::isLiveSubprogramEntry(const UnitEntryPairTy &Entry) {
7711db9f3b2SDimitry Andric DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
7721db9f3b2SDimitry Andric CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
7731db9f3b2SDimitry Andric std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);
7741db9f3b2SDimitry Andric
7751db9f3b2SDimitry Andric std::optional<uint64_t> LowPc;
7761db9f3b2SDimitry Andric std::optional<uint64_t> HighPc;
7771db9f3b2SDimitry Andric std::optional<int64_t> RelocAdjustment;
7781db9f3b2SDimitry Andric if (Info.getTrackLiveness()) {
7791db9f3b2SDimitry Andric LowPc = dwarf::toAddress(LowPCVal);
7801db9f3b2SDimitry Andric if (!LowPc)
7811db9f3b2SDimitry Andric return false;
7821db9f3b2SDimitry Andric
7831db9f3b2SDimitry Andric Info.setHasAnAddress();
7841db9f3b2SDimitry Andric
7851db9f3b2SDimitry Andric RelocAdjustment =
7861db9f3b2SDimitry Andric Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
787*7a6dacacSDimitry Andric DIE, Entry.CU->getGlobalData().getOptions().Verbose);
7881db9f3b2SDimitry Andric if (!RelocAdjustment)
7891db9f3b2SDimitry Andric return false;
7901db9f3b2SDimitry Andric
7911db9f3b2SDimitry Andric if (DIE.getTag() == dwarf::DW_TAG_subprogram) {
7921db9f3b2SDimitry Andric // Validate subprogram address range.
7931db9f3b2SDimitry Andric
7941db9f3b2SDimitry Andric HighPc = DIE.getHighPC(*LowPc);
7951db9f3b2SDimitry Andric if (!HighPc) {
7961db9f3b2SDimitry Andric Entry.CU->warn("function without high_pc. Range will be discarded.",
7971db9f3b2SDimitry Andric &DIE);
7981db9f3b2SDimitry Andric return false;
7991db9f3b2SDimitry Andric }
8001db9f3b2SDimitry Andric
8011db9f3b2SDimitry Andric if (*LowPc > *HighPc) {
8021db9f3b2SDimitry Andric Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
8031db9f3b2SDimitry Andric &DIE);
8041db9f3b2SDimitry Andric return false;
8051db9f3b2SDimitry Andric }
8061db9f3b2SDimitry Andric } else if (DIE.getTag() == dwarf::DW_TAG_label) {
8071db9f3b2SDimitry Andric if (Entry.CU->hasLabelAt(*LowPc))
8081db9f3b2SDimitry Andric return false;
8091db9f3b2SDimitry Andric
8101db9f3b2SDimitry Andric // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
8111db9f3b2SDimitry Andric // labels that don't fall into the CU's aranges. This is wrong IMO. Debug
8121db9f3b2SDimitry Andric // info generation bugs aside, this is really wrong in the case of labels,
8131db9f3b2SDimitry Andric // where a label marking the end of a function will have a PC == CU's
8141db9f3b2SDimitry Andric // high_pc.
8151db9f3b2SDimitry Andric if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
8161db9f3b2SDimitry Andric .value_or(UINT64_MAX) <= LowPc)
8171db9f3b2SDimitry Andric return false;
8181db9f3b2SDimitry Andric
8191db9f3b2SDimitry Andric Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
8201db9f3b2SDimitry Andric }
8211db9f3b2SDimitry Andric } else
8221db9f3b2SDimitry Andric Info.setHasAnAddress();
8231db9f3b2SDimitry Andric
8241db9f3b2SDimitry Andric if (Entry.CU->getGlobalData().getOptions().Verbose) {
8251db9f3b2SDimitry Andric outs() << "Keeping subprogram DIE:";
8261db9f3b2SDimitry Andric DIDumpOptions DumpOpts;
8271db9f3b2SDimitry Andric DumpOpts.ChildRecurseDepth = 0;
8281db9f3b2SDimitry Andric DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
8291db9f3b2SDimitry Andric DIE.dump(outs(), 8 /* Indent */, DumpOpts);
8301db9f3b2SDimitry Andric }
8311db9f3b2SDimitry Andric
8321db9f3b2SDimitry Andric if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
8331db9f3b2SDimitry Andric return true;
8341db9f3b2SDimitry Andric
8351db9f3b2SDimitry Andric Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
8361db9f3b2SDimitry Andric return true;
8371db9f3b2SDimitry Andric }
838