blob: 3293b90df6bad1974d37d88b1a1f9ad68e416ec1 [file] [log] [blame]
//===--- swift-reflection-test.c - Reflection testing application ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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.
//===----------------------------------------------------------------------===//
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define SECTIONS_PER_INFO 6
#include "swift/SwiftRemoteMirror/SwiftRemoteMirror.h"
#include "swift/Demangling/ManglingMacros.h"
#include "messages.h"
#include "overrides.h"
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#elif defined(_WIN32)
#include <io.h>
#include <fcntl.h>
#endif
#if defined(__APPLE__) && defined(__MACH__)
#include <TargetConditionals.h>
#endif
#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
#endif
#if defined(__clang__) || defined(__GNUC__)
#define NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define NORETURN __declspec(noreturn)
#else
#define NORETURN
#endif
typedef struct PipeMemoryReader {
int to_child[2];
int from_child[2];
} PipeMemoryReader;
NORETURN
static void errorAndExit(const char *message) {
fprintf(stderr, "%s\n", message);
abort();
}
NORETURN
static void errnoAndExit(const char *message) {
fprintf(stderr, "%s: %s\n", message, strerror(errno));
abort();
}
#if 0
#include <inttypes.h>
#define DEBUG_LOG(fmt, ...) fprintf(stderr, "%s: " fmt "\n",\
__func__, __VA_ARGS__)
#else
#define DEBUG_LOG(fmt, ...) (void)0
#endif
static const size_t ReadEnd = 0;
static const size_t WriteEnd = 1;
static
int PipeMemoryReader_getParentReadFD(const PipeMemoryReader *Reader) {
return Reader->from_child[ReadEnd];
}
static
int PipeMemoryReader_getChildWriteFD(const PipeMemoryReader *Reader) {
return Reader->from_child[WriteEnd];
}
static
int PipeMemoryReader_getParentWriteFD(const PipeMemoryReader *Reader) {
return Reader->to_child[WriteEnd];
}
static
int PipeMemoryReader_getChildReadFD(const PipeMemoryReader *Reader) {
return Reader->to_child[ReadEnd];
}
static
uint8_t PipeMemoryReader_getPointerSize(void *Context) {
return sizeof(uintptr_t);
}
static
void PipeMemoryReader_collectBytesFromPipe(const PipeMemoryReader *Reader,
void *Dest, size_t Size) {
int ReadFD = PipeMemoryReader_getParentReadFD(Reader);
while (Size) {
int bytesRead = read(ReadFD, Dest, Size);
if (bytesRead < 0)
if (errno == EINTR)
continue;
else
errnoAndExit("collectBytesFromPipe");
else if (bytesRead == 0)
errorAndExit("collectBytesFromPipe: Unexpected end of file");
Size -= bytesRead;
// Arithmetic on a void pointer is a GNU extension.
Dest = (char*)(Dest) + bytesRead;
}
}
static int PipeMemoryReader_queryDataLayout(void *Context,
DataLayoutQueryType type,
void *inBuffer, void *outBuffer) {
#if defined(__APPLE__) && __APPLE__
int applePlatform = 1;
#else
int applePlatform = 0;
#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__))
int iosDerivedPlatform = 1;
#else
int iosDerivedPlatform = 0;
#endif
switch (type) {
case DLQ_GetPointerSize: {
uint8_t *result = (uint8_t *)outBuffer;
*result = sizeof(void *);
return 1;
}
case DLQ_GetSizeSize: {
uint8_t *result = (uint8_t *)outBuffer;
*result = sizeof(size_t);
return 1;
}
case DLQ_GetPtrAuthMask: {
uintptr_t *result = (uintptr_t *)outBuffer;
#if __has_feature(ptrauth_calls)
*result = (uintptr_t)ptrauth_strip((void*)0x0007ffffffffffff, 0);
#else
*result = (uintptr_t)~0ull;
#endif
return 1;
}
case DLQ_GetObjCReservedLowBits: {
uint8_t *result = (uint8_t *)outBuffer;
if (applePlatform && !iosDerivedPlatform && (sizeof(void *) == 8)) {
// Only for 64-bit macOS (not iOS, not even when simulated on x86_64)
*result = 1;
} else {
*result = 0;
}
return 1;
}
case DLQ_GetLeastValidPointerValue: {
uint64_t *result = (uint64_t *)outBuffer;
if (applePlatform && (sizeof(void *) == 8)) {
// Swift reserves the first 4GiB on Apple 64-bit platforms
*result = 0x100000000;
return 1;
} else {
// Swift reserves the first 4KiB everywhere else
*result = 0x1000;
}
return 1;
}
}
return 0;
}
static void PipeMemoryReader_freeBytes(void *reader_context, const void *bytes,
void *context) {
free((void *)bytes);
}
static
const void *PipeMemoryReader_readBytes(void *Context, swift_addr_t Address,
uint64_t Size, void **outFreeContext) {
const PipeMemoryReader *Reader = (const PipeMemoryReader *)Context;
uintptr_t TargetAddress = Address;
size_t TargetSize = (size_t)Size;
DEBUG_LOG("Requesting read of %zu bytes from 0x%" PRIxPTR,
TargetSize, TargetAddress);
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
write(WriteFD, REQUEST_READ_BYTES, 2);
write(WriteFD, &TargetAddress, sizeof(TargetAddress));
write(WriteFD, &TargetSize, sizeof(size_t));
void *Buf = malloc(Size);
PipeMemoryReader_collectBytesFromPipe(Reader, Buf, Size);
*outFreeContext = NULL;
return Buf;
}
static
swift_addr_t PipeMemoryReader_getSymbolAddress(void *Context,
const char *SymbolName,
uint64_t Length) {
const PipeMemoryReader *Reader = (const PipeMemoryReader *)Context;
uintptr_t Address = 0;
DEBUG_LOG("Requesting address of symbol %s", SymbolName);
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
write(WriteFD, REQUEST_SYMBOL_ADDRESS, 2);
write(WriteFD, SymbolName, Length);
write(WriteFD, "\n", 1);
PipeMemoryReader_collectBytesFromPipe(Reader, (uint8_t*)&Address,
sizeof(Address));
DEBUG_LOG("Address of %s is 0x%" PRIxPTR, SymbolName, Address);
return (uintptr_t)Address;
}
static InstanceKind
PipeMemoryReader_receiveInstanceKind(const PipeMemoryReader *Reader) {
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
write(WriteFD, REQUEST_INSTANCE_KIND, 2);
uint8_t KindValue = 0;
PipeMemoryReader_collectBytesFromPipe(Reader, &KindValue, sizeof(KindValue));
DEBUG_LOG("Requested instance kind is %u", KindValue);
return KindValue;
}
static uintptr_t
PipeMemoryReader_receiveInstanceAddress(const PipeMemoryReader *Reader) {
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
write(WriteFD, REQUEST_INSTANCE_ADDRESS, 2);
uintptr_t InstanceAddress = 0;
PipeMemoryReader_collectBytesFromPipe(Reader, (uint8_t *)&InstanceAddress,
sizeof(InstanceAddress));
DEBUG_LOG("Requested instance address is 0x%" PRIxPTR, InstanceAddress);
return InstanceAddress;
}
static
void PipeMemoryReader_sendDoneMessage(const PipeMemoryReader *Reader) {
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
write(WriteFD, REQUEST_DONE, 2);
}
static
PipeMemoryReader createPipeMemoryReader() {
PipeMemoryReader Reader;
#if defined(_WIN32)
if (_pipe(Reader.to_child, 256, _O_BINARY))
errnoAndExit("Couldn't create pipes to child process");
if (_pipe(Reader.from_child, 256, _O_BINARY))
errnoAndExit("Couldn't create pipes from child process");
#else
if (pipe(Reader.to_child))
errnoAndExit("Couldn't create pipes to child process");
if (pipe(Reader.from_child))
errnoAndExit("Couldn't create pipes from child process");
#endif
return Reader;
}
#if defined(__APPLE__) && defined(__MACH__)
static void
PipeMemoryReader_receiveImages(SwiftReflectionContextRef RC,
const PipeMemoryReader *Reader) {
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
write(WriteFD, REQUEST_IMAGES, 2);
size_t NumReflectionInfos;
PipeMemoryReader_collectBytesFromPipe(Reader, &NumReflectionInfos,
sizeof(NumReflectionInfos));
DEBUG_LOG("Receiving %z images from child", NumReflectionInfos);
if (NumReflectionInfos == 0)
return;
struct { uintptr_t Start, Size; } *Images;
Images = calloc(NumReflectionInfos, sizeof(*Images));
PipeMemoryReader_collectBytesFromPipe(Reader, Images,
NumReflectionInfos * sizeof(*Images));
for (size_t i = 0; i < NumReflectionInfos; ++i) {
DEBUG_LOG("Adding image at 0x%" PRIxPTR, Images[i].Start);
swift_reflection_addImage(RC, Images[i].Start);
}
free(Images);
}
#else
static swift_reflection_section_t
makeLocalSection(const void *Buffer,
swift_remote_reflection_section_t Section) {
if (Section.Size == 0) {
swift_reflection_section_t LS = {NULL, NULL};
return LS;
}
swift_reflection_section_t LS = {(void *)Buffer,
(void *)(Buffer + Section.Size)};
return LS;
}
static swift_reflection_mapping_info_t makeNonContiguousReflectionInfo(
swift_remote_reflection_section_t *remote_sections,
swift_reflection_section_t *local_sections) {
swift_reflection_section_mapping_t sections[SECTIONS_PER_INFO];
for (size_t i = 0; i < SECTIONS_PER_INFO; ++i) {
swift_reflection_section_mapping_t section = {local_sections[i],
remote_sections[i]};
sections[i] = section;
}
swift_reflection_mapping_info_t ReflectionMappingInfo = {
sections[0], sections[1], sections[2],
sections[3], sections[4], sections[5]};
return ReflectionMappingInfo;
}
static swift_remote_reflection_section_t
makeRemoteSection(const PipeMemoryReader *Reader) {
uintptr_t Start;
size_t Size;
PipeMemoryReader_collectBytesFromPipe(Reader, &Start, sizeof(Start));
PipeMemoryReader_collectBytesFromPipe(Reader, &Size, sizeof(Size));
swift_remote_reflection_section_t RS = {Start, Size};
DEBUG_LOG("Making remote section with Start = 0x%" PRIxPTR
" End = 0x%" PRIxPTR " and Size = %lu",
RS.StartAddress, RS.StartAddress + RS.Size, RS.Size);
return RS;
}
static const void *PipeMemoryReader_readRemoteSection(
const PipeMemoryReader *Reader,
swift_remote_reflection_section_t *RemoteSection, void **outFreeContext) {
const void *Buffer =
PipeMemoryReader_readBytes((void *)Reader, RemoteSection->StartAddress,
RemoteSection->Size, outFreeContext);
if (!Buffer)
errorAndExit("Couldn't read reflection information");
return Buffer;
}
static void
PipeMemoryReader_receiveReflectionInfo(SwiftReflectionContextRef RC,
const PipeMemoryReader *Reader) {
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
write(WriteFD, REQUEST_REFLECTION_INFO, 2);
size_t NumReflectionInfos;
PipeMemoryReader_collectBytesFromPipe(Reader, &NumReflectionInfos,
sizeof(NumReflectionInfos));
if (NumReflectionInfos == 0)
return;
swift_remote_reflection_section_t *RemoteSections =
calloc(NumReflectionInfos * SECTIONS_PER_INFO,
sizeof(swift_remote_reflection_section_t));
if (RemoteSections == NULL)
errnoAndExit("malloc failed");
// We first read all remote reflection sections, there are 6 for every
// complete reflection info.
// They come ordered as: fieldmd, assocty, builtin, capture, typeref, reflstr.
for (size_t i = 0; i < NumReflectionInfos * SECTIONS_PER_INFO; ++i) {
RemoteSections[i] = makeRemoteSection(Reader);
}
// Now pull in the remote sections into our address space.
swift_reflection_section_t *LocalSections =
calloc(NumReflectionInfos * SECTIONS_PER_INFO,
sizeof(swift_reflection_section_t));
for (size_t i = 0; i < NumReflectionInfos * SECTIONS_PER_INFO; ++i) {
void *outFreeContext = NULL;
const void *Buffer = PipeMemoryReader_readRemoteSection(
(void *)Reader, &RemoteSections[i], &outFreeContext);
LocalSections[i] = makeLocalSection(Buffer, RemoteSections[i]);
}
// Finally, we zip them in a complete reflection info, with a stride of 6.
for (size_t i = 0; i < NumReflectionInfos * SECTIONS_PER_INFO;
i += SECTIONS_PER_INFO) {
swift_reflection_mapping_info_t Info =
makeNonContiguousReflectionInfo(&RemoteSections[i], &LocalSections[i]);
swift_reflection_addReflectionMappingInfo(RC, Info);
}
free(RemoteSections);
free(LocalSections);
}
#endif
uint64_t PipeMemoryReader_getStringLength(void *Context, swift_addr_t Address) {
const PipeMemoryReader *Reader = (const PipeMemoryReader *)Context;
int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
uintptr_t TargetAddress = (uintptr_t)Address;
write(WriteFD, REQUEST_STRING_LENGTH, 2);
write(WriteFD, &TargetAddress, sizeof(TargetAddress));
uintptr_t Length = 0;
PipeMemoryReader_collectBytesFromPipe(Reader, &Length, sizeof(Length));
return Length;
}
int reflectHeapObject(SwiftReflectionContextRef RC,
const PipeMemoryReader Pipe) {
uintptr_t instance = PipeMemoryReader_receiveInstanceAddress(&Pipe);
if (instance == 0) {
// Child has no more instances to examine
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
printf("Instance pointer in child address space: 0x%lx\n",
instance);
swift_typeref_t TR = swift_reflection_typeRefForInstance(RC, instance);
printf("Type reference:\n");
swift_reflection_dumpTypeRef(TR);
printf("\n");
printf("Type info:\n");
swift_reflection_dumpInfoForInstance(RC, instance);
printf("\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 1;
}
int reflectExistential(SwiftReflectionContextRef RC,
const PipeMemoryReader Pipe,
swift_typeref_t MockExistentialTR) {
uintptr_t instance = PipeMemoryReader_receiveInstanceAddress(&Pipe);
if (instance == 0) {
// Child has no more instances to examine
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
printf("Instance pointer in child address space: 0x%lx\n",
instance);
swift_typeref_t InstanceTypeRef;
swift_addr_t StartOfInstanceData = 0;
if (!swift_reflection_projectExistential(RC, instance, MockExistentialTR,
&InstanceTypeRef,
&StartOfInstanceData)) {
printf("swift_reflection_projectExistential failed.\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
printf("Type reference:\n");
swift_reflection_dumpTypeRef(InstanceTypeRef);
printf("\n");
printf("Type info:\n");
swift_reflection_dumpInfoForTypeRef(RC, InstanceTypeRef);
printf("\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 1;
}
int reflectEnum(SwiftReflectionContextRef RC,
const PipeMemoryReader Pipe) {
static const char Name[] = MANGLING_PREFIX_STR "ypD";
swift_typeref_t AnyTR
= swift_reflection_typeRefForMangledTypeName(
RC, Name, sizeof(Name)-1);
uintptr_t AnyInstance = PipeMemoryReader_receiveInstanceAddress(&Pipe);
if (AnyInstance == 0) {
// Child has no more instances to examine
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
swift_typeref_t EnumTypeRef;
swift_addr_t EnumInstance = 0;
if (!swift_reflection_projectExistential(RC, AnyInstance, AnyTR,
&EnumTypeRef,
&EnumInstance)) {
printf("swift_reflection_projectExistential failed.\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
printf("Instance pointer in child address space: 0x%lx\n",
(uintptr_t)EnumInstance);
printf("Type reference:\n");
swift_reflection_dumpTypeRef(EnumTypeRef);
printf("\n");
printf("Type info:\n");
swift_reflection_dumpInfoForTypeRef(RC, EnumTypeRef);
printf("\n");
printf("Enum value:\n");
swift_typeinfo_t InstanceTypeInfo = swift_reflection_infoForTypeRef(RC, EnumTypeRef);
if (InstanceTypeInfo.Kind != SWIFT_NO_PAYLOAD_ENUM
&& InstanceTypeInfo.Kind != SWIFT_SINGLE_PAYLOAD_ENUM
&& InstanceTypeInfo.Kind != SWIFT_MULTI_PAYLOAD_ENUM) {
// Enums with a single payload case and no non-payload cases
// can get rewritten by the compiler to just the payload
// type.
swift_reflection_dumpInfoForTypeRef(RC, EnumTypeRef);
PipeMemoryReader_sendDoneMessage(&Pipe);
return 1;
}
int CaseIndex;
if (!swift_reflection_projectEnumValue(RC, EnumInstance, EnumTypeRef, &CaseIndex)) {
printf("swift_reflection_projectEnumValue failed.\n\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 1; // <<< Test cases also verify failures, so this must "succeed"
}
if ((unsigned)CaseIndex > InstanceTypeInfo.NumFields) {
printf("swift_reflection_projectEnumValue returned invalid case.\n\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
swift_childinfo_t CaseInfo
= swift_reflection_childOfTypeRef(RC, EnumTypeRef, CaseIndex);
if (CaseInfo.TR == 0) {
// Enum case has no payload
printf("(enum_value name=%s index=%llu)\n",
CaseInfo.Name, (unsigned long long)CaseIndex);
} else {
printf("(enum_value name=%s index=%llu\n",
CaseInfo.Name, (unsigned long long)CaseIndex);
swift_reflection_dumpTypeRef(CaseInfo.TR);
printf(")\n");
}
printf("\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 1;
}
int reflectEnumValue(SwiftReflectionContextRef RC,
const PipeMemoryReader Pipe) {
static const char Name[] = MANGLING_PREFIX_STR "ypD";
swift_typeref_t AnyTR
= swift_reflection_typeRefForMangledTypeName(
RC, Name, sizeof(Name)-1);
uintptr_t AnyInstance = PipeMemoryReader_receiveInstanceAddress(&Pipe);
if (AnyInstance == 0) {
// Child has no more instances to examine
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
swift_typeref_t EnumTypeRef;
swift_addr_t EnumInstance = 0;
if (!swift_reflection_projectExistential(RC, AnyInstance, AnyTR,
&EnumTypeRef,
&EnumInstance)) {
printf("swift_reflection_projectExistential failed.\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
printf("Type reference:\n");
swift_reflection_dumpTypeRef(EnumTypeRef);
printf("Value: ");
int parens = 0;
while (EnumTypeRef != 0) {
swift_typeinfo_t EnumTypeInfo = swift_reflection_infoForTypeRef(RC, EnumTypeRef);
if (EnumTypeInfo.Kind != SWIFT_NO_PAYLOAD_ENUM
&& EnumTypeInfo.Kind != SWIFT_SINGLE_PAYLOAD_ENUM
&& EnumTypeInfo.Kind != SWIFT_MULTI_PAYLOAD_ENUM) {
if (parens == 0) {
printf(".??"); // Enum was optimized away, print "something"
} else {
printf("_");
}
break;
}
int CaseIndex;
if (!swift_reflection_projectEnumValue(RC, EnumInstance, EnumTypeRef, &CaseIndex)) {
printf("swift_reflection_projectEnumValue failed.\n\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 1; // <<< Test cases rely on detecting this, so must "succeed"
}
if ((unsigned)CaseIndex > EnumTypeInfo.NumFields) {
printf("swift_reflection_projectEnumValue returned invalid case.\n\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 0;
}
swift_childinfo_t CaseInfo
= swift_reflection_childOfTypeRef(RC, EnumTypeRef, CaseIndex);
printf(".%s", CaseInfo.Name);
EnumTypeRef = CaseInfo.TR;
if (EnumTypeRef != 0) {
printf("(");
parens += 1;
}
}
for (int i = 0; i < parens; ++i) {
printf(")");
}
printf("\n\n");
PipeMemoryReader_sendDoneMessage(&Pipe);
return 1;
}
int doDumpHeapInstance(const char *BinaryFilename) {
PipeMemoryReader Pipe = createPipeMemoryReader();
#if defined(_WIN32)
#else
pid_t pid = _fork();
switch (pid) {
case -1:
errnoAndExit("Couldn't fork child process");
case 0: { // Child:
close(PipeMemoryReader_getParentWriteFD(&Pipe));
close(PipeMemoryReader_getParentReadFD(&Pipe));
dup2(PipeMemoryReader_getChildReadFD(&Pipe), STDIN_FILENO);
dup2(PipeMemoryReader_getChildWriteFD(&Pipe), STDOUT_FILENO);
_execv(BinaryFilename, NULL);
exit(EXIT_SUCCESS);
}
default: { // Parent
close(PipeMemoryReader_getChildReadFD(&Pipe));
close(PipeMemoryReader_getChildWriteFD(&Pipe));
SwiftReflectionContextRef RC =
swift_reflection_createReflectionContextWithDataLayout(
(void *)&Pipe, PipeMemoryReader_queryDataLayout,
PipeMemoryReader_freeBytes, PipeMemoryReader_readBytes,
PipeMemoryReader_getStringLength,
PipeMemoryReader_getSymbolAddress);
uint8_t PointerSize = PipeMemoryReader_getPointerSize((void*)&Pipe);
if (PointerSize != sizeof(uintptr_t))
errorAndExit("Child process had unexpected architecture");
#if defined(__APPLE__) && defined(__MACH__)
PipeMemoryReader_receiveImages(RC, &Pipe);
#else
PipeMemoryReader_receiveReflectionInfo(RC, &Pipe);
#endif
while (1) {
InstanceKind Kind = PipeMemoryReader_receiveInstanceKind(&Pipe);
switch (Kind) {
case Object:
printf("Reflecting an object.\n");
if (!reflectHeapObject(RC, Pipe))
return EXIT_SUCCESS;
break;
case Existential: {
static const char Name[] = MANGLING_PREFIX_STR "ypD";
swift_typeref_t AnyTR
= swift_reflection_typeRefForMangledTypeName(RC,
Name, sizeof(Name)-1);
printf("Reflecting an existential.\n");
if (!reflectExistential(RC, Pipe, AnyTR))
return EXIT_SUCCESS;
break;
}
case ErrorExistential: {
static const char ErrorName[] = MANGLING_PREFIX_STR "s5Error_pD";
swift_typeref_t ErrorTR
= swift_reflection_typeRefForMangledTypeName(RC,
ErrorName, sizeof(ErrorName)-1);
printf("Reflecting an error existential.\n");
if (!reflectExistential(RC, Pipe, ErrorTR))
return EXIT_SUCCESS;
break;
}
case Closure:
printf("Reflecting a closure.\n");
if (!reflectHeapObject(RC, Pipe))
return EXIT_SUCCESS;
break;
case Enum: {
printf("Reflecting an enum.\n");
if (!reflectEnum(RC, Pipe))
return EXIT_SUCCESS;
break;
}
case EnumValue: {
printf("Reflecting an enum value.\n");
if (!reflectEnumValue(RC, Pipe))
return EXIT_SUCCESS;
break;
}
case None:
swift_reflection_destroyReflectionContext(RC);
printf("Done.\n");
return EXIT_SUCCESS;
}
}
}
}
#endif
return EXIT_SUCCESS;
}
#if defined(__APPLE__) && defined(__MACH__)
#include <dlfcn.h>
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
void printUsageAndExit() {
fprintf(stderr, "swift-reflection-test <binary filename>\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
if (argc != 2)
printUsageAndExit();
const char *BinaryFilename = argv[1];
#if defined(_WIN32)
// FIXME(compnerd) weak linking is not permitted on PE/COFF, we should fall
// back to GetProcAddress to see if the symbol is present.
#else
// swift_reflection_classIsSwiftMask is weak linked so we can work
// with older Remote Mirror dylibs.
if (&swift_reflection_classIsSwiftMask != NULL)
swift_reflection_classIsSwiftMask = computeClassIsSwiftMask();
#endif
uint16_t Version = swift_reflection_getSupportedMetadataVersion();
printf("Metadata version: %u\n", Version);
return doDumpHeapInstance(BinaryFilename);
}