xref: /freebsd/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.cpp (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1 //=== DependencyTracker.cpp -----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "DependencyTracker.h"
10 #include "llvm/Support/FormatVariadic.h"
11 
12 using namespace llvm;
13 using namespace dwarf_linker;
14 using namespace dwarf_linker::parallel;
15 
16 /// A broken link in the keep chain. By recording both the parent and the child
17 /// we can show only broken links for DIEs with multiple children.
18 struct BrokenLink {
19   BrokenLink(DWARFDie Parent, DWARFDie Child, const char *Message)
20       : Parent(Parent), Child(Child), Message(Message) {}
21   DWARFDie Parent;
22   DWARFDie Child;
23   std::string Message;
24 };
25 
26 /// Verify the keep chain by looking for DIEs that are kept but who's parent
27 /// isn't.
28 void DependencyTracker::verifyKeepChain() {
29 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
30   SmallVector<DWARFDie> Worklist;
31   Worklist.push_back(CU.getOrigUnit().getUnitDIE());
32 
33   // List of broken links.
34   SmallVector<BrokenLink> BrokenLinks;
35 
36   while (!Worklist.empty()) {
37     const DWARFDie Current = Worklist.back();
38     Worklist.pop_back();
39 
40     if (!Current.isValid())
41       continue;
42 
43     CompileUnit::DIEInfo &CurrentInfo =
44         CU.getDIEInfo(Current.getDebugInfoEntry());
45     const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf();
46     const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable();
47 
48     for (DWARFDie Child : reverse(Current.children())) {
49       Worklist.push_back(Child);
50 
51       CompileUnit::DIEInfo &ChildInfo =
52           CU.getDIEInfo(Child.getDebugInfoEntry());
53       const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf();
54       const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable();
55 
56       if (!ParentPlainDieIsKept && ChildPlainDieIsKept)
57         BrokenLinks.emplace_back(Current, Child,
58                                  "Found invalid link in keep chain");
59 
60       if (Child.getTag() == dwarf::DW_TAG_subprogram) {
61         if (!ChildInfo.getKeep() && isLiveSubprogramEntry(UnitEntryPairTy(
62                                         &CU, Child.getDebugInfoEntry()))) {
63           BrokenLinks.emplace_back(Current, Child,
64                                    "Live subprogram is not marked as kept");
65         }
66       }
67 
68       if (!ChildInfo.getODRAvailable()) {
69         assert(!ChildTypeDieIsKept);
70         continue;
71       }
72 
73       if (!ParentTypeDieIsKept && ChildTypeDieIsKept)
74         BrokenLinks.emplace_back(Current, Child,
75                                  "Found invalid link in keep chain");
76 
77       if (CurrentInfo.getIsInAnonNamespaceScope() &&
78           ChildInfo.needToPlaceInTypeTable()) {
79         BrokenLinks.emplace_back(Current, Child,
80                                  "Found invalid placement marking for member "
81                                  "of anonymous namespace");
82       }
83     }
84   }
85 
86   if (!BrokenLinks.empty()) {
87     for (BrokenLink Link : BrokenLinks) {
88       errs() << "\n=================================\n";
89       WithColor::error() << formatv("{0} between {1:x} and {2:x}", Link.Message,
90                                     Link.Parent.getOffset(),
91                                     Link.Child.getOffset());
92 
93       errs() << "\nParent:";
94       Link.Parent.dump(errs(), 0, {});
95       errs() << "\n";
96       CU.getDIEInfo(Link.Parent).dump();
97 
98       errs() << "\nChild:";
99       Link.Child.dump(errs(), 2, {});
100       errs() << "\n";
101       CU.getDIEInfo(Link.Child).dump();
102     }
103     report_fatal_error("invalid keep chain");
104   }
105 #endif
106 }
107 
108 bool DependencyTracker::resolveDependenciesAndMarkLiveness(
109     bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
110   RootEntriesWorkList.clear();
111 
112   // Search for live root DIEs.
113   CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));
114   CUInfo.setPlacement(CompileUnit::PlainDwarf);
115   collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},
116                      std::nullopt, false);
117 
118   // Mark live DIEs as kept.
119   return markCollectedLiveRootsAsKept(InterCUProcessingStarted,
120                                       HasNewInterconnectedCUs);
121 }
122 
123 void DependencyTracker::addActionToRootEntriesWorkList(
124     LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
125     std::optional<UnitEntryPairTy> ReferencedBy) {
126   if (ReferencedBy) {
127     RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy);
128     return;
129   }
130 
131   RootEntriesWorkList.emplace_back(Action, Entry);
132 }
133 
134 void DependencyTracker::collectRootsToKeep(
135     const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,
136     bool IsLiveParent) {
137   for (const DWARFDebugInfoEntry *CurChild =
138            Entry.CU->getFirstChildEntry(Entry.DieEntry);
139        CurChild && CurChild->getAbbreviationDeclarationPtr();
140        CurChild = Entry.CU->getSiblingEntry(CurChild)) {
141     UnitEntryPairTy ChildEntry(Entry.CU, CurChild);
142     CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild);
143 
144     bool IsLiveChild = false;
145 
146     switch (CurChild->getTag()) {
147     case dwarf::DW_TAG_label: {
148       IsLiveChild = isLiveSubprogramEntry(ChildEntry);
149 
150       // Keep label referencing live address.
151       // Keep label which is child of live parent entry.
152       if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
153         addActionToRootEntriesWorkList(
154             LiveRootWorklistActionTy::MarkLiveEntryRec, ChildEntry,
155             ReferencedBy);
156       }
157     } break;
158     case dwarf::DW_TAG_subprogram: {
159       IsLiveChild = isLiveSubprogramEntry(ChildEntry);
160 
161       // Keep subprogram referencing live address.
162       if (IsLiveChild) {
163         // If subprogram is in module scope and this module allows ODR
164         // deduplication set "TypeTable" placement, otherwise set "" placement
165         LiveRootWorklistActionTy Action =
166             (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
167                 ? LiveRootWorklistActionTy::MarkTypeEntryRec
168                 : LiveRootWorklistActionTy::MarkLiveEntryRec;
169 
170         addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
171       }
172     } break;
173     case dwarf::DW_TAG_constant:
174     case dwarf::DW_TAG_variable: {
175       IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);
176 
177       // Keep variable referencing live address.
178       if (IsLiveChild) {
179         // If variable is in module scope and this module allows ODR
180         // deduplication set "TypeTable" placement, otherwise set "" placement
181 
182         LiveRootWorklistActionTy Action =
183             (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
184                 ? LiveRootWorklistActionTy::MarkTypeEntryRec
185                 : LiveRootWorklistActionTy::MarkLiveEntryRec;
186 
187         addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
188       }
189     } break;
190     case dwarf::DW_TAG_base_type: {
191       // Always keep base types.
192       addActionToRootEntriesWorkList(
193           LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
194           ReferencedBy);
195     } break;
196     case dwarf::DW_TAG_imported_module:
197     case dwarf::DW_TAG_imported_declaration:
198     case dwarf::DW_TAG_imported_unit: {
199       // Always keep DIEs having DW_AT_import attribute.
200       if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
201         addActionToRootEntriesWorkList(
202             LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
203             ReferencedBy);
204         break;
205       }
206 
207       addActionToRootEntriesWorkList(
208           LiveRootWorklistActionTy::MarkSingleTypeEntry, ChildEntry,
209           ReferencedBy);
210     } break;
211     case dwarf::DW_TAG_type_unit:
212     case dwarf::DW_TAG_partial_unit:
213     case dwarf::DW_TAG_compile_unit: {
214       llvm_unreachable("Called for incorrect DIE");
215     } break;
216     default:
217       // Nothing to do.
218       break;
219     }
220 
221     collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
222   }
223 }
224 
225 bool DependencyTracker::markCollectedLiveRootsAsKept(
226     bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
227   bool Res = true;
228 
229   // Mark roots as kept.
230   while (!RootEntriesWorkList.empty()) {
231     LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();
232 
233     if (markDIEEntryAsKeptRec(Root.getAction(), Root.getRootEntry(),
234                               Root.getRootEntry(), InterCUProcessingStarted,
235                               HasNewInterconnectedCUs)) {
236       if (Root.hasReferencedByOtherEntry())
237         Dependencies.push_back(Root);
238     } else
239       Res = false;
240   }
241 
242   return Res;
243 }
244 
245 bool DependencyTracker::updateDependenciesCompleteness() {
246   bool HasNewDependency = false;
247   for (LiveRootWorklistItemTy &Root : Dependencies) {
248     assert(Root.hasReferencedByOtherEntry() &&
249            "Root entry without dependency inside the dependencies list");
250 
251     UnitEntryPairTy RootEntry = Root.getRootEntry();
252     CompileUnit::DIEInfo &RootInfo =
253         RootEntry.CU->getDIEInfo(RootEntry.DieEntry);
254 
255     UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
256     CompileUnit::DIEInfo &ReferencedByInfo =
257         ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
258 
259     if (!RootInfo.needToPlaceInTypeTable() &&
260         ReferencedByInfo.needToPlaceInTypeTable()) {
261       HasNewDependency = true;
262       setPlainDwarfPlacementRec(ReferencedByEntry);
263 
264       // FIXME: we probably need to update getKeepTypeChildren status for
265       // parents of *Root.ReferencedBy.
266     }
267   }
268 
269   return HasNewDependency;
270 }
271 
272 void DependencyTracker::setPlainDwarfPlacementRec(
273     const UnitEntryPairTy &Entry) {
274   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
275   if (Info.getPlacement() == CompileUnit::PlainDwarf &&
276       !Info.getKeepTypeChildren())
277     return;
278 
279   Info.setPlacement(CompileUnit::PlainDwarf);
280   Info.unsetKeepTypeChildren();
281   markParentsAsKeepingChildren(Entry);
282 
283   for (const DWARFDebugInfoEntry *CurChild =
284            Entry.CU->getFirstChildEntry(Entry.DieEntry);
285        CurChild && CurChild->getAbbreviationDeclarationPtr();
286        CurChild = Entry.CU->getSiblingEntry(CurChild))
287     setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});
288 }
289 
290 static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {
291   switch (Entry->getTag()) {
292   case dwarf::DW_TAG_compile_unit:
293   case dwarf::DW_TAG_module:
294   case dwarf::DW_TAG_namespace:
295     return true;
296 
297   default:
298     return false;
299   }
300 }
301 
302 bool isAlreadyMarked(const CompileUnit::DIEInfo &Info,
303                      CompileUnit::DieOutputPlacement NewPlacement) {
304   if (!Info.getKeep())
305     return false;
306 
307   switch (NewPlacement) {
308   case CompileUnit::TypeTable:
309     return Info.needToPlaceInTypeTable();
310 
311   case CompileUnit::PlainDwarf:
312     return Info.needToKeepInPlainDwarf();
313 
314   case CompileUnit::Both:
315     return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
316 
317   case CompileUnit::NotSet:
318     llvm_unreachable("Unset placement type is specified.");
319   };
320 
321   llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");
322 }
323 
324 bool isAlreadyMarked(const UnitEntryPairTy &Entry,
325                      CompileUnit::DieOutputPlacement NewPlacement) {
326   return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
327 }
328 
329 void DependencyTracker::markParentsAsKeepingChildren(
330     const UnitEntryPairTy &Entry) {
331   if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
332     return;
333 
334   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
335   bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
336   bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
337 
338   bool AreTypeParentsDone = !NeedKeepTypeChildren;
339   bool ArePlainParentsDone = !NeedKeepPlainChildren;
340 
341   // Mark parents as 'Keep*Children'.
342   std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
343   while (ParentIdx) {
344     const DWARFDebugInfoEntry *ParentEntry =
345         Entry.CU->getDebugInfoEntry(*ParentIdx);
346     CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);
347 
348     if (!AreTypeParentsDone && NeedKeepTypeChildren) {
349       if (ParentInfo.getKeepTypeChildren())
350         AreTypeParentsDone = true;
351       else {
352         bool AddToWorklist = !isAlreadyMarked(
353             ParentInfo, CompileUnit::DieOutputPlacement::TypeTable);
354         ParentInfo.setKeepTypeChildren();
355         if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
356           addActionToRootEntriesWorkList(
357               LiveRootWorklistActionTy::MarkTypeChildrenRec,
358               UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
359         }
360       }
361     }
362 
363     if (!ArePlainParentsDone && NeedKeepPlainChildren) {
364       if (ParentInfo.getKeepPlainChildren())
365         ArePlainParentsDone = true;
366       else {
367         bool AddToWorklist = !isAlreadyMarked(
368             ParentInfo, CompileUnit::DieOutputPlacement::PlainDwarf);
369         ParentInfo.setKeepPlainChildren();
370         if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
371           addActionToRootEntriesWorkList(
372               LiveRootWorklistActionTy::MarkLiveChildrenRec,
373               UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
374         }
375       }
376     }
377 
378     if (AreTypeParentsDone && ArePlainParentsDone)
379       break;
380 
381     ParentIdx = ParentEntry->getParentIdx();
382   }
383 }
384 
385 // This function tries to set specified \p Placement for the \p Entry.
386 // Depending on the concrete entry, the placement could be:
387 //  a) changed to another.
388 //  b) joined with current entry placement.
389 //  c) set as requested.
390 static CompileUnit::DieOutputPlacement
391 getFinalPlacementForEntry(const UnitEntryPairTy &Entry,
392                           CompileUnit::DieOutputPlacement Placement) {
393   assert((Placement != CompileUnit::NotSet) && "Placement is not set");
394   CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
395 
396   if (!EntryInfo.getODRAvailable())
397     return CompileUnit::PlainDwarf;
398 
399   if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
400     // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
401     // time.
402     if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||
403         EntryInfo.getPlacement() == CompileUnit::Both)
404       return CompileUnit::PlainDwarf;
405 
406     if (Placement == CompileUnit::PlainDwarf || Placement == CompileUnit::Both)
407       return CompileUnit::PlainDwarf;
408   }
409 
410   switch (EntryInfo.getPlacement()) {
411   case CompileUnit::NotSet:
412     return Placement;
413 
414   case CompileUnit::TypeTable:
415     return Placement == CompileUnit::PlainDwarf ? CompileUnit::Both : Placement;
416 
417   case CompileUnit::PlainDwarf:
418     return Placement == CompileUnit::TypeTable ? CompileUnit::Both : Placement;
419 
420   case CompileUnit::Both:
421     return CompileUnit::Both;
422   };
423 
424   llvm_unreachable("Unknown placement type.");
425   return Placement;
426 }
427 
428 bool DependencyTracker::markDIEEntryAsKeptRec(
429     LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
430     const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
431     std::atomic<bool> &HasNewInterconnectedCUs) {
432   if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
433     return true;
434 
435   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
436 
437   // Calculate final placement placement.
438   CompileUnit::DieOutputPlacement Placement = getFinalPlacementForEntry(
439       Entry,
440       isLiveAction(Action) ? CompileUnit::PlainDwarf : CompileUnit::TypeTable);
441   assert((Info.getODRAvailable() || isLiveAction(Action) ||
442           Placement == CompileUnit::PlainDwarf) &&
443          "Wrong kind of placement for ODR unavailable entry");
444 
445   if (!isChildrenAction(Action))
446     if (isAlreadyMarked(Entry, Placement))
447       return true;
448 
449   // Mark current DIE as kept.
450   Info.setKeep();
451   Info.setPlacement(Placement);
452 
453   // Set keep children property for parents.
454   markParentsAsKeepingChildren(Entry);
455 
456   UnitEntryPairTy FinalRootEntry =
457       Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
458 
459   // Analyse referenced DIEs.
460   bool Res = true;
461   if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
462                                InterCUProcessingStarted,
463                                HasNewInterconnectedCUs))
464     Res = false;
465 
466   // Return if we do not need to process children.
467   if (isSingleAction(Action))
468     return Res;
469 
470   // Process children.
471   // Check for subprograms special case.
472   if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
473       Info.getODRAvailable()) {
474     // Subprograms is a special case. As it can be root for type DIEs
475     // and itself may be subject to move into the artificial type unit.
476     //  a) Non removable children(like DW_TAG_formal_parameter) should always
477     //     be cloned. They are placed into the "PlainDwarf" and into the
478     //     "TypeTable".
479     //  b) ODR deduplication candidates(type DIEs) children should not be put
480     //  into the "PlainDwarf".
481     //  c) Children keeping addresses and locations(like DW_TAG_call_site)
482     //  should not be put into the "TypeTable".
483     for (const DWARFDebugInfoEntry *CurChild =
484              Entry.CU->getFirstChildEntry(Entry.DieEntry);
485          CurChild && CurChild->getAbbreviationDeclarationPtr();
486          CurChild = Entry.CU->getSiblingEntry(CurChild)) {
487       CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
488 
489       switch (CurChild->getTag()) {
490       case dwarf::DW_TAG_variable:
491       case dwarf::DW_TAG_constant:
492       case dwarf::DW_TAG_subprogram:
493       case dwarf::DW_TAG_label: {
494         if (ChildInfo.getHasAnAddress())
495           continue;
496       } break;
497 
498       // Entries having following tags could not be removed from the subprogram.
499       case dwarf::DW_TAG_lexical_block:
500       case dwarf::DW_TAG_friend:
501       case dwarf::DW_TAG_inheritance:
502       case dwarf::DW_TAG_formal_parameter:
503       case dwarf::DW_TAG_unspecified_parameters:
504       case dwarf::DW_TAG_template_type_parameter:
505       case dwarf::DW_TAG_template_value_parameter:
506       case dwarf::DW_TAG_GNU_template_parameter_pack:
507       case dwarf::DW_TAG_GNU_formal_parameter_pack:
508       case dwarf::DW_TAG_GNU_template_template_param:
509       case dwarf::DW_TAG_thrown_type: {
510         // Go to the default child handling.
511       } break;
512 
513       default: {
514         bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
515 
516         // Skip child marked to be copied into the artificial type unit.
517         if (isLiveAction(Action) && ChildIsTypeTableCandidate)
518           continue;
519 
520         // Skip child marked to be copied into the plain unit.
521         if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
522           continue;
523 
524         // Go to the default child handling.
525       } break;
526       }
527 
528       if (!markDIEEntryAsKeptRec(
529               Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
530               InterCUProcessingStarted, HasNewInterconnectedCUs))
531         Res = false;
532     }
533 
534     return Res;
535   }
536 
537   // Recursively process children.
538   for (const DWARFDebugInfoEntry *CurChild =
539            Entry.CU->getFirstChildEntry(Entry.DieEntry);
540        CurChild && CurChild->getAbbreviationDeclarationPtr();
541        CurChild = Entry.CU->getSiblingEntry(CurChild)) {
542     CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
543     switch (CurChild->getTag()) {
544     case dwarf::DW_TAG_variable:
545     case dwarf::DW_TAG_constant:
546     case dwarf::DW_TAG_subprogram:
547     case dwarf::DW_TAG_label: {
548       if (ChildInfo.getHasAnAddress())
549         continue;
550     } break;
551     default:
552       break; // Nothing to do.
553     };
554 
555     if (!markDIEEntryAsKeptRec(
556             Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
557             InterCUProcessingStarted, HasNewInterconnectedCUs))
558       Res = false;
559   }
560 
561   return Res;
562 }
563 
564 bool DependencyTracker::isTypeTableCandidate(
565     const DWARFDebugInfoEntry *DIEEntry) {
566   switch (DIEEntry->getTag()) {
567   default:
568     return false;
569 
570   case dwarf::DW_TAG_imported_module:
571   case dwarf::DW_TAG_imported_declaration:
572   case dwarf::DW_TAG_imported_unit:
573   case dwarf::DW_TAG_array_type:
574   case dwarf::DW_TAG_class_type:
575   case dwarf::DW_TAG_enumeration_type:
576   case dwarf::DW_TAG_pointer_type:
577   case dwarf::DW_TAG_reference_type:
578   case dwarf::DW_TAG_string_type:
579   case dwarf::DW_TAG_structure_type:
580   case dwarf::DW_TAG_subroutine_type:
581   case dwarf::DW_TAG_typedef:
582   case dwarf::DW_TAG_union_type:
583   case dwarf::DW_TAG_variant:
584   case dwarf::DW_TAG_module:
585   case dwarf::DW_TAG_ptr_to_member_type:
586   case dwarf::DW_TAG_set_type:
587   case dwarf::DW_TAG_subrange_type:
588   case dwarf::DW_TAG_base_type:
589   case dwarf::DW_TAG_const_type:
590   case dwarf::DW_TAG_enumerator:
591   case dwarf::DW_TAG_file_type:
592   case dwarf::DW_TAG_packed_type:
593   case dwarf::DW_TAG_thrown_type:
594   case dwarf::DW_TAG_volatile_type:
595   case dwarf::DW_TAG_dwarf_procedure:
596   case dwarf::DW_TAG_restrict_type:
597   case dwarf::DW_TAG_interface_type:
598   case dwarf::DW_TAG_namespace:
599   case dwarf::DW_TAG_unspecified_type:
600   case dwarf::DW_TAG_shared_type:
601   case dwarf::DW_TAG_rvalue_reference_type:
602   case dwarf::DW_TAG_coarray_type:
603   case dwarf::DW_TAG_dynamic_type:
604   case dwarf::DW_TAG_atomic_type:
605   case dwarf::DW_TAG_immutable_type:
606   case dwarf::DW_TAG_function_template:
607   case dwarf::DW_TAG_class_template:
608     return true;
609   }
610 }
611 
612 bool DependencyTracker::maybeAddReferencedRoots(
613     LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
614     const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
615     std::atomic<bool> &HasNewInterconnectedCUs) {
616   const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
617   if (Abbrev == nullptr)
618     return true;
619 
620   DWARFUnit &Unit = Entry.CU->getOrigUnit();
621   DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
622   uint64_t Offset =
623       Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
624 
625   // For each DIE attribute...
626   for (const auto &AttrSpec : Abbrev->attributes()) {
627     DWARFFormValue Val(AttrSpec.Form);
628     if (!Val.isFormClass(DWARFFormValue::FC_Reference) ||
629         AttrSpec.Attr == dwarf::DW_AT_sibling) {
630       DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
631                                 Unit.getFormParams());
632       continue;
633     }
634     Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
635 
636     // Resolve reference.
637     std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
638         Val, InterCUProcessingStarted
639                  ? ResolveInterCUReferencesMode::Resolve
640                  : ResolveInterCUReferencesMode::AvoidResolving);
641     if (!RefDie) {
642       Entry.CU->warn("cann't find referenced DIE", Entry.DieEntry);
643       continue;
644     }
645 
646     if (!RefDie->DieEntry) {
647       // Delay resolving reference.
648       RefDie->CU->setInterconnectedCU();
649       Entry.CU->setInterconnectedCU();
650       HasNewInterconnectedCUs = true;
651       return false;
652     }
653 
654     assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
655             InterCUProcessingStarted) &&
656            "Inter-CU reference while inter-CU processing is not started");
657 
658     CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
659     if (!RefInfo.getODRAvailable())
660       Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
661     else if (RefInfo.getODRAvailable() &&
662              llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
663       // Note: getODRAttributes does not include DW_AT_containing_type.
664       // It should be OK as we do getRootForSpecifiedEntry(). So any containing
665       // type would be found as the root for the entry.
666       Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
667     else if (isLiveAction(Action))
668       Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
669     else
670       Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
671 
672     if (AttrSpec.Attr == dwarf::DW_AT_import) {
673       if (isNamespaceLikeEntry(RefDie->DieEntry)) {
674         addActionToRootEntriesWorkList(
675             isTypeAction(Action)
676                 ? LiveRootWorklistActionTy::MarkSingleTypeEntry
677                 : LiveRootWorklistActionTy::MarkSingleLiveEntry,
678             *RefDie, RootEntry);
679         continue;
680       }
681 
682       addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);
683       continue;
684     }
685 
686     UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
687     addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);
688   }
689 
690   return true;
691 }
692 
693 UnitEntryPairTy
694 DependencyTracker::getRootForSpecifiedEntry(UnitEntryPairTy Entry) {
695   UnitEntryPairTy Result = Entry;
696 
697   do {
698     switch (Entry.DieEntry->getTag()) {
699     case dwarf::DW_TAG_subprogram:
700     case dwarf::DW_TAG_label:
701     case dwarf::DW_TAG_variable:
702     case dwarf::DW_TAG_constant: {
703       return Result;
704     } break;
705 
706     default: {
707       // Nothing to do.
708     }
709     }
710 
711     std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
712     if (!ParentIdx)
713       return Result;
714 
715     const DWARFDebugInfoEntry *ParentEntry =
716         Result.CU->getDebugInfoEntry(*ParentIdx);
717     if (isNamespaceLikeEntry(ParentEntry))
718       break;
719     Result.DieEntry = ParentEntry;
720   } while (true);
721 
722   return Result;
723 }
724 
725 bool DependencyTracker::isLiveVariableEntry(const UnitEntryPairTy &Entry,
726                                             bool IsLiveParent) {
727   DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
728   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
729 
730   if (Info.getTrackLiveness()) {
731     const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
732 
733     if (!Info.getIsInFunctionScope() &&
734         Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
735       // Global variables with constant value can always be kept.
736     } else {
737       // See if there is a relocation to a valid debug map entry inside this
738       // variable's location. The order is important here. We want to always
739       // check if the variable has a location expression address. However, we
740       // don't want a static variable in a function to force us to keep the
741       // enclosing function, unless requested explicitly.
742       std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
743           Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
744               DIE, Entry.CU->getGlobalData().getOptions().Verbose);
745 
746       if (LocExprAddrAndRelocAdjustment.first)
747         Info.setHasAnAddress();
748 
749       if (!LocExprAddrAndRelocAdjustment.second)
750         return false;
751 
752       if (!IsLiveParent && Info.getIsInFunctionScope() &&
753           !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
754         return false;
755     }
756   }
757   Info.setHasAnAddress();
758 
759   if (Entry.CU->getGlobalData().getOptions().Verbose) {
760     outs() << "Keeping variable DIE:";
761     DIDumpOptions DumpOpts;
762     DumpOpts.ChildRecurseDepth = 0;
763     DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
764     DIE.dump(outs(), 8 /* Indent */, DumpOpts);
765   }
766 
767   return true;
768 }
769 
770 bool DependencyTracker::isLiveSubprogramEntry(const UnitEntryPairTy &Entry) {
771   DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
772   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
773   std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);
774 
775   std::optional<uint64_t> LowPc;
776   std::optional<uint64_t> HighPc;
777   std::optional<int64_t> RelocAdjustment;
778   if (Info.getTrackLiveness()) {
779     LowPc = dwarf::toAddress(LowPCVal);
780     if (!LowPc)
781       return false;
782 
783     Info.setHasAnAddress();
784 
785     RelocAdjustment =
786         Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
787             DIE, Entry.CU->getGlobalData().getOptions().Verbose);
788     if (!RelocAdjustment)
789       return false;
790 
791     if (DIE.getTag() == dwarf::DW_TAG_subprogram) {
792       // Validate subprogram address range.
793 
794       HighPc = DIE.getHighPC(*LowPc);
795       if (!HighPc) {
796         Entry.CU->warn("function without high_pc. Range will be discarded.",
797                        &DIE);
798         return false;
799       }
800 
801       if (*LowPc > *HighPc) {
802         Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
803                        &DIE);
804         return false;
805       }
806     } else if (DIE.getTag() == dwarf::DW_TAG_label) {
807       if (Entry.CU->hasLabelAt(*LowPc))
808         return false;
809 
810       // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
811       // labels that don't fall into the CU's aranges. This is wrong IMO. Debug
812       // info generation bugs aside, this is really wrong in the case of labels,
813       // where a label marking the end of a function will have a PC == CU's
814       // high_pc.
815       if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
816               .value_or(UINT64_MAX) <= LowPc)
817         return false;
818 
819       Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
820     }
821   } else
822     Info.setHasAnAddress();
823 
824   if (Entry.CU->getGlobalData().getOptions().Verbose) {
825     outs() << "Keeping subprogram DIE:";
826     DIDumpOptions DumpOpts;
827     DumpOpts.ChildRecurseDepth = 0;
828     DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
829     DIE.dump(outs(), 8 /* Indent */, DumpOpts);
830   }
831 
832   if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
833     return true;
834 
835   Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
836   return true;
837 }
838