Skip to content

Commit b961b6b

Browse files
committed
Return protocols and classes paired with their defining Mach-O files
1 parent bb276ad commit b961b6b

File tree

6 files changed

+291
-111
lines changed

6 files changed

+291
-111
lines changed

Sources/MachOObjCSection/Model/Protocol/ObjCProtocolList32.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ public struct ObjCProtocolList32: ObjCProtocolListProtocol {
2626
extension ObjCProtocolList32 {
2727
public func protocols(
2828
in machO: MachOImage
29-
) -> [ObjCProtocol]? {
29+
) -> [(MachOImage, ObjCProtocol)]? {
3030
_readProtocols(in: machO, pointerType: UInt32.self)
3131
}
3232

3333
public func protocols(
3434
in machO: MachOFile
35-
) -> [ObjCProtocol]? {
35+
) -> [(MachOFile, ObjCProtocol)]? {
3636
guard !isListOfLists else {
3737
assertionFailure()
3838
return nil
@@ -63,23 +63,32 @@ extension ObjCProtocolList32 {
6363
let offset = $0 + numericCast(headerStartOffset)
6464
var resolvedOffset = offset
6565

66+
var targetMachO = machO
67+
6668
var fileHandle = machO.fileHandle
6769

6870
if let (_cache, _offset) = machO.cacheAndFileOffset(
6971
fromStart: offset
7072
) {
7173
resolvedOffset = _offset
7274
fileHandle = _cache.fileHandle
75+
76+
let unslidAddress = offset + _cache.mainCacheHeader.sharedRegionStart
77+
if !targetMachO.contains(unslidAddress: unslidAddress),
78+
let machO = _cache.machO(containing: unslidAddress) {
79+
targetMachO = machO
80+
}
7381
}
7482

7583
let layout: ObjCProtocol32.Layout = fileHandle.read(
7684
offset: numericCast(resolvedOffset),
7785
swapHandler: { _ in }
7886
)
79-
return .init(
87+
let `protocol`: ObjCProtocol = .init(
8088
layout: layout,
8189
offset: numericCast(offset) - machO.headerStartOffset
8290
)
91+
return (targetMachO, `protocol`)
8392
}
8493
}
8594
}

Sources/MachOObjCSection/Model/Protocol/ObjCProtocolList64.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ public struct ObjCProtocolList64: ObjCProtocolListProtocol {
2626
extension ObjCProtocolList64 {
2727
public func protocols(
2828
in machO: MachOImage
29-
) -> [ObjCProtocol]? {
29+
) -> [(MachOImage, ObjCProtocol)]? {
3030
_readProtocols(in: machO, pointerType: UInt64.self)
3131
}
3232

3333
public func protocols(
3434
in machO: MachOFile
35-
) -> [ObjCProtocol]? {
35+
) -> [(MachOFile, ObjCProtocol)]? {
3636
guard !isListOfLists else {
3737
assertionFailure()
3838
return nil
@@ -63,23 +63,32 @@ extension ObjCProtocolList64 {
6363
let offset = machO.fileOffset(of: $0) + numericCast(headerStartOffset)
6464
var resolvedOffset = offset
6565

66+
var targetMachO = machO
67+
6668
var fileHandle = machO.fileHandle
6769

6870
if let (_cache, _offset) = machO.cacheAndFileOffset(
6971
fromStart: offset
7072
) {
7173
resolvedOffset = _offset
7274
fileHandle = _cache.fileHandle
75+
76+
let unslidAddress = offset + _cache.mainCacheHeader.sharedRegionStart
77+
if !targetMachO.contains(unslidAddress: unslidAddress),
78+
let machO = _cache.machO(containing: unslidAddress) {
79+
targetMachO = machO
80+
}
7381
}
7482

7583
let layout: ObjCProtocol64.Layout = fileHandle.read(
7684
offset: numericCast(resolvedOffset),
7785
swapHandler: { _ in }
7886
)
79-
return .init(
87+
let `protocol`: ObjCProtocol = .init(
8088
layout: layout,
8189
offset: numericCast(offset) - machO.headerStartOffset
8290
)
91+
return (targetMachO, `protocol`)
8392
}
8493
}
8594
}

Sources/MachOObjCSection/Protocol/Category/ObjCCategoryProtocol.swift

Lines changed: 115 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// MachOObjCSection
44
//
55
// Created by p-x9 on 2024/12/06
6-
//
6+
//
77
//
88

99
import Foundation
@@ -24,8 +24,8 @@ public protocol ObjCCategoryProtocol: _FixupResolvable where LayoutField == ObjC
2424
init(layout: Layout, offset: Int, isCatlist2: Bool)
2525

2626
func name(in machO: MachOFile) -> String?
27-
func `class`(in machO: MachOFile) -> ObjCClass?
28-
func stubClass(in machO: MachOFile) -> ObjCStubClass?
27+
func `class`(in machO: MachOFile) -> (MachOFile, ObjCClass)?
28+
func stubClass(in machO: MachOFile) -> (MachOFile, ObjCStubClass)?
2929
func className(in machO: MachOFile) -> String?
3030
func instanceMethodList(in machO: MachOFile) -> ObjCMethodList?
3131
func classMethodList(in machO: MachOFile) -> ObjCMethodList?
@@ -34,8 +34,8 @@ public protocol ObjCCategoryProtocol: _FixupResolvable where LayoutField == ObjC
3434
func protocolList(in machO: MachOFile) -> ObjCProtocolList?
3535

3636
func name(in machO: MachOImage) -> String?
37-
func `class`(in machO: MachOImage) -> ObjCClass?
38-
func stubClass(in machO: MachOImage) -> ObjCStubClass?
37+
func `class`(in machO: MachOImage) -> (MachOImage, ObjCClass)?
38+
func stubClass(in machO: MachOImage) -> (MachOImage, ObjCStubClass)?
3939
func className(in machO: MachOImage) -> String?
4040
func instanceMethodList(in machO: MachOImage) -> ObjCMethodList?
4141
func classMethodList(in machO: MachOImage) -> ObjCMethodList?
@@ -58,27 +58,28 @@ extension ObjCCategoryProtocol {
5858
return machO.fileHandle.readString(offset: numericCast(offset))
5959
}
6060

61-
public func `class`(in machO: MachOFile) -> ObjCClass? {
62-
guard let cls = _readClass(
61+
public func `class`(in machO: MachOFile) -> (MachOFile, ObjCClass)? {
62+
guard let (machO, cls) = _readClass(
6363
at: numericCast(layout.cls),
6464
field: .cls,
6565
in: machO
6666
) else { return nil }
6767

6868
if cls.isStubClass { return nil }
6969

70-
return cls
70+
return (machO, cls)
7171
}
72-
public func stubClass(in machO: MachOFile) -> ObjCStubClass? {
73-
guard let cls = _readStubClass(
72+
73+
public func stubClass(in machO: MachOFile) -> (MachOFile, ObjCStubClass)? {
74+
guard let (machO, cls) = _readStubClass(
7475
at: numericCast(layout.cls),
7576
field: .cls,
7677
in: machO
7778
) else { return nil }
7879

7980
guard cls.isStubClass else { return nil }
8081

81-
return cls
82+
return (machO, cls)
8283
}
8384

8485
public func className(in machO: MachOFile) -> String? {
@@ -163,38 +164,58 @@ extension ObjCCategoryProtocol {
163164
)
164165
}
165166

166-
public func `class`(in machO: MachOImage) -> ObjCClass? {
167+
public func `class`(in machO: MachOImage) -> (MachOImage, ObjCClass)? {
167168
guard layout.cls > 0 else { return nil }
168169
guard let ptr = UnsafeRawPointer(bitPattern: UInt(layout.cls)) else {
169170
return nil
170171
}
171-
let offset: Int = numericCast(layout.cls) - Int(bitPattern: machO.ptr)
172+
173+
var targetMachO = machO
174+
if !targetMachO.contains(ptr: ptr) {
175+
guard let cache = DyldCacheLoaded.current,
176+
let _targetMachO = cache.machO(containing: ptr) else {
177+
return nil
178+
}
179+
targetMachO = _targetMachO
180+
}
181+
182+
let offset: Int = numericCast(layout.cls) - Int(bitPattern: targetMachO.ptr)
172183

173184
let layout = ptr.assumingMemoryBound(to: ObjCClass.Layout.self).pointee
174185
let cls: ObjCClass = .init(layout: layout, offset: offset)
175186

176187
if cls.isStubClass { return nil }
177188

178-
return cls
189+
return (targetMachO, cls)
179190
}
180191

181-
public func stubClass(in machO: MachOImage) -> ObjCStubClass? {
192+
public func stubClass(in machO: MachOImage) -> (MachOImage, ObjCStubClass)? {
182193
guard layout.cls > 0 else { return nil }
183194
guard let ptr = UnsafeRawPointer(bitPattern: UInt(layout.cls)) else {
184195
return nil
185196
}
186-
let offset: Int = numericCast(layout.cls) - Int(bitPattern: machO.ptr)
197+
198+
var targetMachO = machO
199+
if !targetMachO.contains(ptr: ptr) {
200+
guard let cache = DyldCacheLoaded.current,
201+
let _targetMachO = cache.machO(containing: ptr) else {
202+
return nil
203+
}
204+
targetMachO = _targetMachO
205+
}
206+
207+
let offset: Int = numericCast(layout.cls) - Int(bitPattern: targetMachO.ptr)
187208

188209
let layout = ptr.assumingMemoryBound(to: ObjCStubClass.Layout.self).pointee
189210
let cls: ObjCStubClass = .init(layout: layout, offset: offset)
190211

191212
guard cls.isStubClass else { return nil }
192213

193-
return cls
214+
return (targetMachO, cls)
194215
}
195216

196217
public func className(in machO: MachOImage) -> String? {
197-
guard let cls = `class`(in: machO) else {
218+
guard let (machO, cls) = `class`(in: machO) else {
198219
if let section = machO.sectionNumber(for: .__objc_const),
199220
let symbol = machO.symbol(
200221
for: offset, inSection: section
@@ -261,12 +282,50 @@ extension ObjCCategoryProtocol {
261282
}
262283
}
263284

285+
extension ObjCCategoryProtocol {
286+
@available(*, deprecated, renamed: "class(in:)", message: "Use `class(in:)` that returns machO that contains class")
287+
public func `class`(in machO: MachOFile) -> ObjCClass? {
288+
guard let (_, cls) = self.class(in: machO) else {
289+
return nil
290+
}
291+
return cls
292+
}
293+
294+
@available(*, deprecated, renamed: "stubClass(in:)", message: "Use `stubCclass(in:)` that returns machO that contains class")
295+
public func stubClass(in machO: MachOFile) -> ObjCStubClass? {
296+
guard let (_, cls) = self.stubClass(in: machO) else {
297+
return nil
298+
}
299+
return cls
300+
}
301+
302+
@available(*, deprecated, renamed: "class(in:)", message: "Use `class(in:)` that returns machO that contains class")
303+
func `class`(in machO: MachOImage) -> ObjCClass? {
304+
guard let (targetMachO, cls) = self.class(in: machO) else { return nil }
305+
let diff = Int(bitPattern: targetMachO.ptr) - Int(bitPattern: machO.ptr)
306+
return .init(
307+
layout: cls.layout,
308+
offset: cls.offset + diff
309+
)
310+
}
311+
312+
@available(*, deprecated, renamed: "stubClass(in:)", message: "Use `stubCclass(in:)` that returns machO that contains class")
313+
func stubClass(in machO: MachOImage) -> ObjCStubClass? {
314+
guard let (targetMachO, cls) = self.stubClass(in: machO) else { return nil }
315+
let diff = Int(bitPattern: targetMachO.ptr) - Int(bitPattern: machO.ptr)
316+
return .init(
317+
layout: cls.layout,
318+
offset: cls.offset + diff
319+
)
320+
}
321+
}
322+
264323
extension ObjCCategoryProtocol {
265324
private func _readClass(
266325
at offset: UInt64,
267326
field: LayoutField,
268327
in machO: MachOFile
269-
) -> ObjCClass? {
328+
) -> (MachOFile, ObjCClass)? {
270329
guard offset > 0 else { return nil }
271330
var offset: UInt64 = machO.fileOffset(
272331
of: numericCast(offset)
@@ -277,50 +336,69 @@ extension ObjCCategoryProtocol {
277336
}
278337
if isBind(field, in: machO) { return nil }
279338

339+
var targetMachO = machO
340+
341+
var fileHandle = machO.fileHandle
280342
var resolvedOffset = offset
281-
if let cache = machO.cache {
282-
guard let _offset = cache.fileOffset(of: offset + cache.mainCacheHeader.sharedRegionStart) else {
283-
return nil
284-
}
343+
if let (_cache, _offset) = machO.cacheAndFileOffset(
344+
fromStart: offset
345+
) {
285346
resolvedOffset = _offset
347+
fileHandle = _cache.fileHandle
348+
349+
let unslidAddress = offset + _cache.mainCacheHeader.sharedRegionStart
350+
if !targetMachO.contains(unslidAddress: unslidAddress),
351+
let machO = _cache.machO(containing: unslidAddress) {
352+
targetMachO = machO
353+
}
286354
}
287355

288-
let layout: ObjCClass.Layout = machO.fileHandle.read(offset: resolvedOffset)
289-
return .init(
356+
let layout: ObjCClass.Layout = fileHandle.read(offset: resolvedOffset)
357+
let cls: ObjCClass = .init(
290358
layout: layout,
291359
offset: numericCast(offset) - machO.headerStartOffset
292360
)
361+
return (targetMachO, cls)
293362
}
294363

295364
func _readStubClass(
296365
at offset: UInt64,
297366
field: LayoutField,
298367
in machO: MachOFile
299-
) -> ObjCStubClass? {
368+
) -> (MachOFile, ObjCStubClass)? {
300369
guard offset > 0 else { return nil }
301370
var offset: UInt64 = machO.fileOffset(
302371
of: numericCast(offset)
303372
) + numericCast(machO.headerStartOffset)
304373

305-
306374
if let resolved = resolveRebase(field, in: machO) {
307375
offset = machO.fileOffset(of: resolved) + numericCast(machO.headerStartOffset)
308376
}
309377
if isBind(field, in: machO) { return nil }
310378

379+
var targetMachO = machO
380+
381+
var fileHandle = machO.fileHandle
311382
var resolvedOffset = offset
312-
if let cache = machO.cache {
313-
guard let _offset = cache.fileOffset(of: offset + cache.mainCacheHeader.sharedRegionStart) else {
314-
return nil
315-
}
383+
if let (_cache, _offset) = machO.cacheAndFileOffset(
384+
fromStart: offset
385+
) {
316386
resolvedOffset = _offset
387+
fileHandle = _cache.fileHandle
388+
389+
let unslidAddress = offset + _cache.mainCacheHeader.sharedRegionStart
390+
if !targetMachO.contains(unslidAddress: unslidAddress),
391+
let machO = _cache.machO(containing: unslidAddress) {
392+
targetMachO = machO
393+
}
317394
}
318395

319-
let layout: ObjCStubClass.Layout = machO.fileHandle.read(offset: resolvedOffset)
320-
return .init(
396+
let layout: ObjCStubClass.Layout = fileHandle.read(offset: resolvedOffset)
397+
let cls: ObjCStubClass = .init(
321398
layout: layout,
322399
offset: numericCast(offset) - machO.headerStartOffset
323400
)
401+
return (targetMachO, cls)
324402
}
325403

326404
private func _readClassName(
@@ -330,13 +408,13 @@ extension ObjCCategoryProtocol {
330408
) -> String? {
331409
guard offset > 0 else { return nil }
332410

333-
if let cls = _readClass(
411+
if let (targetMachO, cls) = _readClass(
334412
at: offset,
335413
field: field,
336414
in: machO
337415
), !cls.isStubClass ,
338-
let data = cls.classROData(in: machO) {
339-
return data.name(in: machO)
416+
let data = cls.classROData(in: targetMachO) {
417+
return data.name(in: targetMachO)
340418
}
341419

342420
if let bindSymbolName = resolveBind(field, in: machO) {
@@ -360,7 +438,7 @@ extension ObjCCategoryProtocol {
360438
) + numericCast(machO.headerStartOffset)
361439

362440
if let resolved = resolveRebase(field, in: machO),
363-
resolved != offset {
441+
resolved != offset {
364442
offset = machO.fileOffset(of: resolved) + numericCast(machO.headerStartOffset)
365443
}
366444
// if isBind(\.baseMethods, in: machO) { return nil }

0 commit comments

Comments
 (0)