LLVM 23.0.0git
DependencyTracker.cpp
Go to the documentation of this file.
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"
11
12using namespace llvm;
13using namespace dwarf_linker;
14using 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.
25
26/// Verify the keep chain by looking for DIEs that are kept but who's parent
27/// isn't.
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
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));
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
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
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())) {
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
166 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
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
183 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
186
187 addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
188 }
189 } break;
190 case dwarf::DW_TAG_base_type: {
191 // Always keep base types.
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) {
203 ReferencedBy);
204 break;
205 }
206
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 // A forward-declared type nested in a DW_TAG_module is the module's
218 // record that the name exists, even when no full definition has been
219 // emitted. Route it through the type pool: when another CU emits a
220 // real definition for the same synthetic name, the existing
221 // decl-vs-def race resolution in allocateTypeDie + getFinalDie keeps
222 // the definition and drops this declaration at emission time. For
223 // non-ODR languages getFinalPlacementForEntry forces PlainDwarf,
224 // so the forward decl is kept in place under its module.
225 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_module &&
226 dwarf::isType(CurChild->getTag()) &&
227 dwarf::toUnsigned(Entry.CU->find(CurChild, dwarf::DW_AT_declaration),
228 0)) {
231 ReferencedBy);
232 }
233 break;
234 }
235
236 collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
237 }
238}
239
241 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
242 bool Res = true;
243
244 // Mark roots as kept.
245 while (!RootEntriesWorkList.empty()) {
246 LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();
247
249 Root.getRootEntry(), InterCUProcessingStarted,
250 HasNewInterconnectedCUs)) {
251 if (Root.hasReferencedByOtherEntry())
252 Dependencies.push_back(Root);
253 } else
254 Res = false;
255 }
256
257 return Res;
258}
259
261 bool HasNewDependency = false;
263 assert(Root.hasReferencedByOtherEntry() &&
264 "Root entry without dependency inside the dependencies list");
265
266 UnitEntryPairTy RootEntry = Root.getRootEntry();
267 CompileUnit::DIEInfo &RootInfo =
268 RootEntry.CU->getDIEInfo(RootEntry.DieEntry);
269
270 UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
271 CompileUnit::DIEInfo &ReferencedByInfo =
272 ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
273
274 if (!RootInfo.needToPlaceInTypeTable() &&
275 ReferencedByInfo.needToPlaceInTypeTable()) {
276 HasNewDependency = true;
277 setPlainDwarfPlacementRec(ReferencedByEntry);
278
279 // FIXME: we probably need to update getKeepTypeChildren status for
280 // parents of *Root.ReferencedBy.
281 }
282 }
283
284 return HasNewDependency;
285}
286
288 const UnitEntryPairTy &Entry) {
289 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
290 if (Info.getPlacement() == CompileUnit::PlainDwarf &&
291 !Info.getKeepTypeChildren())
292 return;
293
295 Info.unsetKeepTypeChildren();
297
298 for (const DWARFDebugInfoEntry *CurChild =
299 Entry.CU->getFirstChildEntry(Entry.DieEntry);
300 CurChild && CurChild->getAbbreviationDeclarationPtr();
301 CurChild = Entry.CU->getSiblingEntry(CurChild))
302 setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});
303}
304
305static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {
306 switch (Entry->getTag()) {
307 case dwarf::DW_TAG_compile_unit:
308 case dwarf::DW_TAG_module:
309 case dwarf::DW_TAG_namespace:
310 return true;
311
312 default:
313 return false;
314 }
315}
316
318 CompileUnit::DieOutputPlacement NewPlacement) {
319 if (!Info.getKeep())
320 return false;
321
322 switch (NewPlacement) {
324 return Info.needToPlaceInTypeTable();
325
327 return Info.needToKeepInPlainDwarf();
328
330 return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
331
333 llvm_unreachable("Unset placement type is specified.");
334 };
335
336 llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");
337}
338
340 CompileUnit::DieOutputPlacement NewPlacement) {
341 return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
342}
343
345 const UnitEntryPairTy &Entry) {
346 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
347 return;
348
349 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
350 bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
351 bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
352
353 bool AreTypeParentsDone = !NeedKeepTypeChildren;
354 bool ArePlainParentsDone = !NeedKeepPlainChildren;
355
356 // Mark parents as 'Keep*Children'.
357 std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
358 while (ParentIdx) {
359 const DWARFDebugInfoEntry *ParentEntry =
360 Entry.CU->getDebugInfoEntry(*ParentIdx);
361 CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);
362
363 if (!AreTypeParentsDone && NeedKeepTypeChildren) {
364 if (ParentInfo.getKeepTypeChildren())
365 AreTypeParentsDone = true;
366 else {
367 bool AddToWorklist = !isAlreadyMarked(
369 ParentInfo.setKeepTypeChildren();
370 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
373 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
374 }
375 }
376 }
377
378 if (!ArePlainParentsDone && NeedKeepPlainChildren) {
379 if (ParentInfo.getKeepPlainChildren())
380 ArePlainParentsDone = true;
381 else {
382 bool AddToWorklist = !isAlreadyMarked(
384 ParentInfo.setKeepPlainChildren();
385 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
388 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
389 }
390 }
391 }
392
393 if (AreTypeParentsDone && ArePlainParentsDone)
394 break;
395
396 ParentIdx = ParentEntry->getParentIdx();
397 }
398}
399
400// This function tries to set specified \p Placement for the \p Entry.
401// Depending on the concrete entry, the placement could be:
402// a) changed to another.
403// b) joined with current entry placement.
404// c) set as requested.
408 assert((Placement != CompileUnit::NotSet) && "Placement is not set");
409 CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
410
411 if (!EntryInfo.getODRAvailable())
413
414 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
415 // In-class static member declarations (e.g. "static constexpr int x = 1;")
416 // are DW_TAG_variable children of a DW_TAG_class_type /
417 // DW_TAG_structure_type / DW_TAG_union_type with DW_AT_declaration set.
418 // They are part of the class type and belong in the TypeTable together with
419 // the class. Forcing them into PlainDwarf would also drag the parent class
420 // into PlainDwarf (via markParentsAsKeepingChildren), producing a duplicate
421 // empty class declaration DIE alongside the full class definition emitted
422 // in another CU.
423 bool IsDeclaration = dwarf::toUnsigned(
424 Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_declaration), 0);
425 bool ParentIsType = false;
426 if (IsDeclaration) {
427 if (std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx()) {
428 dwarf::Tag ParentTag =
429 Entry.CU->getDebugInfoEntry(*ParentIdx)->getTag();
430 ParentIsType = ParentTag == dwarf::DW_TAG_class_type ||
431 ParentTag == dwarf::DW_TAG_structure_type ||
432 ParentTag == dwarf::DW_TAG_union_type;
433 }
434 }
435 if (IsDeclaration && ParentIsType) {
436 // Pure declarations have no runtime address; they belong with the class
437 // type. Always place in TypeTable regardless of how they were reached.
439 }
440
441 // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
442 // time.
443 if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||
444 EntryInfo.getPlacement() == CompileUnit::Both)
446
449 }
450
451 switch (EntryInfo.getPlacement()) {
453 return Placement;
454
457
460
462 return CompileUnit::Both;
463 };
464
465 llvm_unreachable("Unknown placement type.");
466 return Placement;
467}
468
470 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
471 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
472 std::atomic<bool> &HasNewInterconnectedCUs) {
473 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
474 return true;
475
476 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
477
478 // Calculate final placement placement.
480 Entry,
482 assert((Info.getODRAvailable() || isLiveAction(Action) ||
484 "Wrong kind of placement for ODR unavailable entry");
485
486 if (!isChildrenAction(Action))
487 if (isAlreadyMarked(Entry, Placement))
488 return true;
489
490 // Mark current DIE as kept.
491 Info.setKeep();
492 Info.setPlacement(Placement);
493
494 // Set keep children property for parents.
496
497 UnitEntryPairTy FinalRootEntry =
498 Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
499
500 // Analyse referenced DIEs.
501 bool Res = true;
502 if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
503 InterCUProcessingStarted,
504 HasNewInterconnectedCUs))
505 Res = false;
506
507 // Return if we do not need to process children.
508 if (isSingleAction(Action))
509 return Res;
510
511 // Process children.
512 // Check for subprograms special case.
513 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
514 Info.getODRAvailable()) {
515 // Subprograms is a special case. As it can be root for type DIEs
516 // and itself may be subject to move into the artificial type unit.
517 // a) Non removable children(like DW_TAG_formal_parameter) should always
518 // be cloned. They are placed into the "PlainDwarf" and into the
519 // "TypeTable".
520 // b) ODR deduplication candidates(type DIEs) children should not be put
521 // into the "PlainDwarf".
522 // c) Children keeping addresses and locations(like DW_TAG_call_site)
523 // should not be put into the "TypeTable".
524 for (const DWARFDebugInfoEntry *CurChild =
525 Entry.CU->getFirstChildEntry(Entry.DieEntry);
526 CurChild && CurChild->getAbbreviationDeclarationPtr();
527 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
528 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
529
530 switch (CurChild->getTag()) {
531 case dwarf::DW_TAG_variable:
532 case dwarf::DW_TAG_constant:
533 case dwarf::DW_TAG_subprogram:
534 case dwarf::DW_TAG_label: {
535 if (ChildInfo.getHasAnAddress())
536 continue;
537 } break;
538
539 // Entries having following tags could not be removed from the subprogram.
540 case dwarf::DW_TAG_lexical_block:
541 case dwarf::DW_TAG_friend:
542 case dwarf::DW_TAG_inheritance:
543 case dwarf::DW_TAG_formal_parameter:
544 case dwarf::DW_TAG_unspecified_parameters:
545 case dwarf::DW_TAG_template_type_parameter:
546 case dwarf::DW_TAG_template_value_parameter:
547 case dwarf::DW_TAG_GNU_template_parameter_pack:
548 case dwarf::DW_TAG_GNU_formal_parameter_pack:
549 case dwarf::DW_TAG_GNU_template_template_param:
550 case dwarf::DW_TAG_thrown_type: {
551 // Go to the default child handling.
552 } break;
553
554 default: {
555 bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
556
557 // Skip child marked to be copied into the artificial type unit.
558 if (isLiveAction(Action) && ChildIsTypeTableCandidate)
559 continue;
560
561 // Skip child marked to be copied into the plain unit.
562 if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
563 continue;
564
565 // Go to the default child handling.
566 } break;
567 }
568
570 Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
571 InterCUProcessingStarted, HasNewInterconnectedCUs))
572 Res = false;
573 }
574
575 return Res;
576 }
577
578 // Recursively process children.
579 for (const DWARFDebugInfoEntry *CurChild =
580 Entry.CU->getFirstChildEntry(Entry.DieEntry);
581 CurChild && CurChild->getAbbreviationDeclarationPtr();
582 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
583 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
584 switch (CurChild->getTag()) {
585 case dwarf::DW_TAG_variable:
586 case dwarf::DW_TAG_constant:
587 case dwarf::DW_TAG_subprogram:
588 case dwarf::DW_TAG_label: {
589 if (ChildInfo.getHasAnAddress())
590 continue;
591 } break;
592 default:
593 break; // Nothing to do.
594 };
595
597 Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
598 InterCUProcessingStarted, HasNewInterconnectedCUs))
599 Res = false;
600 }
601
602 return Res;
603}
604
607 switch (DIEEntry->getTag()) {
608 default:
609 return false;
610
611 case dwarf::DW_TAG_imported_module:
612 case dwarf::DW_TAG_imported_declaration:
613 case dwarf::DW_TAG_imported_unit:
614 case dwarf::DW_TAG_array_type:
615 case dwarf::DW_TAG_class_type:
616 case dwarf::DW_TAG_enumeration_type:
617 case dwarf::DW_TAG_pointer_type:
618 case dwarf::DW_TAG_reference_type:
619 case dwarf::DW_TAG_string_type:
620 case dwarf::DW_TAG_structure_type:
621 case dwarf::DW_TAG_subroutine_type:
622 case dwarf::DW_TAG_typedef:
623 case dwarf::DW_TAG_union_type:
624 case dwarf::DW_TAG_variant:
625 case dwarf::DW_TAG_module:
626 case dwarf::DW_TAG_ptr_to_member_type:
627 case dwarf::DW_TAG_set_type:
628 case dwarf::DW_TAG_subrange_type:
629 case dwarf::DW_TAG_base_type:
630 case dwarf::DW_TAG_const_type:
631 case dwarf::DW_TAG_enumerator:
632 case dwarf::DW_TAG_file_type:
633 case dwarf::DW_TAG_packed_type:
634 case dwarf::DW_TAG_thrown_type:
635 case dwarf::DW_TAG_volatile_type:
636 case dwarf::DW_TAG_dwarf_procedure:
637 case dwarf::DW_TAG_restrict_type:
638 case dwarf::DW_TAG_interface_type:
639 case dwarf::DW_TAG_namespace:
640 case dwarf::DW_TAG_unspecified_type:
641 case dwarf::DW_TAG_shared_type:
642 case dwarf::DW_TAG_rvalue_reference_type:
643 case dwarf::DW_TAG_coarray_type:
644 case dwarf::DW_TAG_dynamic_type:
645 case dwarf::DW_TAG_atomic_type:
646 case dwarf::DW_TAG_immutable_type:
647 case dwarf::DW_TAG_function_template:
648 case dwarf::DW_TAG_class_template:
649 return true;
650 }
651}
652
654 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
655 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
656 std::atomic<bool> &HasNewInterconnectedCUs) {
657 const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
658 if (Abbrev == nullptr)
659 return true;
660
661 DWARFUnit &Unit = Entry.CU->getOrigUnit();
662 DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
664 Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
665
666 // For each DIE attribute...
667 for (const auto &AttrSpec : Abbrev->attributes()) {
668 DWARFFormValue Val(AttrSpec.Form);
670 AttrSpec.Attr == dwarf::DW_AT_sibling) {
671 DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
672 Unit.getFormParams());
673 continue;
674 }
675 Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
676
677 // Resolve reference.
678 std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
679 Val, InterCUProcessingStarted
682 if (!RefDie) {
683 Entry.CU->warn("could not find referenced DIE", Entry.DieEntry);
684 continue;
685 }
686
687 if (!RefDie->DieEntry) {
688 // Delay resolving reference.
689 RefDie->CU->setInterconnectedCU();
690 Entry.CU->setInterconnectedCU();
691 HasNewInterconnectedCUs = true;
692 return false;
693 }
694
695 assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
696 InterCUProcessingStarted) &&
697 "Inter-CU reference while inter-CU processing is not started");
698
699 CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
700 if (!RefInfo.getODRAvailable())
702 else if (RefInfo.getODRAvailable() &&
703 llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
704 // Note: getODRAttributes does not include DW_AT_containing_type.
705 // It should be OK as we do getRootForSpecifiedEntry(). So any containing
706 // type would be found as the root for the entry.
708 else if (isLiveAction(Action))
710 else
712
713 if (AttrSpec.Attr == dwarf::DW_AT_import) {
714 if (isNamespaceLikeEntry(RefDie->DieEntry)) {
716 isTypeAction(Action)
719 *RefDie, RootEntry);
720 continue;
721 }
722
723 addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);
724 continue;
725 }
726
727 UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
728 addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);
729 }
730
731 return true;
732}
733
736 UnitEntryPairTy Result = Entry;
737
738 do {
739 switch (Entry.DieEntry->getTag()) {
740 case dwarf::DW_TAG_subprogram:
741 case dwarf::DW_TAG_label:
742 case dwarf::DW_TAG_variable:
743 case dwarf::DW_TAG_constant: {
744 return Result;
745 } break;
746
747 default: {
748 // Nothing to do.
749 }
750 }
751
752 std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
753 if (!ParentIdx)
754 return Result;
755
756 const DWARFDebugInfoEntry *ParentEntry =
757 Result.CU->getDebugInfoEntry(*ParentIdx);
758 if (isNamespaceLikeEntry(ParentEntry))
759 break;
760 Result.DieEntry = ParentEntry;
761 } while (true);
762
763 return Result;
764}
765
766static void dumpKeptDIE(const DWARFDie &DIE, StringRef Kind, bool Verbose) {
767 if (!Verbose)
768 return;
769 outs() << "Keeping " << Kind << " DIE:";
770 DIDumpOptions DumpOpts;
771 DumpOpts.ChildRecurseDepth = 0;
772 DumpOpts.Verbose = Verbose;
773 DIE.dump(outs(), /*Indent=*/8, DumpOpts);
774}
775
777 bool IsLiveParent) {
778 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
779 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
780
781 if (Info.getTrackLiveness()) {
782 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
783
784 if (!Info.getIsInFunctionScope() &&
785 Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
786 // Global variables with constant value can always be kept.
787 } else {
788 // See if there is a relocation to a valid debug map entry inside this
789 // variable's location. The order is important here. We want to always
790 // check if the variable has a location expression address. However, we
791 // don't want a static variable in a function to force us to keep the
792 // enclosing function, unless requested explicitly.
793 std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
794 Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
795 DIE, Entry.CU->getGlobalData().getOptions().Verbose);
796
797 if (LocExprAddrAndRelocAdjustment.first)
798 Info.setHasAnAddress();
799
800 if (!LocExprAddrAndRelocAdjustment.second)
801 return false;
802
803 if (!IsLiveParent && Info.getIsInFunctionScope() &&
804 !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
805 return false;
806 }
807 }
808 Info.setHasAnAddress();
809
810 dumpKeptDIE(DIE, "variable", Entry.CU->getGlobalData().getOptions().Verbose);
811
812 return true;
813}
814
816 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
817 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
818 std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);
819
820 const bool Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
821 std::optional<uint64_t> LowPc;
822 std::optional<uint64_t> HighPc;
823 std::optional<int64_t> RelocAdjustment;
824 if (Info.getTrackLiveness()) {
825 LowPc = dwarf::toAddress(LowPCVal);
826 if (!LowPc)
827 return false;
828
829 Info.setHasAnAddress();
830
831 RelocAdjustment =
832 Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
833 DIE, Verbose);
834 if (!RelocAdjustment)
835 return false;
836
837 if (DIE.getTag() == dwarf::DW_TAG_subprogram) {
838 // Validate subprogram address range.
839
840 HighPc = DIE.getHighPC(*LowPc);
841 if (!HighPc) {
842 Entry.CU->warn("function without high_pc. Range will be discarded.",
843 &DIE);
844 return false;
845 }
846
847 if (*LowPc > *HighPc) {
848 Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
849 &DIE);
850 return false;
851 }
852 } else if (DIE.getTag() == dwarf::DW_TAG_label) {
853 if (Entry.CU->hasLabelAt(*LowPc))
854 return false;
855
856 // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
857 // labels that don't fall into the CU's aranges. This is wrong IMO. Debug
858 // info generation bugs aside, this is really wrong in the case of labels,
859 // where a label marking the end of a function will have a PC == CU's
860 // high_pc.
861 if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
862 .value_or(UINT64_MAX) <= LowPc)
863 return false;
864
865 // For assembly-language CUs there are typically no DW_TAG_subprogram
866 // DIEs, so labels are the only addresses we see. Fall back to the
867 // assembly-range lookup to recover a function range for the line-table
868 // filter; otherwise the output line table would be empty.
869 uint16_t Language = dwarf::toUnsigned(
870 Entry.CU->getOrigUnit().getUnitDIE().find(dwarf::DW_AT_language), 0);
871 if (Language == dwarf::DW_LANG_Mips_Assembler ||
872 Language == dwarf::DW_LANG_Assembly) {
873 if (auto Range = Entry.CU->getContaingFile()
874 .Addresses->getAssemblyRangeForAddress(*LowPc))
875 Entry.CU->addFunctionRange(Range->LowPC, Range->HighPC,
876 *RelocAdjustment);
877 }
878
879 Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
880 }
881 } else
882 Info.setHasAnAddress();
883
884 dumpKeptDIE(DIE, "subprogram", Verbose);
885
886 if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
887 return true;
888
889 Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
890 return true;
891}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
bool isAlreadyMarked(const CompileUnit::DIEInfo &Info, CompileUnit::DieOutputPlacement NewPlacement)
static void dumpKeptDIE(const DWARFDie &DIE, StringRef Kind, bool Verbose)
static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry)
static CompileUnit::DieOutputPlacement getFinalPlacementForEntry(const UnitEntryPairTy &Entry, CompileUnit::DieOutputPlacement Placement)
Branch Probability Basic Block Placement
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
A pointer to another debug information entry.
Definition DIE.h:325
A structured debug information entry.
Definition DIE.h:828
dwarf::Tag getTag() const
Definition DIE.h:864
LLVM_ABI void dump() const
Definition DIE.cpp:261
A DWARFDataExtractor (typically for an in-memory copy of an object-file section) plus a relocation ma...
DWARFDebugInfoEntry - A DIE with only the minimum required data.
std::optional< uint32_t > getParentIdx() const
Returns index of the parent die.
const DWARFAbbreviationDeclaration * getAbbreviationDeclarationPtr() const
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition DWARFDie.h:43
iterator_range< iterator > children() const
Definition DWARFDie.h:406
const DWARFDebugInfoEntry * getDebugInfoEntry() const
Definition DWARFDie.h:54
bool isValid() const
Definition DWARFDie.h:52
LLVM_ABI bool isFormClass(FormClass FC) const
LLVM_ABI bool extractValue(const DWARFDataExtractor &Data, uint64_t *OffsetPtr, dwarf::FormParams FormParams, const DWARFContext *Context=nullptr, const DWARFUnit *Unit=nullptr)
Extracts a value in Data at offset *OffsetPtr.
bool skipValue(DataExtractor DebugInfoData, uint64_t *OffsetPtr, const dwarf::FormParams Params) const
Skip a form's value in DebugInfoData at the offset specified by OffsetPtr.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
static LLVM_ABI raw_ostream & error()
Convenience method for printing "error: " to stderr.
Definition WithColor.cpp:83
DieOutputPlacement
Kinds of placement for the output die.
@ Both
Corresponding DIE goes to type table and to plain dwarf.
@ TypeTable
Corresponding DIE goes to the type table only.
@ PlainDwarf
Corresponding DIE goes to the plain dwarf only.
void verifyKeepChain()
Recursively walk the DIE tree and check "keepness" and "placement" information.
RootEntriesListTy Dependencies
List of entries dependencies.
void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry)
Mark parents as keeping children.
UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry)
bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Examine worklist and mark all 'root DIE's as kept and set "Placement" property.
bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Check referenced DIEs and add them into the worklist.
bool isLiveAction(LiveRootWorklistActionTy Action)
bool isChildrenAction(LiveRootWorklistActionTy Action)
bool isTypeAction(LiveRootWorklistActionTy Action)
bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Mark whole DIE tree as kept recursively.
bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry)
void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry)
Mark whole DIE tree as placed in "PlainDwarf".
RootEntriesListTy RootEntriesWorkList
List of entries which are 'root DIE's.
void addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy)
Add action item to the work list.
static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry)
Returns true if specified subprogram references live code section.
bool resolveDependenciesAndMarkLiveness(bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Recursively walk the DIE tree and look for DIEs to keep.
static bool isLiveVariableEntry(const UnitEntryPairTy &Entry, bool IsLiveParent)
Returns true if specified variable references live code section.
@ MarkTypeEntryRec
Mark current item and all its children as type entry.
@ MarkLiveChildrenRec
Mark all children of current item as live entry.
@ MarkLiveEntryRec
Mark current item and all its children as live entry.
@ MarkTypeChildrenRec
Mark all children of current item as type entry.
void collectRootsToKeep(const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy, bool IsLiveParent)
This function navigates DIEs tree starting from specified Entry.
bool updateDependenciesCompleteness()
Check if dependencies have incompatible placement.
DIEInfo & getDIEInfo(unsigned Idx)
Idx index of the DIE.
#define UINT64_MAX
Definition DataTypes.h:77
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
ArrayRef< dwarf::Attribute > getODRAttributes()
std::optional< uint64_t > toAddress(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an address.
bool isType(Tag T)
Definition Dwarf.h:113
std::optional< uint64_t > toUnsigned(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an unsigned constant.
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:558
LLVM_ABI raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
auto reverse(ContainerTy &&C)
Definition STLExtras.h:407
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
LLVM_ABI unsigned getULEB128Size(uint64_t Value)
Utility function to get the size of the ULEB128-encoded value.
Definition LEB128.cpp:19
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1946
Container for dump options that control which debug information will be dumped.
Definition DIContext.h:196
unsigned ChildRecurseDepth
Definition DIContext.h:198
Information gathered about a DIE in the object file.
void setPlacement(DieOutputPlacement Placement)
Sets Placement kind for the corresponding die.
This is a helper structure which keeps a debug info entry with it's containing compilation unit.