Skip to content

Commit 5016b3f

Browse files
committed
Add entrypoints to the runtime that exposes metadata necessary for reflection tests on Linux
1 parent ddc0494 commit 5016b3f

File tree

13 files changed

+367
-208
lines changed

13 files changed

+367
-208
lines changed

include/swift/Remote/MetadataReader.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ class MetadataReader {
509509
if (!meta || meta->getKind() != MetadataKind::Class)
510510
return None;
511511

512+
#if SWIFT_OBJC_INTEROP
512513
// The following algorithm only works on the non-fragile Apple runtime.
513514

514515
// Grab the RO-data pointer. This part is not ABI.
@@ -524,6 +525,23 @@ class MetadataReader {
524525
return None;
525526

526527
return start;
528+
#else
529+
// All swift class instances start with an isa pointer,
530+
// followed by the retain counts (which are the size of a long long).
531+
size_t isaAndRetainCountSize = sizeof(StoredSize) + sizeof(long long);
532+
size_t start = isaAndRetainCountSize;
533+
534+
auto classMeta = cast<TargetClassMetadata<Runtime>>(meta);
535+
while (classMeta->Superclass) {
536+
classMeta = cast<TargetClassMetadata<Runtime>>(
537+
readMetadata(classMeta->Superclass));
538+
539+
// Subtract the size contribution of the isa and retain counts from
540+
// the super class.
541+
start += classMeta->InstanceSize - isaAndRetainCountSize;
542+
}
543+
return start;
544+
#endif
527545
}
528546

529547
/// Given a pointer to the metadata, attempt to read the value

include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ void
8080
swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
8181
swift_reflection_info_t Info);
8282

83+
/// Add reflection sections from a loaded Swift image.
84+
SWIFT_REMOTE_MIRROR_LINKAGE
85+
void swift_reflection_addReflectionMappingInfo(
86+
SwiftReflectionContextRef ContextRef, swift_reflection_mapping_info_t Info);
87+
8388
/// Add reflection information from a loaded Swift image.
8489
/// Returns true on success, false if the image's memory couldn't be read.
8590
SWIFT_REMOTE_MIRROR_LINKAGE

include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,23 @@ typedef struct swift_reflection_section {
4848
void *End;
4949
} swift_reflection_section_t;
5050

51+
/// Represents the remote address and size of an image's section
52+
typedef struct swift_remote_reflection_section {
53+
uintptr_t StartAddress;
54+
uintptr_t Size;
55+
} swift_remote_reflection_section_t;
56+
5157
typedef struct swift_reflection_section_pair {
5258
swift_reflection_section_t section;
5359
swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero
5460
} swift_reflection_section_pair_t;
5561

62+
/// Represents the mapping between an image sections's local and remote addresses
63+
typedef struct swift_reflection_section_mapping {
64+
swift_reflection_section_t local_section;
65+
swift_remote_reflection_section_t remote_section;
66+
} swift_reflection_section_mapping_t;
67+
5668
/// Represents the set of Swift reflection sections of an image.
5769
/// Not all sections may be present.
5870
///
@@ -71,6 +83,16 @@ typedef struct swift_reflection_info {
7183
swift_reflection_ptr_t RemoteStartAddress;
7284
} swift_reflection_info_t;
7385

86+
/// Represents the set of Swift reflection sections of an image,
87+
typedef struct swift_reflection_mapping_info {
88+
swift_reflection_section_mapping_t field;
89+
swift_reflection_section_mapping_t associated_types;
90+
swift_reflection_section_mapping_t builtin_types;
91+
swift_reflection_section_mapping_t capture;
92+
swift_reflection_section_mapping_t type_references;
93+
swift_reflection_section_mapping_t reflection_strings;
94+
} swift_reflection_mapping_info_t;
95+
7496
/// The layout kind of a Swift type.
7597
typedef enum swift_layout_kind {
7698
// Nothing is known about the size or contents of this value.

stdlib/private/CMakeLists.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ if(SWIFT_BUILD_SDK_OVERLAY)
2323

2424
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
2525
add_subdirectory(StdlibUnittestFoundationExtras)
26-
if (SWIFT_INCLUDE_TESTS)
27-
add_subdirectory(SwiftReflectionTest)
28-
endif()
26+
endif()
27+
# Currently SwiftReflectionTest cannot be built on Windows, due to
28+
# dependencies on POSIX symbols
29+
if (SWIFT_INCLUDE_TESTS AND (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows"))
30+
add_subdirectory(SwiftReflectionTest)
2931
endif()
3032
endif()

stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift

Lines changed: 129 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616
//
1717
//===----------------------------------------------------------------------===//
1818

19-
// FIXME: Make this work with Linux
20-
21-
import MachO
22-
import Darwin
23-
2419
let RequestInstanceKind = "k"
2520
let RequestInstanceAddress = "i"
2621
let RequestReflectionInfos = "r"
@@ -31,56 +26,10 @@ let RequestStringLength = "l"
3126
let RequestDone = "d"
3227
let RequestPointerSize = "p"
3328

34-
internal func debugLog(_ message: @autoclosure () -> String) {
35-
#if DEBUG_LOG
36-
fputs("Child: \(message())\n", stderr)
37-
fflush(stderr)
38-
#endif
39-
}
40-
41-
public enum InstanceKind : UInt8 {
42-
case None
43-
case Object
44-
case Existential
45-
case ErrorExistential
46-
case Closure
47-
case Enum
48-
case EnumValue
49-
}
50-
51-
/// Represents a section in a loaded image in this process.
52-
internal struct Section {
53-
/// The absolute start address of the section's data in this address space.
54-
let startAddress: UnsafeRawPointer
55-
56-
/// The size of the section in bytes.
57-
let size: UInt
58-
}
5929

60-
/// Holds the addresses and sizes of sections related to reflection
61-
internal struct ReflectionInfo : Sequence {
62-
/// The name of the loaded image
63-
internal let imageName: String
64-
65-
/// Reflection metadata sections
66-
internal let fieldmd: Section?
67-
internal let assocty: Section?
68-
internal let builtin: Section?
69-
internal let capture: Section?
70-
internal let typeref: Section?
71-
internal let reflstr: Section?
72-
73-
internal func makeIterator() -> AnyIterator<Section?> {
74-
return AnyIterator([
75-
fieldmd,
76-
assocty,
77-
builtin,
78-
capture,
79-
typeref,
80-
reflstr
81-
].makeIterator())
82-
}
83-
}
30+
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
31+
import MachO
32+
import Darwin
8433

8534
#if arch(x86_64) || arch(arm64)
8635
typealias MachHeader = mach_header_64
@@ -105,6 +54,36 @@ internal func getSectionInfo(_ name: String,
10554
return Section(startAddress: nonNullAddress, size: size)
10655
}
10756

57+
/// Get the TEXT segment location and size for a loaded image.
58+
///
59+
/// - Parameter i: The index of the loaded image as reported by Dyld.
60+
/// - Returns: The image name, address, and size.
61+
internal func getAddressInfoForImage(atIndex i: UInt32) ->
62+
(name: String, address: UnsafeMutablePointer<UInt8>?, size: UInt) {
63+
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
64+
let header = unsafeBitCast(_dyld_get_image_header(i),
65+
to: UnsafePointer<MachHeader>.self)
66+
let name = String(validatingUTF8: _dyld_get_image_name(i)!)!
67+
var size: UInt = 0
68+
let address = getsegmentdata(header, "__TEXT", &size)
69+
return (name, address, size)
70+
}
71+
72+
/// Send all loadedimages loaded in the current process.
73+
internal func sendImages() {
74+
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
75+
let infos = (0..<getImageCount()).map(getAddressInfoForImage)
76+
77+
debugLog("\(infos.count) reflection info bundles.")
78+
precondition(infos.count >= 1)
79+
sendValue(infos.count)
80+
for (name, address, size) in infos {
81+
debugLog("Sending info for \(name)")
82+
sendValue(address)
83+
sendValue(size)
84+
}
85+
}
86+
10887
/// Get the Swift Reflection section locations for a loaded image.
10988
///
11089
/// An image of interest must have the following sections in the __TEXT
@@ -140,19 +119,100 @@ internal func getReflectionInfoForImage(atIndex i: UInt32) -> ReflectionInfo? {
140119
reflstr: reflstr)
141120
}
142121

143-
/// Get the TEXT segment location and size for a loaded image.
144-
///
145-
/// - Parameter i: The index of the loaded image as reported by Dyld.
146-
/// - Returns: The image name, address, and size.
147-
internal func getAddressInfoForImage(atIndex i: UInt32) ->
148-
(name: String, address: UnsafeMutablePointer<UInt8>?, size: UInt) {
149-
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
150-
let header = unsafeBitCast(_dyld_get_image_header(i),
151-
to: UnsafePointer<MachHeader>.self)
152-
let name = String(validatingUTF8: _dyld_get_image_name(i)!)!
153-
var size: UInt = 0
154-
let address = getsegmentdata(header, "__TEXT", &size)
155-
return (name, address, size)
122+
internal func getImageCount() -> UInt32 {
123+
return _dyld_image_count()
124+
}
125+
126+
let rtldDefault = UnsafeMutableRawPointer(bitPattern: Int(-2))
127+
#elseif !os(Windows)
128+
import SwiftShims
129+
import Glibc
130+
131+
let rtldDefault: UnsafeMutableRawPointer? = nil
132+
133+
extension Section {
134+
init(range: MetadataSectionRange) {
135+
self.startAddress = UnsafeRawPointer(bitPattern: range.start)!
136+
self.size = UInt(range.length)
137+
}
138+
}
139+
140+
internal func getReflectionInfoForImage(atIndex i: UInt32) -> ReflectionInfo? {
141+
return _getMetadataSection(UInt(i)).map { rawPointer in
142+
let name = _getMetadataSectionName(rawPointer)
143+
let metadataSection = rawPointer.bindMemory(to: MetadataSections.self, capacity: 1).pointee
144+
return ReflectionInfo(imageName: String(validatingUTF8: name)!,
145+
fieldmd: Section(range: metadataSection.swift5_fieldmd),
146+
assocty: Section(range: metadataSection.swift5_assocty),
147+
builtin: Section(range: metadataSection.swift5_builtin),
148+
capture: Section(range: metadataSection.swift5_capture),
149+
typeref: Section(range: metadataSection.swift5_typeref),
150+
reflstr: Section(range: metadataSection.swift5_reflstr))
151+
}
152+
}
153+
154+
internal func getImageCount() -> UInt32 {
155+
return UInt32(_getMetadataSectionCount())
156+
}
157+
158+
internal func sendImages() {
159+
preconditionFailure("Should only be called in macOS!")
160+
}
161+
162+
163+
#else // os(Linux)
164+
#error("SwiftReflectionTest does not currently support this OS.")
165+
#endif
166+
167+
internal func debugLog(_ message: @autoclosure () -> String) {
168+
#if DEBUG_LOG
169+
fputs("Child: \(message())\n", stderr)
170+
fflush(stderr)
171+
#endif
172+
}
173+
174+
public enum InstanceKind: UInt8 {
175+
case None
176+
case Object
177+
case Existential
178+
case ErrorExistential
179+
case Closure
180+
case Enum
181+
case EnumValue
182+
}
183+
184+
/// Represents a section in a loaded image in this process.
185+
internal struct Section {
186+
/// The absolute start address of the section's data in this address space.
187+
let startAddress: UnsafeRawPointer
188+
189+
/// The size of the section in bytes.
190+
let size: UInt
191+
}
192+
193+
/// Holds the addresses and sizes of sections related to reflection.
194+
internal struct ReflectionInfo : Sequence {
195+
/// The name of the loaded image.
196+
internal let imageName: String
197+
198+
/// Reflection metadata sections.
199+
internal let fieldmd: Section?
200+
internal let assocty: Section?
201+
internal let builtin: Section?
202+
internal let capture: Section?
203+
internal let typeref: Section?
204+
internal let reflstr: Section?
205+
206+
internal func makeIterator() -> AnyIterator<Section?> {
207+
return AnyIterator([
208+
fieldmd,
209+
assocty,
210+
builtin,
211+
capture,
212+
typeref,
213+
reflstr
214+
].makeIterator())
215+
}
156216
}
157217

158218
internal func sendBytes<T>(from address: UnsafePointer<T>, count: Int) {
@@ -197,7 +257,7 @@ internal func readUInt() -> UInt {
197257
/// process.
198258
internal func sendReflectionInfos() {
199259
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
200-
let infos = (0..<_dyld_image_count()).compactMap(getReflectionInfoForImage)
260+
let infos = (0..<getImageCount()).compactMap(getReflectionInfoForImage)
201261

202262
var numInfos = infos.count
203263
debugLog("\(numInfos) reflection info bundles.")
@@ -212,21 +272,6 @@ internal func sendReflectionInfos() {
212272
}
213273
}
214274

215-
/// Send all loadedimages loaded in the current process.
216-
internal func sendImages() {
217-
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
218-
let infos = (0..<_dyld_image_count()).map(getAddressInfoForImage)
219-
220-
debugLog("\(infos.count) reflection info bundles.")
221-
precondition(infos.count >= 1)
222-
sendValue(infos.count)
223-
for (name, address, size) in infos {
224-
debugLog("Sending info for \(name)")
225-
sendValue(address)
226-
sendValue(size)
227-
}
228-
}
229-
230275
internal func printErrnoAndExit() {
231276
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
232277
let errorCString = strerror(errno)!
@@ -261,8 +306,7 @@ internal func sendSymbolAddress() {
261306
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
262307
let name = readLine()!
263308
name.withCString {
264-
let handle = UnsafeMutableRawPointer(bitPattern: Int(-2))!
265-
let symbol = dlsym(handle, $0)
309+
let symbol = dlsym(rtldDefault, $0)
266310
let symbolAddress = unsafeBitCast(symbol, to: UInt.self)
267311
sendValue(symbolAddress)
268312
}

0 commit comments

Comments
 (0)