Skip to content

Runtime: Refactor platform-dependent image inspection code. #5846

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions stdlib/public/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
106 changes: 0 additions & 106 deletions stdlib/public/runtime/CygwinPort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<HMODULE> 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<int32_t *>(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 *)&sectionHeader[8];
uint32_t virtualAddress = *(uint32_t *)&sectionHeader[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 *)) {
Expand Down
42 changes: 42 additions & 0 deletions stdlib/public/runtime/ImageInspection.h
Original file line number Diff line number Diff line change
@@ -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 <cstdint>

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
101 changes: 101 additions & 0 deletions stdlib/public/runtime/ImageInspectionELF.cpp
Original file line number Diff line number Diff line change
@@ -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 <elf.h>
#include <link.h>
#include <dlfcn.h>
#include <string.h>

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<const InspectArgs *>(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<const char*>(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__)
73 changes: 73 additions & 0 deletions stdlib/public/runtime/ImageInspectionMachO.cpp
Original file line number Diff line number Diff line change
@@ -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 <mach-o/dyld.h>
#include <mach-o/getsect.h>
#include <assert.h>

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<const char *SECTION_NAME,
void CONSUME_BLOCK(const void *start, uintptr_t size)>
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<const mach_header_platform *>(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<ProtocolConformancesSection,
addImageProtocolConformanceBlockCallback>);
}
void swift::initializeTypeMetadataRecordLookup() {
_dyld_register_func_for_add_image(
addImageCallback<TypeMetadataRecordSection,
addImageTypeMetadataRecordBlockCallback>);

}

#endif // defined(__APPLE__) && defined(__MACH__)
Loading