-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Adds entry points to the runtime that exposes metadata #32339
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,11 +48,23 @@ typedef struct swift_reflection_section { | |
| void *End; | ||
| } swift_reflection_section_t; | ||
|
|
||
| /// Represents the remote address and size of an image's section | ||
| typedef struct swift_remote_reflection_section { | ||
|
||
| uintptr_t StartAddress; | ||
| uintptr_t Size; | ||
| } swift_remote_reflection_section_t; | ||
|
|
||
| typedef struct swift_reflection_section_pair { | ||
| swift_reflection_section_t section; | ||
| swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero | ||
| } swift_reflection_section_pair_t; | ||
|
|
||
| /// Represents the mapping between an image sections's local and remote addresses | ||
| typedef struct swift_reflection_section_mapping { | ||
| swift_reflection_section_t local_section; | ||
| swift_remote_reflection_section_t remote_section; | ||
| } swift_reflection_section_mapping_t; | ||
|
|
||
| /// Represents the set of Swift reflection sections of an image. | ||
| /// Not all sections may be present. | ||
| /// | ||
|
|
@@ -71,6 +83,16 @@ typedef struct swift_reflection_info { | |
| swift_reflection_ptr_t RemoteStartAddress; | ||
| } swift_reflection_info_t; | ||
|
|
||
| /// Represents the set of Swift reflection sections of an image, | ||
| typedef struct swift_reflection_mapping_info { | ||
| swift_reflection_section_mapping_t field; | ||
| swift_reflection_section_mapping_t associated_types; | ||
| swift_reflection_section_mapping_t builtin_types; | ||
| swift_reflection_section_mapping_t capture; | ||
| swift_reflection_section_mapping_t type_references; | ||
| swift_reflection_section_mapping_t reflection_strings; | ||
| } swift_reflection_mapping_info_t; | ||
|
|
||
| /// The layout kind of a Swift type. | ||
| typedef enum swift_layout_kind { | ||
| // Nothing is known about the size or contents of this value. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,11 +16,6 @@ | |
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // FIXME: Make this work with Linux | ||
|
|
||
| import MachO | ||
| import Darwin | ||
|
|
||
| let RequestInstanceKind = "k" | ||
| let RequestInstanceAddress = "i" | ||
| let RequestReflectionInfos = "r" | ||
|
|
@@ -31,56 +26,10 @@ let RequestStringLength = "l" | |
| let RequestDone = "d" | ||
| let RequestPointerSize = "p" | ||
|
|
||
| internal func debugLog(_ message: @autoclosure () -> String) { | ||
| #if DEBUG_LOG | ||
| fputs("Child: \(message())\n", stderr) | ||
| fflush(stderr) | ||
| #endif | ||
| } | ||
|
|
||
| public enum InstanceKind : UInt8 { | ||
| case None | ||
| case Object | ||
| case Existential | ||
| case ErrorExistential | ||
| case Closure | ||
| case Enum | ||
| case EnumValue | ||
| } | ||
|
|
||
| /// Represents a section in a loaded image in this process. | ||
| internal struct Section { | ||
| /// The absolute start address of the section's data in this address space. | ||
| let startAddress: UnsafeRawPointer | ||
|
|
||
| /// The size of the section in bytes. | ||
| let size: UInt | ||
| } | ||
|
|
||
| /// Holds the addresses and sizes of sections related to reflection | ||
| internal struct ReflectionInfo : Sequence { | ||
| /// The name of the loaded image | ||
| internal let imageName: String | ||
|
|
||
| /// Reflection metadata sections | ||
| internal let fieldmd: Section? | ||
| internal let assocty: Section? | ||
| internal let builtin: Section? | ||
| internal let capture: Section? | ||
| internal let typeref: Section? | ||
| internal let reflstr: Section? | ||
|
|
||
| internal func makeIterator() -> AnyIterator<Section?> { | ||
| return AnyIterator([ | ||
| fieldmd, | ||
| assocty, | ||
| builtin, | ||
| capture, | ||
| typeref, | ||
| reflstr | ||
| ].makeIterator()) | ||
| } | ||
| } | ||
| #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) | ||
| import MachO | ||
| import Darwin | ||
|
|
||
| #if arch(x86_64) || arch(arm64) | ||
| typealias MachHeader = mach_header_64 | ||
|
|
@@ -105,6 +54,36 @@ internal func getSectionInfo(_ name: String, | |
| return Section(startAddress: nonNullAddress, size: size) | ||
| } | ||
|
|
||
| /// Get the TEXT segment location and size for a loaded image. | ||
| /// | ||
| /// - Parameter i: The index of the loaded image as reported by Dyld. | ||
| /// - Returns: The image name, address, and size. | ||
| internal func getAddressInfoForImage(atIndex i: UInt32) -> | ||
| (name: String, address: UnsafeMutablePointer<UInt8>?, size: UInt) { | ||
| debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") } | ||
| let header = unsafeBitCast(_dyld_get_image_header(i), | ||
| to: UnsafePointer<MachHeader>.self) | ||
| let name = String(validatingUTF8: _dyld_get_image_name(i)!)! | ||
| var size: UInt = 0 | ||
| let address = getsegmentdata(header, "__TEXT", &size) | ||
| return (name, address, size) | ||
| } | ||
|
|
||
| /// Send all loadedimages loaded in the current process. | ||
| internal func sendImages() { | ||
| debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") } | ||
| let infos = (0..<getImageCount()).map(getAddressInfoForImage) | ||
|
|
||
| debugLog("\(infos.count) reflection info bundles.") | ||
| precondition(infos.count >= 1) | ||
| sendValue(infos.count) | ||
| for (name, address, size) in infos { | ||
| debugLog("Sending info for \(name)") | ||
| sendValue(address) | ||
| sendValue(size) | ||
| } | ||
| } | ||
|
|
||
| /// Get the Swift Reflection section locations for a loaded image. | ||
| /// | ||
| /// An image of interest must have the following sections in the __TEXT | ||
|
|
@@ -140,19 +119,100 @@ internal func getReflectionInfoForImage(atIndex i: UInt32) -> ReflectionInfo? { | |
| reflstr: reflstr) | ||
| } | ||
|
|
||
| /// Get the TEXT segment location and size for a loaded image. | ||
| /// | ||
| /// - Parameter i: The index of the loaded image as reported by Dyld. | ||
| /// - Returns: The image name, address, and size. | ||
| internal func getAddressInfoForImage(atIndex i: UInt32) -> | ||
| (name: String, address: UnsafeMutablePointer<UInt8>?, size: UInt) { | ||
| debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") } | ||
| let header = unsafeBitCast(_dyld_get_image_header(i), | ||
| to: UnsafePointer<MachHeader>.self) | ||
| let name = String(validatingUTF8: _dyld_get_image_name(i)!)! | ||
| var size: UInt = 0 | ||
| let address = getsegmentdata(header, "__TEXT", &size) | ||
| return (name, address, size) | ||
| internal func getImageCount() -> UInt32 { | ||
| return _dyld_image_count() | ||
| } | ||
|
|
||
| let rtldDefault = UnsafeMutableRawPointer(bitPattern: Int(-2)) | ||
| #elseif !os(Windows) | ||
| import SwiftShims | ||
| import Glibc | ||
|
||
|
|
||
| let rtldDefault: UnsafeMutableRawPointer? = nil | ||
|
|
||
| extension Section { | ||
| init(range: MetadataSectionRange) { | ||
| self.startAddress = UnsafeRawPointer(bitPattern: range.start)! | ||
| self.size = UInt(range.length) | ||
| } | ||
| } | ||
|
|
||
| internal func getReflectionInfoForImage(atIndex i: UInt32) -> ReflectionInfo? { | ||
| return _getMetadataSection(UInt(i)).map { rawPointer in | ||
| let name = _getMetadataSectionName(rawPointer) | ||
| let metadataSection = rawPointer.bindMemory(to: MetadataSections.self, capacity: 1).pointee | ||
| return ReflectionInfo(imageName: String(validatingUTF8: name)!, | ||
| fieldmd: Section(range: metadataSection.swift5_fieldmd), | ||
| assocty: Section(range: metadataSection.swift5_assocty), | ||
| builtin: Section(range: metadataSection.swift5_builtin), | ||
| capture: Section(range: metadataSection.swift5_capture), | ||
| typeref: Section(range: metadataSection.swift5_typeref), | ||
| reflstr: Section(range: metadataSection.swift5_reflstr)) | ||
| } | ||
| } | ||
|
|
||
| internal func getImageCount() -> UInt32 { | ||
| return UInt32(_getMetadataSectionCount()) | ||
| } | ||
|
|
||
| internal func sendImages() { | ||
| preconditionFailure("Should only be called in macOS!") | ||
| } | ||
|
|
||
|
|
||
| #else // os(Linux) | ||
| #error("SwiftReflectionTest does not currently support this OS.") | ||
| #endif | ||
|
|
||
| internal func debugLog(_ message: @autoclosure () -> String) { | ||
| #if DEBUG_LOG | ||
| fputs("Child: \(message())\n", stderr) | ||
| fflush(stderr) | ||
| #endif | ||
| } | ||
|
|
||
| public enum InstanceKind: UInt8 { | ||
| case None | ||
| case Object | ||
| case Existential | ||
| case ErrorExistential | ||
| case Closure | ||
| case Enum | ||
| case EnumValue | ||
| } | ||
|
|
||
| /// Represents a section in a loaded image in this process. | ||
| internal struct Section { | ||
| /// The absolute start address of the section's data in this address space. | ||
| let startAddress: UnsafeRawPointer | ||
|
|
||
| /// The size of the section in bytes. | ||
| let size: UInt | ||
| } | ||
|
|
||
| /// Holds the addresses and sizes of sections related to reflection. | ||
| internal struct ReflectionInfo : Sequence { | ||
| /// The name of the loaded image. | ||
| internal let imageName: String | ||
|
|
||
| /// Reflection metadata sections. | ||
| internal let fieldmd: Section? | ||
| internal let assocty: Section? | ||
| internal let builtin: Section? | ||
| internal let capture: Section? | ||
| internal let typeref: Section? | ||
| internal let reflstr: Section? | ||
|
|
||
| internal func makeIterator() -> AnyIterator<Section?> { | ||
| return AnyIterator([ | ||
| fieldmd, | ||
| assocty, | ||
| builtin, | ||
| capture, | ||
| typeref, | ||
| reflstr | ||
| ].makeIterator()) | ||
| } | ||
| } | ||
|
|
||
| internal func sendBytes<T>(from address: UnsafePointer<T>, count: Int) { | ||
|
|
@@ -197,7 +257,7 @@ internal func readUInt() -> UInt { | |
| /// process. | ||
| internal func sendReflectionInfos() { | ||
| debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") } | ||
| let infos = (0..<_dyld_image_count()).compactMap(getReflectionInfoForImage) | ||
| let infos = (0..<getImageCount()).compactMap(getReflectionInfoForImage) | ||
|
|
||
| var numInfos = infos.count | ||
| debugLog("\(numInfos) reflection info bundles.") | ||
|
|
@@ -212,21 +272,6 @@ internal func sendReflectionInfos() { | |
| } | ||
| } | ||
|
|
||
| /// Send all loadedimages loaded in the current process. | ||
| internal func sendImages() { | ||
| debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") } | ||
| let infos = (0..<_dyld_image_count()).map(getAddressInfoForImage) | ||
|
|
||
| debugLog("\(infos.count) reflection info bundles.") | ||
| precondition(infos.count >= 1) | ||
| sendValue(infos.count) | ||
| for (name, address, size) in infos { | ||
| debugLog("Sending info for \(name)") | ||
| sendValue(address) | ||
| sendValue(size) | ||
| } | ||
| } | ||
|
|
||
| internal func printErrnoAndExit() { | ||
| debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") } | ||
| let errorCString = strerror(errno)! | ||
|
|
@@ -261,8 +306,7 @@ internal func sendSymbolAddress() { | |
| debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") } | ||
| let name = readLine()! | ||
| name.withCString { | ||
| let handle = UnsafeMutableRawPointer(bitPattern: Int(-2))! | ||
| let symbol = dlsym(handle, $0) | ||
| let symbol = dlsym(rtldDefault, $0) | ||
| let symbolAddress = unsafeBitCast(symbol, to: UInt.self) | ||
| sendValue(symbolAddress) | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.