diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index 5321c195c55db..232b1359a9788 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -40,6 +40,9 @@ set(swift_runtime_sources ErrorDefaultImpls.cpp Heap.cpp HeapObject.cpp + ImageInspectionMachO.cpp + ImageInspectionELF.cpp + ImageInspectionWin32.cpp KnownMetadata.cpp Metadata.cpp MetadataLookup.cpp diff --git a/stdlib/public/runtime/CygwinPort.cpp b/stdlib/public/runtime/CygwinPort.cpp index e7ddcfe828cda..80403ac99aae3 100644 --- a/stdlib/public/runtime/CygwinPort.cpp +++ b/stdlib/public/runtime/CygwinPort.cpp @@ -32,112 +32,6 @@ using namespace swift; static std::mutex swiftOnceMutex; -int swift::_swift_dl_iterate_phdr(int (*Callback)(struct dl_phdr_info *info, - size_t size, void *data), - void *data) { - DWORD procId = GetCurrentProcessId(); - HANDLE procHandle = - OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, procId); - if (!procHandle) { - swift::fatalError(/* flags = */ 0, "OpenProcess() failed"); - return 0; - } - - int lastRet = 0; - - std::vector modules(1024); - DWORD neededSize; - - BOOL ret = EnumProcessModules(procHandle, modules.data(), - modules.size() * sizeof(HMODULE), &neededSize); - - if (!ret) { - swift::fatalError(/* flags = */ 0, "EnumProcessModules() failed"); - return 0; - } - - if (modules.size() * sizeof(HMODULE) < neededSize) { - modules.resize(neededSize / sizeof(HMODULE)); - ret = EnumProcessModules(procHandle, modules.data(), - modules.size() * sizeof(HMODULE), &neededSize); - } - - if (!ret) { - swift::fatalError(/* flags = */ 0, "EnumProcessModules() failed"); - return 0; - } - - for (unsigned i = 0; i < neededSize / sizeof(HMODULE); i++) { - char modName[MAX_PATH]; - - if (!GetModuleFileNameExA(procHandle, modules[i], modName, - sizeof(modName))) { - swift::fatalError(/* flags = */ 0, "GetModuleFileNameExA() failed"); - } - - dl_phdr_info hdr; - hdr.dlpi_name = modName; - hdr.dlpi_addr = modules[i]; - - lastRet = Callback(&hdr, sizeof(hdr), data); - if (lastRet != 0) - break; - } - - CloseHandle(procHandle); - - return lastRet; -} - -uint8_t *swift::_swift_getSectionDataPE(void *handle, const char *sectionName, - unsigned long *sectionSize) { - // In Cygwin, dlopen() returns PE/COFF image pointer. - // This is relying on undocumented feature of Windows API LoadLibrary(). - unsigned char *peStart = (unsigned char *)handle; - - const int kLocationOfNtHeaderOffset = 0x3C; - int ntHeadersOffset = - *reinterpret_cast(peStart + kLocationOfNtHeaderOffset); - - bool assert1 = - peStart[ntHeadersOffset] == 'P' && peStart[ntHeadersOffset + 1] == 'E'; - if (!assert1) { - swift::fatalError(/* flags = */ 0, "_swift_getSectionDataPE()'s finding PE failed"); - } - - unsigned char *coff = peStart + ntHeadersOffset + 4; - - int16_t numberOfSections = *(int16_t *)(coff + 2); - - // SizeOfOptionalHeader - int16_t sizeOfOptionalHeader = *(int16_t *)(coff + 16); - - const int kCoffFileHeaderSize = 20; - unsigned char *sectionTableBase = - coff + kCoffFileHeaderSize + sizeOfOptionalHeader; - - // Section Header Record - const int kSectionRecordSize = 40; - - unsigned char *sectionHeader = sectionTableBase; - for (int i = 0; i < numberOfSections; i++) { - uint32_t virtualSize = *(uint32_t *)§ionHeader[8]; - uint32_t virtualAddress = *(uint32_t *)§ionHeader[12]; - - char nameOfThisSection[9]; - memcpy(nameOfThisSection, sectionHeader, 8); - nameOfThisSection[8] = '\0'; - - if (strcmp(sectionName, nameOfThisSection) == 0) { - *sectionSize = virtualSize; - return (uint8_t *)handle + virtualAddress; - } - sectionHeader += kSectionRecordSize; - } - - return nullptr; -} - #if !defined(_MSC_VER) void swift::_swift_once_f(uintptr_t *predicate, void *context, void (*function)(void *)) { diff --git a/stdlib/public/runtime/ImageInspection.h b/stdlib/public/runtime/ImageInspection.h new file mode 100644 index 0000000000000..2eb6931f0c991 --- /dev/null +++ b/stdlib/public/runtime/ImageInspection.h @@ -0,0 +1,42 @@ +//===--- ImageInspection.h - Image inspection routines --------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file includes routines that extract metadata from executable and +// dynamic library image files generated by the Swift compiler. The +// concrete implementations vary greatly by platform. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_RUNTIME_IMAGE_INSPECTION_H +#define SWIFT_RUNTIME_IMAGE_INSPECTION_H + +#include + +namespace swift { + +/// Load the metadata from the image necessary to find a type's +/// protocol conformance. +void initializeProtocolConformanceLookup(); + +/// Load the metadata from the image necessary to find a type by name. +void initializeTypeMetadataRecordLookup(); + +// Callbacks to register metadata from an image to the runtime. + +void addImageProtocolConformanceBlockCallback(const void *start, + uintptr_t size); +void addImageTypeMetadataRecordBlockCallback(const void *start, + uintptr_t size); + +} // end namespace swift + +#endif // SWIFT_RUNTIME_IMAGE_INSPECTION_H diff --git a/stdlib/public/runtime/ImageInspectionELF.cpp b/stdlib/public/runtime/ImageInspectionELF.cpp new file mode 100644 index 0000000000000..e09be02e599f4 --- /dev/null +++ b/stdlib/public/runtime/ImageInspectionELF.cpp @@ -0,0 +1,101 @@ +//===--- ImageInspectionELFDynamic.cpp - ELF image inspection -------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file includes routines that interact with ld*.so on ELF-based platforms +// to extract runtime metadata embedded in dynamically linked ELF images +// generated by the Swift compiler. +// +//===----------------------------------------------------------------------===// + +#if defined(__ELF__) || defined(__ANDROID__) + +#include "ImageInspection.h" +#include +#include +#include +#include + +using namespace swift; + +/// The symbol name in the image that identifies the beginning of the +/// protocol conformances table. +static const char ProtocolConformancesSymbol[] = + ".swift2_protocol_conformances_start"; +/// The symbol name in the image that identifies the beginning of the +/// type metadata record table. +static const char TypeMetadataRecordsSymbol[] = + ".swift2_type_metadata_start"; + +/// Context arguments passed down from dl_iterate_phdr to its callback. +struct InspectArgs { + /// Symbol name to look up. + const char *symbolName; + /// Callback function to invoke with the metadata block. + void (*addBlock)(const void *start, uintptr_t size); +}; + +static int iteratePHDRCallback(struct dl_phdr_info *info, + size_t size, void *data) { + const InspectArgs *inspectArgs = reinterpret_cast(data); + void *handle; + if (!info->dlpi_name || info->dlpi_name[0] == '\0') { + handle = dlopen(nullptr, RTLD_LAZY); + } else { + handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); + } + + if (!handle) { + // Not a shared library. + return 0; + } + + const char *conformances = + reinterpret_cast(dlsym(handle, inspectArgs->symbolName)); + + if (!conformances) { + // if there are no conformances, don't hold this handle open. + dlclose(handle); + return 0; + } + + // Extract the size of the conformances block from the head of the section. + uint64_t conformancesSize; + memcpy(&conformancesSize, conformances, sizeof(conformancesSize)); + conformances += sizeof(conformancesSize); + + inspectArgs->addBlock(conformances, conformancesSize); + + dlclose(handle); + return 0; +} + +void swift::initializeProtocolConformanceLookup() { + // Search the loaded dls. This only searches the already + // loaded ones. + // FIXME: Find a way to have this continue to happen for dlopen-ed images. + // rdar://problem/19045112 + InspectArgs ProtocolConformanceArgs = { + ProtocolConformancesSymbol, + addImageProtocolConformanceBlockCallback + }; + dl_iterate_phdr(iteratePHDRCallback, &ProtocolConformanceArgs); +} + +void swift::initializeTypeMetadataRecordLookup() { + InspectArgs TypeMetadataRecordArgs = { + TypeMetadataRecordsSymbol, + addImageTypeMetadataRecordBlockCallback + }; + dl_iterate_phdr(iteratePHDRCallback, &TypeMetadataRecordArgs); +} + +#endif // defined(__ELF__) || defined(__ANDROID__) diff --git a/stdlib/public/runtime/ImageInspectionMachO.cpp b/stdlib/public/runtime/ImageInspectionMachO.cpp new file mode 100644 index 0000000000000..54a3ff5f5c009 --- /dev/null +++ b/stdlib/public/runtime/ImageInspectionMachO.cpp @@ -0,0 +1,73 @@ +//===--- ImageInspectionMachO.cpp - Mach-O image inspection ---------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file includes routines that interact with dyld on Mach-O-based platforms +// to extract runtime metadata embedded in images generated by the Swift +// compiler. +// +//===----------------------------------------------------------------------===// + +#if defined(__APPLE__) && defined(__MACH__) + +#include "ImageInspection.h" +#include +#include +#include + +using namespace swift; + +namespace { +/// The Mach-O section name for the section containing protocol conformances. +/// This lives within SEG_TEXT. +constexpr const char ProtocolConformancesSection[] = "__swift2_proto"; +/// The Mach-O section name for the section containing type references. +/// This lives within SEG_TEXT. +constexpr const char TypeMetadataRecordSection[] = "__swift2_types"; + +template +void addImageCallback(const mach_header *mh, intptr_t vmaddr_slide) { +#ifdef __LP64__ + using mach_header_platform = mach_header_64; + assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); +#else + using mach_header_platform = mach_header; +#endif + + // Look for a __swift2_proto section. + unsigned long size; + const uint8_t *section = + getsectiondata(reinterpret_cast(mh), + SEG_TEXT, SECTION_NAME, + &size); + + if (!section) + return; + + CONSUME_BLOCK(section, size); +} + +} // end anonymous namespace + +void swift::initializeProtocolConformanceLookup() { + _dyld_register_func_for_add_image( + addImageCallback); +} +void swift::initializeTypeMetadataRecordLookup() { + _dyld_register_func_for_add_image( + addImageCallback); + +} + +#endif // defined(__APPLE__) && defined(__MACH__) diff --git a/stdlib/public/runtime/ImageInspectionWin32.cpp b/stdlib/public/runtime/ImageInspectionWin32.cpp new file mode 100644 index 0000000000000..fe912fce8d6f9 --- /dev/null +++ b/stdlib/public/runtime/ImageInspectionWin32.cpp @@ -0,0 +1,219 @@ +//===--- ImageInspectionWin32.cpp - Win32 image inspection ----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file includes routines that interact with the Win32 API on +// Windows platforms to extract runtime metadata embedded in executables and +// DLLs generated by the Swift compiler. +// +//===----------------------------------------------------------------------===// + +#if defined(_MSC_VER) || defined(__CYGWIN__) + +#include "ImageInspection.h" +#include "swift/Runtime/Debug.h" +#include +#include + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#include + +#if defined(__CYGWIN__) +#include +#endif + +using namespace swift; + +/// PE section name for the section that contains protocol conformance records. +static const char ProtocolConformancesSection[] = ".sw2prtc"; +/// PE section name for the section that contains type metadata records. +static const char TypeMetadataRecordsSection[] = ".sw2tymd"; + +/// Context information passed down from _swift_dl_iterate_phdr to the +/// callback function. +struct InspectArgs { + void (*fnAddImageBlock)(const void *, uintptr_t); + const char *sectionName; +}; + +struct _swift_dl_phdr_info { + void *dlpi_addr; + const char *dlpi_name; +}; + +static int _swift_dl_iterate_phdr(int (*Callback)(struct _swift_dl_phdr_info *info, + size_t size, const void *data), + const void *data) { + DWORD procId = GetCurrentProcessId(); + HANDLE procHandle = + OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, procId); + if (!procHandle) { + swift::fatalError(/* flags = */ 0, "OpenProcess() failed"); + return 0; + } + + int lastRet = 0; + + std::vector modules(1024); + DWORD neededSize; + + BOOL ret = EnumProcessModules(procHandle, modules.data(), + modules.size() * sizeof(HMODULE), &neededSize); + + if (!ret) { + swift::fatalError(/* flags = */ 0, "EnumProcessModules() failed"); + return 0; + } + + if (modules.size() * sizeof(HMODULE) < neededSize) { + modules.resize(neededSize / sizeof(HMODULE)); + ret = EnumProcessModules(procHandle, modules.data(), + modules.size() * sizeof(HMODULE), &neededSize); + } + + if (!ret) { + swift::fatalError(/* flags = */ 0, "EnumProcessModules() failed"); + return 0; + } + + for (unsigned i = 0; i < neededSize / sizeof(HMODULE); i++) { + char modName[MAX_PATH]; + + if (!GetModuleFileNameExA(procHandle, modules[i], modName, + sizeof(modName))) { + swift::fatalError(/* flags = */ 0, "GetModuleFileNameExA() failed"); + } + + _swift_dl_phdr_info hdr; + hdr.dlpi_name = modName; + hdr.dlpi_addr = modules[i]; + + lastRet = Callback(&hdr, sizeof(hdr), data); + if (lastRet != 0) + break; + } + + CloseHandle(procHandle); + + return lastRet; +} + +static uint8_t *_swift_getSectionDataPE(const void *handle, const char *sectionName, + unsigned long *sectionSize) { + // In Cygwin, dlopen() returns PE/COFF image pointer. + // This is relying on undocumented feature of Windows API LoadLibrary(). + unsigned char *peStart = (unsigned char *)handle; + + const int kLocationOfNtHeaderOffset = 0x3C; + int ntHeadersOffset = + *reinterpret_cast(peStart + kLocationOfNtHeaderOffset); + + bool assert1 = + peStart[ntHeadersOffset] == 'P' && peStart[ntHeadersOffset + 1] == 'E'; + if (!assert1) { + swift::fatalError(/* flags = */ 0, "_swift_getSectionDataPE()'s finding PE failed"); + } + + unsigned char *coff = peStart + ntHeadersOffset + 4; + + int16_t numberOfSections = *(int16_t *)(coff + 2); + + // SizeOfOptionalHeader + int16_t sizeOfOptionalHeader = *(int16_t *)(coff + 16); + + const int kCoffFileHeaderSize = 20; + unsigned char *sectionTableBase = + coff + kCoffFileHeaderSize + sizeOfOptionalHeader; + + // Section Header Record + const int kSectionRecordSize = 40; + + unsigned char *sectionHeader = sectionTableBase; + for (int i = 0; i < numberOfSections; i++) { + uint32_t virtualSize = *(uint32_t *)§ionHeader[8]; + uint32_t virtualAddress = *(uint32_t *)§ionHeader[12]; + + char nameOfThisSection[9]; + memcpy(nameOfThisSection, sectionHeader, 8); + nameOfThisSection[8] = '\0'; + + if (strcmp(sectionName, nameOfThisSection) == 0) { + *sectionSize = virtualSize; + return (uint8_t *)handle + virtualAddress; + } + sectionHeader += kSectionRecordSize; + } + + return nullptr; +} + +static int _addImageCallback(struct _swift_dl_phdr_info *info, + size_t size, const void *data) { + const InspectArgs *inspectArgs = (InspectArgs *)data; + // inspectArgs contains addImage*Block function and the section name +#if defined(_MSC_VER) + HMODULE handle; + + if (!info->dlpi_name || info->dlpi_name[0] == '\0') + handle = GetModuleHandle(nullptr); + else + handle = GetModuleHandle(info->dlpi_name); +#else + void *handle; + if (!info->dlpi_name || info->dlpi_name[0] == '\0') + handle = dlopen(nullptr, RTLD_LAZY); + else + handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); +#endif + + unsigned long conformancesSize; + const uint8_t *conformances = + _swift_getSectionDataPE(handle, inspectArgs->sectionName, + &conformancesSize); + + if (conformances) + inspectArgs->fnAddImageBlock(conformances, conformancesSize); + +#if defined(_MSC_VER) + FreeLibrary(handle); +#else + dlclose(handle); +#endif + return 0; +} + +void swift::initializeProtocolConformanceLookup() { + // Search the loaded dls. This only searches the already + // loaded ones. + // FIXME: Find a way to have this continue to happen for dlopen-ed images. + // rdar://problem/19045112 + const InspectArgs ProtocolConformancesArgs = { + ProtocolConformancesSection, + addImageProtocolConformanceBlockCallback + }; + _swift_dl_iterate_phdr(_addImageCallback, &ProtocolConformancesArgs); +} + +void swift::initializeTypeMetadataRecordLookup() { + // Search the loaded dls. This only searches the already + // loaded ones. + // FIXME: Find a way to have this continue to happen for dlopen-ed images. + // rdar://problem/19045112 + const InspectArgs TypeMetadataRecordsArgs = { + TypeMetadataRecordsSection, + addImageTypeMetadataRecordBlockCallback + }; + _swift_dl_iterate_phdr(_addImageCallback, &TypeMetadataRecordsArgs); +} + +#endif // defined(_MSC_VER) || defined(__CYGWIN__) diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 5822a930520c0..825bac2f5f09b 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -25,14 +25,7 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/StringExtras.h" #include "Private.h" - -#if defined(__APPLE__) && defined(__MACH__) -#include -#include -#elif defined(__ELF__) || defined(__ANDROID__) -#include -#include -#endif +#include "ImageInspection.h" using namespace swift; using namespace Demangle; @@ -43,14 +36,6 @@ using namespace Demangle; #include #endif -#if defined(__APPLE__) && defined(__MACH__) -#define SWIFT_TYPE_METADATA_SECTION "__swift2_types" -#elif defined(__ELF__) -#define SWIFT_TYPE_METADATA_SECTION ".swift2_type_metadata_start" -#elif defined(__CYGWIN__) || defined(_MSC_VER) -#define SWIFT_TYPE_METADATA_SECTION ".sw2tymd" -#endif - // Type Metadata Cache. namespace { @@ -89,19 +74,6 @@ namespace { }; } -#if defined(__APPLE__) && defined(__MACH__) -static void _initializeCallbacksToInspectDylib(); -#else -namespace swift { - void _swift_initializeCallbacksToInspectDylib( - void (*fnAddImageBlock)(const uint8_t *, size_t), - const char *sectionName); -} - -static void _addImageTypeMetadataRecordsBlock(const uint8_t *records, - size_t recordsSize); -#endif - struct TypeMetadataState { ConcurrentMap Cache; std::vector SectionsToScan; @@ -109,13 +81,7 @@ struct TypeMetadataState { TypeMetadataState() { SectionsToScan.reserve(16); -#if defined(__APPLE__) && defined(__MACH__) - _initializeCallbacksToInspectDylib(); -#else - _swift_initializeCallbacksToInspectDylib( - _addImageTypeMetadataRecordsBlock, - SWIFT_TYPE_METADATA_SECTION); -#endif + initializeTypeMetadataRecordLookup(); } }; @@ -130,54 +96,26 @@ _registerTypeMetadataRecords(TypeMetadataState &T, T.SectionsToScan.push_back(TypeMetadataSection{begin, end}); } -static void _addImageTypeMetadataRecordsBlock(const uint8_t *records, - size_t recordsSize) { +void swift::addImageTypeMetadataRecordBlockCallback(const void *records, + uintptr_t recordsSize) { assert(recordsSize % sizeof(TypeMetadataRecord) == 0 && "weird-sized type metadata section?!"); // If we have a section, enqueue the type metadata for lookup. + auto recordBytes = reinterpret_cast(records); auto recordsBegin = reinterpret_cast(records); auto recordsEnd - = reinterpret_cast - (records + recordsSize); + = reinterpret_cast(recordBytes + recordsSize); - // type metadata cache should always be sufficiently initialized by this point. + // Type metadata cache should always be sufficiently initialized by this + // point. Attempting to go through get() may also lead to an infinite loop, + // since we register records during the initialization of + // TypeMetadataRecords. _registerTypeMetadataRecords(TypeMetadataRecords.unsafeGetAlreadyInitialized(), recordsBegin, recordsEnd); } -#if defined(__APPLE__) && defined(__MACH__) -static void _addImageTypeMetadataRecords(const mach_header *mh, - intptr_t vmaddr_slide) { -#ifdef __LP64__ - using mach_header_platform = mach_header_64; - assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); -#else - using mach_header_platform = mach_header; -#endif - - // Look for a __swift2_types section. - unsigned long recordsSize; - const uint8_t *records = - getsectiondata(reinterpret_cast(mh), - SEG_TEXT, SWIFT_TYPE_METADATA_SECTION, - &recordsSize); - - if (!records) - return; - - _addImageTypeMetadataRecordsBlock(records, recordsSize); -} - -static void _initializeCallbacksToInspectDylib() { - // Install our dyld callback. - // Dyld will invoke this on our behalf for all images that have already - // been loaded. - _dyld_register_func_for_add_image(_addImageTypeMetadataRecords); -} -#endif - void swift::swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin, const TypeMetadataRecord *end) { diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index 28b16c2bfac9b..c3b09f2add9e2 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -172,18 +172,6 @@ namespace swift { dest = newValue; } -#if defined(__CYGWIN__) || defined(_MSC_VER) - struct dl_phdr_info { - void *dlpi_addr; - const char *dlpi_name; - }; - - int _swift_dl_iterate_phdr(int (*Callback)(struct dl_phdr_info *info, - size_t size, void *data), - void *data); - uint8_t *_swift_getSectionDataPE(void *handle, const char *sectionName, - unsigned long *sectionSize); -#endif #if defined(__CYGWIN__) void _swift_once_f(uintptr_t *predicate, void *context, void (*function)(void *)); diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index 4219a0383476d..b5ace7df20c3d 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -19,23 +19,9 @@ #include "swift/Runtime/Concurrent.h" #include "swift/Runtime/Metadata.h" #include "swift/Runtime/Mutex.h" +#include "ImageInspection.h" #include "Private.h" - -#if defined(__APPLE__) && defined(__MACH__) -#include -#include -#elif defined(__ELF__) || defined(__ANDROID__) -#include -#include -#endif - -#if defined(_MSC_VER) -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#else #include -#endif using namespace swift; @@ -146,14 +132,6 @@ const { } } -#if defined(__APPLE__) && defined(__MACH__) -#define SWIFT_PROTOCOL_CONFORMANCES_SECTION "__swift2_proto" -#elif defined(__ELF__) -#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".swift2_protocol_conformances_start" -#elif defined(__CYGWIN__) || defined(_MSC_VER) -#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".sw2prtc" -#endif - namespace { struct ConformanceSection { const ProtocolConformanceRecord *Begin, *End; @@ -232,19 +210,6 @@ namespace { } // Conformance Cache. -#if defined(__APPLE__) && defined(__MACH__) -static void _initializeCallbacksToInspectDylib(); -#else -namespace swift { - void _swift_initializeCallbacksToInspectDylib( - void (*fnAddImageBlock)(const uint8_t *, size_t), - const char *sectionName); -} - -static void _addImageProtocolConformancesBlock(const uint8_t *conformances, - size_t conformancesSize); -#endif - struct ConformanceState { ConcurrentMap Cache; std::vector SectionsToScan; @@ -252,13 +217,7 @@ struct ConformanceState { ConformanceState() { SectionsToScan.reserve(16); -#if defined(__APPLE__) && defined(__MACH__) - _initializeCallbacksToInspectDylib(); -#else - _swift_initializeCallbacksToInspectDylib( - _addImageProtocolConformancesBlock, - SWIFT_PROTOCOL_CONFORMANCES_SECTION); -#endif + initializeProtocolConformanceLookup(); } void cacheSuccess(const void *type, const ProtocolDescriptor *proto, @@ -300,155 +259,24 @@ _registerProtocolConformances(ConformanceState &C, C.SectionsToScan.push_back(ConformanceSection{begin, end}); } -static void _addImageProtocolConformancesBlock(const uint8_t *conformances, - size_t conformancesSize) { +void swift::addImageProtocolConformanceBlockCallback(const void *conformances, + uintptr_t conformancesSize) { assert(conformancesSize % sizeof(ProtocolConformanceRecord) == 0 && "weird-sized conformances section?!"); // If we have a section, enqueue the conformances for lookup. + auto conformanceBytes = reinterpret_cast(conformances); auto recordsBegin = reinterpret_cast(conformances); auto recordsEnd = reinterpret_cast - (conformances + conformancesSize); + (conformanceBytes + conformancesSize); // Conformance cache should always be sufficiently initialized by this point. _registerProtocolConformances(Conformances.unsafeGetAlreadyInitialized(), recordsBegin, recordsEnd); } -#if !defined(__APPLE__) || !defined(__MACH__) -// Common Structure -struct InspectArgs { - void (*fnAddImageBlock)(const uint8_t *, size_t); - const char *sectionName; -}; -#endif - -#if defined(__APPLE__) && defined(__MACH__) -static void _addImageProtocolConformances(const mach_header *mh, - intptr_t vmaddr_slide) { -#ifdef __LP64__ - using mach_header_platform = mach_header_64; - assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); -#else - using mach_header_platform = mach_header; -#endif - - // Look for a __swift2_proto section. - unsigned long conformancesSize; - const uint8_t *conformances = - getsectiondata(reinterpret_cast(mh), - SEG_TEXT, SWIFT_PROTOCOL_CONFORMANCES_SECTION, - &conformancesSize); - - if (!conformances) - return; - - _addImageProtocolConformancesBlock(conformances, conformancesSize); -} - -static void _initializeCallbacksToInspectDylib() { - // Install our dyld callback. - // Dyld will invoke this on our behalf for all images that have already - // been loaded. - _dyld_register_func_for_add_image(_addImageProtocolConformances); -} - -#elif defined(__ELF__) || defined(__ANDROID__) -static int _addImageProtocolConformances(struct dl_phdr_info *info, - size_t size, void *data) { - // inspectArgs contains addImage*Block function and the section name - InspectArgs *inspectArgs = reinterpret_cast(data); - - void *handle; - if (!info->dlpi_name || info->dlpi_name[0] == '\0') { - handle = dlopen(nullptr, RTLD_LAZY); - } else - handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); - - if (!handle) { - // Not a shared library. - return 0; - } - - auto conformances = reinterpret_cast( - dlsym(handle, inspectArgs->sectionName)); - - if (!conformances) { - // if there are no conformances, don't hold this handle open. - dlclose(handle); - return 0; - } - - // Extract the size of the conformances block from the head of the section - auto conformancesSize = *reinterpret_cast(conformances); - conformances += sizeof(conformancesSize); - - inspectArgs->fnAddImageBlock(conformances, conformancesSize); - - dlclose(handle); - return 0; -} - -void swift::_swift_initializeCallbacksToInspectDylib( - void (*fnAddImageBlock)(const uint8_t *, size_t), - const char *sectionName) { - InspectArgs inspectArgs = {fnAddImageBlock, sectionName}; - - // Search the loaded dls. Unlike the above, this only searches the already - // loaded ones. - // FIXME: Find a way to have this continue to happen after. - // rdar://problem/19045112 - dl_iterate_phdr(_addImageProtocolConformances, &inspectArgs); -} -#elif defined(__CYGWIN__) || defined(_MSC_VER) -static int _addImageProtocolConformances(struct dl_phdr_info *info, - size_t size, void *data) { - InspectArgs *inspectArgs = (InspectArgs *)data; - // inspectArgs contains addImage*Block function and the section name -#if defined(_MSC_VER) - HMODULE handle; - - if (!info->dlpi_name || info->dlpi_name[0] == '\0') - handle = GetModuleHandle(nullptr); - else - handle = GetModuleHandle(info->dlpi_name); -#else - void *handle; - if (!info->dlpi_name || info->dlpi_name[0] == '\0') - handle = dlopen(nullptr, RTLD_LAZY); - else - handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); -#endif - - unsigned long conformancesSize; - const uint8_t *conformances = - _swift_getSectionDataPE(handle, inspectArgs->sectionName, - &conformancesSize); - - if (conformances) - inspectArgs->fnAddImageBlock(conformances, conformancesSize); - -#if defined(_MSC_VER) - FreeLibrary(handle); -#else - dlclose(handle); -#endif - return 0; -} - -void swift::_swift_initializeCallbacksToInspectDylib( - void (*fnAddImageBlock)(const uint8_t *, size_t), - const char *sectionName) { - InspectArgs inspectArgs = {fnAddImageBlock, sectionName}; - - _swift_dl_iterate_phdr(_addImageProtocolConformances, &inspectArgs); -} -#else -# error No known mechanism to inspect dynamic libraries on this platform. -#endif - // This variable is used to signal when a cache was generated and // it is correct to avoid a new scan. static unsigned ConformanceCacheGeneration = 0;