1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
//===------------------------ SwiftScan.swift -----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import protocol Foundation.CustomNSError
import var Foundation.NSLocalizedDescriptionKey
#if os(Windows)
import WinSDK
#elseif os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(Musl)
import Musl
#elseif canImport(Android)
import Android
#endif
internal enum Loader {
}
extension Loader {
internal enum Error: Swift.Error {
case `open`(String)
case close(String)
}
}
extension Loader.Error: CustomNSError {
public var errorUserInfo: [String:Any] {
return [NSLocalizedDescriptionKey: "\(self)"]
}
}
#if !os(Windows)
extension Loader {
private static func error() -> String? {
if let error: UnsafeMutablePointer<CChar> = dlerror() {
return String(cString: error)
}
return nil
}
}
#endif
extension Loader {
internal final class Handle {
#if os(Windows)
typealias ValueType = HMODULE
#else
typealias ValueType = UnsafeMutableRawPointer
#endif
fileprivate var value: ValueType?
init(value: ValueType) {
self.value = value
}
deinit {
precondition(value == nil,
"Handle must be closed or explicitly leaked before deinit")
}
public func close() throws {
if let handle = self.value {
#if os(Windows)
guard FreeLibrary(handle) else {
throw Loader.Error.close("FreeLibrary failure: \(GetLastError())")
}
#else
guard dlclose(handle) == 0 else {
throw Loader.Error.close(Loader.error() ?? "unknown error")
}
#endif
}
self.value = nil
}
public func leak() {
self.value = nil
}
}
}
extension Loader {
internal struct Flags: RawRepresentable, OptionSet {
public var rawValue: Int32
public init(rawValue: Int32) {
self.rawValue = rawValue
}
}
}
#if !os(Windows)
extension Loader.Flags {
public static var lazy: Loader.Flags {
Loader.Flags(rawValue: RTLD_LAZY)
}
public static var now: Loader.Flags {
Loader.Flags(rawValue: RTLD_NOW)
}
public static var local: Loader.Flags {
Loader.Flags(rawValue: RTLD_LOCAL)
}
public static var global: Loader.Flags {
Loader.Flags(rawValue: RTLD_GLOBAL)
}
// Platform-specific flags
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
public static var first: Loader.Flags {
Loader.Flags(rawValue: RTLD_FIRST)
}
public static var deepBind: Loader.Flags {
Loader.Flags(rawValue: 0)
}
#else
public static var first: Loader.Flags {
Loader.Flags(rawValue: 0)
}
#if os(Linux) && canImport(Glibc)
public static var deepBind: Loader.Flags {
Loader.Flags(rawValue: RTLD_DEEPBIND)
}
#else
public static var deepBind: Loader.Flags {
Loader.Flags(rawValue: 0)
}
#endif
#endif
}
#endif
extension Loader {
public static func load(_ path: String?, mode: Flags) throws -> Handle {
#if os(Windows)
guard let handle = path?.withCString(encodedAs: UTF16.self, LoadLibraryW) else {
throw Loader.Error.open("LoadLibraryW failure: \(GetLastError())")
}
#else
guard let handle = dlopen(path, mode.rawValue) else {
throw Loader.Error.open(Loader.error() ?? "unknown error")
}
#endif
return Handle(value: handle)
}
public static func lookup<T>(symbol: String, in module: Handle) -> T? {
#if os(Windows)
guard let pointer = GetProcAddress(module.value!, symbol) else {
return nil
}
#else
guard let pointer = dlsym(module.value!, symbol) else {
return nil
}
#endif
return unsafeBitCast(pointer, to: T.self)
}
public static func unload(_ handle: Handle) throws {
try handle.close()
}
}
|