-
Notifications
You must be signed in to change notification settings - Fork 3
Supports for Split Dyld Cache Layout #13
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
Conversation
- Returns nil if not loaded from DyldCache - Constructs FullDyldCache using the URL without its extensions
- Implemented a computed property in MachOFile to retrieve the offset. - Added a similar property in DyldCacheRepresentable for consistency. - Updated ObjCMethodList to utilize the new property from MachOFile.
- Ensure offset method returns nil if layout.offset is not positive - Ensure type method returns nil if layout.type is not positive
- Simplifies the code by eliminating unnecessary functionality
- Implement the `layoutOffset(of:)` method using kayPath as the default implementation. - Introduce the `UnresolvedValue` structure to resolve rebase/bind
- Changed dependency versioning for MachOKit in Package.swift - Updated revision in Package.resolved to match the latest state
- Introduced ResolvedValue struct to encapsulate address and offset information, improving clarity in the resolution process. - Removed deprecated code related to cache handling and rebase resolution, ensuring cleaner and more maintainable code.
- Deleted `fullCache` and `cache` properties as they were redundant
- Changed dependency from branch 'main' to version '0.40.0' - Updated revision in Package.resolved to match the new version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors the Mach-O Objective-C section handling to support split dyld cache layouts. The key changes involve centralizing fixup resolution through a new abstraction layer and adapting file I/O operations to work across multiple cache files.
- Introduces
UnresolvedValueandResolvedValuetypes to represent pre- and post-fixup values - Refactors the
_FixupResolvableprotocol to use field-based resolution instead of offset-based - Updates MachOKit dependency from 0.34.0 to 0.40.0
Reviewed Changes
Copilot reviewed 31 out of 32 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| Sources/MachOObjCSection/Util/FixupResolvable.swift | Adds value types and refactors protocol to use field-based resolution with keyPath approach |
| Sources/MachOObjCSection/Protocol/Protocol/_ObjCProtocolLayoutProtocol.swift | Comments out unused size and flags fields |
| Sources/MachOObjCSection/Protocol/Protocol/ObjCProtocolProtocol.swift | Migrates to field-based resolution pattern using unresolvedValue/resolveRebase |
| Sources/MachOObjCSection/Protocol/Ivar/_ObjCIvarLayoutProtocol.swift | Comments out unused alignment and size fields |
| Sources/MachOObjCSection/Protocol/Ivar/ObjCIvarProtocol.swift | Adopts new resolution pattern for ivar fields |
| Sources/MachOObjCSection/Protocol/Class/_ObjCClassLayoutProtocol.swift | Comments out unused swiftClassFlags field |
| Sources/MachOObjCSection/Protocol/Class/RO/_ObjCClassRODataLayoutProtocol.swift | Comments out unused flags, instanceStart, and instanceSize fields |
| Sources/MachOObjCSection/Protocol/Class/RO/ObjCClassRODataProtocol.swift | Refactors all field access to use new resolution pattern |
| Sources/MachOObjCSection/Protocol/Class/ObjCClassProtocol.swift | Updates class reading methods to use field-based resolution |
| Sources/MachOObjCSection/Protocol/Category/ObjCCategoryProtocol.swift | Migrates category protocol handling to new resolution pattern |
| Sources/MachOObjCSection/Model/Protocol/ObjCProtocolList64.swift | Refactors protocol list iteration to use UnresolvedValue approach |
| Sources/MachOObjCSection/Model/Protocol/ObjCProtocolList32.swift | Applies same protocol list refactoring for 32-bit architecture |
| Sources/MachOObjCSection/Model/Protocol/ObjCProtocol64.swift | Changes layoutOffset method to return KeyPath instead |
| Sources/MachOObjCSection/Model/Protocol/ObjCProtocol32.swift | Applies same keyPath change for 32-bit protocol |
| Sources/MachOObjCSection/Model/Property/ObjCPropertyList.swift | Rewrites property list parsing to use resolution pattern |
| Sources/MachOObjCSection/Model/Property/ObjCProperty.swift | Adds UnresolvedProperty and ResolvedProperty types |
| Sources/MachOObjCSection/Model/Method/ObjCMethodList.swift | Refactors method list parsing for new file I/O approach |
| Sources/MachOObjCSection/Model/Ivar/ObjCIvar64.swift | Updates to return KeyPath and removes layout offset calculation |
| Sources/MachOObjCSection/Model/Ivar/ObjCIvar32.swift | Applies same keyPath changes for 32-bit ivar |
| Sources/MachOObjCSection/Model/Class/RO/ObjCClassROData64.swift | Simplifies keyPath switch to only include used fields |
| Sources/MachOObjCSection/Model/Class/RO/ObjCClassROData32.swift | Applies same simplification for 32-bit class RO data |
| Sources/MachOObjCSection/Model/Class/ObjCClass64.swift | Refactors classROData loading with new resolution pattern |
| Sources/MachOObjCSection/Model/Class/ObjCClass32.swift | Applies same classROData refactoring for 32-bit |
| Sources/MachOObjCSection/Model/Category/ObjCCategory64.swift | Simplifies keyPath method for category fields |
| Sources/MachOObjCSection/Model/Category/ObjCCategory32.swift | Applies same category keyPath changes for 32-bit |
| Sources/MachOObjCSection/MachOFile+ObjectiveC.swift | Adds _fileSliceForSection helper and updates section parsing |
| Sources/MachOObjCSection/Extension/MachOFile+.swift | Adds file handle resolution and rebase helper methods |
| Sources/MachOObjCSection/Extension/FullDyldCache+.swift | New file adding fileHandle and fileSegment support |
| Sources/MachOObjCSection/Extension/DyldCacheRepresentable+.swift | New file adding relativeMethodSelectorBaseAddressOffset property |
| Sources/MachOObjCSection/Extension/DyldCache+.swift | Removes unused mainCache property |
| Package.swift | Updates MachOKit dependency to version 0.40.0 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 31 out of 32 changed files in this pull request and generated 13 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #endif | ||
|
|
||
| extension _FixupResolvable { | ||
| #if false |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dead code block (lines 102-133) should be removed rather than commented out with #if false. If this code needs to be preserved for reference, consider documenting why in a comment or moving it to version control history.
| } | ||
| } | ||
|
|
||
| #if false |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dead code block (lines 193-207) should be removed rather than commented out with #if false. Consider removing this unused extension entirely.
| // case size | ||
| // case flags |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out enum cases should be removed if they are no longer needed. If they need to be preserved for future use, add a TODO comment explaining why.
| // case size | |
| // case flags |
| associatedtype ObjCProtocolList: ObjCProtocolListProtocol where ObjCProtocolList.ObjCProtocol == Self | ||
|
|
||
| var layout: Layout { get } | ||
| // var layout: Layout { get } |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out protocol requirement should be removed if no longer needed. The layout property is already inherited from LayoutWrapper protocol.
| // var layout: Layout { get } |
| // case alignment | ||
| // case size |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out enum cases should be removed if they are no longer needed. If they need to be preserved for future use, add a TODO comment explaining why.
| // case alignment | |
| // case size |
| associatedtype ObjCProtocolRelativeListList: ObjCProtocolRelativeListListProtocol where ObjCProtocolRelativeListList.List == ObjCProtocolList | ||
|
|
||
| var layout: Layout { get } | ||
| // var layout: Layout { get } |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out protocol requirement should be removed if no longer needed. The layout property is already inherited from LayoutWrapper protocol.
| // var layout: Layout { get } |
| associatedtype ClassRWData: LayoutWrapper, ObjCClassRWDataProtocol where ClassRWData.Layout.Pointer == Layout.Pointer, ClassRWData.ObjCClassROData == ClassROData | ||
|
|
||
| var layout: Layout { get } | ||
| // var layout: Layout { get } |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out protocol requirement should be removed if no longer needed. The layout property is already inherited from LayoutWrapper protocol.
| // var layout: Layout { get } |
| typealias ObjCProtocolList = ObjCClass.ClassROData.ObjCProtocolList | ||
|
|
||
| var layout: Layout { get } | ||
| // var layout: Layout { get } |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out protocol requirement should be removed if no longer needed. The layout property is already inherited from LayoutWrapper protocol.
| // var layout: Layout { get } |
| case .isa: \.isa | ||
| case .mangledName: \.mangledName | ||
| case .protocols: \.protocols | ||
| case .instanceMethods: \.instanceMethods | ||
| case .classMethods: \.classMethods | ||
| case .optionalInstanceMethods: \.optionalInstanceMethods | ||
| case .optionalClassMethods: \.optionalClassMethods | ||
| case .instanceProperties: \.instanceProperties | ||
| case ._extendedMethodTypes: \._extendedMethodTypes | ||
| case ._demangledName: \._demangledName | ||
| case ._classProperties: \._classProperties |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The switch statement should use return explicitly for each case rather than relying on implicit return. This improves clarity and follows Swift best practices for non-trivial switch statements.
| case .isa: \.isa | |
| case .mangledName: \.mangledName | |
| case .protocols: \.protocols | |
| case .instanceMethods: \.instanceMethods | |
| case .classMethods: \.classMethods | |
| case .optionalInstanceMethods: \.optionalInstanceMethods | |
| case .optionalClassMethods: \.optionalClassMethods | |
| case .instanceProperties: \.instanceProperties | |
| case ._extendedMethodTypes: \._extendedMethodTypes | |
| case ._demangledName: \._demangledName | |
| case ._classProperties: \._classProperties | |
| case .isa: return \.isa | |
| case .mangledName: return \.mangledName | |
| case .protocols: return \.protocols | |
| case .instanceMethods: return \.instanceMethods | |
| case .classMethods: return \.classMethods | |
| case .optionalInstanceMethods: return \.optionalInstanceMethods | |
| case .optionalClassMethods: return \.optionalClassMethods | |
| case .instanceProperties: return \.instanceProperties | |
| case ._extendedMethodTypes: return \._extendedMethodTypes | |
| case ._demangledName: return \._demangledName | |
| case ._classProperties: return \._classProperties |
|
|
||
| return .init( | ||
| address: unresolvedValue.value, | ||
| offset: fileOffset(of: unresolvedValue.value)! |
Copilot
AI
Nov 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Force unwrapping could crash if fileOffset returns nil. Add proper error handling or document why this is guaranteed to succeed.
| offset: fileOffset(of: unresolvedValue.value)! | |
| // If fileOffset returns nil, fallback to 0 to avoid crash. | |
| offset: fileOffset(of: unresolvedValue.value) ?? 0 |
- Updated ObjCClass32, ObjCClass64, and ObjCMethodList extensions - Improved code clarity and consistency
- Simplified offset handling in readString calls for better clarity
- Simplified offset calculation by removing unnecessary variables - Used guard statement for fileHandle and fileOffset retrieval
…machokit-objc-support into feature/support-split-cache-layout
| extension DyldCache { | ||
| var mainCache: DyldCache? { | ||
| if url.lastPathComponent.contains(".") { | ||
| var url = url | ||
| url.deletePathExtension() | ||
| return try? .init(url: url) | ||
| } else { | ||
| return self | ||
| } | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented in MachOKit.
| var cache: DyldCache? { | ||
| guard isLoadedFromDyldCache else { return nil } | ||
| guard let cache = try? DyldCache(url: url) else { | ||
| return nil | ||
| } | ||
| if let mainCache = cache.mainCache { | ||
| return try? .init( | ||
| subcacheUrl: cache.url, | ||
| mainCacheHeader: mainCache.header | ||
| ) | ||
| } | ||
| return cache | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented in MachOKit.
In the iOS dyld shared cache, the DATA and LINKEDIT sections are separated into distinct subcaches.
Fixed to account for these cases when reading sections.
Additionally, parts that had not undergone rebase processing have been corrected to ensure they are processed correctly.