//===--- swift-remoteast-test.cpp - RemoteAST testing application ---------===// // // 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 // //===----------------------------------------------------------------------===// // This file supports performing target-specific remote reflection tests // on live swift executables. //===----------------------------------------------------------------------===// #include "swift/RemoteAST/RemoteAST.h" #include "swift/Remote/InProcessMemoryReader.h" #include "swift/Remote/MetadataReader.h" #include "swift/Runtime/Metadata.h" #include "swift/Frontend/Frontend.h" #include "swift/FrontendTool/FrontendTool.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/LLVMInitialize.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include #if defined(__ELF__) #define SWIFT_REMOTEAST_TEST_ABI __attribute__((__visibility__("default"))) #elif defined(__MACH__) #define SWIFT_REMOTEAST_TEST_ABI __attribute__((__visibility__("default"))) #else #define SWIFT_REMOTEAST_TEST_ABI __declspec(dllexport) #endif using namespace swift; using namespace swift::remote; using namespace swift::remoteAST; #if defined(__APPLE__) && defined(__MACH__) #include static unsigned long long computeClassIsSwiftMask(void) { uintptr_t *objc_debug_swift_stable_abi_bit_ptr = (uintptr_t *)dlsym(RTLD_DEFAULT, "objc_debug_swift_stable_abi_bit"); return objc_debug_swift_stable_abi_bit_ptr ? *objc_debug_swift_stable_abi_bit_ptr : 1; } #else static unsigned long long computeClassIsSwiftMask(void) { return 1; } #endif extern "C" unsigned long long _swift_classIsSwiftMask = computeClassIsSwiftMask(); /// The context for the code we're running. Set by the observer. static ASTContext *context = nullptr; /// The RemoteAST for the code we're running. std::unique_ptr remoteContext; static RemoteASTContext &getRemoteASTContext() { if (remoteContext) return *remoteContext; std::shared_ptr reader(new InProcessMemoryReader()); remoteContext.reset(new RemoteASTContext(*context, std::move(reader))); return *remoteContext; } // FIXME: swiftcall /// func printType(forMetadata: Any.Type) extern "C" void SWIFT_REMOTEAST_TEST_ABI LLVM_ATTRIBUTE_USED printMetadataType(const Metadata *typeMetadata) { auto &remoteAST = getRemoteASTContext(); auto &out = llvm::outs(); auto result = remoteAST.getTypeForRemoteTypeMetadata(RemoteAddress(typeMetadata)); if (result) { out << "found type: "; result.getValue().print(out); out << '\n'; } else { out << result.getFailure().render() << '\n'; } } // FIXME: swiftcall /// func printDynamicType(_: AnyObject) extern "C" void SWIFT_REMOTEAST_TEST_ABI LLVM_ATTRIBUTE_USED printHeapMetadataType(void *object) { auto &remoteAST = getRemoteASTContext(); auto &out = llvm::outs(); auto metadataResult = remoteAST.getHeapMetadataForObject(RemoteAddress(object)); if (!metadataResult) { out << metadataResult.getFailure().render() << '\n'; return; } auto metadata = metadataResult.getValue(); auto result = remoteAST.getTypeForRemoteTypeMetadata(metadata, /*skipArtificial*/ true); if (result) { out << "found type: "; result.getValue().print(out); out << '\n'; } else { out << result.getFailure().render() << '\n'; } } static void printMemberOffset(const Metadata *typeMetadata, StringRef memberName, bool passMetadata) { auto &remoteAST = getRemoteASTContext(); auto &out = llvm::outs(); // The first thing we have to do is get the type. auto typeResult = remoteAST.getTypeForRemoteTypeMetadata(RemoteAddress(typeMetadata)); if (!typeResult) { out << "failed to find type: " << typeResult.getFailure().render() << '\n'; return; } Type type = typeResult.getValue(); RemoteAddress address = (passMetadata ? RemoteAddress(typeMetadata) : RemoteAddress(nullptr)); auto offsetResult = remoteAST.getOffsetOfMember(type, address, memberName); if (!offsetResult) { out << "failed to find offset: " << offsetResult.getFailure().render() << '\n'; return; } out << "found offset: " << offsetResult.getValue() << '\n'; } // FIXME: swiftcall /// func printTypeMemberOffset(forType: Any.Type, memberName: StaticString) extern "C" void SWIFT_REMOTEAST_TEST_ABI LLVM_ATTRIBUTE_USED printTypeMemberOffset(const Metadata *typeMetadata, const char *memberName) { printMemberOffset(typeMetadata, memberName, /*pass metadata*/ false); } // FIXME: swiftcall /// func printTypeMetadataMemberOffset(forType: Any.Type, /// memberName: StaticString) extern "C" void SWIFT_REMOTEAST_TEST_ABI LLVM_ATTRIBUTE_USED printTypeMetadataMemberOffset(const Metadata *typeMetadata, const char *memberName) { printMemberOffset(typeMetadata, memberName, /*pass metadata*/ true); } // FIXME: swiftcall /// func printDynamicTypeAndAddressForExistential(_: T) extern "C" void SWIFT_REMOTEAST_TEST_ABI LLVM_ATTRIBUTE_USED printDynamicTypeAndAddressForExistential(void *object, const Metadata *typeMetadata) { auto &remoteAST = getRemoteASTContext(); auto &out = llvm::outs(); // First, retrieve the static type of the existential, so we can understand // which kind of existential this is. auto staticTypeResult = remoteAST.getTypeForRemoteTypeMetadata(RemoteAddress(typeMetadata)); if (!staticTypeResult) { out << "failed to resolve static type: " << staticTypeResult.getFailure().render() << '\n'; return; } // OK, we can reconstruct the dynamic type and the address now. auto result = remoteAST.getDynamicTypeAndAddressForExistential( RemoteAddress(object), staticTypeResult.getValue()); if (result) { out << "found type: "; result.getValue().InstanceType.print(out); out << "\n"; } else { out << result.getFailure().render() << '\n'; } } // FIXME: swiftcall /// func stopRemoteAST(_: AnyObject) extern "C" void SWIFT_REMOTEAST_TEST_ABI LLVM_ATTRIBUTE_USED stopRemoteAST() { if (remoteContext) remoteContext.reset(); } namespace { struct Observer : public FrontendObserver { void configuredCompiler(CompilerInstance &instance) override { context = &instance.getASTContext(); } }; } // end anonymous namespace int main(int argc, const char *argv[]) { PROGRAM_START(argc, argv); unsigned numForwardedArgs = argc - 1 // we drop argv[0] + 1; // -interpret SmallVector forwardedArgs; forwardedArgs.reserve(numForwardedArgs); forwardedArgs.append(&argv[1], &argv[argc]); forwardedArgs.push_back("-interpret"); assert(forwardedArgs.size() == numForwardedArgs); Observer observer; return performFrontend(forwardedArgs, argv[0], (void*) &printMetadataType, &observer); }