Skip to content

Commit

Permalink
Merge pull request #142 from p-x9/feature/support-old-prebuild-loader
Browse files Browse the repository at this point in the history
[dyld cache] Support latest and older version of prebuilt loader
  • Loading branch information
p-x9 authored Nov 9, 2024
2 parents 57956f0 + c58aa5f commit 2cd02cf
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 23 deletions.
10 changes: 5 additions & 5 deletions Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import Foundation

public struct PrebuiltLoader: LayoutWrapper {
public struct PrebuiltLoader: LayoutWrapper, PrebuiltLoaderProtocol {
public typealias Layout = prebuilt_loader

public var layout: Layout
Expand All @@ -18,11 +18,11 @@ public struct PrebuiltLoader: LayoutWrapper {
extension PrebuiltLoader {
// always true
public var isPrebuilt: Bool {
layout.isPrebuilt != 0
layout.loader.isPrebuilt != 0
}

public var ref: LoaderRef {
.init(layout: layout.ref)
.init(layout: layout.loader.ref)
}
}

Expand Down Expand Up @@ -61,7 +61,7 @@ extension PrebuiltLoader {
)
}

public func dependentLoaderRefs(in cache: DyldCache) -> MemorySequence<LoaderRef>? {
public func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence<LoaderRef>? {
// swiftlint:disable:previous unused_parameter
guard layout.dependentLoaderRefsArrayOffset != 0,
let baseAddress = UnsafeRawPointer(bitPattern: address) else {
Expand All @@ -79,7 +79,7 @@ extension PrebuiltLoader {
extension PrebuiltLoader {
// [dyld implementation](https://github.com/apple-oss-distributions/dyld/blob/65bbeed63cec73f313b1d636e63f243964725a9d/dyld/Loader.h#L317)
public var magic: String? {
withUnsafeBytes(of: layout.magic.bigEndian, {
withUnsafeBytes(of: layout.loader.magic.bigEndian, {
let cString = $0.map({ CChar($0)} ) + [0]
return String(
cString: cString,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// PrebuiltLoaderProtocol.swift
// MachOKit
//
// Created by p-x9 on 2024/11/09
//
//


import Foundation

public protocol PrebuiltLoaderProtocol {
/// Address where this loader is located.
///
/// Slides after loading are not included.
var address: Int { get }

/// magic of loader starts
var magic: String? { get }
/// PrebuiltLoader vs JustInTimeLoader
var isPrebuilt: Bool { get }
var ref: LoaderRef { get }

/// path for target mach-o image
/// - Parameter cache: DyldCache to which `self` belongs
/// - Returns: path name
func path(in cache: DyldCache) -> String?
/// loader reference list of target 's dependencies
/// - Parameter cache: DyldCache to which `self` belongs
/// - Returns: sequence of loader reference
func dependentLoaderRefs(in cache: DyldCache) -> DataSequence<LoaderRef>?

/// path for target mach-o image
/// - Parameter cache: DyldCacheLoaded to which `self` belongs
/// - Returns: path name
func path(in cache: DyldCacheLoaded) -> String?
/// loader reference list of target 's dependencies
/// - Parameter cache: DyldCacheLoaded to which `self` belongs
/// - Returns: sequence of loader reference
func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence<LoaderRef>?
}
112 changes: 107 additions & 5 deletions Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public struct PrebuiltLoaderSet: LayoutWrapper {

extension PrebuiltLoaderSet {
public func loaders(in cache: DyldCache) -> [PrebuiltLoader]? {
guard isLatestVersion else { return nil }

guard let offset = cache.fileOffset(of: numericCast(address)) else {
return nil
}
Expand All @@ -34,8 +36,8 @@ extension PrebuiltLoaderSet {
offset: numericCast(offset),
size: PrebuiltLoader.layoutSize
).withUnsafeBytes {
let loader = $0.load(as: prebuilt_loader.self)
return PrebuiltLoader(
let loader = $0.load(as: PrebuiltLoader.Layout.self)
return .init(
layout: loader,
address: address + numericCast(_offset)
)
Expand All @@ -45,6 +47,8 @@ extension PrebuiltLoaderSet {

public func loaders(in cache: DyldCacheLoaded) -> [PrebuiltLoader]? {
// swiftlint:disable:previous unused_parameter
guard isLatestVersion else { return nil }

guard let basePointer = UnsafeRawPointer(bitPattern: address) else {
return nil
}
Expand All @@ -55,10 +59,65 @@ extension PrebuiltLoaderSet {
numberOfElements: numericCast(layout.loadersArrayCount)
)
return offsets.compactMap { _offset -> PrebuiltLoader? in
let layout: prebuilt_loader = basePointer
let layout: PrebuiltLoader.Layout = basePointer
.advanced(by: numericCast(_offset))
.assumingMemoryBound(to: prebuilt_loader.self).pointee
return PrebuiltLoader(
.autoBoundPointee()
return .init(
layout: layout,
address: address + numericCast(_offset)
)
}
}
}

extension PrebuiltLoaderSet {
public func loaders_pre1165_3(in cache: DyldCache) -> [PrebuiltLoader_Pre1165_3]? {
guard let version, version.isPre1165_3 else { return nil }

guard let offset = cache.fileOffset(of: numericCast(address)) else {
return nil
}
let offsets: DataSequence<UInt32> = cache.fileHandle.readDataSequence(
offset: offset + numericCast(layout.loadersArrayOffset),
numberOfElements: numericCast(layout.loadersArrayCount)
)
return offsets.compactMap { _offset -> PrebuiltLoader_Pre1165_3? in
guard let offset = cache.fileOffset(
of: numericCast(address) + numericCast(_offset)
) else {
return nil
}
return cache.fileHandle.readData(
offset: numericCast(offset),
size: PrebuiltLoader_Pre1165_3.layoutSize
).withUnsafeBytes {
let loader = $0.load(as: PrebuiltLoader_Pre1165_3.Layout.self)
return .init(
layout: loader,
address: address + numericCast(_offset)
)
}
}
}

public func loaders_pre1165_3(in cache: DyldCacheLoaded) -> [PrebuiltLoader_Pre1165_3]? {
// swiftlint:disable:previous unused_parameter
guard let version, version.isPre1165_3 else { return nil }

guard let basePointer = UnsafeRawPointer(bitPattern: address) else {
return nil
}
let offsets: MemorySequence<UInt32> = .init(
basePointer: basePointer
.advanced(by: numericCast(layout.loadersArrayOffset))
.assumingMemoryBound(to: UInt32.self),
numberOfElements: numericCast(layout.loadersArrayCount)
)
return offsets.compactMap { _offset -> PrebuiltLoader_Pre1165_3? in
let layout: PrebuiltLoader_Pre1165_3.Layout = basePointer
.advanced(by: numericCast(_offset))
.autoBoundPointee()
return .init(
layout: layout,
address: address + numericCast(_offset)
)
Expand Down Expand Up @@ -154,3 +213,46 @@ extension PrebuiltLoaderSet {
})
}
}

extension PrebuiltLoaderSet {
public enum KnownVersion: UInt32, CaseIterable {
/// from dyld-940
case v0x041c09d6 = 0x041c09d6
/// from dyld-955
case v0xcb8ba960 = 0xcb8ba960
/// from dyld-1042.1
case v0x4d2b8647 = 0x4d2b8647
/// from dyld-1122.1
case v0xd647423f = 0xd647423f
/// from dyld-1160.6
case v0x9a661060 = 0x9a661060
/// from dyld-1231.3
case v0x173a676e = 0x173a676e

public var isLatest: Bool {
self == .v0x173a676e
}

public var isPre1165_3: Bool {
[
.v0x041c09d6,
.v0xcb8ba960,
.v0x4d2b8647,
.v0xd647423f,
.v0x9a661060
].contains(self)
}
}

public var version: KnownVersion? {
KnownVersion(rawValue: layout.versionHash)
}

public var isKnownVersion: Bool {
version != nil
}

public var isLatestVersion: Bool {
version?.isLatest ?? false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//
// PrebuiltLoader_Pre1165_3.swift
// MachOKit
//
// Created by p-x9 on 2024/11/09
//
//

public struct PrebuiltLoader_Pre1165_3: LayoutWrapper, PrebuiltLoaderProtocol {
public typealias Layout = prebuilt_loader_pre1165_3

public var layout: Layout
public var address: Int
}

extension PrebuiltLoader_Pre1165_3 {
// always true
public var isPrebuilt: Bool {
layout.loader.isPrebuilt != 0
}

public var ref: LoaderRef {
.init(layout: layout.loader.ref)
}
}

extension PrebuiltLoader_Pre1165_3 {
public func path(in cache: DyldCache) -> String? {
guard let offset = cache.fileOffset(
of: numericCast(address) + numericCast(layout.pathOffset)
) else { return nil }
return cache.fileHandle.readString(offset: offset)
}

public func dependentLoaderRefs(in cache: DyldCache) -> DataSequence<LoaderRef>? {
guard layout.dependentLoaderRefsArrayOffset != 0,
let offset = cache.fileOffset(
of: numericCast(address) + numericCast(layout.dependentLoaderRefsArrayOffset)
) else {
return nil
}
return cache.fileHandle.readDataSequence(
offset: offset,
numberOfElements: numericCast(layout.depCount)
)
}
}

extension PrebuiltLoader_Pre1165_3 {
public func path(in cache: DyldCacheLoaded) -> String? {
// swiftlint:disable:previous unused_parameter
guard let baseAddress = UnsafeRawPointer(bitPattern: address) else {
return nil
}
return String(
cString: baseAddress
.advanced(by: numericCast(layout.pathOffset))
.assumingMemoryBound(to: CChar.self)
)
}

public func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence<LoaderRef>? {
// swiftlint:disable:previous unused_parameter
guard layout.dependentLoaderRefsArrayOffset != 0,
let baseAddress = UnsafeRawPointer(bitPattern: address) else {
return nil
}
return .init(
basePointer: baseAddress
.advanced(by: numericCast(layout.dependentLoaderRefsArrayOffset))
.assumingMemoryBound(to: LoaderRef.self),
numberOfElements: numericCast(layout.depCount)
)
}
}

extension PrebuiltLoader_Pre1165_3 {
// [dyld implementation](https://github.com/apple-oss-distributions/dyld/blob/65bbeed63cec73f313b1d636e63f243964725a9d/dyld/Loader.h#L317)
public var magic: String? {
withUnsafeBytes(of: layout.loader.magic.bigEndian, {
let cString = $0.map({ CChar($0)} ) + [0]
return String(
cString: cString,
encoding: .utf8
)
})
}
}
Loading

0 comments on commit 2cd02cf

Please sign in to comment.