Loading...
--- dyld/dyld-1340/framework/MachO.swift
+++ /dev/null
@@ -1,297 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- vim: ft=cpp et ts=4 sw=4:
- *
- * Copyright (c) 2023 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-enum MachOError: Error {
- case truncatedRead
- case badMagic(UInt32)
-}
-
-// TODO: Convert everything in this file from UnsafeRawBufferPointer to Span
-// Only implement what we need until then
-//
-
-enum MachO {
- case notMachO
- case thinMachO(MachO.File)
- case universalMachO(MachO.UniversalFile)
- init(_ buffer: UnsafeRawBufferPointer) throws(MachOError) {
- var slice = buffer[0..<buffer.count]
- guard let magic: UInt32 = try? slice.read(as: UInt32.self) else {
- throw .truncatedRead
- }
- switch magic {
- case 0xFEED_FACE, 0xFEED_FACF, 0xCEFA_EDFE, 0xCFFA_EDFE:
- self = .thinMachO(try MachO.File(buffer))
- case 0xCAFE_BABE, 0xCAFE_BABF, 0xBEBA_FECA, 0xBFBA_FECA:
- self = .universalMachO(try MachO.UniversalFile(buffer))
- default:
- self = .notMachO
- }
- }
-}
-
-extension MachO {
- struct File {
- fileprivate let buffer: UnsafeRawBufferPointer
- fileprivate let endian: Endian
- fileprivate let is64bit: Bool
- init(_ buffer: UnsafeRawBufferPointer) throws(MachOError) {
- var slice = buffer[0..<buffer.count]
- guard let magic: UInt32 = try? slice.read(as: UInt32.self) else {
- throw .truncatedRead
- }
- switch magic {
- case 0xFEED_FACE:
- endian = .native
- is64bit = false
- case 0xFEED_FACF:
- endian = .native
- is64bit = true
- case 0xCEFA_EDFE:
- endian = .reverse
- is64bit = false
- case 0xCFFA_EDFE:
- endian = .reverse
- is64bit = true
- default:
- throw .badMagic(magic)
- }
- self.buffer = buffer
- }
- var uuid: UUID? {
- for loadCommand in loadCommands {
- switch loadCommand {
- case .uuid(let uuid):
- return uuid
- default:
- continue
- }
- }
- return nil
- }
- var loadCommands: LoadCommandSequence {
- return LoadCommandSequence(self)
- }
- fileprivate struct Header {
- let buffer: UnsafeRawBufferPointer
- let endian: Endian
- init(_ macho: MachO.File) {
- self.buffer = macho.buffer
- self.endian = macho.endian
- }
- var magic: UInt32 { return buffer.load(fromByteOffset:0, as:UInt32.self).from(endian:endian) }
- var cputype: cpu_type_t { return buffer.load(fromByteOffset:4, as:Int32.self).from(endian:endian) }
- var cpusubtype: cpu_subtype_t { return buffer.load(fromByteOffset:8, as:Int32.self).from(endian:endian) }
- var filetype: UInt32 { return buffer.load(fromByteOffset:12, as:UInt32.self).from(endian:endian) }
- var ncmds: UInt32 { return buffer.load(fromByteOffset:16, as:UInt32.self).from(endian:endian) }
- var sizeofcmds: UInt32 { return buffer.load(fromByteOffset:20, as:UInt32.self).from(endian:endian) }
- var flags: UInt32 { return buffer.load(fromByteOffset:24, as:UInt32.self).from(endian:endian) }
- }
- }
-}
-
-fileprivate let LC_UUID: UInt32 = 0x0000001b
-
-extension MachO {
- enum LoadCommand {
- case uuid(UUID)
- case unknown(UInt32)
- }
-
- struct LoadCommandSequence: Sequence {
- fileprivate var macho: MachO.File
- fileprivate init(_ macho: MachO.File) {
- self.macho = macho
- }
- func makeIterator() -> LoadCommandIterator {
- return LoadCommandIterator(macho)
- }
- }
-
- struct LoadCommandIterator: IteratorProtocol {
- fileprivate var slice: Slice<UnsafeRawBufferPointer>
- fileprivate let endian: Endian
- init(_ macho: MachO.File) {
- let header = MachO.File.Header(macho)
- let lowerBound = macho.buffer.indices.lowerBound
- self.slice = macho.buffer[lowerBound..<lowerBound+Int(header.sizeofcmds)]
- if macho.is64bit {
- self.slice = self.slice.dropFirst(32)
- } else {
- self.slice = self.slice.dropFirst(28)
- }
- self.endian = macho.endian
- }
- mutating func next() -> LoadCommand? {
- guard let commandType = try? slice.read(endian:endian, as: UInt32.self),
- let commandSize = try? slice.read(endian:endian, as: UInt32.self) else {
- return nil
- }
- switch commandType {
- case LC_UUID:
- guard let uuid = try? slice.readUuid() else { return nil }
- let remainingBytes = Int(commandSize) - 24 // We already read the type, size, and uuid data
- slice = slice.dropFirst(remainingBytes) // Skip to the next comand
- return .uuid(uuid)
- default:
- let remainingBytes = Int(commandSize) - 8 // We already read the type and size
- slice = slice.dropFirst(remainingBytes) // Skip to the next comand
- return .unknown(commandType)
- }
- }
- }
-}
-
-extension MachO {
- struct UniversalFile {
- private let buffer: UnsafeRawBufferPointer
- private let is64bit: Bool
- init(_ buffer: UnsafeRawBufferPointer) throws(MachOError) {
- var slice = buffer[0..<buffer.count]
- guard let magic: UInt32 = try? slice.read(endian:.big, as: UInt32.self) else {
- throw .truncatedRead
- }
- switch magic {
- case 0xCAFE_BABE:
- is64bit = false
- case 0xCAFE_BABF:
- is64bit = true
- default:
- throw .badMagic(magic)
- }
- self.buffer = buffer
- }
-
- var slices: SliceSequence {
- return SliceSequence(self)
- }
-
- var sliceInfos: SliceInfoSequence {
- return SliceInfoSequence(self)
- }
-
- struct SliceInfo {
- private let slice: Slice<UnsafeRawBufferPointer>
- private let is64Bit: Bool
- init(slice: Slice<UnsafeRawBufferPointer>, is64Bit: Bool) {
- self.slice = slice
- self.is64Bit = is64Bit
- }
- // FIXME: Move these to enums later
- var cpuType: cpu_type_t { return slice.load(fromByteOffset:0, as:Int32.self).from(endian:.big) }
- var cpuSubType: cpu_subtype_t { return slice.load(fromByteOffset:4, as:Int32.self).from(endian:.big) }
- var offset: Int {
- if is64Bit {
- return Int(slice.load(fromByteOffset:8, as:UInt64.self).from(endian:.big))
- } else {
- return Int(slice.load(fromByteOffset:8, as:UInt32.self).from(endian:.big))
- }
- }
- var size: Int {
- if is64Bit {
- return Int(slice.load(fromByteOffset:16, as:UInt64.self).from(endian:.big))
- } else {
- return Int(slice.load(fromByteOffset:12, as:UInt32.self).from(endian:.big))
- }
- }
- }
-
- struct SliceInfoSequence: Sequence {
- fileprivate let universalFile: UniversalFile
- fileprivate init(_ universalFile: UniversalFile) {
- self.universalFile = universalFile
- }
- func makeIterator() -> SliceInfoIterator {
- return SliceInfoIterator(universalFile)
- }
- }
-
- struct SliceInfoIterator: IteratorProtocol {
- private var slice: Slice<UnsafeRawBufferPointer>
- private var index: Int = 0
- private let header: MachO.UniversalFile.Header
- private let is64Bit: Bool
- init(_ universalFile: UniversalFile) {
- self.header = MachO.UniversalFile.Header(universalFile)
- self.slice = universalFile.buffer[universalFile.buffer.indices]
- self.is64Bit = universalFile.is64bit
- }
- mutating func next() -> SliceInfo? {
- guard index < header.nfat_arch else { return nil }
- var result: SliceInfo
- if is64Bit {
- let lowerBound = slice.indices.lowerBound + 8 + (32 * index) // Header + index * size of 63 bit fat record
- result = SliceInfo(slice:slice[lowerBound..<slice.indices.upperBound], is64Bit:true)
- } else {
- let lowerBound = slice.indices.lowerBound + 8 + (20 * index) // Header + index * size of 63 bit fat record
- result = SliceInfo(slice:slice[lowerBound..<slice.indices.upperBound], is64Bit:false)
- }
- index += 1
- return result
- }
- }
-
- // This is a bit confusing because we use `slice` as a term of art within MachO, and swift uses
- // slice to refer to range of collection. Once we have Span most of the uses of swift slices will
- // go away and this will be cleaerer
- struct SliceSequence: Sequence {
- fileprivate let universalFile: UniversalFile
- fileprivate init(_ universalFile: UniversalFile) {
- self.universalFile = universalFile
- }
- func makeIterator() -> SliceIterator {
- return SliceIterator(universalFile)
- }
- }
-
- struct SliceIterator: IteratorProtocol {
- private let slice: Slice<UnsafeRawBufferPointer>
- private var sliceInfoIterator: SliceInfoIterator
- init(_ universalFile: UniversalFile) {
- self.slice = universalFile.buffer[universalFile.buffer.indices]
- self.sliceInfoIterator = SliceInfoIterator(universalFile)
- }
- mutating func next() -> MachO.File? {
- guard let sliceInfo = sliceInfoIterator.next() else { return nil }
- let lowerBound = slice.indices.lowerBound+sliceInfo.offset
- let sliceSlice = slice[lowerBound..<lowerBound+sliceInfo.size]
- return try? MachO.File(UnsafeRawBufferPointer(rebasing:sliceSlice))
- }
- }
-
- fileprivate struct Header {
- let buffer: UnsafeRawBufferPointer
- init(_ universalFile: UniversalFile) {
- self.buffer = universalFile.buffer
- }
- var magic: UInt32 {
- return buffer.load(as:UInt32.self).from(endian:.big)
- }
- var nfat_arch: UInt32 {
- return buffer.load(fromByteOffset:4, as:UInt32.self).from(endian:.big)
- }
- }
-
- }
-}