|
21 | 21 | #include "llvm/DebugInfo/PDB/PDBContext.h" |
22 | 22 | #include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h" |
23 | 23 | #include "llvm/Demangle/Demangle.h" |
| 24 | +#include "llvm/Object/Archive.h" |
24 | 25 | #include "llvm/Object/BuildID.h" |
25 | 26 | #include "llvm/Object/COFF.h" |
26 | 27 | #include "llvm/Object/ELFObjectFile.h" |
@@ -285,7 +286,7 @@ LLVMSymbolizer::findSymbol(ArrayRef<uint8_t> BuildID, StringRef Symbol, |
285 | 286 | } |
286 | 287 |
|
287 | 288 | void LLVMSymbolizer::flush() { |
288 | | - ObjectForUBPathAndArch.clear(); |
| 289 | + ObjectFileCache.clear(); |
289 | 290 | LRUBinaries.clear(); |
290 | 291 | CacheSize = 0; |
291 | 292 | BinaryForPath.clear(); |
@@ -557,57 +558,164 @@ LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path, |
557 | 558 | if (!DbgObj) |
558 | 559 | DbgObj = Obj; |
559 | 560 | ObjectPair Res = std::make_pair(Obj, DbgObj); |
560 | | - std::string DbgObjPath = DbgObj->getFileName().str(); |
561 | 561 | auto Pair = |
562 | 562 | ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res); |
563 | | - BinaryForPath.find(DbgObjPath)->second.pushEvictor([this, I = Pair.first]() { |
564 | | - ObjectPairForPathArch.erase(I); |
565 | | - }); |
| 563 | + std::string FullDbgObjKey; |
| 564 | + auto It = ObjectToArchivePath.find(DbgObj); |
| 565 | + if (It != ObjectToArchivePath.end()) { |
| 566 | + StringRef ArchivePath = It->second; |
| 567 | + StringRef MemberName = sys::path::filename(DbgObj->getFileName()); |
| 568 | + FullDbgObjKey = (ArchivePath + "(" + MemberName + ")").str(); |
| 569 | + } else { |
| 570 | + FullDbgObjKey = DbgObj->getFileName().str(); |
| 571 | + } |
| 572 | + BinaryForPath.find(FullDbgObjKey) |
| 573 | + ->second.pushEvictor( |
| 574 | + [this, I = Pair.first]() { ObjectPairForPathArch.erase(I); }); |
566 | 575 | return Res; |
567 | 576 | } |
568 | 577 |
|
569 | | -Expected<ObjectFile *> |
570 | | -LLVMSymbolizer::getOrCreateObject(const std::string &Path, |
571 | | - const std::string &ArchName) { |
572 | | - Binary *Bin; |
573 | | - auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>()); |
| 578 | +Expected<object::Binary *> |
| 579 | +LLVMSymbolizer::loadOrGetBinary(const std::string &ArchivePathKey, |
| 580 | + std::optional<StringRef> FullPathKey) { |
| 581 | + // If no separate cache key is provided, use the archive path itself. |
| 582 | + std::string FullPathKeyStr = |
| 583 | + FullPathKey ? FullPathKey->str() : ArchivePathKey; |
| 584 | + auto Pair = BinaryForPath.emplace(FullPathKeyStr, OwningBinary<Binary>()); |
574 | 585 | if (!Pair.second) { |
575 | | - Bin = Pair.first->second->getBinary(); |
576 | 586 | recordAccess(Pair.first->second); |
577 | | - } else { |
578 | | - Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path); |
579 | | - if (!BinOrErr) |
580 | | - return BinOrErr.takeError(); |
| 587 | + return Pair.first->second->getBinary(); |
| 588 | + } |
| 589 | + |
| 590 | + Expected<OwningBinary<Binary>> BinOrErr = createBinary(ArchivePathKey); |
| 591 | + if (!BinOrErr) |
| 592 | + return BinOrErr.takeError(); |
581 | 593 |
|
582 | | - CachedBinary &CachedBin = Pair.first->second; |
583 | | - CachedBin = std::move(BinOrErr.get()); |
584 | | - CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); }); |
585 | | - LRUBinaries.push_back(CachedBin); |
586 | | - CacheSize += CachedBin.size(); |
587 | | - Bin = CachedBin->getBinary(); |
| 594 | + CachedBinary &CachedBin = Pair.first->second; |
| 595 | + CachedBin = std::move(*BinOrErr); |
| 596 | + CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); }); |
| 597 | + LRUBinaries.push_back(CachedBin); |
| 598 | + CacheSize += CachedBin.size(); |
| 599 | + return CachedBin->getBinary(); |
| 600 | +} |
| 601 | + |
| 602 | +Expected<ObjectFile *> LLVMSymbolizer::findOrCacheObject( |
| 603 | + const ContainerCacheKey &Key, |
| 604 | + llvm::function_ref<Expected<std::unique_ptr<ObjectFile>>()> Loader, |
| 605 | + const std::string &PathForBinaryCache) { |
| 606 | + auto It = ObjectFileCache.find(Key); |
| 607 | + if (It != ObjectFileCache.end()) |
| 608 | + return It->second.get(); |
| 609 | + |
| 610 | + Expected<std::unique_ptr<ObjectFile>> ObjOrErr = Loader(); |
| 611 | + if (!ObjOrErr) { |
| 612 | + ObjectFileCache.emplace(Key, std::unique_ptr<ObjectFile>()); |
| 613 | + return ObjOrErr.takeError(); |
588 | 614 | } |
589 | 615 |
|
590 | | - if (!Bin) |
591 | | - return static_cast<ObjectFile *>(nullptr); |
| 616 | + ObjectFile *Res = ObjOrErr->get(); |
| 617 | + auto NewEntry = ObjectFileCache.emplace(Key, std::move(*ObjOrErr)); |
| 618 | + auto CacheIter = BinaryForPath.find(PathForBinaryCache); |
| 619 | + if (CacheIter != BinaryForPath.end()) |
| 620 | + CacheIter->second.pushEvictor( |
| 621 | + [this, Iter = NewEntry.first]() { ObjectFileCache.erase(Iter); }); |
| 622 | + return Res; |
| 623 | +} |
592 | 624 |
|
593 | | - if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) { |
594 | | - auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName)); |
595 | | - if (I != ObjectForUBPathAndArch.end()) |
596 | | - return I->second.get(); |
597 | | - |
598 | | - Expected<std::unique_ptr<ObjectFile>> ObjOrErr = |
599 | | - UB->getMachOObjectForArch(ArchName); |
600 | | - if (!ObjOrErr) { |
601 | | - ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), |
602 | | - std::unique_ptr<ObjectFile>()); |
603 | | - return ObjOrErr.takeError(); |
| 625 | +Expected<ObjectFile *> LLVMSymbolizer::getOrCreateObjectFromArchive( |
| 626 | + StringRef ArchivePath, StringRef MemberName, StringRef ArchName, |
| 627 | + StringRef FullPath) { |
| 628 | + Expected<object::Binary *> BinOrErr = |
| 629 | + loadOrGetBinary(ArchivePath.str(), FullPath); |
| 630 | + if (!BinOrErr) |
| 631 | + return BinOrErr.takeError(); |
| 632 | + object::Binary *Bin = *BinOrErr; |
| 633 | + |
| 634 | + object::Archive *Archive = dyn_cast_if_present<object::Archive>(Bin); |
| 635 | + if (!Archive) |
| 636 | + return createStringError(std::errc::invalid_argument, |
| 637 | + "'%s' is not a valid archive", |
| 638 | + ArchivePath.str().c_str()); |
| 639 | + |
| 640 | + Error Err = Error::success(); |
| 641 | + for (auto &Child : Archive->children(Err, /*SkipInternal=*/true)) { |
| 642 | + Expected<StringRef> NameOrErr = Child.getName(); |
| 643 | + if (!NameOrErr) { |
| 644 | + // TODO: Report this as a warning to the client. Consider adding a |
| 645 | + // callback mechanism to report warning-level issues. |
| 646 | + consumeError(NameOrErr.takeError()); |
| 647 | + continue; |
| 648 | + } |
| 649 | + if (*NameOrErr == MemberName) { |
| 650 | + Expected<std::unique_ptr<object::Binary>> MemberOrErr = |
| 651 | + Child.getAsBinary(); |
| 652 | + if (!MemberOrErr) { |
| 653 | + // TODO: Report this as a warning to the client. Consider adding a |
| 654 | + // callback mechanism to report warning-level issues. |
| 655 | + consumeError(MemberOrErr.takeError()); |
| 656 | + continue; |
| 657 | + } |
| 658 | + |
| 659 | + std::unique_ptr<object::Binary> Binary = std::move(*MemberOrErr); |
| 660 | + if (auto *Obj = dyn_cast<object::ObjectFile>(Binary.get())) { |
| 661 | + ObjectToArchivePath[Obj] = ArchivePath.str(); |
| 662 | + Triple::ArchType ObjArch = Obj->makeTriple().getArch(); |
| 663 | + Triple RequestedTriple; |
| 664 | + RequestedTriple.setArch(Triple::getArchTypeForLLVMName(ArchName)); |
| 665 | + if (ObjArch != RequestedTriple.getArch()) |
| 666 | + continue; |
| 667 | + |
| 668 | + ContainerCacheKey CacheKey{ArchivePath.str(), MemberName.str(), |
| 669 | + ArchName.str()}; |
| 670 | + Expected<ObjectFile *> Res = findOrCacheObject( |
| 671 | + CacheKey, |
| 672 | + [O = std::unique_ptr<ObjectFile>( |
| 673 | + Obj)]() mutable -> Expected<std::unique_ptr<ObjectFile>> { |
| 674 | + return std::move(O); |
| 675 | + }, |
| 676 | + ArchivePath.str()); |
| 677 | + Binary.release(); |
| 678 | + return Res; |
| 679 | + } |
| 680 | + } |
| 681 | + } |
| 682 | + if (Err) |
| 683 | + return std::move(Err); |
| 684 | + return createStringError(std::errc::invalid_argument, |
| 685 | + "no matching member '%s' with arch '%s' in '%s'", |
| 686 | + MemberName.str().c_str(), ArchName.str().c_str(), |
| 687 | + ArchivePath.str().c_str()); |
| 688 | +} |
| 689 | + |
| 690 | +Expected<ObjectFile *> |
| 691 | +LLVMSymbolizer::getOrCreateObject(const std::string &Path, |
| 692 | + const std::string &ArchName) { |
| 693 | + // First check for archive(member) format - more efficient to check closing |
| 694 | + // paren first. |
| 695 | + if (!Path.empty() && Path.back() == ')') { |
| 696 | + size_t OpenParen = Path.rfind('(', Path.size() - 1); |
| 697 | + if (OpenParen != std::string::npos) { |
| 698 | + StringRef ArchivePath = StringRef(Path).substr(0, OpenParen); |
| 699 | + StringRef MemberName = |
| 700 | + StringRef(Path).substr(OpenParen + 1, Path.size() - OpenParen - 2); |
| 701 | + return getOrCreateObjectFromArchive(ArchivePath, MemberName, ArchName, |
| 702 | + Path); |
604 | 703 | } |
605 | | - ObjectFile *Res = ObjOrErr->get(); |
606 | | - auto Pair = ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), |
607 | | - std::move(ObjOrErr.get())); |
608 | | - BinaryForPath.find(Path)->second.pushEvictor( |
609 | | - [this, Iter = Pair.first]() { ObjectForUBPathAndArch.erase(Iter); }); |
610 | | - return Res; |
| 704 | + } |
| 705 | + |
| 706 | + Expected<object::Binary *> BinOrErr = loadOrGetBinary(Path); |
| 707 | + if (!BinOrErr) |
| 708 | + return BinOrErr.takeError(); |
| 709 | + object::Binary *Bin = *BinOrErr; |
| 710 | + |
| 711 | + if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) { |
| 712 | + ContainerCacheKey CacheKey{Path, "", ArchName}; |
| 713 | + return findOrCacheObject( |
| 714 | + CacheKey, |
| 715 | + [UB, ArchName]() -> Expected<std::unique_ptr<ObjectFile>> { |
| 716 | + return UB->getMachOObjectForArch(ArchName); |
| 717 | + }, |
| 718 | + Path); |
611 | 719 | } |
612 | 720 | if (Bin->isObject()) { |
613 | 721 | return cast<ObjectFile>(Bin); |
|
0 commit comments