From 87b27c6451f61ae043c3e29147b8364e0eb13973 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 17 Nov 2016 14:40:14 -0800 Subject: [PATCH] Runtime: Refactor platform-dependent image inspection code. The code we use to interface with the platform dynamic linker is turning into a rat's nest of conditionals that's hard to maintain and extend. Since ELF, Mach-O, and PE platforms have pretty fundamentally different dynamic linker interfaces and capabilities, it makes sense to factor that code into a separate file per-platform, instead of trying to conditionalize the logic in-line. This patch factors out a much simpler portable interface for lazily kicking off the protocol conformance and type metadata lookup caches, and factors the guts out into separate MachO, ELF, and Win32 backends. This should also be a much cleaner interface to interface static binary behavior into, assisting #5349. --- stdlib/public/runtime/CMakeLists.txt | 3 + stdlib/public/runtime/CygwinPort.cpp | 106 --------- stdlib/public/runtime/ImageInspection.h | 42 ++++ stdlib/public/runtime/ImageInspectionELF.cpp | 101 ++++++++ .../public/runtime/ImageInspectionMachO.cpp | 73 ++++++ .../public/runtime/ImageInspectionWin32.cpp | 219 ++++++++++++++++++ stdlib/public/runtime/MetadataLookup.cpp | 82 +------ stdlib/public/runtime/Private.h | 12 - stdlib/public/runtime/ProtocolConformance.cpp | 184 +-------------- 9 files changed, 454 insertions(+), 368 deletions(-) create mode 100644 stdlib/public/runtime/ImageInspection.h create mode 100644 stdlib/public/runtime/ImageInspectionELF.cpp create mode 100644 stdlib/public/runtime/ImageInspectionMachO.cpp create mode 100644 stdlib/public/runtime/ImageInspectionWin32.cpp 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;