1 //=== DependencyTracker.cpp -----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "DependencyTracker.h"
10 #include "llvm/Support/FormatVariadic.h"
13 using namespace dwarf_linker
;
14 using namespace dwarf_linker::parallel
;
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.
19 BrokenLink(DWARFDie Parent
, DWARFDie Child
, const char *Message
)
20 : Parent(Parent
), Child(Child
), Message(Message
) {}
26 /// Verify the keep chain by looking for DIEs that are kept but who's parent
28 void DependencyTracker::verifyKeepChain() {
29 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
30 SmallVector
<DWARFDie
> Worklist
;
31 Worklist
.push_back(CU
.getOrigUnit().getUnitDIE());
33 // List of broken links.
34 SmallVector
<BrokenLink
> BrokenLinks
;
36 while (!Worklist
.empty()) {
37 const DWARFDie Current
= Worklist
.back();
40 if (!Current
.isValid())
43 CompileUnit::DIEInfo
&CurrentInfo
=
44 CU
.getDIEInfo(Current
.getDebugInfoEntry());
45 const bool ParentPlainDieIsKept
= CurrentInfo
.needToKeepInPlainDwarf();
46 const bool ParentTypeDieIsKept
= CurrentInfo
.needToPlaceInTypeTable();
48 for (DWARFDie Child
: reverse(Current
.children())) {
49 Worklist
.push_back(Child
);
51 CompileUnit::DIEInfo
&ChildInfo
=
52 CU
.getDIEInfo(Child
.getDebugInfoEntry());
53 const bool ChildPlainDieIsKept
= ChildInfo
.needToKeepInPlainDwarf();
54 const bool ChildTypeDieIsKept
= ChildInfo
.needToPlaceInTypeTable();
56 if (!ParentPlainDieIsKept
&& ChildPlainDieIsKept
)
57 BrokenLinks
.emplace_back(Current
, Child
,
58 "Found invalid link in keep chain");
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");
68 if (!ChildInfo
.getODRAvailable()) {
69 assert(!ChildTypeDieIsKept
);
73 if (!ParentTypeDieIsKept
&& ChildTypeDieIsKept
)
74 BrokenLinks
.emplace_back(Current
, Child
,
75 "Found invalid link in keep chain");
77 if (CurrentInfo
.getIsInAnonNamespaceScope() &&
78 ChildInfo
.needToPlaceInTypeTable()) {
79 BrokenLinks
.emplace_back(Current
, Child
,
80 "Found invalid placement marking for member "
81 "of anonymous namespace");
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());
93 errs() << "\nParent:";
94 Link
.Parent
.dump(errs(), 0, {});
96 CU
.getDIEInfo(Link
.Parent
).dump();
99 Link
.Child
.dump(errs(), 2, {});
101 CU
.getDIEInfo(Link
.Child
).dump();
103 report_fatal_error("invalid keep chain");
108 bool DependencyTracker::resolveDependenciesAndMarkLiveness(
109 bool InterCUProcessingStarted
, std::atomic
<bool> &HasNewInterconnectedCUs
) {
110 RootEntriesWorkList
.clear();
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);
118 // Mark live DIEs as kept.
119 return markCollectedLiveRootsAsKept(InterCUProcessingStarted
,
120 HasNewInterconnectedCUs
);
123 void DependencyTracker::addActionToRootEntriesWorkList(
124 LiveRootWorklistActionTy Action
, const UnitEntryPairTy
&Entry
,
125 std::optional
<UnitEntryPairTy
> ReferencedBy
) {
127 RootEntriesWorkList
.emplace_back(Action
, Entry
, *ReferencedBy
);
131 RootEntriesWorkList
.emplace_back(Action
, Entry
);
134 void DependencyTracker::collectRootsToKeep(
135 const UnitEntryPairTy
&Entry
, std::optional
<UnitEntryPairTy
> ReferencedBy
,
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
);
144 bool IsLiveChild
= false;
146 switch (CurChild
->getTag()) {
147 case dwarf::DW_TAG_label
: {
148 IsLiveChild
= isLiveSubprogramEntry(ChildEntry
);
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
,
158 case dwarf::DW_TAG_subprogram
: {
159 IsLiveChild
= isLiveSubprogramEntry(ChildEntry
);
161 // Keep subprogram referencing live address.
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
;
170 addActionToRootEntriesWorkList(Action
, ChildEntry
, ReferencedBy
);
173 case dwarf::DW_TAG_constant
:
174 case dwarf::DW_TAG_variable
: {
175 IsLiveChild
= isLiveVariableEntry(ChildEntry
, IsLiveParent
);
177 // Keep variable referencing live address.
179 // If variable is in module scope and this module allows ODR
180 // deduplication set "TypeTable" placement, otherwise set "" placement
182 LiveRootWorklistActionTy Action
=
183 (ChildInfo
.getIsInMouduleScope() && ChildInfo
.getODRAvailable())
184 ? LiveRootWorklistActionTy::MarkTypeEntryRec
185 : LiveRootWorklistActionTy::MarkLiveEntryRec
;
187 addActionToRootEntriesWorkList(Action
, ChildEntry
, ReferencedBy
);
190 case dwarf::DW_TAG_base_type
: {
191 // Always keep base types.
192 addActionToRootEntriesWorkList(
193 LiveRootWorklistActionTy::MarkSingleLiveEntry
, ChildEntry
,
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
,
207 addActionToRootEntriesWorkList(
208 LiveRootWorklistActionTy::MarkSingleTypeEntry
, ChildEntry
,
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");
221 collectRootsToKeep(ChildEntry
, ReferencedBy
, IsLiveChild
|| IsLiveParent
);
225 bool DependencyTracker::markCollectedLiveRootsAsKept(
226 bool InterCUProcessingStarted
, std::atomic
<bool> &HasNewInterconnectedCUs
) {
229 // Mark roots as kept.
230 while (!RootEntriesWorkList
.empty()) {
231 LiveRootWorklistItemTy Root
= RootEntriesWorkList
.pop_back_val();
233 if (markDIEEntryAsKeptRec(Root
.getAction(), Root
.getRootEntry(),
234 Root
.getRootEntry(), InterCUProcessingStarted
,
235 HasNewInterconnectedCUs
)) {
236 if (Root
.hasReferencedByOtherEntry())
237 Dependencies
.push_back(Root
);
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");
251 UnitEntryPairTy RootEntry
= Root
.getRootEntry();
252 CompileUnit::DIEInfo
&RootInfo
=
253 RootEntry
.CU
->getDIEInfo(RootEntry
.DieEntry
);
255 UnitEntryPairTy ReferencedByEntry
= Root
.getReferencedByEntry();
256 CompileUnit::DIEInfo
&ReferencedByInfo
=
257 ReferencedByEntry
.CU
->getDIEInfo(ReferencedByEntry
.DieEntry
);
259 if (!RootInfo
.needToPlaceInTypeTable() &&
260 ReferencedByInfo
.needToPlaceInTypeTable()) {
261 HasNewDependency
= true;
262 setPlainDwarfPlacementRec(ReferencedByEntry
);
264 // FIXME: we probably need to update getKeepTypeChildren status for
265 // parents of *Root.ReferencedBy.
269 return HasNewDependency
;
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())
279 Info
.setPlacement(CompileUnit::PlainDwarf
);
280 Info
.unsetKeepTypeChildren();
281 markParentsAsKeepingChildren(Entry
);
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
});
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
:
302 bool isAlreadyMarked(const CompileUnit::DIEInfo
&Info
,
303 CompileUnit::DieOutputPlacement NewPlacement
) {
307 switch (NewPlacement
) {
308 case CompileUnit::TypeTable
:
309 return Info
.needToPlaceInTypeTable();
311 case CompileUnit::PlainDwarf
:
312 return Info
.needToKeepInPlainDwarf();
314 case CompileUnit::Both
:
315 return Info
.needToPlaceInTypeTable() && Info
.needToKeepInPlainDwarf();
317 case CompileUnit::NotSet
:
318 llvm_unreachable("Unset placement type is specified.");
321 llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");
324 bool isAlreadyMarked(const UnitEntryPairTy
&Entry
,
325 CompileUnit::DieOutputPlacement NewPlacement
) {
326 return isAlreadyMarked(Entry
.CU
->getDIEInfo(Entry
.DieEntry
), NewPlacement
);
329 void DependencyTracker::markParentsAsKeepingChildren(
330 const UnitEntryPairTy
&Entry
) {
331 if (Entry
.DieEntry
->getAbbreviationDeclarationPtr() == nullptr)
334 CompileUnit::DIEInfo
&Info
= Entry
.CU
->getDIEInfo(Entry
.DieEntry
);
335 bool NeedKeepTypeChildren
= Info
.needToPlaceInTypeTable();
336 bool NeedKeepPlainChildren
= Info
.needToKeepInPlainDwarf();
338 bool AreTypeParentsDone
= !NeedKeepTypeChildren
;
339 bool ArePlainParentsDone
= !NeedKeepPlainChildren
;
341 // Mark parents as 'Keep*Children'.
342 std::optional
<uint32_t> ParentIdx
= Entry
.DieEntry
->getParentIdx();
344 const DWARFDebugInfoEntry
*ParentEntry
=
345 Entry
.CU
->getDebugInfoEntry(*ParentIdx
);
346 CompileUnit::DIEInfo
&ParentInfo
= Entry
.CU
->getDIEInfo(*ParentIdx
);
348 if (!AreTypeParentsDone
&& NeedKeepTypeChildren
) {
349 if (ParentInfo
.getKeepTypeChildren())
350 AreTypeParentsDone
= true;
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
);
363 if (!ArePlainParentsDone
&& NeedKeepPlainChildren
) {
364 if (ParentInfo
.getKeepPlainChildren())
365 ArePlainParentsDone
= true;
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
);
378 if (AreTypeParentsDone
&& ArePlainParentsDone
)
381 ParentIdx
= ParentEntry
->getParentIdx();
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
);
396 if (!EntryInfo
.getODRAvailable())
397 return CompileUnit::PlainDwarf
;
399 if (Entry
.DieEntry
->getTag() == dwarf::DW_TAG_variable
) {
400 // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
402 if (EntryInfo
.getPlacement() == CompileUnit::PlainDwarf
||
403 EntryInfo
.getPlacement() == CompileUnit::Both
)
404 return CompileUnit::PlainDwarf
;
406 if (Placement
== CompileUnit::PlainDwarf
|| Placement
== CompileUnit::Both
)
407 return CompileUnit::PlainDwarf
;
410 switch (EntryInfo
.getPlacement()) {
411 case CompileUnit::NotSet
:
414 case CompileUnit::TypeTable
:
415 return Placement
== CompileUnit::PlainDwarf
? CompileUnit::Both
: Placement
;
417 case CompileUnit::PlainDwarf
:
418 return Placement
== CompileUnit::TypeTable
? CompileUnit::Both
: Placement
;
420 case CompileUnit::Both
:
421 return CompileUnit::Both
;
424 llvm_unreachable("Unknown placement type.");
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)
435 CompileUnit::DIEInfo
&Info
= Entry
.CU
->getDIEInfo(Entry
.DieEntry
);
437 // Calculate final placement placement.
438 CompileUnit::DieOutputPlacement Placement
= getFinalPlacementForEntry(
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");
445 if (!isChildrenAction(Action
))
446 if (isAlreadyMarked(Entry
, Placement
))
449 // Mark current DIE as kept.
451 Info
.setPlacement(Placement
);
453 // Set keep children property for parents.
454 markParentsAsKeepingChildren(Entry
);
456 UnitEntryPairTy FinalRootEntry
=
457 Entry
.DieEntry
->getTag() == dwarf::DW_TAG_subprogram
? Entry
: RootEntry
;
459 // Analyse referenced DIEs.
461 if (!maybeAddReferencedRoots(Action
, FinalRootEntry
, Entry
,
462 InterCUProcessingStarted
,
463 HasNewInterconnectedCUs
))
466 // Return if we do not need to process children.
467 if (isSingleAction(Action
))
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
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
);
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())
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.
514 bool ChildIsTypeTableCandidate
= isTypeTableCandidate(CurChild
);
516 // Skip child marked to be copied into the artificial type unit.
517 if (isLiveAction(Action
) && ChildIsTypeTableCandidate
)
520 // Skip child marked to be copied into the plain unit.
521 if (isTypeAction(Action
) && !ChildIsTypeTableCandidate
)
524 // Go to the default child handling.
528 if (!markDIEEntryAsKeptRec(
529 Action
, FinalRootEntry
, UnitEntryPairTy
{Entry
.CU
, CurChild
},
530 InterCUProcessingStarted
, HasNewInterconnectedCUs
))
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())
552 break; // Nothing to do.
555 if (!markDIEEntryAsKeptRec(
556 Action
, FinalRootEntry
, UnitEntryPairTy
{Entry
.CU
, CurChild
},
557 InterCUProcessingStarted
, HasNewInterconnectedCUs
))
564 bool DependencyTracker::isTypeTableCandidate(
565 const DWARFDebugInfoEntry
*DIEEntry
) {
566 switch (DIEEntry
->getTag()) {
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
:
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)
620 DWARFUnit
&Unit
= Entry
.CU
->getOrigUnit();
621 DWARFDataExtractor Data
= Unit
.getDebugInfoExtractor();
623 Entry
.DieEntry
->getOffset() + getULEB128Size(Abbrev
->getCode());
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());
634 Val
.extractValue(Data
, &Offset
, Unit
.getFormParams(), &Unit
);
636 // Resolve reference.
637 std::optional
<UnitEntryPairTy
> RefDie
= Entry
.CU
->resolveDIEReference(
638 Val
, InterCUProcessingStarted
639 ? ResolveInterCUReferencesMode::Resolve
640 : ResolveInterCUReferencesMode::AvoidResolving
);
642 Entry
.CU
->warn("cann't find referenced DIE", Entry
.DieEntry
);
646 if (!RefDie
->DieEntry
) {
647 // Delay resolving reference.
648 RefDie
->CU
->setInterconnectedCU();
649 Entry
.CU
->setInterconnectedCU();
650 HasNewInterconnectedCUs
= true;
654 assert((Entry
.CU
->getUniqueID() == RefDie
->CU
->getUniqueID() ||
655 InterCUProcessingStarted
) &&
656 "Inter-CU reference while inter-CU processing is not started");
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
;
670 Action
= LiveRootWorklistActionTy::MarkTypeEntryRec
;
672 if (AttrSpec
.Attr
== dwarf::DW_AT_import
) {
673 if (isNamespaceLikeEntry(RefDie
->DieEntry
)) {
674 addActionToRootEntriesWorkList(
676 ? LiveRootWorklistActionTy::MarkSingleTypeEntry
677 : LiveRootWorklistActionTy::MarkSingleLiveEntry
,
682 addActionToRootEntriesWorkList(Action
, *RefDie
, RootEntry
);
686 UnitEntryPairTy RootForReferencedDie
= getRootForSpecifiedEntry(*RefDie
);
687 addActionToRootEntriesWorkList(Action
, RootForReferencedDie
, RootEntry
);
694 DependencyTracker::getRootForSpecifiedEntry(UnitEntryPairTy Entry
) {
695 UnitEntryPairTy Result
= Entry
;
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
: {
711 std::optional
<uint32_t> ParentIdx
= Result
.DieEntry
->getParentIdx();
715 const DWARFDebugInfoEntry
*ParentEntry
=
716 Result
.CU
->getDebugInfoEntry(*ParentIdx
);
717 if (isNamespaceLikeEntry(ParentEntry
))
719 Result
.DieEntry
= ParentEntry
;
725 bool DependencyTracker::isLiveVariableEntry(const UnitEntryPairTy
&Entry
,
727 DWARFDie DIE
= Entry
.CU
->getDIE(Entry
.DieEntry
);
728 CompileUnit::DIEInfo
&Info
= Entry
.CU
->getDIEInfo(DIE
);
730 if (Info
.getTrackLiveness()) {
731 const auto *Abbrev
= DIE
.getAbbreviationDeclarationPtr();
733 if (!Info
.getIsInFunctionScope() &&
734 Abbrev
->findAttributeIndex(dwarf::DW_AT_const_value
)) {
735 // Global variables with constant value can always be kept.
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
);
746 if (LocExprAddrAndRelocAdjustment
.first
)
747 Info
.setHasAnAddress();
749 if (!LocExprAddrAndRelocAdjustment
.second
)
752 if (!IsLiveParent
&& Info
.getIsInFunctionScope() &&
753 !Entry
.CU
->getGlobalData().getOptions().KeepFunctionForStatic
)
757 Info
.setHasAnAddress();
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
);
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
);
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
);
783 Info
.setHasAnAddress();
786 Entry
.CU
->getContaingFile().Addresses
->getSubprogramRelocAdjustment(
787 DIE
, Entry
.CU
->getGlobalData().getOptions().Verbose
);
788 if (!RelocAdjustment
)
791 if (DIE
.getTag() == dwarf::DW_TAG_subprogram
) {
792 // Validate subprogram address range.
794 HighPc
= DIE
.getHighPC(*LowPc
);
796 Entry
.CU
->warn("function without high_pc. Range will be discarded.",
801 if (*LowPc
> *HighPc
) {
802 Entry
.CU
->warn("low_pc greater than high_pc. Range will be discarded.",
806 } else if (DIE
.getTag() == dwarf::DW_TAG_label
) {
807 if (Entry
.CU
->hasLabelAt(*LowPc
))
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
815 if (dwarf::toAddress(Entry
.CU
->find(Entry
.DieEntry
, dwarf::DW_AT_high_pc
))
816 .value_or(UINT64_MAX
) <= LowPc
)
819 Entry
.CU
->addLabelLowPc(*LowPc
, *RelocAdjustment
);
822 Info
.setHasAnAddress();
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
);
832 if (!Info
.getTrackLiveness() || DIE
.getTag() == dwarf::DW_TAG_label
)
835 Entry
.CU
->addFunctionRange(*LowPc
, *HighPc
, *RelocAdjustment
);