//===--- SwiftRemoteMirror.cpp - C wrapper for Reflection API -------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/SwiftRemoteMirror/Platform.h" #include "swift/SwiftRemoteMirror/SwiftRemoteMirror.h" #define SWIFT_CLASS_IS_SWIFT_MASK swift_reflection_classIsSwiftMask extern "C" { SWIFT_REMOTE_MIRROR_LINKAGE unsigned long long swift_reflection_classIsSwiftMask = 2; } #include "swift/Demangling/Demangler.h" #include "swift/Reflection/ReflectionContext.h" #include "swift/Reflection/TypeLowering.h" #include "swift/Remote/CMemoryReader.h" #include "swift/Runtime/Unreachable.h" #if defined(__APPLE__) && defined(__MACH__) #include #endif using namespace swift; using namespace swift::reflection; using namespace swift::remote; using Runtime = External>; using NativeReflectionContext = swift::reflection::ReflectionContext; struct SwiftReflectionContext { NativeReflectionContext *nativeContext; std::vector> freeFuncs; std::vector> dataSegments; std::string lastString; SwiftReflectionContext(MemoryReaderImpl impl) { auto Reader = std::make_shared(impl); nativeContext = new NativeReflectionContext(Reader); } ~SwiftReflectionContext() { delete nativeContext; for (auto f : freeFuncs) f(); } }; uint16_t swift_reflection_getSupportedMetadataVersion() { return SWIFT_REFLECTION_METADATA_VERSION; } template static int minimalDataLayoutQueryFunction(void *ReaderContext, DataLayoutQueryType type, void *inBuffer, void *outBuffer) { // TODO: The following should be set based on the target. // This code sets it to match the platform this code was compiled for. #if defined(__APPLE__) && __APPLE__ auto applePlatform = true; #else auto applePlatform = false; #endif #if defined(__APPLE__) && __APPLE__ && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_IOS) && TARGET_OS_WATCH) || (defined(TARGET_OS_TV) && TARGET_OS_TV) || defined(__arm64__)) auto iosDerivedPlatform = true; #else auto iosDerivedPlatform = false; #endif if (type == DLQ_GetPointerSize || type == DLQ_GetSizeSize) { auto result = static_cast(outBuffer); *result = WordSize; return 1; } if (type == DLQ_GetObjCReservedLowBits) { auto result = static_cast(outBuffer); if (applePlatform && !iosDerivedPlatform && WordSize == 8) { // Obj-C reserves low bit on 64-bit macOS only. // Other Apple platforms don't reserve this bit (even when // running on x86_64-based simulators). *result = 1; } else { *result = 0; } return 1; } if (type == DLQ_GetLeastValidPointerValue) { auto result = static_cast(outBuffer); if (applePlatform && WordSize == 8) { // Swift reserves the first 4GiB on all 64-bit Apple platforms *result = 0x100000000; } else { // Swift reserves the first 4KiB everywhere else *result = 0x1000; } return 1; } return 0; } // Caveat: This basically only works correctly if running on the same // host as the target. Otherwise, you'll need to use // swift_reflection_createReflectionContextWithDataLayout() below // with an appropriate data layout query function that understands // the target environment. SwiftReflectionContextRef swift_reflection_createReflectionContext(void *ReaderContext, uint8_t PointerSize, FreeBytesFunction Free, ReadBytesFunction ReadBytes, GetStringLengthFunction GetStringLength, GetSymbolAddressFunction GetSymbolAddress) { assert((PointerSize == 4 || PointerSize == 8) && "We only support 32-bit and 64-bit."); assert(PointerSize == sizeof(uintptr_t) && "We currently only support the pointer size this file was compiled with."); auto *DataLayout = PointerSize == 4 ? minimalDataLayoutQueryFunction<4> : minimalDataLayoutQueryFunction<8>; MemoryReaderImpl ReaderImpl { ReaderContext, DataLayout, Free, ReadBytes, GetStringLength, GetSymbolAddress }; return new SwiftReflectionContext(ReaderImpl); } SwiftReflectionContextRef swift_reflection_createReflectionContextWithDataLayout(void *ReaderContext, QueryDataLayoutFunction DataLayout, FreeBytesFunction Free, ReadBytesFunction ReadBytes, GetStringLengthFunction GetStringLength, GetSymbolAddressFunction GetSymbolAddress) { MemoryReaderImpl ReaderImpl { ReaderContext, DataLayout, Free, ReadBytes, GetStringLength, GetSymbolAddress }; return new SwiftReflectionContext(ReaderImpl); } void swift_reflection_destroyReflectionContext(SwiftReflectionContextRef ContextRef) { delete ContextRef; } template ReflectionSection sectionFromInfo(const swift_reflection_info_t &Info, const swift_reflection_section_pair_t &Section) { auto RemoteSectionStart = (uint64_t)(uintptr_t)Section.section.Begin - Info.LocalStartAddress + Info.RemoteStartAddress; auto Start = RemoteRef(RemoteSectionStart, Section.section.Begin); return ReflectionSection(Start, (uintptr_t)Section.section.End - (uintptr_t)Section.section.Begin); } template ReflectionSection reflectionSectionFromLocalAndRemote( const swift_reflection_section_mapping_t &Section) { auto RemoteSectionStart = (uint64_t)Section.remote_section.StartAddress; auto Start = RemoteRef(RemoteSectionStart, Section.local_section.Begin); return ReflectionSection(Start, (uintptr_t)Section.remote_section.Size); } void swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef, swift_reflection_info_t Info) { auto Context = ContextRef->nativeContext; // The `offset` fields must be zero. if (Info.field.offset != 0 || Info.associated_types.offset != 0 || Info.builtin_types.offset != 0 || Info.capture.offset != 0 || Info.type_references.offset != 0 || Info.reflection_strings.offset != 0) { fprintf(stderr, "reserved field in swift_reflection_info_t is not zero\n"); abort(); } ReflectionInfo ContextInfo{ sectionFromInfo(Info, Info.field), sectionFromInfo(Info, Info.associated_types), sectionFromInfo(Info, Info.builtin_types), sectionFromInfo(Info, Info.capture), sectionFromInfo(Info, Info.type_references), sectionFromInfo(Info, Info.reflection_strings)}; Context->addReflectionInfo(ContextInfo); } void swift_reflection_addReflectionMappingInfo( SwiftReflectionContextRef ContextRef, swift_reflection_mapping_info_t Info) { auto Context = ContextRef->nativeContext; ReflectionInfo ContextInfo{ reflectionSectionFromLocalAndRemote(Info.field), reflectionSectionFromLocalAndRemote( Info.associated_types), reflectionSectionFromLocalAndRemote( Info.builtin_types), reflectionSectionFromLocalAndRemote( Info.capture), reflectionSectionFromLocalAndRemote(Info.type_references), reflectionSectionFromLocalAndRemote( Info.reflection_strings)}; Context->addReflectionInfo(ContextInfo); } int swift_reflection_addImage(SwiftReflectionContextRef ContextRef, swift_addr_t imageStart) { auto Context = ContextRef->nativeContext; return Context->addImage(RemoteAddress(imageStart)); } int swift_reflection_readIsaMask(SwiftReflectionContextRef ContextRef, uintptr_t *outIsaMask) { auto Context = ContextRef->nativeContext; auto isaMask = Context->readIsaMask(); if (isaMask) { *outIsaMask = *isaMask; return true; } *outIsaMask = 0; return false; } swift_typeref_t swift_reflection_typeRefForMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata) { auto Context = ContextRef->nativeContext; auto TR = Context->readTypeFromMetadata(Metadata); return reinterpret_cast(TR); } int swift_reflection_ownsObject(SwiftReflectionContextRef ContextRef, uintptr_t Object) { auto Context = ContextRef->nativeContext; return Context->ownsObject(RemoteAddress(Object)); } int swift_reflection_ownsAddress(SwiftReflectionContextRef ContextRef, uintptr_t Address) { auto Context = ContextRef->nativeContext; return Context->ownsAddress(RemoteAddress(Address)); } uintptr_t swift_reflection_metadataForObject(SwiftReflectionContextRef ContextRef, uintptr_t Object) { auto Context = ContextRef->nativeContext; auto MetadataAddress = Context->readMetadataFromInstance(Object); if (!MetadataAddress) return 0; return *MetadataAddress; } swift_typeref_t swift_reflection_typeRefForInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object) { auto Context = ContextRef->nativeContext; auto MetadataAddress = Context->readMetadataFromInstance(Object); if (!MetadataAddress) return 0; auto TR = Context->readTypeFromMetadata(*MetadataAddress); return reinterpret_cast(TR); } swift_typeref_t swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef, const char *MangledTypeName, uint64_t Length) { auto Context = ContextRef->nativeContext; auto TR = Context->readTypeFromMangledName(MangledTypeName, Length).getType(); return reinterpret_cast(TR); } char * swift_reflection_copyDemangledNameForTypeRef( SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef) { auto TR = reinterpret_cast(OpaqueTypeRef); Demangle::Demangler Dem; auto Name = nodeToString(TR->getDemangling(Dem)); return strdup(Name.c_str()); } SWIFT_REMOTE_MIRROR_LINKAGE char * swift_reflection_copyDemangledNameForProtocolDescriptor( SwiftReflectionContextRef ContextRef, swift_reflection_ptr_t Proto) { auto Context = ContextRef->nativeContext; Demangle::Demangler Dem; auto Demangling = Context->readDemanglingForContextDescriptor(Proto, Dem); auto Name = nodeToString(Demangling); return strdup(Name.c_str()); } swift_typeref_t swift_reflection_genericArgumentOfTypeRef(swift_typeref_t OpaqueTypeRef, unsigned Index) { auto TR = reinterpret_cast(OpaqueTypeRef); if (auto BG = dyn_cast(TR)) { auto &Params = BG->getGenericParams(); assert(Index < Params.size()); return reinterpret_cast(Params[Index]); } return 0; } unsigned swift_reflection_genericArgumentCountOfTypeRef(swift_typeref_t OpaqueTypeRef) { auto TR = reinterpret_cast(OpaqueTypeRef); if (auto BG = dyn_cast(TR)) { auto &Params = BG->getGenericParams(); return Params.size(); } return 0; } swift_layout_kind_t getTypeInfoKind(const TypeInfo &TI) { switch (TI.getKind()) { case TypeInfoKind::Invalid: { return SWIFT_UNKNOWN; } case TypeInfoKind::Builtin: { auto &BuiltinTI = cast(TI); if (BuiltinTI.getMangledTypeName() == "Bp") return SWIFT_RAW_POINTER; return SWIFT_BUILTIN; } case TypeInfoKind::Record: { auto &RecordTI = cast(TI); switch (RecordTI.getRecordKind()) { case RecordKind::Invalid: return SWIFT_UNKNOWN; case RecordKind::Tuple: return SWIFT_TUPLE; case RecordKind::Struct: return SWIFT_STRUCT; case RecordKind::ThickFunction: return SWIFT_THICK_FUNCTION; case RecordKind::OpaqueExistential: return SWIFT_OPAQUE_EXISTENTIAL; case RecordKind::ClassExistential: return SWIFT_CLASS_EXISTENTIAL; case RecordKind::ErrorExistential: return SWIFT_ERROR_EXISTENTIAL; case RecordKind::ExistentialMetatype: return SWIFT_EXISTENTIAL_METATYPE; case RecordKind::ClassInstance: return SWIFT_CLASS_INSTANCE; case RecordKind::ClosureContext: return SWIFT_CLOSURE_CONTEXT; } } case TypeInfoKind::Enum: { auto &EnumTI = cast(TI); switch (EnumTI.getEnumKind()) { case EnumKind::NoPayloadEnum: return SWIFT_NO_PAYLOAD_ENUM; case EnumKind::SinglePayloadEnum: return SWIFT_SINGLE_PAYLOAD_ENUM; case EnumKind::MultiPayloadEnum: return SWIFT_MULTI_PAYLOAD_ENUM; } } case TypeInfoKind::Reference: { auto &ReferenceTI = cast(TI); switch (ReferenceTI.getReferenceKind()) { case ReferenceKind::Strong: return SWIFT_STRONG_REFERENCE; #define REF_STORAGE(Name, name, NAME) \ case ReferenceKind::Name: return SWIFT_##NAME##_REFERENCE; #include "swift/AST/ReferenceStorage.def" } } } swift_runtime_unreachable("Unhandled TypeInfoKind in switch"); } static swift_typeinfo_t convertTypeInfo(const TypeInfo *TI) { if (TI == nullptr) { return { SWIFT_UNKNOWN, 0, 0, 0, 0 }; } unsigned NumFields = 0; if (auto *RecordTI = dyn_cast(TI)) { NumFields = RecordTI->getNumCases(); } else if (auto *RecordTI = dyn_cast(TI)) { NumFields = RecordTI->getNumFields(); } return { getTypeInfoKind(*TI), TI->getSize(), TI->getAlignment(), TI->getStride(), NumFields }; } static swift_childinfo_t convertChild(const TypeInfo *TI, unsigned Index) { if (!TI) return {}; const FieldInfo *FieldInfo; if (auto *EnumTI = dyn_cast(TI)) { FieldInfo = &(EnumTI->getCases()[Index]); } else if (auto *RecordTI = dyn_cast(TI)) { FieldInfo = &(RecordTI->getFields()[Index]); } else { assert(false && "convertChild(TI): TI must be record or enum typeinfo"); } return { FieldInfo->Name.c_str(), FieldInfo->Offset, getTypeInfoKind(FieldInfo->TI), reinterpret_cast(FieldInfo->TR), }; } static const char *returnableCString(SwiftReflectionContextRef ContextRef, llvm::Optional String) { if (String) { ContextRef->lastString = *String; return ContextRef->lastString.c_str(); } return nullptr; } swift_typeinfo_t swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef) { auto Context = ContextRef->nativeContext; auto TR = reinterpret_cast(OpaqueTypeRef); auto TI = Context->getTypeInfo(TR); return convertTypeInfo(TI); } swift_childinfo_t swift_reflection_childOfTypeRef(SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef, unsigned Index) { auto Context = ContextRef->nativeContext; auto TR = reinterpret_cast(OpaqueTypeRef); auto *TI = Context->getTypeInfo(TR); return convertChild(TI, Index); } swift_typeinfo_t swift_reflection_infoForMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata) { auto Context = ContextRef->nativeContext; auto *TI = Context->getMetadataTypeInfo(Metadata); return convertTypeInfo(TI); } swift_childinfo_t swift_reflection_childOfMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata, unsigned Index) { auto Context = ContextRef->nativeContext; auto *TI = Context->getMetadataTypeInfo(Metadata); return convertChild(TI, Index); } swift_typeinfo_t swift_reflection_infoForInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object) { auto Context = ContextRef->nativeContext; auto *TI = Context->getInstanceTypeInfo(Object); return convertTypeInfo(TI); } swift_childinfo_t swift_reflection_childOfInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object, unsigned Index) { auto Context = ContextRef->nativeContext; auto *TI = Context->getInstanceTypeInfo(Object); return convertChild(TI, Index); } int swift_reflection_projectExistential(SwiftReflectionContextRef ContextRef, swift_addr_t ExistentialAddress, swift_typeref_t ExistentialTypeRef, swift_typeref_t *InstanceTypeRef, swift_addr_t *StartOfInstanceData) { auto Context = ContextRef->nativeContext; auto ExistentialTR = reinterpret_cast(ExistentialTypeRef); auto RemoteExistentialAddress = RemoteAddress(ExistentialAddress); const TypeRef *InstanceTR = nullptr; RemoteAddress RemoteStartOfInstanceData(nullptr); auto Success = Context->projectExistential(RemoteExistentialAddress, ExistentialTR, &InstanceTR, &RemoteStartOfInstanceData); if (Success) { *InstanceTypeRef = reinterpret_cast(InstanceTR); *StartOfInstanceData = RemoteStartOfInstanceData.getAddressData(); } return Success; } int swift_reflection_projectEnumValue(SwiftReflectionContextRef ContextRef, swift_addr_t EnumAddress, swift_typeref_t EnumTypeRef, int *CaseIndex) { auto Context = ContextRef->nativeContext; auto EnumTR = reinterpret_cast(EnumTypeRef); auto RemoteEnumAddress = RemoteAddress(EnumAddress); if (!Context->projectEnumValue(RemoteEnumAddress, EnumTR, CaseIndex)) { return false; } auto TI = Context->getTypeInfo(EnumTR); auto *RecordTI = dyn_cast(TI); assert(RecordTI != nullptr); if (static_cast(*CaseIndex) >= RecordTI->getNumCases()) { return false; } return true; } void swift_reflection_dumpTypeRef(swift_typeref_t OpaqueTypeRef) { auto TR = reinterpret_cast(OpaqueTypeRef); if (TR == nullptr) { fprintf(stdout, "\n"); } else { TR->dump(stdout); } } void swift_reflection_dumpInfoForTypeRef(SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef) { auto Context = ContextRef->nativeContext; auto TR = reinterpret_cast(OpaqueTypeRef); auto TI = Context->getTypeInfo(TR); if (TI == nullptr) { fprintf(stdout, "\n"); } else { TI->dump(stdout); Demangle::Demangler Dem; std::string MangledName = mangleNode(TR->getDemangling(Dem)); fprintf(stdout, "Mangled name: %s%s\n", MANGLING_PREFIX_STR, MangledName.c_str()); char *DemangledName = swift_reflection_copyDemangledNameForTypeRef(ContextRef, OpaqueTypeRef); fprintf(stdout, "Demangled name: %s\n", DemangledName); free(DemangledName); #ifndef NDEBUG assert(mangleNode(TR->getDemangling(Dem)) == MangledName && "round-trip diff"); #endif } } void swift_reflection_dumpInfoForMetadata(SwiftReflectionContextRef ContextRef, uintptr_t Metadata) { auto Context = ContextRef->nativeContext; auto TI = Context->getMetadataTypeInfo(Metadata); if (TI == nullptr) { fprintf(stdout, "\n"); } else { TI->dump(stdout); } } void swift_reflection_dumpInfoForInstance(SwiftReflectionContextRef ContextRef, uintptr_t Object) { auto Context = ContextRef->nativeContext; auto TI = Context->getInstanceTypeInfo(Object); if (TI == nullptr) { fprintf(stdout, "%s", "\n"); } else { TI->dump(stdout); } } size_t swift_reflection_demangle(const char *MangledName, size_t Length, char *OutDemangledName, size_t MaxLength) { if (MangledName == nullptr || Length == 0) return 0; std::string Mangled(MangledName, Length); auto Demangled = Demangle::demangleTypeAsString(Mangled); strncpy(OutDemangledName, Demangled.c_str(), MaxLength); return Demangled.size(); } const char *swift_reflection_iterateConformanceCache( SwiftReflectionContextRef ContextRef, void (*Call)(swift_reflection_ptr_t Type, swift_reflection_ptr_t Proto, void *ContextPtr), void *ContextPtr) { auto Context = ContextRef->nativeContext; auto Error = Context->iterateConformances([&](auto Type, auto Proto) { Call(Type, Proto, ContextPtr); }); return returnableCString(ContextRef, Error); } const char *swift_reflection_iterateMetadataAllocations( SwiftReflectionContextRef ContextRef, void (*Call)(swift_metadata_allocation_t Allocation, void *ContextPtr), void *ContextPtr) { auto Context = ContextRef->nativeContext; auto Error = Context->iterateMetadataAllocations([&](auto Allocation) { swift_metadata_allocation CAllocation; CAllocation.Tag = Allocation.Tag; CAllocation.Ptr = Allocation.Ptr; CAllocation.Size = Allocation.Size; Call(CAllocation, ContextPtr); }); return returnableCString(ContextRef, Error); } swift_reflection_ptr_t swift_reflection_allocationMetadataPointer( SwiftReflectionContextRef ContextRef, swift_metadata_allocation_t Allocation) { auto Context = ContextRef->nativeContext; MetadataAllocation NativeAllocation; NativeAllocation.Tag = Allocation.Tag; NativeAllocation.Ptr = Allocation.Ptr; NativeAllocation.Size = Allocation.Size; return Context->allocationMetadataPointer(NativeAllocation); } const char *swift_reflection_metadataAllocationTagName( SwiftReflectionContextRef ContextRef, swift_metadata_allocation_tag_t Tag) { auto Context = ContextRef->nativeContext; auto Result = Context->metadataAllocationTagName(Tag); return returnableCString(ContextRef, Result); } int swift_reflection_metadataAllocationCacheNode( SwiftReflectionContextRef ContextRef, swift_metadata_allocation_t Allocation, swift_metadata_cache_node_t *OutNode) { auto Context = ContextRef->nativeContext; MetadataAllocation ConvertedAllocation; ConvertedAllocation.Tag = Allocation.Tag; ConvertedAllocation.Ptr = Allocation.Ptr; ConvertedAllocation.Size = Allocation.Size; auto Result = Context->metadataAllocationCacheNode(ConvertedAllocation); if (!Result) return 0; OutNode->Left = Result->Left; OutNode->Right = Result->Right; return 1; } const char *swift_reflection_iterateMetadataAllocationBacktraces( SwiftReflectionContextRef ContextRef, swift_metadataAllocationBacktraceIterator Call, void *ContextPtr) { auto Context = ContextRef->nativeContext; auto Error = Context->iterateMetadataAllocationBacktraces( [&](auto AllocationPtr, auto Count, auto Ptrs) { // Ptrs is an array of StoredPointer, but the callback expects an array // of swift_reflection_ptr_t. Those may are not always the same type. // (For example, swift_reflection_ptr_t can be 64-bit on 32-bit systems, // while StoredPointer is always the pointer size of the target system.) // Convert the array to an array of swift_reflection_ptr_t. std::vector ConvertedPtrs{&Ptrs[0], &Ptrs[Count]}; Call(AllocationPtr, Count, ConvertedPtrs.data(), ContextPtr); }); return returnableCString(ContextRef, Error); }