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