|
27 | 27 | #include "swift/Remote/MemoryReader.h" |
28 | 28 | #include "swift/Remote/MetadataReader.h" |
29 | 29 | #include "swift/Reflection/Records.h" |
| 30 | +#include "swift/Reflection/RuntimeInternals.h" |
30 | 31 | #include "swift/Reflection/TypeLowering.h" |
31 | 32 | #include "swift/Reflection/TypeRef.h" |
32 | 33 | #include "swift/Reflection/TypeRefBuilder.h" |
@@ -104,7 +105,10 @@ class ReflectionContext |
104 | 105 | using super::readMetadataAndValueOpaqueExistential; |
105 | 106 | using super::readMetadataFromInstance; |
106 | 107 | using super::readTypeFromMetadata; |
| 108 | + using super::stripSignedPointer; |
107 | 109 | using typename super::StoredPointer; |
| 110 | + using typename super::StoredSignedPointer; |
| 111 | + using typename super::StoredSize; |
108 | 112 |
|
109 | 113 | explicit ReflectionContext(std::shared_ptr<MemoryReader> reader) |
110 | 114 | : super(std::move(reader), *this) |
@@ -768,6 +772,156 @@ class ReflectionContext |
768 | 772 | } |
769 | 773 | } |
770 | 774 |
|
| 775 | + /// Iterate the protocol conformance cache tree rooted at NodePtr, calling |
| 776 | + /// Call with the type and protocol in each node. |
| 777 | + void iterateConformanceTree(StoredPointer NodePtr, |
| 778 | + std::function<void(StoredPointer Type, StoredPointer Proto)> Call) { |
| 779 | + if (!NodePtr) |
| 780 | + return; |
| 781 | + auto NodeBytes = getReader().readBytes(RemoteAddress(NodePtr), sizeof(Node)); |
| 782 | + auto NodeData = |
| 783 | + reinterpret_cast<const ConformanceNode<Runtime> *>(NodeBytes.get()); |
| 784 | + if (!NodeData) |
| 785 | + return; |
| 786 | + Call(NodeData->Type, NodeData->Proto); |
| 787 | + iterateConformanceTree(NodeData->Left, Call); |
| 788 | + iterateConformanceTree(NodeData->Right, Call); |
| 789 | + } |
| 790 | + |
| 791 | + /// Iterate the protocol conformance cache in the target process, calling Call |
| 792 | + /// with the type and protocol of each conformance. Returns None on success, |
| 793 | + /// and a string describing the error on failure. |
| 794 | + llvm::Optional<std::string> iterateConformances( |
| 795 | + std::function<void(StoredPointer Type, StoredPointer Proto)> Call) { |
| 796 | + std::string ConformancesPointerName = |
| 797 | + "__swift_debug_protocolConformanceStatePointer"; |
| 798 | + auto ConformancesAddrAddr = |
| 799 | + getReader().getSymbolAddress(ConformancesPointerName); |
| 800 | + if (!ConformancesAddrAddr) |
| 801 | + return "unable to look up debug variable " + ConformancesPointerName; |
| 802 | + |
| 803 | + auto ConformancesAddr = |
| 804 | + getReader().readPointer(ConformancesAddrAddr, sizeof(StoredPointer)); |
| 805 | + if (!ConformancesAddr) |
| 806 | + return "unable to read value of " + ConformancesPointerName; |
| 807 | + |
| 808 | + auto Root = getReader().readPointer(ConformancesAddr->getResolvedAddress(), |
| 809 | + sizeof(StoredPointer)); |
| 810 | + iterateConformanceTree(Root->getResolvedAddress().getAddressData(), Call); |
| 811 | + return llvm::None; |
| 812 | + } |
| 813 | + |
| 814 | + /// Fetch the metadata pointer from a metadata allocation, or 0 if this |
| 815 | + /// allocation's tag is not handled or an error occurred. |
| 816 | + StoredPointer allocationMetadataPointer( |
| 817 | + MetadataAllocation<Runtime> Allocation) { |
| 818 | + if (Allocation.Tag == GenericMetadataCacheTag) { |
| 819 | + struct GenericMetadataCacheEntry { |
| 820 | + StoredPointer Left, Right; |
| 821 | + StoredPointer LockedStorage; |
| 822 | + uint8_t LockedStorageKind; |
| 823 | + uint8_t TrackingInfo; |
| 824 | + uint16_t NumKeyParameters; |
| 825 | + uint16_t NumWitnessTables; |
| 826 | + uint32_t Hash; |
| 827 | + StoredPointer Value; |
| 828 | + }; |
| 829 | + auto AllocationBytes = |
| 830 | + getReader().readBytes(RemoteAddress(Allocation.Ptr), |
| 831 | + Allocation.Size); |
| 832 | + auto Entry = reinterpret_cast<const GenericMetadataCacheEntry *>( |
| 833 | + AllocationBytes.get()); |
| 834 | + if (!Entry) |
| 835 | + return 0; |
| 836 | + return Entry->Value; |
| 837 | + } |
| 838 | + return 0; |
| 839 | + } |
| 840 | + |
| 841 | + /// Iterate the metadata allocations in the target process, calling Call with |
| 842 | + /// each allocation found. Returns None on success, and a string describing |
| 843 | + /// the error on failure. |
| 844 | + llvm::Optional<std::string> iterateMetadataAllocations( |
| 845 | + std::function<void (MetadataAllocation<Runtime>)> Call) { |
| 846 | + std::string IterationEnabledName = |
| 847 | + "__swift_debug_metadataAllocationIterationEnabled"; |
| 848 | + std::string AllocationPoolPointerName = |
| 849 | + "__swift_debug_allocationPoolPointer"; |
| 850 | + |
| 851 | + auto IterationEnabledAddr = |
| 852 | + getReader().getSymbolAddress(IterationEnabledName); |
| 853 | + if (!IterationEnabledAddr) |
| 854 | + return "unable to look up debug variable " + IterationEnabledName; |
| 855 | + char IterationEnabled; |
| 856 | + if (!getReader().readInteger(IterationEnabledAddr, &IterationEnabled)) |
| 857 | + return "failed to read value of " + IterationEnabledName; |
| 858 | + if (!IterationEnabled) |
| 859 | + return std::string("remote process does not have metadata allocation " |
| 860 | + "iteration enabled"); |
| 861 | + |
| 862 | + auto AllocationPoolAddrAddr = |
| 863 | + getReader().getSymbolAddress(AllocationPoolPointerName); |
| 864 | + if (!AllocationPoolAddrAddr) |
| 865 | + return "unable to look up debug variable " + AllocationPoolPointerName; |
| 866 | + auto AllocationPoolAddr = |
| 867 | + getReader().readPointer(AllocationPoolAddrAddr, sizeof(StoredPointer)); |
| 868 | + if (!AllocationPoolAddr) |
| 869 | + return "failed to read value of " + AllocationPoolPointerName; |
| 870 | + |
| 871 | + struct PoolRange { |
| 872 | + StoredPointer Begin; |
| 873 | + StoredSize Remaining; |
| 874 | + }; |
| 875 | + struct PoolTrailer { |
| 876 | + StoredPointer PrevTrailer; |
| 877 | + StoredSize PoolSize; |
| 878 | + }; |
| 879 | + struct alignas(StoredPointer) AllocationHeader { |
| 880 | + uint16_t Size; |
| 881 | + uint16_t Tag; |
| 882 | + }; |
| 883 | + |
| 884 | + auto PoolBytes = getReader() |
| 885 | + .readBytes(AllocationPoolAddr->getResolvedAddress(), sizeof(PoolRange)); |
| 886 | + auto Pool = reinterpret_cast<const PoolRange *>(PoolBytes.get()); |
| 887 | + if (!Pool) |
| 888 | + return std::string("failure reading allocation pool contents"); |
| 889 | + |
| 890 | + auto TrailerPtr = Pool->Begin + Pool->Remaining; |
| 891 | + while (TrailerPtr) { |
| 892 | + auto TrailerBytes = getReader() |
| 893 | + .readBytes(RemoteAddress(TrailerPtr), sizeof(PoolTrailer)); |
| 894 | + auto Trailer = reinterpret_cast<const PoolTrailer *>(TrailerBytes.get()); |
| 895 | + if (!Trailer) |
| 896 | + break; |
| 897 | + auto PoolStart = TrailerPtr - Trailer->PoolSize; |
| 898 | + auto PoolBytes = getReader() |
| 899 | + .readBytes(RemoteAddress(PoolStart), Trailer->PoolSize); |
| 900 | + auto PoolPtr = (const char *)PoolBytes.get(); |
| 901 | + if (!PoolPtr) |
| 902 | + break; |
| 903 | + |
| 904 | + uintptr_t Offset = 0; |
| 905 | + while (Offset < Trailer->PoolSize) { |
| 906 | + auto AllocationPtr = PoolPtr + Offset; |
| 907 | + auto Header = (const AllocationHeader *)AllocationPtr; |
| 908 | + if (Header->Size == 0) |
| 909 | + break; |
| 910 | + auto RemoteAddr = PoolStart + Offset + sizeof(AllocationHeader); |
| 911 | + MetadataAllocation<Runtime> Allocation; |
| 912 | + Allocation.Tag = Header->Tag; |
| 913 | + Allocation.Ptr = RemoteAddr; |
| 914 | + Allocation.Size = Header->Size; |
| 915 | + Call(Allocation); |
| 916 | + |
| 917 | + Offset += sizeof(AllocationHeader) + Header->Size; |
| 918 | + } |
| 919 | + |
| 920 | + TrailerPtr = Trailer->PrevTrailer; |
| 921 | + } |
| 922 | + return llvm::None; |
| 923 | + } |
| 924 | + |
771 | 925 | private: |
772 | 926 | const TypeInfo *getClosureContextInfo(StoredPointer Context, |
773 | 927 | const ClosureContextInfo &Info) { |
|
0 commit comments