Skip to content

Commit 87b27c6

Browse files
committed
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.
1 parent 2325b06 commit 87b27c6

File tree

9 files changed

+454
-368
lines changed

9 files changed

+454
-368
lines changed

stdlib/public/runtime/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ set(swift_runtime_sources
4040
ErrorDefaultImpls.cpp
4141
Heap.cpp
4242
HeapObject.cpp
43+
ImageInspectionMachO.cpp
44+
ImageInspectionELF.cpp
45+
ImageInspectionWin32.cpp
4346
KnownMetadata.cpp
4447
Metadata.cpp
4548
MetadataLookup.cpp

stdlib/public/runtime/CygwinPort.cpp

Lines changed: 0 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -32,112 +32,6 @@ using namespace swift;
3232

3333
static std::mutex swiftOnceMutex;
3434

35-
int swift::_swift_dl_iterate_phdr(int (*Callback)(struct dl_phdr_info *info,
36-
size_t size, void *data),
37-
void *data) {
38-
DWORD procId = GetCurrentProcessId();
39-
HANDLE procHandle =
40-
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, procId);
41-
if (!procHandle) {
42-
swift::fatalError(/* flags = */ 0, "OpenProcess() failed");
43-
return 0;
44-
}
45-
46-
int lastRet = 0;
47-
48-
std::vector<HMODULE> modules(1024);
49-
DWORD neededSize;
50-
51-
BOOL ret = EnumProcessModules(procHandle, modules.data(),
52-
modules.size() * sizeof(HMODULE), &neededSize);
53-
54-
if (!ret) {
55-
swift::fatalError(/* flags = */ 0, "EnumProcessModules() failed");
56-
return 0;
57-
}
58-
59-
if (modules.size() * sizeof(HMODULE) < neededSize) {
60-
modules.resize(neededSize / sizeof(HMODULE));
61-
ret = EnumProcessModules(procHandle, modules.data(),
62-
modules.size() * sizeof(HMODULE), &neededSize);
63-
}
64-
65-
if (!ret) {
66-
swift::fatalError(/* flags = */ 0, "EnumProcessModules() failed");
67-
return 0;
68-
}
69-
70-
for (unsigned i = 0; i < neededSize / sizeof(HMODULE); i++) {
71-
char modName[MAX_PATH];
72-
73-
if (!GetModuleFileNameExA(procHandle, modules[i], modName,
74-
sizeof(modName))) {
75-
swift::fatalError(/* flags = */ 0, "GetModuleFileNameExA() failed");
76-
}
77-
78-
dl_phdr_info hdr;
79-
hdr.dlpi_name = modName;
80-
hdr.dlpi_addr = modules[i];
81-
82-
lastRet = Callback(&hdr, sizeof(hdr), data);
83-
if (lastRet != 0)
84-
break;
85-
}
86-
87-
CloseHandle(procHandle);
88-
89-
return lastRet;
90-
}
91-
92-
uint8_t *swift::_swift_getSectionDataPE(void *handle, const char *sectionName,
93-
unsigned long *sectionSize) {
94-
// In Cygwin, dlopen() returns PE/COFF image pointer.
95-
// This is relying on undocumented feature of Windows API LoadLibrary().
96-
unsigned char *peStart = (unsigned char *)handle;
97-
98-
const int kLocationOfNtHeaderOffset = 0x3C;
99-
int ntHeadersOffset =
100-
*reinterpret_cast<int32_t *>(peStart + kLocationOfNtHeaderOffset);
101-
102-
bool assert1 =
103-
peStart[ntHeadersOffset] == 'P' && peStart[ntHeadersOffset + 1] == 'E';
104-
if (!assert1) {
105-
swift::fatalError(/* flags = */ 0, "_swift_getSectionDataPE()'s finding PE failed");
106-
}
107-
108-
unsigned char *coff = peStart + ntHeadersOffset + 4;
109-
110-
int16_t numberOfSections = *(int16_t *)(coff + 2);
111-
112-
// SizeOfOptionalHeader
113-
int16_t sizeOfOptionalHeader = *(int16_t *)(coff + 16);
114-
115-
const int kCoffFileHeaderSize = 20;
116-
unsigned char *sectionTableBase =
117-
coff + kCoffFileHeaderSize + sizeOfOptionalHeader;
118-
119-
// Section Header Record
120-
const int kSectionRecordSize = 40;
121-
122-
unsigned char *sectionHeader = sectionTableBase;
123-
for (int i = 0; i < numberOfSections; i++) {
124-
uint32_t virtualSize = *(uint32_t *)&sectionHeader[8];
125-
uint32_t virtualAddress = *(uint32_t *)&sectionHeader[12];
126-
127-
char nameOfThisSection[9];
128-
memcpy(nameOfThisSection, sectionHeader, 8);
129-
nameOfThisSection[8] = '\0';
130-
131-
if (strcmp(sectionName, nameOfThisSection) == 0) {
132-
*sectionSize = virtualSize;
133-
return (uint8_t *)handle + virtualAddress;
134-
}
135-
sectionHeader += kSectionRecordSize;
136-
}
137-
138-
return nullptr;
139-
}
140-
14135
#if !defined(_MSC_VER)
14236
void swift::_swift_once_f(uintptr_t *predicate, void *context,
14337
void (*function)(void *)) {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===--- ImageInspection.h - Image inspection routines --------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file includes routines that extract metadata from executable and
14+
// dynamic library image files generated by the Swift compiler. The
15+
// concrete implementations vary greatly by platform.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_RUNTIME_IMAGE_INSPECTION_H
20+
#define SWIFT_RUNTIME_IMAGE_INSPECTION_H
21+
22+
#include <cstdint>
23+
24+
namespace swift {
25+
26+
/// Load the metadata from the image necessary to find a type's
27+
/// protocol conformance.
28+
void initializeProtocolConformanceLookup();
29+
30+
/// Load the metadata from the image necessary to find a type by name.
31+
void initializeTypeMetadataRecordLookup();
32+
33+
// Callbacks to register metadata from an image to the runtime.
34+
35+
void addImageProtocolConformanceBlockCallback(const void *start,
36+
uintptr_t size);
37+
void addImageTypeMetadataRecordBlockCallback(const void *start,
38+
uintptr_t size);
39+
40+
} // end namespace swift
41+
42+
#endif // SWIFT_RUNTIME_IMAGE_INSPECTION_H
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//===--- ImageInspectionELFDynamic.cpp - ELF image inspection -------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file includes routines that interact with ld*.so on ELF-based platforms
14+
// to extract runtime metadata embedded in dynamically linked ELF images
15+
// generated by the Swift compiler.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#if defined(__ELF__) || defined(__ANDROID__)
20+
21+
#include "ImageInspection.h"
22+
#include <elf.h>
23+
#include <link.h>
24+
#include <dlfcn.h>
25+
#include <string.h>
26+
27+
using namespace swift;
28+
29+
/// The symbol name in the image that identifies the beginning of the
30+
/// protocol conformances table.
31+
static const char ProtocolConformancesSymbol[] =
32+
".swift2_protocol_conformances_start";
33+
/// The symbol name in the image that identifies the beginning of the
34+
/// type metadata record table.
35+
static const char TypeMetadataRecordsSymbol[] =
36+
".swift2_type_metadata_start";
37+
38+
/// Context arguments passed down from dl_iterate_phdr to its callback.
39+
struct InspectArgs {
40+
/// Symbol name to look up.
41+
const char *symbolName;
42+
/// Callback function to invoke with the metadata block.
43+
void (*addBlock)(const void *start, uintptr_t size);
44+
};
45+
46+
static int iteratePHDRCallback(struct dl_phdr_info *info,
47+
size_t size, void *data) {
48+
const InspectArgs *inspectArgs = reinterpret_cast<const InspectArgs *>(data);
49+
void *handle;
50+
if (!info->dlpi_name || info->dlpi_name[0] == '\0') {
51+
handle = dlopen(nullptr, RTLD_LAZY);
52+
} else {
53+
handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD);
54+
}
55+
56+
if (!handle) {
57+
// Not a shared library.
58+
return 0;
59+
}
60+
61+
const char *conformances =
62+
reinterpret_cast<const char*>(dlsym(handle, inspectArgs->symbolName));
63+
64+
if (!conformances) {
65+
// if there are no conformances, don't hold this handle open.
66+
dlclose(handle);
67+
return 0;
68+
}
69+
70+
// Extract the size of the conformances block from the head of the section.
71+
uint64_t conformancesSize;
72+
memcpy(&conformancesSize, conformances, sizeof(conformancesSize));
73+
conformances += sizeof(conformancesSize);
74+
75+
inspectArgs->addBlock(conformances, conformancesSize);
76+
77+
dlclose(handle);
78+
return 0;
79+
}
80+
81+
void swift::initializeProtocolConformanceLookup() {
82+
// Search the loaded dls. This only searches the already
83+
// loaded ones.
84+
// FIXME: Find a way to have this continue to happen for dlopen-ed images.
85+
// rdar://problem/19045112
86+
InspectArgs ProtocolConformanceArgs = {
87+
ProtocolConformancesSymbol,
88+
addImageProtocolConformanceBlockCallback
89+
};
90+
dl_iterate_phdr(iteratePHDRCallback, &ProtocolConformanceArgs);
91+
}
92+
93+
void swift::initializeTypeMetadataRecordLookup() {
94+
InspectArgs TypeMetadataRecordArgs = {
95+
TypeMetadataRecordsSymbol,
96+
addImageTypeMetadataRecordBlockCallback
97+
};
98+
dl_iterate_phdr(iteratePHDRCallback, &TypeMetadataRecordArgs);
99+
}
100+
101+
#endif // defined(__ELF__) || defined(__ANDROID__)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//===--- ImageInspectionMachO.cpp - Mach-O image inspection ---------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file includes routines that interact with dyld on Mach-O-based platforms
14+
// to extract runtime metadata embedded in images generated by the Swift
15+
// compiler.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#if defined(__APPLE__) && defined(__MACH__)
20+
21+
#include "ImageInspection.h"
22+
#include <mach-o/dyld.h>
23+
#include <mach-o/getsect.h>
24+
#include <assert.h>
25+
26+
using namespace swift;
27+
28+
namespace {
29+
/// The Mach-O section name for the section containing protocol conformances.
30+
/// This lives within SEG_TEXT.
31+
constexpr const char ProtocolConformancesSection[] = "__swift2_proto";
32+
/// The Mach-O section name for the section containing type references.
33+
/// This lives within SEG_TEXT.
34+
constexpr const char TypeMetadataRecordSection[] = "__swift2_types";
35+
36+
template<const char *SECTION_NAME,
37+
void CONSUME_BLOCK(const void *start, uintptr_t size)>
38+
void addImageCallback(const mach_header *mh, intptr_t vmaddr_slide) {
39+
#ifdef __LP64__
40+
using mach_header_platform = mach_header_64;
41+
assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!");
42+
#else
43+
using mach_header_platform = mach_header;
44+
#endif
45+
46+
// Look for a __swift2_proto section.
47+
unsigned long size;
48+
const uint8_t *section =
49+
getsectiondata(reinterpret_cast<const mach_header_platform *>(mh),
50+
SEG_TEXT, SECTION_NAME,
51+
&size);
52+
53+
if (!section)
54+
return;
55+
56+
CONSUME_BLOCK(section, size);
57+
}
58+
59+
} // end anonymous namespace
60+
61+
void swift::initializeProtocolConformanceLookup() {
62+
_dyld_register_func_for_add_image(
63+
addImageCallback<ProtocolConformancesSection,
64+
addImageProtocolConformanceBlockCallback>);
65+
}
66+
void swift::initializeTypeMetadataRecordLookup() {
67+
_dyld_register_func_for_add_image(
68+
addImageCallback<TypeMetadataRecordSection,
69+
addImageTypeMetadataRecordBlockCallback>);
70+
71+
}
72+
73+
#endif // defined(__APPLE__) && defined(__MACH__)

0 commit comments

Comments
 (0)