├── .github
└── workflows
│ ├── ci.yml
│ ├── docc.yml
│ ├── release.yml
│ └── update-prebuild-spm.yml
├── .gitignore
├── .spi.yml
├── .swiftlint.yml
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── LICENSE
├── MachOKit.docc
├── MachOKit.md
└── MachOKitC.md
├── Makefile
├── Package.resolved
├── Package.swift
├── README.md
├── Sources
├── MachOKit
│ ├── DyldCache+SubCaches.swift
│ ├── DyldCache.swift
│ ├── DyldCacheLoaded+SubCaches.swift
│ ├── DyldCacheLoaded+static.swift
│ ├── DyldCacheLoaded.swift
│ ├── Extension
│ │ ├── Data+.swift
│ │ ├── FileHandle+.swift
│ │ ├── FixedWidthInteger+.swift
│ │ ├── Sequence+.swift
│ │ ├── String+.swift
│ │ ├── TrieTreeProtocol+.swift
│ │ ├── UUID+.swift
│ │ ├── UnsafePointer+.swift
│ │ ├── UnsafeRawPointer+.swift
│ │ ├── _FileIOProtocol+.swift
│ │ └── dyld_chained_ptr+.swift
│ ├── FatFile.swift
│ ├── Header
│ │ ├── CPU.swift
│ │ ├── CPUSubType.swift
│ │ ├── CPUType.swift
│ │ ├── DyldCacheHeader
│ │ │ ├── DyldCacheHeader.swift
│ │ │ └── DyldCacheType.swift
│ │ ├── FatHeader
│ │ │ ├── FatArch.swift
│ │ │ └── FatHeader.swift
│ │ ├── MachHeader
│ │ │ ├── FileType.swift
│ │ │ ├── MachHeader+Flags+Bit.swift
│ │ │ ├── MachHeader+Flags.swift
│ │ │ └── MachHeader.swift
│ │ └── Magic.swift
│ ├── LoadCommand
│ │ ├── BuildVersionCommand.swift
│ │ ├── DylibCommand.swift
│ │ ├── DylibUseCommand.swift
│ │ ├── DylinkerCommand.swift
│ │ ├── EncryptionInfoCommand.swift
│ │ ├── EntryPointCommand.swift
│ │ ├── LinkerOptionCommand.swift
│ │ ├── LoadCommand.swift
│ │ ├── LoadCommandInfo.swift
│ │ ├── LoadCommandType.swift
│ │ ├── Model
│ │ │ ├── BuildToolVersion.swift
│ │ │ ├── Dylib.swift
│ │ │ ├── DylibUseFlags.swift
│ │ │ ├── Platform.swift
│ │ │ ├── Section+Attribute.swift
│ │ │ ├── Section+Flags.swift
│ │ │ ├── Section+Type.swift
│ │ │ ├── Section.swift
│ │ │ ├── ThreadState.swift
│ │ │ ├── ThreadStateFlavor.swift
│ │ │ ├── Tool.swift
│ │ │ ├── VMProtection.swift
│ │ │ └── Version.swift
│ │ ├── NoteCommand.swift
│ │ ├── RpathCommand.swift
│ │ ├── SegmentCommand+Flags.swift
│ │ ├── SegmentCommand.swift
│ │ ├── SourceVersionCommand.swift
│ │ ├── TargetTripleCommand.swift
│ │ ├── ThreadCommand.swift
│ │ ├── UUIDCommand.swift
│ │ └── VersionMinCommand.swift
│ ├── MachOFile+BindOperations.swift
│ ├── MachOFile+CodeSign.swift
│ ├── MachOFile+DyldChainedFixups.swift
│ ├── MachOFile+ExportTrie.swift
│ ├── MachOFile+FunctionStarts.swift
│ ├── MachOFile+LoadCommands.swift
│ ├── MachOFile+RebaseOperations.swift
│ ├── MachOFile+Strings.swift
│ ├── MachOFile+Symbols.swift
│ ├── MachOFile.swift
│ ├── MachOImage+BindOperations.swift
│ ├── MachOImage+CodeSign.swift
│ ├── MachOImage+DyldChainedFixups..swift
│ ├── MachOImage+ExportTrie.swift
│ ├── MachOImage+FunctionStarts.swift
│ ├── MachOImage+LoadCommands.swift
│ ├── MachOImage+RebaseOperations.swift
│ ├── MachOImage+Strings.swift
│ ├── MachOImage+Symbols.swift
│ ├── MachOImage+static.swift
│ ├── MachOImage.swift
│ ├── MachOKit.swift
│ ├── Model
│ │ ├── Bind
│ │ │ ├── BindOpcode.swift
│ │ │ ├── BindOperation.swift
│ │ │ ├── BindOperationsKind.swift
│ │ │ ├── BindSpecial.swift
│ │ │ ├── BindType.swift
│ │ │ └── ClassicBindType.swift
│ │ ├── BindingSymbol.swift
│ │ ├── ClassicBindingSymbol.swift
│ │ ├── Codesign
│ │ │ ├── CodeDirectory
│ │ │ │ ├── CodeSignCodeDirectory+codeLimit64.swift
│ │ │ │ ├── CodeSignCodeDirectory+executableSegment.swift
│ │ │ │ ├── CodeSignCodeDirectory+runtime.swift
│ │ │ │ ├── CodeSignCodeDirectory+scatter.swift
│ │ │ │ ├── CodeSignCodeDirectory+teamID.swift
│ │ │ │ └── CodeSignCodeDirectory.swift
│ │ │ ├── CodeSignBlobIndex.swift
│ │ │ ├── CodeSignExecSegmentFlags.swift
│ │ │ ├── CodeSignGenericBlob.swift
│ │ │ ├── CodeSignHashType.swift
│ │ │ ├── CodeSignMagic.swift
│ │ │ ├── CodeSignSlot.swift
│ │ │ ├── CodeSignSpecialSlotType.swift
│ │ │ └── CodeSignSuperBlob.swift
│ │ ├── CoreFoundation
│ │ │ └── CFString.swift
│ │ ├── DataInCodeEntry.swift
│ │ ├── DependedDylib.swift
│ │ ├── DyldCache
│ │ │ ├── DyldCacheDynamicData.swift
│ │ │ ├── DyldCacheFunctionVariantEntry.swift
│ │ │ ├── DyldCacheFunctionVariantInfo.swift
│ │ │ ├── DyldCacheImageInfo.swift
│ │ │ ├── DyldCacheImageTextInfo.swift
│ │ │ ├── DyldCacheLocalSymbolsEntry.swift
│ │ │ ├── DyldCacheLocalSymbolsInfo.swift
│ │ │ ├── DyldCacheMappingAndSlideInfo.swift
│ │ │ ├── DyldCacheMappingFlags.swift
│ │ │ ├── DyldCacheMappingInfo.swift
│ │ │ ├── DyldCachePrewarming.swift
│ │ │ ├── DyldCachePrewarmingEntry.swift
│ │ │ ├── DyldCacheTproMappingInfo.swift
│ │ │ ├── DyldSubCacheEntry.swift
│ │ │ ├── DylibIndex.swift
│ │ │ ├── DylibsTrieNodeContent.swift
│ │ │ ├── Loader
│ │ │ │ ├── LoaderRef.swift
│ │ │ │ ├── ObjCBinaryInfo.swift
│ │ │ │ ├── PrebuiltLoader.swift
│ │ │ │ ├── PrebuiltLoaderProtocol.swift
│ │ │ │ ├── PrebuiltLoaderSet.swift
│ │ │ │ ├── PrebuiltLoader_Pre1165_3.swift
│ │ │ │ └── SectionLocations.swift
│ │ │ ├── ObjCOptimization
│ │ │ │ ├── ObjCHeaderInfoRO.swift
│ │ │ │ ├── ObjCHeaderInfoRW.swift
│ │ │ │ ├── ObjCHeaderOptimizationRO.swift
│ │ │ │ ├── ObjCHeaderOptimizationRW.swift
│ │ │ │ ├── ObjCImageInfo.swift
│ │ │ │ ├── ObjCOptimization.swift
│ │ │ │ └── OldObjCOptimization.swift
│ │ │ ├── ProgramOffset.swift
│ │ │ ├── ProgramsTrieNodeContent.swift
│ │ │ ├── SlideInfo
│ │ │ │ ├── DyldCacheSlideInfo.swift
│ │ │ │ ├── DyldCacheSlideInfo1.swift
│ │ │ │ ├── DyldCacheSlideInfo2.swift
│ │ │ │ ├── DyldCacheSlideInfo3.swift
│ │ │ │ ├── DyldCacheSlideInfo4.swift
│ │ │ │ └── DyldCacheSlideInfo5.swift
│ │ │ └── SwiftOptimization.swift
│ │ ├── DyldChain
│ │ │ ├── DyldChainedFixupPointer.swift
│ │ │ ├── DyldChainedFixupPointerContent.swift
│ │ │ ├── DyldChainedFixupPointerFormat.swift
│ │ │ ├── DyldChainedFixupPointerInfo.swift
│ │ │ ├── DyldChainedFixupsHeader.swift
│ │ │ ├── DyldChainedImport.swift
│ │ │ ├── DyldChainedImportFormat.swift
│ │ │ ├── DyldChainedPage.swift
│ │ │ ├── DyldChainedStartsInImage.swift
│ │ │ ├── DyldChainedStartsInSegment.swift
│ │ │ ├── DyldChainedStartsOffsets.swift
│ │ │ └── DyldChainedSymbolsFormat.swift
│ │ ├── Export
│ │ │ ├── ExportSymbolFlags.swift
│ │ │ ├── ExportSymbolKind.swift
│ │ │ └── ExportTrieEntry.swift
│ │ ├── ExportedSymbol.swift
│ │ ├── FunctionStart.swift
│ │ ├── IndirectSymbol.swift
│ │ ├── Rebase.swift
│ │ ├── Rebase
│ │ │ ├── RebaseOpcode.swift
│ │ │ ├── RebaseOperation.swift
│ │ │ └── RebaseType.swift
│ │ ├── Relocation
│ │ │ ├── Relocation.swift
│ │ │ ├── RelocationInfo.swift
│ │ │ ├── RelocationLength.swift
│ │ │ ├── RelocationType.swift
│ │ │ └── ScatteredRelocationInfo.swift
│ │ ├── StringTableEntry.swift
│ │ └── Symbol
│ │ │ ├── Nlist.swift
│ │ │ ├── Stab.swift
│ │ │ ├── SymbolDescription.swift
│ │ │ ├── SymbolFlags.swift
│ │ │ ├── SymbolLibraryOrdinalType.swift
│ │ │ ├── SymbolReferenceFlag.swift
│ │ │ └── SymbolType.swift
│ ├── Protocol
│ │ ├── CodeSignProtocol.swift
│ │ ├── DyldCacheLocalSymbolsEntryProtocol.swift
│ │ ├── DyldCacheRepresentable.swift
│ │ ├── DyldChainedFixupsProtocol.swift
│ │ ├── DyldChainedImportProtocol.swift
│ │ ├── LayoutWrapper.swift
│ │ ├── LoadCommandWrapper.swift
│ │ ├── LoadCommandsProtocol.swift
│ │ ├── MachORepresentable.swift
│ │ ├── StringTable.swift
│ │ └── SymbolProtocol.swift
│ └── Util
│ │ ├── BitFlags.swift
│ │ ├── Sequence
│ │ ├── DataSequence.swift
│ │ └── MemorySequence.swift
│ │ ├── SwiftDemangle.swift
│ │ ├── TrieTree
│ │ ├── DataTrieTree.swift
│ │ ├── MemoryTrieTree.swift
│ │ ├── Model
│ │ │ └── TrieNode.swift
│ │ └── Protocol
│ │ │ ├── TrieNodeContent.swift
│ │ │ └── TrieTreeProtocol.swift
│ │ ├── exported.swift
│ │ └── global.swift
└── MachOKitC
│ ├── include
│ ├── backports.h
│ ├── codesign.h
│ ├── core_foundation.h
│ ├── dyld_cache.h
│ ├── dyld_cache_format.h
│ ├── dyld_cache_loader.h
│ ├── fixup-chains.h
│ ├── mach-o.h
│ ├── objc.h
│ ├── swift.h
│ └── thread_state.h
│ ├── mach-o-linux.c
│ ├── mach-o
│ ├── fat.h
│ ├── loader.h
│ ├── nlist.h
│ ├── reloc.h
│ └── stab.h
│ └── mach
│ ├── machine.h
│ └── vm_prot.h
├── Tests
└── MachOKitTests
│ ├── DyldCacheLoadedPrintTests.swift
│ ├── DyldCachePrintTests.swift
│ ├── MachOFilePrintTests.swift
│ ├── MachOKitTests.swift
│ └── MachOPrintTests.swift
└── scripts
├── docc-preview.sh
├── docc.sh
├── generate-symbols.sh
└── xcframework.sh
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths-ignore:
8 | - README.md
9 | - LICENSE
10 | pull_request:
11 | paths-ignore:
12 | - README.md
13 | - LICENSE
14 | workflow_dispatch:
15 |
16 | permissions:
17 | contents: read
18 |
19 | env:
20 | DEVELOPER_DIR: /Applications/Xcode_16.2.app
21 |
22 | jobs:
23 | build:
24 | name: Build & Test
25 | runs-on: macos-15
26 | steps:
27 | - name: Checkout
28 | uses: actions/checkout@v4
29 |
30 | - name: Select Xcode 16
31 | run: sudo xcode-select -s /Applications/Xcode_16.2.app
32 |
33 | - name: Build
34 | run: swift build
35 |
36 | linux-build:
37 | name: Linux Test
38 | runs-on: ubuntu-22.04
39 | steps:
40 | - name: Install Swift
41 | # WORKAROUND:https://github.com/swift-actions/setup-swift/pull/680
42 | uses: swift-actions/setup-swift@bb83339d1e8577741bdc6c65ba551ce7dc0fb854
43 | with:
44 | swift-version: '5.10.1'
45 |
46 | - uses: actions/checkout@v4
47 |
48 | - name: Build
49 | run: swift build
50 |
--------------------------------------------------------------------------------
/.github/workflows/docc.yml:
--------------------------------------------------------------------------------
1 | name: DocC
2 |
3 | on:
4 | workflow_call:
5 | workflow_dispatch:
6 |
7 | jobs:
8 | build:
9 | name: Generate DocC
10 | runs-on: macos-15
11 | steps:
12 | - uses: actions/checkout@v3
13 |
14 | - name: Select Xcode 16
15 | run: sudo xcode-select -s /Applications/Xcode_16.0.app
16 |
17 | - name: Build DocC
18 | run: |
19 | make docc
20 |
21 | - uses: actions/upload-pages-artifact@v3
22 | with:
23 | path: docs
24 |
25 | deploy:
26 | needs: build
27 | permissions:
28 | pages: write
29 | id-token: write
30 | environment:
31 | name: github-pages
32 | url: ${{ steps.deployment.outputs.page_url }}
33 | runs-on: macos-15
34 | steps:
35 | - name: Deploy to GitHub Pages
36 | id: deployment
37 | uses: actions/deploy-pages@v4
38 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*.*.*'
7 | workflow_dispatch:
8 |
9 | env:
10 | DEVELOPER_DIR: /Applications/Xcode_15.2.app
11 |
12 | jobs:
13 | build:
14 | name: Release
15 | runs-on: macos-14
16 | steps:
17 | - name: Checkout
18 | uses: actions/checkout@v4
19 |
20 | - name: Select Xcode 15
21 | run: sudo xcode-select -s /Applications/Xcode_15.2.app
22 |
23 | - name: Install visionOS
24 | run: |
25 | sudo xcodebuild -runFirstLaunch
26 | sudo xcrun simctl list
27 | sudo xcodebuild -downloadPlatform visionOS
28 | sudo xcodebuild -runFirstLaunch
29 |
30 | - name: Build
31 | run: bash scripts/xcframework.sh
32 |
33 | - name: Check Sum
34 | run: |
35 | machokit="$(swift package compute-checksum XCFrameworks/MachOKit.xcframework.zip)"
36 | machokitc="$(swift package compute-checksum XCFrameworks/MachOKitC.xcframework.zip)"
37 | echo "machokit_checksum=$machokit" >> $GITHUB_ENV
38 | echo "machokitc_checksum=$machokitc" >> $GITHUB_ENV
39 | echo "MachOKit $machokit"
40 | echo "MachOKitC $machokitc"
41 |
42 | - name: Get tag version
43 | id: get_tag_version
44 | run: |
45 | echo "$(git tag --sort=creatordate | tail -n 1)" > CURRENT_TAG
46 | echo "current_tag=$(cat CURRENT_TAG)" >> $GITHUB_OUTPUT
47 | echo "previous_tag=$(\
48 | curl -H 'Accept: application/vnd.github.v3+json' \
49 | -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' \
50 | https://api.github.com/repos/${{ github.repository }}/releases/latest \
51 | | jq -r .tag_name)\
52 | " >> $GITHUB_OUTPUT
53 |
54 | - name: Generate release note
55 | id: release_note
56 | run: |
57 | echo -e "$(\
58 | curl -X POST \
59 | -H 'Accept: application/vnd.github.v3+json' \
60 | -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' \
61 | https://api.github.com/repos/${{ github.repository }}/releases/generate-notes \
62 | -d '{"tag_name":"${{ steps.get_tag_version.outputs.current_tag }}", "previous_tag_name":"${{ steps.get_tag_version.outputs.previous_tag }}"}' \
63 | | jq .body| sed 's/"//g'\
64 | )" > release_body.txt
65 | echo -e "\n" >> release_body.txt
66 | echo -e "MachOKit\n$machokit_checksum\n" >> release_body.txt
67 | echo -e "MachOKitC\n$machokitc_checksum" >> release_body.txt
68 |
69 | - name: Release
70 | env:
71 | GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
72 | uses: softprops/action-gh-release@v1
73 | with:
74 | body_path: "./release_body.txt"
75 | files: |
76 | ./XCFrameworks/MachOKit.xcframework.zip
77 | ./XCFrameworks/MachOKitC.xcframework.zip
78 |
79 | docc:
80 | name: Deploy Document
81 | needs: [build]
82 | uses: ./.github/workflows/docc.yml
83 |
--------------------------------------------------------------------------------
/.github/workflows/update-prebuild-spm.yml:
--------------------------------------------------------------------------------
1 | name: Update Prebuilt SPM
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | update-binary-target:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - name: Extract Release Information
13 | id: release_info
14 | env:
15 | VERSION: ${{ github.event.release.tag_name }}
16 | RELEASE_BODY: ${{ github.event.release.body }}
17 | run: |
18 | MACHOKIT_CHECKSUM=$(echo "$RELEASE_BODY" | awk -v target="MachOKit" '
19 | found { print; exit }
20 | $0 == target { found=1 }
21 | ')
22 | MACHOKITC_CHECKSUM=$(echo "$RELEASE_BODY" | awk -v target="MachOKitC" '
23 | found { print; exit }
24 | $0 == target { found=1 }
25 | ')
26 |
27 | echo "VERSION=${VERSION}" >> $GITHUB_ENV
28 | echo "MACHOKIT_CHECKSUM=${MACHOKIT_CHECKSUM}" >> $GITHUB_ENV
29 | echo "MACHOKITC_CHECKSUM=${MACHOKITC_CHECKSUM}" >> $GITHUB_ENV
30 |
31 | - name: Send repository_dispatch event
32 | run: |
33 | curl -X POST -H "Accept: application/vnd.github.v3+json" \
34 | -H "Authorization: token ${{ secrets.PERSONAL_ACCESS_TOKEN }}" \
35 | https://api.github.com/repos/p-x9/MachOKit-SPM/dispatches \
36 | --data "$(jq -n \
37 | --arg version "$VERSION" \
38 | --arg machOKitChecksum "$MACHOKIT_CHECKSUM" \
39 | --arg machOKitCChecksum "$MACHOKITC_CHECKSUM" \
40 | '{event_type: "update_binary_version", client_payload: {version: $version, "mach-o_kit_checksum": $machOKitChecksum, "mach-o_kit_c_checksum": $machOKitCChecksum}}')"
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | xcuserdata/
5 | DerivedData/
6 | .swiftpm/configuration/registries.json
7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8 | .netrc
9 |
10 | XCFrameworks/
11 | docs/
12 | symbol-graphs/
--------------------------------------------------------------------------------
/.spi.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 | external_links:
3 | documentation: "https://p-x9.github.io/MachOKit/documentation/machokit/"
4 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 p-x9
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MachOKit.docc/MachOKit.md:
--------------------------------------------------------------------------------
1 | # ``MachOKit``
2 |
3 | 🔬 A Swift library for parsing MachO files to obtain various information.
4 |
--------------------------------------------------------------------------------
/MachOKit.docc/MachOKitC.md:
--------------------------------------------------------------------------------
1 | # ``MachOKitC``
2 |
3 | 🔬 A Swift library for parsing MachO files to obtain various information.
4 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: xcframework
2 | xcframework:
3 | bash scripts/xcframework.sh
4 |
5 | .PHONY: docc
6 | docc:
7 | bash scripts/docc.sh
8 |
9 | .PHONY: docc-preview
10 | docc-preview:
11 | bash scripts/docc-preview.sh
12 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "pins" : [
3 | {
4 | "identity" : "swift-fileio",
5 | "kind" : "remoteSourceControl",
6 | "location" : "https://github.com/p-x9/swift-fileio.git",
7 | "state" : {
8 | "revision" : "23349fe1eb23c6ca2876d461a46ff60c0fa92f9c",
9 | "version" : "0.9.0"
10 | }
11 | }
12 | ],
13 | "version" : 2
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/MachOKit/DyldCacheLoaded+static.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheLoaded+static.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/01/09
6 | //
7 | //
8 |
9 | #if canImport(Darwin)
10 | extension DyldCacheLoaded {
11 | public static var current: DyldCacheLoaded? {
12 | var size = 0
13 | guard let ptr = _dyld_get_shared_cache_range(&size),
14 | let cache = try? DyldCacheLoaded(ptr: ptr) else {
15 | return nil
16 | }
17 | return cache
18 | }
19 | }
20 | #endif
21 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Extension/Data+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Data+.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/02/02
6 | //
7 | //
8 | import Foundation
9 |
10 | extension Data {
11 | func byteSwapped(_ type: T.Type) -> Data {
12 | guard count >= MemoryLayout.size else { return self }
13 |
14 | let valueArray = self.withUnsafeBytes {
15 | Array($0.bindMemory(to: T.self))
16 | }
17 |
18 | let swappedArray = valueArray.map { $0.byteSwapped }
19 |
20 | var swappedData = swappedArray.withUnsafeBufferPointer {
21 | Data(buffer: $0)
22 | }
23 |
24 | let remainingBytes = count % MemoryLayout.size
25 | if remainingBytes > 0 {
26 | swappedData.append(self.suffix(remainingBytes))
27 | }
28 |
29 | return swappedData
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Extension/FixedWidthInteger+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FixedWidthInteger+.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2024/11/20
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension FixedWidthInteger {
12 | var uleb128Size: Int {
13 | var value = self
14 | var result = 0
15 |
16 | repeat {
17 | value = value >> 7
18 | result += 1
19 | } while value != 0
20 |
21 | return result
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Extension/String+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/28.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension String {
12 | @_spi(Support)
13 | public typealias CCharTuple16 = (CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar)
14 |
15 | @_spi(Support)
16 | public init(tuple: CCharTuple16) {
17 | self = withUnsafePointer(to: tuple) {
18 | let size = MemoryLayout.size
19 | let data = Data(bytes: $0, count: size) + [0]
20 | return String(cString: data) ?? ""
21 | }
22 | }
23 | }
24 |
25 | extension String {
26 | @_spi(Support)
27 | public typealias CCharTuple32 = (CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar)
28 |
29 | @_spi(Support)
30 | public init(tuple: CCharTuple32) {
31 | self = withUnsafePointer(to: tuple) {
32 | let size = MemoryLayout.size
33 | let data = Data(bytes: $0, count: size) + [0]
34 | return String(cString: data) ?? ""
35 | }
36 | }
37 | }
38 |
39 | extension String {
40 | @_spi(Support)
41 | public init?(cString data: Data) {
42 | guard !data.isEmpty else { return nil }
43 | let string: String? = data.withUnsafeBytes {
44 | guard let baseAddress = $0.baseAddress else { return nil }
45 | let ptr = baseAddress.assumingMemoryBound(to: CChar.self)
46 | return String(cString: ptr)
47 | }
48 | guard let string else {
49 | return nil
50 | }
51 | self = string
52 | }
53 | }
54 |
55 | extension String {
56 | @inline(__always)
57 | func isEqual(to tuple: CCharTuple16) -> Bool {
58 | var buffer = tuple
59 | return withUnsafePointer(to: &buffer.0) { tuple in
60 | withCString { str in
61 | strcmp(str, tuple) == 0
62 | }
63 | }
64 | }
65 |
66 | @inline(__always)
67 | func isEqual(to tuple: CCharTuple32) -> Bool {
68 | var buffer = tuple
69 | return withUnsafePointer(to: &buffer.0) { tuple in
70 | withCString { str in
71 | strcmp(str, tuple) == 0
72 | }
73 | }
74 | }
75 | }
76 |
77 | @_spi(Support)
78 | public func == (string: String, tuple: String.CCharTuple16) -> Bool {
79 | string.isEqual(to: tuple)
80 | }
81 |
82 | @_spi(Support)
83 | public func == (tuple: String.CCharTuple16, string: String) -> Bool {
84 | string.isEqual(to: tuple)
85 | }
86 |
87 | @_spi(Support)
88 | public func == (string: String, tuple: String.CCharTuple32) -> Bool {
89 | string.isEqual(to: tuple)
90 | }
91 |
92 | @_spi(Support)
93 | public func == (tuple: String.CCharTuple32, string: String) -> Bool {
94 | string.isEqual(to: tuple)
95 | }
96 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Extension/UUID+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UUID+.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/10/19
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension UUID {
12 | // swiftlint:disable:next force_unwrapping
13 | static let zero: UUID = .init(uuidString: "00000000-0000-0000-0000-000000000000")!
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Extension/UnsafePointer+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UnsafePointer+.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/03.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension UnsafePointer {
12 | /// (value, size)
13 | @_spi(Support)
14 | public func readULEB128() -> (UInt, Int) {
15 | var value: UInt = 0
16 | var shift: UInt = 0
17 | var offset: Int = 0
18 |
19 | var byte: UInt8 = 0
20 |
21 | repeat {
22 | byte = advanced(by: offset).pointee
23 |
24 | value += UInt(byte & 0x7F) << shift
25 | shift += 7
26 | offset += 1
27 | } while byte >= 128
28 |
29 | return (value, offset)
30 | }
31 |
32 | /// (value, size)
33 | @_spi(Support)
34 | public func readSLEB128() -> (Int, Int) {
35 | var value: Int = 0
36 | var shift: UInt = 0
37 | var offset: Int = 0
38 |
39 | var byte: UInt8 = 0
40 |
41 | repeat {
42 | byte = advanced(by: offset).pointee
43 |
44 | value += Int(byte & 0x7F) << shift
45 | shift += 7
46 | offset += 1
47 | } while byte >= 128
48 |
49 | if byte & 0x40 != 0 {
50 | value |= -(1 << shift)
51 | }
52 |
53 | return (value, offset)
54 | }
55 | }
56 |
57 | extension UnsafePointer {
58 | func readString() -> (String, Int) {
59 | let offset = Int(bitPattern: strchr(self, 0)) + 1 - Int(bitPattern: self)
60 | let string = String(cString: self)
61 |
62 | return (string, offset)
63 | }
64 | }
65 |
66 | extension UnsafePointer {
67 | func readString() -> (String, Int) {
68 | let offset = Int(bitPattern: strchr(self, 0)) + 1 - Int(bitPattern: self)
69 | let string = String(cString: self)
70 |
71 | return (string, offset)
72 | }
73 | }
74 |
75 | extension UnsafePointer where Pointee: FixedWidthInteger {
76 | func findNullTerminator() -> UnsafePointer {
77 | var ptr = self
78 | while ptr.pointee != 0 {
79 | ptr = ptr.advanced(by: 1)
80 | }
81 | return ptr
82 | }
83 |
84 | func readString(
85 | as encoding: Encoding.Type
86 | ) -> (String, Int) where Pointee == Encoding.CodeUnit {
87 | let nullTerminator = findNullTerminator()
88 | let offset = Int(bitPattern: nullTerminator) + MemoryLayout.size - Int(bitPattern: self)
89 | let string = String(decodingCString: self, as: Encoding.self)
90 |
91 | return (string, offset)
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Extension/UnsafeRawPointer+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UnsafeRawPointer+.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/28.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension UnsafeRawPointer {
12 | func autoBoundPointee() -> Out {
13 | bindMemory(to: Out.self, capacity: 1).pointee
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/MachOKit/FatFile.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FatFile.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/04.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public class FatFile {
12 | let url: URL
13 | let fileHandle: FileHandle
14 |
15 | public private(set) var isSwapped: Bool
16 | public let header: FatHeader
17 |
18 | public var is64bit: Bool { header.magic.is64BitFat }
19 | public var headerSize: Int {
20 | MemoryLayout.size
21 | }
22 | public var archesSize: Int {
23 | Int(header.nfat_arch) * (is64bit ? MemoryLayout.size : MemoryLayout.size)
24 | }
25 |
26 | public var archesStartOffset: Int {
27 | headerSize
28 | }
29 |
30 | public var arches: [FatArch] {
31 | let data = fileHandle.readData(
32 | offset: UInt64(archesStartOffset),
33 | size: archesSize
34 | )
35 | return header.arches(data: data, isSwapped: isSwapped)
36 | }
37 |
38 | init(url: URL) throws {
39 | self.url = url
40 | self.fileHandle = try FileHandle(forReadingFrom: url)
41 |
42 | var header: FatHeader = fileHandle.read(
43 | offset: 0
44 | )
45 |
46 | let isSwapped = header.magic.isSwapped
47 | if isSwapped {
48 | swap_fat_header(&header.layout, NXHostByteOrder())
49 | }
50 |
51 | self.isSwapped = isSwapped
52 | self.header = header
53 | }
54 |
55 | deinit {
56 | fileHandle.closeFile()
57 | }
58 | }
59 |
60 | extension FatFile {
61 | public func machOFiles() throws -> [MachOFile] {
62 | try arches.map {
63 | try .init(url: url, headerStartOffset: Int($0.offset))
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Header/CPU.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CPU.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct CPU {
12 | public let typeRawValue: cpu_type_t
13 | public let subtypeRawValue: cpu_subtype_t
14 |
15 | public var type: CPUType? {
16 | .init(rawValue: typeRawValue)
17 | }
18 |
19 | public var subtype: CPUSubType? {
20 | if let type {
21 | let subtypeRaw = (cpu_subtype_t(subtypeRawValue) & cpu_subtype_t(~CPU_SUBTYPE_MASK))
22 | return .init(rawValue: subtypeRaw, of: type)
23 | }
24 | return nil
25 | }
26 | }
27 |
28 | extension CPU: CustomStringConvertible {
29 | public var description: String {
30 | let type = type?.description ?? "unknown\(typeRawValue)"
31 | let subtype = subtype?.description ?? "unknown"
32 |
33 | return "\(type)(\(subtype))"
34 | }
35 | }
36 |
37 | extension CPU {
38 | public var is64Bit: Bool {
39 | typeRawValue & CPU_ARCH_ABI64 != 0
40 | }
41 |
42 | public var is64BitHardwareWith32BitType: Bool {
43 | typeRawValue & CPU_ARCH_ABI64_32 != 0
44 | }
45 | }
46 |
47 | #if canImport(Darwin)
48 | extension CPU {
49 | /// CPU type and subtype of host pc
50 | static var current: CPU? {
51 | guard let type: CPUType = .current,
52 | let subtype: CPUSubType = .current else {
53 | return nil
54 | }
55 | return .init(
56 | typeRawValue: type.rawValue,
57 | subtypeRawValue: subtype.rawValue
58 | )
59 | }
60 | }
61 | #endif
62 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Header/DyldCacheHeader/DyldCacheType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheType.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/14.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum DyldCacheType: UInt64 {
12 | case development
13 | case production
14 | case multiCache
15 | }
16 |
17 | public enum DyldCacheSubType: UInt32 {
18 | case development
19 | case production
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Header/FatHeader/FatArch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FatArch.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/04.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct FatArch: LayoutWrapper {
12 | public var layout: fat_arch
13 |
14 | public var cpuType: CPUType? {
15 | cpu.type
16 | }
17 |
18 | public var cpuSubType: CPUSubType? {
19 | cpu.subtype
20 | }
21 |
22 | public var cpu: CPU {
23 | .init(
24 | typeRawValue: layout.cputype,
25 | subtypeRawValue: layout.cpusubtype
26 | )
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Header/FatHeader/FatHeader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FatHeader.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/04.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct FatHeader: LayoutWrapper {
12 | public var layout: fat_header
13 |
14 | public var magic: Magic! {
15 | .init(rawValue: layout.magic)
16 | }
17 | }
18 |
19 | extension FatHeader {
20 | public func arches(data: Data, isSwapped: Bool) -> [FatArch] {
21 | if magic.is64BitFat {
22 | return data.withUnsafeBytes {
23 | let ptr = $0.bindMemory(to: fat_arch_64.self)
24 |
25 | if isSwapped {
26 | swap_fat_arch_64(.init(mutating: ptr.baseAddress), layout.nfat_arch, NXHostByteOrder())
27 | }
28 |
29 | guard let baseAddress = ptr.baseAddress else { return [] }
30 |
31 | return ptr.indices.map {
32 | let layout = UnsafeRawPointer(baseAddress.advanced(by: $0))
33 | .bindMemory(to: fat_arch.self, capacity: 1)
34 | .pointee
35 | return .init(layout: layout)
36 | }
37 | }
38 | } else {
39 | return data.withUnsafeBytes {
40 | let ptr = $0.bindMemory(to: fat_arch.self)
41 |
42 | if isSwapped {
43 | swap_fat_arch(.init(mutating: ptr.baseAddress), layout.nfat_arch, NXHostByteOrder())
44 | }
45 |
46 | return ptr
47 | .map { .init(layout: $0) }
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Header/MachHeader/FileType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FileType.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum FileType {
12 | /// MH_OBJECT
13 | case object
14 | /// MH_EXECUTE
15 | case execute
16 | /// MH_FVMLIB
17 | case fvmlib
18 | /// MH_CORE
19 | case core
20 | /// MH_PRELOAD
21 | case preload
22 | /// MH_DYLIB
23 | case dylib
24 | /// MH_DYLINKER
25 | case dylinker
26 | /// MH_BUNDLE
27 | case bundle
28 | /// MH_DYLIB_STUB
29 | case dylibStub
30 | /// MH_DSYM
31 | case dsym
32 | /// MH_KEXT_BUNDLE
33 | case kextBundle
34 | /// MH_FILESET
35 | case fileset
36 | /// MH_GPU_EXECUTE
37 | case gpuExecute
38 | /// MH_GPU_DYLIB
39 | case gpuDylib
40 | }
41 |
42 | extension FileType: RawRepresentable {
43 | public typealias RawValue = Int32
44 |
45 | public init?(rawValue: Int32) {
46 | switch rawValue {
47 | case MH_OBJECT: self = .object
48 | case MH_EXECUTE: self = .execute
49 | case MH_FVMLIB: self = .fvmlib
50 | case MH_CORE: self = .core
51 | case MH_PRELOAD: self = .preload
52 | case MH_DYLIB: self = .dylib
53 | case MH_DYLINKER: self = .dylinker
54 | case MH_BUNDLE: self = .bundle
55 | case MH_DYLIB_STUB: self = .dylibStub
56 | case MH_DSYM: self = .dsym
57 | case MH_KEXT_BUNDLE: self = .kextBundle
58 | case MH_FILESET: self = .fileset
59 | case MH_GPU_EXECUTE: self = .gpuExecute
60 | case MH_GPU_DYLIB: self = .gpuDylib
61 | default: return nil
62 | }
63 | }
64 |
65 | public var rawValue: Int32 {
66 | switch self {
67 | case .object: MH_OBJECT
68 | case .execute: MH_EXECUTE
69 | case .fvmlib: MH_FVMLIB
70 | case .core: MH_CORE
71 | case .preload: MH_PRELOAD
72 | case .dylib: MH_DYLIB
73 | case .dylinker: MH_DYLINKER
74 | case .bundle: MH_BUNDLE
75 | case .dylibStub: MH_DYLIB_STUB
76 | case .dsym: MH_DSYM
77 | case .kextBundle: MH_KEXT_BUNDLE
78 | case .fileset: MH_FILESET
79 | case .gpuExecute: MH_GPU_EXECUTE
80 | case .gpuDylib: MH_GPU_DYLIB
81 | }
82 | }
83 | }
84 |
85 | extension FileType: CustomStringConvertible {
86 | public var description: String {
87 | switch self {
88 | case .object: "MH_OBJECT"
89 | case .execute: "MH_EXECUTE"
90 | case .fvmlib: "MH_FVMLIB"
91 | case .core: "MH_CORE"
92 | case .preload: "MH_PRELOAD"
93 | case .dylib: "MH_DYLIB"
94 | case .dylinker: "MH_DYLINKER"
95 | case .bundle: "MH_BUNDLE"
96 | case .dylibStub: "MH_DYLIB_STUB"
97 | case .dsym: "MH_DSYM"
98 | case .kextBundle: "MH_KEXT_BUNDLE"
99 | case .fileset: "MH_FILESET"
100 | case .gpuExecute: "MH_GPU_EXECUTE"
101 | case .gpuDylib: "MH_GPU_DYLIB"
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Header/MachHeader/MachHeader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MachHeader.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct MachHeader: LayoutWrapper {
12 | public var layout: mach_header
13 |
14 | public var magic: Magic! {
15 | .init(rawValue: layout.magic)
16 | }
17 |
18 | public var cpuType: CPUType? {
19 | cpu.type
20 | }
21 |
22 | public var cpuSubType: CPUSubType? {
23 | cpu.subtype
24 | }
25 |
26 | public var cpu: CPU {
27 | .init(
28 | typeRawValue: layout.cputype,
29 | subtypeRawValue: layout.cpusubtype
30 | )
31 | }
32 |
33 | public var fileType: FileType? {
34 | .init(rawValue: numericCast(layout.filetype))
35 | }
36 |
37 | public var flags: Flags {
38 | .init(rawValue: numericCast(layout.flags))
39 | }
40 | }
41 |
42 | extension MachHeader {
43 | /// A boolean value that indicates whether this MachO exists in the dyld cache or not.
44 | public var isInDyldCache: Bool {
45 | flags.contains(.dylib_in_cache)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Header/Magic.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Magic.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/01.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum Magic: CaseIterable, Codable, Equatable {
12 | /// MH_MAGIC
13 | case magic
14 | /// MH_CIGAM
15 | case cigam
16 |
17 | /// MH_MAGIC_64
18 | case magic64
19 | /// MH_CIGAM_64
20 | case cigam64
21 |
22 | /// FAT_MAGIC
23 | case fatMagic
24 | /// FAT_CIGAM
25 | case fatCigam
26 |
27 | /// FAT_MAGIC_64
28 | case fatMagic64
29 | /// FAT_CIGAM_64
30 | case fatCigam64
31 | }
32 |
33 | extension Magic {
34 | public var isFat: Bool {
35 | [.fatMagic, .fatCigam, .fatMagic64, .fatCigam64].contains(self)
36 | }
37 |
38 | public var isMach: Bool {
39 | [.magic, .magic64, .cigam, .cigam64].contains(self)
40 | }
41 |
42 | public var is64BitMach: Bool {
43 | [.magic64, .cigam64].contains(self)
44 | }
45 |
46 | public var is64BitFat: Bool {
47 | [.fatMagic64, .fatCigam64].contains(self)
48 | }
49 |
50 | public var is64Bit: Bool {
51 | is64BitMach || is64BitFat
52 | }
53 |
54 | public var isSwapped: Bool {
55 | [.cigam, .cigam64, .fatCigam, .fatCigam64].contains(self)
56 | }
57 | }
58 |
59 | extension Magic: RawRepresentable {
60 | public typealias RawValue = UInt32
61 |
62 | public init?(rawValue: UInt32) {
63 | switch rawValue {
64 | case MH_MAGIC: self = .magic
65 | case MH_CIGAM: self = .cigam
66 | case MH_MAGIC_64: self = .magic64
67 | case MH_CIGAM_64: self = .cigam64
68 | case FAT_MAGIC: self = .fatMagic
69 | case FAT_CIGAM: self = .fatCigam
70 | case FAT_MAGIC_64: self = .fatMagic64
71 | case FAT_CIGAM_64: self = .fatCigam64
72 | default: return nil
73 | }
74 | }
75 |
76 | public var rawValue: UInt32 {
77 | switch self {
78 | case .magic: MH_MAGIC
79 | case .cigam: MH_CIGAM
80 | case .magic64: MH_MAGIC_64
81 | case .cigam64: MH_CIGAM_64
82 | case .fatMagic: FAT_MAGIC
83 | case .fatCigam: FAT_CIGAM
84 | case .fatMagic64: FAT_MAGIC_64
85 | case .fatCigam64: FAT_CIGAM_64
86 | }
87 | }
88 | }
89 |
90 | extension Magic: CustomStringConvertible {
91 | public var description: String {
92 | switch self {
93 | case .magic: "MH_MAGIC"
94 | case .cigam: "MH_CIGAM"
95 | case .magic64: "MH_MAGIC_64"
96 | case .cigam64: "MH_CIGAM_64"
97 | case .fatMagic: "FAT_MAGIC"
98 | case .fatCigam: "FAT_CIGAM"
99 | case .fatMagic64: "FAT_MAGIC_64"
100 | case .fatCigam64: "FAT_CIGAM_64"
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/BuildVersionCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BuildVersionCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct BuildVersionCommand: LoadCommandWrapper {
12 | public typealias Layout = build_version_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension BuildVersionCommand {
24 | public var platform: Platform {
25 | .init(rawValue: layout.platform) ?? .unknown
26 | }
27 |
28 | public var minos: Version {
29 | .init(layout.minos)
30 | }
31 |
32 | public var sdk: Version {
33 | .init(layout.sdk)
34 | }
35 | }
36 |
37 | extension BuildVersionCommand {
38 | public func tools(
39 | cmdsStart: UnsafeRawPointer
40 | ) -> MemorySequence {
41 | let base = cmdsStart
42 | .advanced(by: offset)
43 | .advanced(by: layoutSize)
44 | .assumingMemoryBound(to: BuildToolVersion.self)
45 | return .init(
46 | basePointer: base,
47 | numberOfElements: Int(layout.ntools)
48 | )
49 | }
50 | }
51 |
52 | extension BuildVersionCommand {
53 | public func tools(
54 | in machO: MachOFile
55 | ) -> DataSequence {
56 | let offset = machO.cmdsStartOffset + offset + layoutSize
57 |
58 | return machO.fileHandle.readDataSequence(
59 | offset: numericCast(offset),
60 | numberOfElements: numericCast(layout.ntools),
61 | swapHandler: { data in
62 | guard machO.isSwapped else { return }
63 | data.withUnsafeBytes {
64 | guard let baseAddress = $0.baseAddress else { return }
65 | let ptr = UnsafeMutableRawPointer(mutating: baseAddress)
66 | .assumingMemoryBound(to: build_tool_version.self)
67 | swap_build_tool_version(ptr, layout.ntools, NXHostByteOrder())
68 | }
69 | }
70 | )
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/DylibCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DylibCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DylibCommand: LoadCommandWrapper {
12 | public typealias Layout = dylib_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension DylibCommand {
24 | public func dylib(cmdsStart: UnsafeRawPointer) -> Dylib {
25 | let ptr = cmdsStart
26 | .advanced(by: offset)
27 | .advanced(by: Int(layout.dylib.name.offset))
28 | .assumingMemoryBound(to: CChar.self)
29 |
30 | return .init(
31 | name: String(cString: ptr),
32 | timestamp: Date(timeIntervalSince1970: TimeInterval(layout.dylib.timestamp)),
33 | currentVersion: .init(layout.dylib.current_version),
34 | compatibilityVersion: .init(layout.dylib.compatibility_version)
35 | )
36 | }
37 | }
38 |
39 | extension DylibCommand {
40 | public func dylib(in machO: MachOFile) -> Dylib {
41 | let offset = machO.cmdsStartOffset + offset + Int(layout.dylib.name.offset)
42 | // swap is not needed
43 | let string = machO.fileHandle.readString(
44 | offset: numericCast(offset),
45 | size: Int(layout.cmdsize) - layoutSize
46 | ) ?? ""
47 |
48 | return .init(
49 | name: string,
50 | timestamp: Date(timeIntervalSince1970: TimeInterval(layout.dylib.timestamp)),
51 | currentVersion: .init(layout.dylib.current_version),
52 | compatibilityVersion: .init(layout.dylib.compatibility_version)
53 | )
54 | }
55 | }
56 |
57 | extension DylibCommand {
58 | public var isDylibUseCommand: Bool {
59 | layout.dylib.timestamp == DYLIB_USE_MARKER
60 | }
61 |
62 | public func dylibUseCommand(in machO: MachOImage) -> DylibUseCommand? {
63 | guard isDylibUseCommand else { return nil }
64 |
65 | let ptr = machO.cmdsStartPtr
66 | .advanced(by: offset)
67 | .assumingMemoryBound(to: DylibUseCommand.Layout.self)
68 | return .init(ptr.pointee, offset: offset)
69 | }
70 |
71 | public func dylibUseCommand(in machO: MachOFile) -> DylibUseCommand? {
72 | guard isDylibUseCommand else { return nil }
73 |
74 | let offset = machO.cmdsStartOffset + offset
75 | let layout: DylibUseCommand.Layout = machO.fileHandle.read(
76 | offset: numericCast(offset),
77 | swapHandler: {
78 | guard machO.isSwapped else { return }
79 | return $0.withUnsafeBytes {
80 | guard let baseAddress = $0.baseAddress else { return }
81 | let ptr = UnsafeMutableRawPointer(mutating: baseAddress)
82 | .assumingMemoryBound(to: dylib_use_command.self)
83 | swap_dylib_use_command(ptr, NXHostByteOrder())
84 | }
85 | }
86 | )
87 | return .init(layout, offset: offset)
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/DylibUseCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DylibUseCommand.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2024/12/12
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DylibUseCommand: LoadCommandWrapper {
12 | public typealias Layout = dylib_use_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension DylibUseCommand {
24 | public var flags: DylibUseFlags {
25 | .init(rawValue: layout.flags)
26 | }
27 | }
28 |
29 | extension DylibUseCommand {
30 | public func dylib(cmdsStart: UnsafeRawPointer) -> Dylib {
31 | let ptr = cmdsStart
32 | .advanced(by: offset)
33 | .advanced(by: Int(layout.nameoff))
34 | .assumingMemoryBound(to: CChar.self)
35 |
36 | return .init(
37 | name: String(cString: ptr),
38 | timestamp: Date(timeIntervalSince1970: TimeInterval(layout.marker)),
39 | currentVersion: .init(layout.current_version),
40 | compatibilityVersion: .init(layout.compat_version)
41 | )
42 | }
43 | }
44 |
45 | extension DylibUseCommand {
46 | public func dylib(in machO: MachOFile) -> Dylib {
47 | let offset = machO.cmdsStartOffset + offset + Int(layout.nameoff)
48 | // swap is not needed
49 | let string = machO.fileHandle.readString(
50 | offset: numericCast(offset),
51 | size: Int(layout.cmdsize) - layoutSize
52 | ) ?? ""
53 |
54 | return .init(
55 | name: string,
56 | timestamp: Date(timeIntervalSince1970: TimeInterval(layout.marker)),
57 | currentVersion: .init(layout.current_version),
58 | compatibilityVersion: .init(layout.compat_version)
59 | )
60 | }
61 | }
62 |
63 | public func swap_dylib_use_command(
64 | _ dl: UnsafeMutablePointer!,
65 | _ target_byte_sex: NXByteOrder
66 | ) {
67 | dl.pointee.cmd = dl.pointee.cmd.byteSwapped
68 | dl.pointee.cmdsize = dl.pointee.cmdsize.byteSwapped
69 | dl.pointee.nameoff = dl.pointee.nameoff.byteSwapped
70 | dl.pointee.marker = dl.pointee.marker.byteSwapped
71 | dl.pointee.current_version = dl.pointee.current_version.byteSwapped
72 | dl.pointee.compat_version = dl.pointee.compat_version.byteSwapped
73 | dl.pointee.flags = dl.pointee.flags.byteSwapped
74 | }
75 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/DylinkerCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DylinkerCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/02.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DylinkerCommand: LoadCommandWrapper {
12 | public typealias Layout = dylinker_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension DylinkerCommand {
24 | public func name(cmdsStart: UnsafeRawPointer) -> String {
25 | let ptr = cmdsStart
26 | .advanced(by: offset)
27 | .advanced(by: Int(layout.name.offset))
28 | .assumingMemoryBound(to: CChar.self)
29 | return String(cString: ptr)
30 | }
31 | }
32 |
33 | extension DylinkerCommand {
34 | public func name(in machO: MachOFile) -> String {
35 | let offset = machO.cmdsStartOffset + offset + Int(layout.name.offset)
36 | return machO.fileHandle.readString(
37 | offset: numericCast(offset),
38 | size: Int(layout.cmdsize) - layoutSize
39 | ) ?? ""
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/EncryptionInfoCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EncryptionInfoCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/02/23.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol EncryptionInfoCommandProtocol: LoadCommandWrapper {
12 | var cryptId: Int { get }
13 | }
14 |
15 | extension EncryptionInfoCommandProtocol {
16 | public var isEncrypted: Bool {
17 | cryptId != 0
18 | }
19 | }
20 |
21 | public struct EncryptionInfoCommand: LoadCommandWrapper {
22 | public typealias Layout = encryption_info_command
23 |
24 | public var layout: Layout
25 | public var offset: Int // offset from mach header trailing
26 |
27 | init(_ layout: Layout, offset: Int) {
28 | self.layout = layout
29 | self.offset = offset
30 | }
31 | }
32 |
33 | public struct EncryptionInfoCommand64: LoadCommandWrapper {
34 | public typealias Layout = encryption_info_command_64
35 |
36 | public var layout: Layout
37 | public var offset: Int // offset from mach header trailing
38 |
39 | init(_ layout: Layout, offset: Int) {
40 | self.layout = layout
41 | self.offset = offset
42 | }
43 | }
44 |
45 | extension EncryptionInfoCommand: EncryptionInfoCommandProtocol {
46 | public var cryptId: Int {
47 | numericCast(layout.cryptid)
48 | }
49 | }
50 |
51 | extension EncryptionInfoCommand64: EncryptionInfoCommandProtocol {
52 | public var cryptId: Int {
53 | numericCast(layout.cryptid)
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/EntryPointCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EntryPointCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/01.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct EntryPointCommand: LoadCommandWrapper {
12 | public typealias Layout = entry_point_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension EntryPointCommand {
24 | public func mainStartPointer(machOStart: UnsafeRawPointer) -> UnsafeRawPointer {
25 | machOStart
26 | .advanced(by: numericCast(layout.entryoff))
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/LinkerOptionCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LinkerOptionCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/18.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct LinkerOptionCommand: LoadCommandWrapper {
12 | public typealias Layout = linker_option_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension LinkerOptionCommand {
24 | public func options(cmdsStart: UnsafeRawPointer) -> [String] {
25 | // swiftlint:disable:next empty_count
26 | guard layout.count > 0 else { return [] }
27 |
28 | let ptr = cmdsStart
29 | .advanced(by: offset)
30 | .advanced(by: layoutSize)
31 | .assumingMemoryBound(to: UInt8.self)
32 | let strings = MachOImage.Strings(
33 | basePointer: ptr,
34 | tableSize: Int(layout.cmdsize) - layoutSize
35 | ).map(\.string)
36 |
37 | return Array(strings[0.. [String] {
41 | // swiftlint:disable:next empty_count
42 | guard layout.count > 0 else { return [] }
43 |
44 | let offset = machO.cmdsStartOffset + offset + layoutSize
45 | let size = Int(layout.cmdsize) - layoutSize
46 |
47 | let strings = MachOFile.Strings(
48 | machO: machO,
49 | offset: offset,
50 | size: size,
51 | isSwapped: machO.isSwapped
52 | ).map(\.string)
53 |
54 | return Array(strings[0..: LoadCommandWrapper {
12 | public var layout: Layout
13 | public var offset: Int // offset from mach header trailing
14 |
15 | init(_ layout: Layout, offset: Int) {
16 | self.layout = layout
17 | self.offset = offset
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/Model/BuildToolVersion.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BuildToolVersion.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct BuildToolVersion: LayoutWrapper {
12 | public var layout: build_tool_version
13 |
14 | public var tool: Tool? {
15 | .init(rawValue: Int32(layout.tool))
16 | }
17 |
18 | public var version: Version {
19 | .init(layout.version)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/Model/Dylib.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dylib.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct Dylib {
12 | /// library's path name
13 | public var name: String
14 |
15 | /// library's build time stamp
16 | public var timestamp: Date
17 |
18 | /// library's current version number
19 | public var currentVersion: Version
20 |
21 | /// library's compatibility vers number
22 | public var compatibilityVersion: Version
23 | }
24 |
25 | extension Dylib {
26 | /// A boolean value that indicates whether self is loaded from `dylib_use_command`
27 | public var isFromDylibUseCommand: Bool {
28 | timestamp.timeIntervalSince1970 == TimeInterval(DYLIB_USE_MARKER)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/Model/DylibUseFlags.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DylibUseFlags.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2024/12/12
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DylibUseFlags: BitFlags {
12 | public typealias RawValue = UInt32
13 |
14 | public let rawValue: RawValue
15 |
16 | public init(rawValue: RawValue) {
17 | self.rawValue = rawValue
18 | }
19 | }
20 |
21 | extension DylibUseFlags {
22 | /// DYLIB_USE_WEAK_LINK
23 | public static let weak_link = MachHeader.Flags(
24 | rawValue: Bit.weak_link.rawValue
25 | )
26 | /// DYLIB_USE_REEXPORT
27 | public static let reexport = MachHeader.Flags(
28 | rawValue: Bit.reexport.rawValue
29 | )
30 | /// DYLIB_USE_UPWARD
31 | public static let upward = MachHeader.Flags(
32 | rawValue: Bit.upward.rawValue
33 | )
34 | /// DYLIB_USE_DELAYED_INIT
35 | public static let delayed_init = MachHeader.Flags(
36 | rawValue: Bit.delayed_init.rawValue
37 | )
38 | }
39 |
40 | extension DylibUseFlags {
41 | public enum Bit: CaseIterable {
42 | /// DYLIB_USE_WEAK_LINK
43 | case weak_link
44 | /// DYLIB_USE_REEXPORT
45 | case reexport
46 | /// DYLIB_USE_UPWARD
47 | case upward
48 | /// DYLIB_USE_DELAYED_INIT
49 | case delayed_init
50 | }
51 | }
52 |
53 | extension DylibUseFlags.Bit: RawRepresentable {
54 | public typealias RawValue = UInt32
55 |
56 | public init?(rawValue: RawValue) {
57 | switch rawValue {
58 | case RawValue(DYLIB_USE_WEAK_LINK): self = .weak_link
59 | case RawValue(DYLIB_USE_REEXPORT): self = .reexport
60 | case RawValue(DYLIB_USE_UPWARD): self = .upward
61 | case RawValue(DYLIB_USE_DELAYED_INIT): self = .delayed_init
62 | default: return nil
63 | }
64 | }
65 |
66 | public var rawValue: RawValue {
67 | switch self {
68 | case .weak_link: RawValue(DYLIB_USE_WEAK_LINK)
69 | case .reexport: RawValue(DYLIB_USE_REEXPORT)
70 | case .upward: RawValue(DYLIB_USE_UPWARD)
71 | case .delayed_init: RawValue(DYLIB_USE_DELAYED_INIT)
72 | }
73 | }
74 | }
75 |
76 | extension DylibUseFlags.Bit: CustomStringConvertible {
77 | public var description: String {
78 | switch self {
79 | case .weak_link: "DYLIB_USE_WEAK_LINK"
80 | case .reexport: "DYLIB_USE_REEXPORT"
81 | case .upward: "DYLIB_USE_UPWARD"
82 | case .delayed_init: "DYLIB_USE_DELAYED_INIT"
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/Model/Section+Flags.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Section+Flags.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/01.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct SectionFlags {
12 | public let rawValue: UInt32
13 |
14 | public var type: SectionType? {
15 | let rawValue = rawValue & UInt32(SECTION_TYPE)
16 | return .init(rawValue: Int32(rawValue))
17 | }
18 |
19 | public var attributes: SectionAttributes {
20 | .init(rawValue: rawValue & SECTION_ATTRIBUTES)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/Model/ThreadState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreadState.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/01/13
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public enum ThreadState {
13 | case arm(ARMThreadState)
14 | case arm64(ARM64ThreadState)
15 | case i386(i386ThreadState)
16 | case x86_64(x86_64ThreadState)
17 | }
18 |
19 | public struct x86_64ThreadState: LayoutWrapper {
20 | public typealias Layout = x86_thread_state64
21 |
22 | public var layout: Layout
23 | }
24 |
25 | public struct i386ThreadState: LayoutWrapper {
26 | public typealias Layout = i386_thread_state
27 |
28 | public var layout: Layout
29 | }
30 |
31 | public struct ARMThreadState: LayoutWrapper {
32 | public typealias Layout = arm_thread_state
33 |
34 | public var layout: Layout
35 | }
36 |
37 | public struct ARM64ThreadState: LayoutWrapper {
38 | public typealias Layout = arm_thread_state64
39 |
40 | public var layout: Layout
41 | }
42 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/Model/Tool.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Tool.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum Tool {
12 | /// TOOL_CLANG
13 | case clang
14 | /// TOOL_SWIFT
15 | case swift
16 | /// TOOL_LD
17 | case ld
18 | /// TOOL_LLD
19 | case lld
20 |
21 | /* values for gpu tools (1024 to 1048) */
22 | /// TOOL_METAL
23 | case metal
24 | /// TOOL_AIRLLD
25 | case airLld
26 | /// TOOL_AIRNT
27 | case airNt
28 | /// TOOL_AIRNT_PLUGIN
29 | case airNtPlugin
30 | /// TOOL_AIRPACK
31 | case airPack
32 | /// TOOL_GPUARCHIVER
33 | case gpuArchiver
34 | /// TOOL_METAL_FRAMEWORK
35 | case metalFramework
36 | }
37 |
38 | extension Tool: RawRepresentable {
39 | public typealias RawValue = Int32
40 |
41 | public init?(rawValue: Int32) {
42 | switch rawValue {
43 | case TOOL_CLANG: self = .clang
44 | case TOOL_SWIFT: self = .swift
45 | case TOOL_LD: self = .ld
46 | case TOOL_LLD: self = .lld
47 | case TOOL_METAL: self = .metal
48 | case TOOL_AIRLLD: self = .airLld
49 | case TOOL_AIRNT: self = .airNt
50 | case TOOL_AIRNT_PLUGIN: self = .airNtPlugin
51 | case TOOL_AIRPACK: self = .airPack
52 | case TOOL_GPUARCHIVER: self = .gpuArchiver
53 | case TOOL_METAL_FRAMEWORK: self = .metalFramework
54 | default: return nil
55 | }
56 | }
57 |
58 | public var rawValue: Int32 {
59 | switch self {
60 | case .clang: TOOL_CLANG
61 | case .swift: TOOL_SWIFT
62 | case .ld: TOOL_LD
63 | case .lld: TOOL_LLD
64 | case .metal: TOOL_METAL
65 | case .airLld: TOOL_AIRLLD
66 | case .airNt: TOOL_AIRNT
67 | case .airNtPlugin: TOOL_AIRNT_PLUGIN
68 | case .airPack: TOOL_AIRPACK
69 | case .gpuArchiver: TOOL_GPUARCHIVER
70 | case .metalFramework: TOOL_METAL_FRAMEWORK
71 | }
72 | }
73 | }
74 |
75 | extension Tool: CustomStringConvertible {
76 | public var description: String {
77 | switch self {
78 | case .clang: "TOOL_CLANG"
79 | case .swift: "TOOL_SWIFT"
80 | case .ld: "TOOL_LD"
81 | case .lld: "TOOL_LLD"
82 | case .metal: "TOOL_METAL"
83 | case .airLld: "TOOL_AIRLLD"
84 | case .airNt: "TOOL_AIRNT"
85 | case .airNtPlugin: "TOOL_AIRNT_PLUGIN"
86 | case .airPack: "TOOL_AIRPACK"
87 | case .gpuArchiver: "TOOL_GPUARCHIVER"
88 | case .metalFramework: "TOOL_METAL_FRAMEWORK"
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/Model/Version.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Version.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct Version: Equatable {
12 | public let major: Int
13 | public let minor: Int
14 | public let patch: Int
15 | }
16 |
17 | extension Version {
18 | init(_ version: UInt32) {
19 | self.init(
20 | major: Int((version & 0xFFFF0000) >> 16),
21 | minor: Int((version & 0x0000FF00) >> 8),
22 | patch: Int(version & 0x000000FF)
23 | )
24 | }
25 | }
26 |
27 | extension Version: CustomStringConvertible {
28 | public var description: String {
29 | "\(major).\(minor).\(patch)"
30 | }
31 | }
32 |
33 | extension Version: Comparable {
34 | public static func < (lhs: Version, rhs: Version) -> Bool {
35 | if lhs.major != rhs.major { return lhs.major < rhs.major }
36 | if lhs.minor != rhs.minor { return lhs.minor < rhs.minor }
37 | if lhs.patch != rhs.patch { return lhs.patch < rhs.patch }
38 | return false
39 | }
40 | }
41 |
42 | public struct SourceVersion {
43 | public let a: Int
44 | public let b: Int
45 | public let c: Int
46 | public let d: Int
47 | public let e: Int
48 | }
49 |
50 | extension SourceVersion {
51 | init(_ version: UInt64) {
52 | self.init(
53 | a: Int((version >> 40) & 0xFFFFFF),
54 | b: Int((version >> 30) & 0x3FF),
55 | c: Int((version >> 20) & 0x3FF),
56 | d: Int((version >> 10) & 0x3FF),
57 | e: Int((version >> 0) & 0x3FF)
58 | )
59 | }
60 | }
61 |
62 | extension SourceVersion: CustomStringConvertible {
63 | public var description: String {
64 | var components = [a, b, c, d, e]
65 | if e == 0 { _ = components.popLast() }
66 | if e == 0 && d == 0 { _ = components.popLast() }
67 | return components.map(String.init).joined(separator: ".")
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/NoteCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NoteCommand.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2024/12/11
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct NoteCommand: LoadCommandWrapper {
12 | public typealias Layout = note_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension NoteCommand {
24 | public var dataOwner: String {
25 | .init(tuple: layout.data_owner)
26 | }
27 |
28 | public func data(in machO: MachOFile) -> Data {
29 | try! machO.fileHandle.readData(
30 | offset: machO.headerStartOffset + numericCast(layout.offset),
31 | length: numericCast(layout.size)
32 | )
33 | }
34 |
35 | public func data(in machO: MachOImage) -> Data {
36 | .init(
37 | bytes: machO.ptr
38 | .advanced(by: numericCast(layout.offset)),
39 | count: numericCast(layout.size)
40 | )
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/RpathCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RpathCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct RpathCommand: LoadCommandWrapper {
12 | public typealias Layout = rpath_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension RpathCommand {
24 | public func path(cmdsStart: UnsafeRawPointer) -> String {
25 | let ptr = cmdsStart
26 | .advanced(by: offset)
27 | .advanced(by: Int(layout.path.offset))
28 | .assumingMemoryBound(to: CChar.self)
29 | return String(cString: ptr)
30 | }
31 | }
32 |
33 | extension RpathCommand {
34 | public func path(in machO: MachOFile) -> String {
35 | let offset = machO.cmdsStartOffset + offset + Int(layout.path.offset)
36 | return machO.fileHandle.readString(
37 | offset: numericCast(offset),
38 | size: Int(layout.cmdsize) - layoutSize
39 | ) ?? ""
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/SegmentCommand+Flags.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SegmentCommand+Flags.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/01.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct SegmentCommandFlags: BitFlags {
12 | public typealias RawValue = UInt32
13 |
14 | public let rawValue: RawValue
15 |
16 | public init(rawValue: RawValue) {
17 | self.rawValue = rawValue
18 | }
19 | }
20 |
21 | extension SegmentCommandFlags {
22 | /// SG_HIGHVM
23 | public static let highvm = SegmentCommandFlags(
24 | rawValue: Bit.highvm.rawValue
25 | )
26 | /// SG_FVMLIB
27 | public static let fvmlib = SegmentCommandFlags(
28 | rawValue: Bit.fvmlib.rawValue
29 | )
30 | /// SG_NORELOC
31 | public static let noreloc = SegmentCommandFlags(
32 | rawValue: Bit.noreloc.rawValue
33 | )
34 | /// SG_PROTECTED_VERSION_1
35 | public static let protected_version_1 = SegmentCommandFlags(
36 | rawValue: Bit.protected_version_1.rawValue
37 | )
38 | /// SG_READ_ONLY
39 | public static let read_only = SegmentCommandFlags(
40 | rawValue: Bit.read_only.rawValue
41 | )
42 | }
43 |
44 | extension SegmentCommandFlags {
45 | public enum Bit: CaseIterable {
46 | /// SG_HIGHVM
47 | case highvm
48 | /// SG_FVMLIB
49 | case fvmlib
50 | /// SG_NORELOC
51 | case noreloc
52 | /// SG_PROTECTED_VERSION_1
53 | case protected_version_1
54 | /// SG_READ_ONLY
55 | case read_only
56 | }
57 | }
58 |
59 | extension SegmentCommandFlags.Bit: RawRepresentable {
60 | public typealias RawValue = UInt32
61 |
62 | public init?(rawValue: UInt32) {
63 | switch rawValue {
64 | case RawValue(SG_HIGHVM): self = .highvm
65 | case RawValue(SG_FVMLIB): self = .fvmlib
66 | case RawValue(SG_NORELOC): self = .noreloc
67 | case RawValue(SG_PROTECTED_VERSION_1): self = .protected_version_1
68 | case RawValue(SG_READ_ONLY): self = .read_only
69 | default: return nil
70 | }
71 | }
72 |
73 | public var rawValue: UInt32 {
74 | switch self {
75 | case .highvm: RawValue(SG_HIGHVM)
76 | case .fvmlib: RawValue(SG_FVMLIB)
77 | case .noreloc: RawValue(SG_NORELOC)
78 | case .protected_version_1: RawValue(SG_PROTECTED_VERSION_1)
79 | case .read_only: RawValue(SG_READ_ONLY)
80 | }
81 | }
82 | }
83 |
84 | extension SegmentCommandFlags.Bit: CustomStringConvertible {
85 | public var description: String {
86 | switch self {
87 | case .highvm: "SG_HIGHVM"
88 | case .fvmlib: "SG_FVMLIB"
89 | case .noreloc: "SG_NORELOC"
90 | case .protected_version_1: "SG_PROTECTED_VERSION_1"
91 | case .read_only: "SG_READ_ONLY"
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/SourceVersionCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SourceVersionCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/30.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct SourceVersionCommand: LoadCommandWrapper {
12 | public typealias Layout = source_version_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension SourceVersionCommand {
24 | public var version: SourceVersion {
25 | .init(layout.version)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/TargetTripleCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TargetTripleCommand.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/02/22
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct TargetTripleCommand: LoadCommandWrapper {
12 | public typealias Layout = target_triple_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | init(_ layout: Layout, offset: Int) {
18 | self.layout = layout
19 | self.offset = offset
20 | }
21 | }
22 |
23 | extension TargetTripleCommand {
24 | public func triple(cmdsStart: UnsafeRawPointer) -> String {
25 | let ptr = cmdsStart
26 | .advanced(by: offset)
27 | .advanced(by: Int(layout.triple.offset))
28 | .assumingMemoryBound(to: CChar.self)
29 | return String(cString: ptr)
30 | }
31 | }
32 |
33 | extension TargetTripleCommand {
34 | public func path(in machO: MachOFile) -> String {
35 | let offset = machO.cmdsStartOffset + offset + Int(layout.triple.offset)
36 | return machO.fileHandle.readString(
37 | offset: numericCast(offset),
38 | size: Int(layout.cmdsize) - layoutSize
39 | ) ?? ""
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/UUIDCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UUIDCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct UUIDCommand: LoadCommandWrapper {
12 | public typealias Layout = uuid_command
13 |
14 | public var layout: Layout
15 | public var offset: Int // offset from mach header trailing
16 |
17 | public var uuid: UUID {
18 | .init(uuid: layout.uuid)
19 | }
20 |
21 | init(_ layout: Layout, offset: Int) {
22 | self.layout = layout
23 | self.offset = offset
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/MachOKit/LoadCommand/VersionMinCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VersionMinCommand.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct VersionMinCommand: LoadCommandWrapper {
12 | public typealias Layout = version_min_command
13 |
14 | public var layout: version_min_command
15 |
16 | public var offset: Int
17 |
18 | init(_ layout: Layout, offset: Int) {
19 | self.layout = layout
20 | self.offset = offset
21 | }
22 | }
23 |
24 | extension VersionMinCommand {
25 | public var version: Version {
26 | .init(layout.version)
27 | }
28 |
29 | public var sdk: Version {
30 | .init(layout.version)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Sources/MachOKit/MachOFile+BindOperations.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MachOFile+BindOperations.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/09.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension MachOFile {
12 | public struct BindOperations: Sequence {
13 | public let data: Data
14 | public let bindOffset: Int
15 | public let bindSize: Int
16 |
17 | public func makeIterator() -> Iterator {
18 | .init(data: data)
19 | }
20 | }
21 | }
22 |
23 | extension MachOFile.BindOperations {
24 | init(
25 | machO: MachOFile,
26 | info: dyld_info_command,
27 | kind: BindOperationsKind = .normal
28 | ) {
29 | let bindOffset = Int(kind.bindOffset(of: info))
30 | let bindSize = Int(kind.bindSize(of: info))
31 | let offset = machO.headerStartOffset + bindOffset
32 | let data = try! machO.fileHandle.readData(
33 | offset: offset,
34 | length: bindSize
35 | )
36 | self.init(data: data, bindOffset: bindOffset, bindSize: bindSize)
37 | }
38 | }
39 |
40 | extension MachOFile.BindOperations {
41 | public struct Iterator: IteratorProtocol {
42 | public typealias Element = BindOperation
43 |
44 | private let data: Data
45 | private var nextOffset: Int = 0
46 |
47 | init(data: Data) {
48 | self.data = data
49 | }
50 |
51 | public mutating func next() -> Element? {
52 | guard nextOffset < data.count else { return nil }
53 |
54 | return data.withUnsafeBytes {
55 | guard let basePointer = $0.baseAddress else { return nil }
56 |
57 | return BindOperation.readNext(
58 | basePointer: basePointer.assumingMemoryBound(to: UInt8.self),
59 | bindSize: data.count,
60 | nextOffset: &nextOffset
61 | )
62 | }
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Sources/MachOKit/MachOFile+LoadCommands.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MachOFile+LoadCommands.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/04.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension MachOFile {
12 | public struct LoadCommands: Sequence {
13 | public let data: Data
14 | public let numberOfCommands: Int
15 | public let isSwapped: Bool
16 |
17 | public func makeIterator() -> Iterator {
18 | Iterator(
19 | data: data,
20 | numberOfCommands: numberOfCommands,
21 | isSwapped: isSwapped
22 | )
23 | }
24 | }
25 | }
26 |
27 | extension MachOFile.LoadCommands {
28 | public struct Iterator: IteratorProtocol {
29 | public typealias Element = LoadCommand
30 |
31 | public let data: Data
32 | public let numberOfCommands: Int
33 | public let isSwapped: Bool
34 |
35 | private var nextOffset: Int = 0
36 | private var nextIndex: Int = 0
37 |
38 | public init(
39 | data: Data,
40 | numberOfCommands: Int,
41 | isSwapped: Bool
42 | ) {
43 | self.data = data
44 | self.numberOfCommands = numberOfCommands
45 | self.isSwapped = isSwapped
46 | }
47 |
48 | public mutating func next() -> Element? {
49 | guard nextOffset < data.count else {
50 | return nil
51 | }
52 | guard nextIndex < numberOfCommands else {
53 | return nil
54 | }
55 |
56 | return data.withUnsafeBytes {
57 | guard let baseAddress = $0.baseAddress else { return nil }
58 |
59 | let ptr = UnsafeMutableRawPointer(mutating: baseAddress.advanced(by: nextOffset))
60 | .assumingMemoryBound(to: load_command.self)
61 |
62 | var next = LoadCommand.convert(UnsafePointer(ptr), offset: nextOffset)
63 |
64 | if isSwapped {
65 | next = next?.swapped()
66 | }
67 |
68 | nextOffset += Int(isSwapped ? ptr.pointee.cmdsize.byteSwapped : ptr.pointee.cmdsize)
69 | nextIndex += 1
70 |
71 | return next
72 | }
73 | }
74 | }
75 | }
76 |
77 | extension MachOFile.LoadCommands: LoadCommandsProtocol {}
78 |
--------------------------------------------------------------------------------
/Sources/MachOKit/MachOFile+RebaseOperations.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MachOFile+RebaseOperations.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/09.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension MachOFile {
12 | public struct RebaseOperations: Sequence {
13 | public let data: Data
14 | public let rebaseOffset: Int
15 | public let rebaseSize: Int
16 |
17 | public func makeIterator() -> Iterator {
18 | .init(data: data)
19 | }
20 | }
21 | }
22 |
23 | extension MachOFile.RebaseOperations {
24 | init(
25 | machO: MachOFile,
26 | rebaseOffset: Int,
27 | rebaseSize: Int
28 | ) {
29 | let offset = machO.headerStartOffset + rebaseOffset
30 | let data = try! machO.fileHandle.readData(
31 | offset: offset,
32 | length: rebaseSize
33 | )
34 |
35 | self.init(
36 | data: data,
37 | rebaseOffset: rebaseOffset,
38 | rebaseSize: rebaseSize
39 | )
40 | }
41 |
42 | init(
43 | machO: MachOFile,
44 | info: dyld_info_command
45 | ) {
46 | self.init(
47 | machO: machO,
48 | rebaseOffset: Int(info.rebase_off),
49 | rebaseSize: Int(info.rebase_size)
50 | )
51 | }
52 | }
53 |
54 | extension MachOFile.RebaseOperations {
55 | public struct Iterator: IteratorProtocol {
56 | public typealias Element = RebaseOperation
57 |
58 | private let data: Data
59 | private var nextOffset: Int = 0
60 | private var done = false
61 |
62 | init(data: Data) {
63 | self.data = data
64 | }
65 |
66 | public mutating func next() -> Element? {
67 | guard !done, nextOffset < data.count else { return nil }
68 |
69 | return data.withUnsafeBytes {
70 | guard let basePointer = $0.baseAddress else { return nil }
71 |
72 | return RebaseOperation.readNext(
73 | basePointer: basePointer.assumingMemoryBound(to: UInt8.self),
74 | rebaseSize: data.count,
75 | nextOffset: &nextOffset,
76 | done: &done
77 | )
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Sources/MachOKit/MachOImage+BindOperations.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MachO+BindOperations.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/03.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension MachOImage {
12 | public struct BindOperations: Sequence {
13 | public let basePointer: UnsafePointer
14 | public let bindSize: Int
15 |
16 | public func makeIterator() -> Iterator {
17 | .init(basePointer: basePointer, bindSize: bindSize)
18 | }
19 | }
20 | }
21 |
22 | extension MachOImage.BindOperations {
23 | init(
24 | ptr: UnsafeRawPointer,
25 | text: SegmentCommand64,
26 | linkedit: SegmentCommand64,
27 | info: dyld_info_command,
28 | kind: BindOperationsKind = .normal
29 | ) {
30 | let fileSlide = Int(linkedit.vmaddr) - Int(text.vmaddr) - Int(linkedit.fileoff)
31 | let ptr = ptr
32 | .advanced(by: Int(kind.bindOffset(of: info)))
33 | .advanced(by: Int(fileSlide))
34 | .assumingMemoryBound(to: UInt8.self)
35 |
36 | self.init(basePointer: ptr, bindSize: Int(kind.bindSize(of: info)))
37 | }
38 |
39 | init(
40 | ptr: UnsafeRawPointer,
41 | text: SegmentCommand,
42 | linkedit: SegmentCommand,
43 | info: dyld_info_command,
44 | kind: BindOperationsKind = .normal
45 | ) {
46 | let fileSlide = Int(linkedit.vmaddr) - Int(text.vmaddr) - Int(linkedit.fileoff)
47 | let ptr = ptr
48 | .advanced(by: Int(kind.bindOffset(of: info)))
49 | .advanced(by: Int(fileSlide))
50 | .assumingMemoryBound(to: UInt8.self)
51 |
52 | self.init(basePointer: ptr, bindSize: Int(kind.bindSize(of: info)))
53 | }
54 | }
55 |
56 | extension MachOImage.BindOperations {
57 | public struct Iterator: IteratorProtocol {
58 | public typealias Element = BindOperation
59 |
60 | private let basePointer: UnsafePointer
61 | private let bindSize: Int
62 |
63 | private var nextOffset: Int = 0
64 |
65 | init(basePointer: UnsafePointer, bindSize: Int) {
66 | self.basePointer = basePointer
67 | self.bindSize = bindSize
68 | }
69 |
70 | public mutating func next() -> Element? {
71 | BindOperation.readNext(
72 | basePointer: basePointer,
73 | bindSize: bindSize,
74 | nextOffset: &nextOffset
75 | )
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Sources/MachOKit/MachOImage+LoadCommands.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MachOImage+LoadCommands.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/28.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension MachOImage {
12 | public struct LoadCommands: Sequence {
13 | public let start: UnsafeRawPointer
14 | public let numberOfCommands: Int
15 |
16 | public func makeIterator() -> Iterator {
17 | Iterator(
18 | start: start,
19 | numberOfCommands: numberOfCommands
20 | )
21 | }
22 | }
23 | }
24 |
25 | extension MachOImage.LoadCommands {
26 | public struct Iterator: IteratorProtocol {
27 | public typealias Element = LoadCommand
28 |
29 | public let start: UnsafeRawPointer
30 | public let numberOfCommands: Int
31 |
32 | private var nextOffset: Int = 0
33 | private var nextIndex: Int = 0
34 |
35 | public init(
36 | start: UnsafeRawPointer,
37 | numberOfCommands: Int
38 | ) {
39 | self.start = start
40 | self.numberOfCommands = numberOfCommands
41 | }
42 |
43 | public mutating func next() -> Element? {
44 | guard nextIndex < numberOfCommands else {
45 | return nil
46 | }
47 | let ptr = start.advanced(by: nextOffset)
48 | .assumingMemoryBound(to: load_command.self)
49 |
50 | defer {
51 | nextOffset += numericCast(ptr.pointee.cmdsize)
52 | nextIndex += 1
53 | }
54 |
55 | return LoadCommand.convert(ptr, offset: nextOffset)
56 | }
57 | }
58 | }
59 |
60 | extension MachOImage.LoadCommands: LoadCommandsProtocol {}
61 |
--------------------------------------------------------------------------------
/Sources/MachOKit/MachOImage+RebaseOperations.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MachO+RebaseOperations.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/03.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension MachOImage {
12 | public struct RebaseOperations: Sequence {
13 | public let basePointer: UnsafePointer
14 | public let rebaseSize: Int
15 |
16 | public func makeIterator() -> Iterator {
17 | .init(basePointer: basePointer, rebaseSize: rebaseSize)
18 | }
19 | }
20 | }
21 |
22 | extension MachOImage.RebaseOperations {
23 | init(
24 | ptr: UnsafeRawPointer,
25 | text: SegmentCommand64,
26 | linkedit: SegmentCommand64,
27 | info: dyld_info_command
28 | ) {
29 | let fileSlide = Int(linkedit.vmaddr) - Int(text.vmaddr) - Int(linkedit.fileoff)
30 | let ptr = ptr
31 | .advanced(by: Int(info.rebase_off))
32 | .advanced(by: Int(fileSlide))
33 | .assumingMemoryBound(to: UInt8.self)
34 |
35 | self.init(basePointer: ptr, rebaseSize: Int(info.rebase_size))
36 | }
37 |
38 | init(
39 | ptr: UnsafeRawPointer,
40 | text: SegmentCommand,
41 | linkedit: SegmentCommand,
42 | info: dyld_info_command
43 | ) {
44 | let fileSlide = Int(linkedit.vmaddr) - Int(text.vmaddr) - Int(linkedit.fileoff)
45 | let ptr = ptr
46 | .advanced(by: Int(info.rebase_off))
47 | .advanced(by: Int(fileSlide))
48 | .assumingMemoryBound(to: UInt8.self)
49 |
50 | self.init(basePointer: ptr, rebaseSize: Int(info.rebase_size))
51 | }
52 | }
53 |
54 | extension MachOImage.RebaseOperations {
55 | public struct Iterator: IteratorProtocol {
56 | public typealias Element = RebaseOperation
57 |
58 | private let basePointer: UnsafePointer
59 | private let rebaseSize: Int
60 |
61 | private var nextOffset: Int = 0
62 | private var done = false
63 |
64 | init(basePointer: UnsafePointer, rebaseSize: Int) {
65 | self.basePointer = basePointer
66 | self.rebaseSize = rebaseSize
67 | }
68 |
69 | public mutating func next() -> Element? {
70 | RebaseOperation.readNext(
71 | basePointer: basePointer,
72 | rebaseSize: rebaseSize,
73 | nextOffset: &nextOffset,
74 | done: &done
75 | )
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Sources/MachOKit/MachOKit.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public enum File {
4 | case machO(MachOFile)
5 | case fat(FatFile)
6 | }
7 |
8 | public enum MachOKitError: LocalizedError {
9 | case invalidMagic
10 | case invalidCpuType
11 | }
12 |
13 | public func loadFromFile(url: URL) throws -> File {
14 | let fileHandle = try FileHandle(forReadingFrom: url)
15 | let magicRaw: UInt32 = fileHandle.read(offset: 0)
16 |
17 | guard let magic = Magic(rawValue: magicRaw) else {
18 | throw MachOKitError.invalidMagic
19 | }
20 |
21 | if magic.isFat {
22 | return .fat(try FatFile(url: url))
23 | } else {
24 | return .machO(try MachOFile(url: url))
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Bind/BindOperationsKind.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BindOperationsKind.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/09.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum BindOperationsKind {
12 | case normal
13 | case weak
14 | case lazy
15 | }
16 |
17 | extension BindOperationsKind {
18 | func bindOffset(of info: dyld_info_command) -> UInt32 {
19 | switch self {
20 | case .normal: info.bind_off
21 | case .weak: info.weak_bind_off
22 | case .lazy: info.lazy_bind_off
23 | }
24 | }
25 |
26 | func bindSize(of info: dyld_info_command) -> UInt32 {
27 | switch self {
28 | case .normal: info.bind_size
29 | case .weak: info.weak_bind_size
30 | case .lazy: info.lazy_bind_size
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Bind/BindSpecial.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BindSpecial.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/03.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum BindSpecial {
12 | /// BIND_SPECIAL_DYLIB_SELF
13 | case dylib_self
14 | /// BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
15 | case dylib_main_executable
16 | /// BIND_SPECIAL_DYLIB_FLAT_LOOKUP
17 | case dylib_flat_lookup
18 | /// BIND_SPECIAL_DYLIB_WEAK_LOOKUP
19 | case dylib_weak_lookup
20 | }
21 |
22 | extension BindSpecial: RawRepresentable {
23 | public typealias RawValue = Int32
24 |
25 | public init?(rawValue: RawValue) {
26 | switch rawValue {
27 | case BIND_SPECIAL_DYLIB_SELF: self = .dylib_self
28 | case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE: self = .dylib_main_executable
29 | case BIND_SPECIAL_DYLIB_FLAT_LOOKUP: self = .dylib_flat_lookup
30 | case BIND_SPECIAL_DYLIB_WEAK_LOOKUP: self = .dylib_weak_lookup
31 | default: return nil
32 | }
33 | }
34 |
35 | public var rawValue: RawValue {
36 | switch self {
37 | case .dylib_self: BIND_SPECIAL_DYLIB_SELF
38 | case .dylib_main_executable: BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
39 | case .dylib_flat_lookup: BIND_SPECIAL_DYLIB_FLAT_LOOKUP
40 | case .dylib_weak_lookup: BIND_SPECIAL_DYLIB_WEAK_LOOKUP
41 | }
42 | }
43 | }
44 |
45 | extension BindSpecial: CustomStringConvertible {
46 | public var description: String {
47 | switch self {
48 | case .dylib_self: "BIND_SPECIAL_DYLIB_SELF"
49 | case .dylib_main_executable: "BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE"
50 | case .dylib_flat_lookup: "BIND_SPECIAL_DYLIB_FLAT_LOOKUP"
51 | case .dylib_weak_lookup: "BIND_SPECIAL_DYLIB_WEAK_LOOKUP"
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Bind/BindType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BindType.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/03.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum BindType {
12 | /// BIND_TYPE_POINTER
13 | case pointer
14 | /// BIND_TYPE_TEXT_ABSOLUTE32
15 | case text_absolute32
16 | /// BIND_TYPE_TEXT_PCREL32
17 | case text_pcrel32
18 | }
19 |
20 | extension BindType: RawRepresentable {
21 | public typealias RawValue = Int32
22 |
23 | public init?(rawValue: RawValue) {
24 | switch rawValue {
25 | case BIND_TYPE_POINTER: self = .pointer
26 | case BIND_TYPE_TEXT_ABSOLUTE32: self = .text_absolute32
27 | case BIND_TYPE_TEXT_PCREL32: self = .text_pcrel32
28 | default: return nil
29 | }
30 | }
31 |
32 | public var rawValue: RawValue {
33 | switch self {
34 | case .pointer: BIND_TYPE_POINTER
35 | case .text_absolute32: BIND_TYPE_TEXT_ABSOLUTE32
36 | case .text_pcrel32: BIND_TYPE_TEXT_PCREL32
37 | }
38 | }
39 | }
40 |
41 | extension BindType: CustomStringConvertible {
42 | public var description: String {
43 | switch self {
44 | case .pointer: "BIND_TYPE_POINTER"
45 | case .text_absolute32: "BIND_TYPE_TEXT_ABSOLUTE32"
46 | case .text_pcrel32: "BIND_TYPE_TEXT_PCREL32"
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Bind/ClassicBindType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ClassicBindType.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/03/04
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum ClassicBindType {
12 | case relocation(RelocationType)
13 | case pointer
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/ClassicBindingSymbol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ClassicBindingSymbol.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/03/04
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct ClassicBindingSymbol {
12 | public let type: ClassicBindType
13 | public let address: UInt
14 | public let symbolIndex: Int
15 | public let addend: Int
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeDirectory/CodeSignCodeDirectory+codeLimit64.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignCodeDirectory+codeLimit64.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension CodeSignCodeDirectory {
12 | public func codeLimit64(in signature: MachOFile.CodeSign) -> CodeLimit64? {
13 | guard isSupportsCodeLimit64 else {
14 | return nil
15 | }
16 | let layout: CS_CodeDirectory_CodeLimit64 = signature.fileSice.ptr
17 | .advanced(by: offset)
18 | .advanced(by: layoutSize)
19 | .advanced(by: ScatterOffset.layoutSize)
20 | .advanced(by: TeamIdOffset.layoutSize)
21 | .assumingMemoryBound(to: CS_CodeDirectory_CodeLimit64.self)
22 | .pointee
23 | return .init(
24 | layout: signature.isSwapped ? layout.swapped : layout
25 | )
26 | }
27 | }
28 |
29 | extension CodeSignCodeDirectory {
30 | public func codeLimit64(in signature: MachOImage.CodeSign) -> CodeLimit64? {
31 | guard isSupportsCodeLimit64 else {
32 | return nil
33 | }
34 | let layout: CS_CodeDirectory_CodeLimit64? = signature.basePointer
35 | .advanced(by: offset)
36 | .advanced(by: layoutSize)
37 | .advanced(by: ScatterOffset.layoutSize)
38 | .advanced(by: TeamIdOffset.layoutSize)
39 | .assumingMemoryBound(to: CS_CodeDirectory_CodeLimit64.self)
40 | .pointee
41 | guard let layout else { return nil }
42 | return .init(
43 | layout: signature.isSwapped ? layout.swapped : layout
44 | )
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeDirectory/CodeSignCodeDirectory+executableSegment.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignCodeDirectory+executableSegment.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension CodeSignCodeDirectory {
12 | public func executableSegment(in signature: MachOFile.CodeSign) -> ExecutableSegment? {
13 | guard isSupportsExecSegment else {
14 | return nil
15 | }
16 | let layout: CS_CodeDirectory_ExecSeg = signature.fileSice.ptr
17 | .advanced(by: offset)
18 | .advanced(by: layoutSize)
19 | .advanced(by: ScatterOffset.layoutSize)
20 | .advanced(by: TeamIdOffset.layoutSize)
21 | .advanced(by: CodeLimit64.layoutSize)
22 | .assumingMemoryBound(to: CS_CodeDirectory_ExecSeg.self)
23 | .pointee
24 | return .init(
25 | layout: signature.isSwapped ? layout.swapped : layout
26 | )
27 | }
28 | }
29 |
30 | extension CodeSignCodeDirectory {
31 | public func executableSegment(in signature: MachOImage.CodeSign) -> ExecutableSegment? {
32 | guard isSupportsExecSegment else {
33 | return nil
34 | }
35 | let layout: CS_CodeDirectory_ExecSeg? = signature.basePointer
36 | .advanced(by: offset)
37 | .advanced(by: layoutSize)
38 | .advanced(by: ScatterOffset.layoutSize)
39 | .advanced(by: TeamIdOffset.layoutSize)
40 | .advanced(by: CodeLimit64.layoutSize)
41 | .assumingMemoryBound(to: CS_CodeDirectory_ExecSeg.self)
42 | .pointee
43 | guard let layout else { return nil }
44 | return .init(
45 | layout: signature.isSwapped ? layout.swapped : layout
46 | )
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeDirectory/CodeSignCodeDirectory+runtime.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignCodeDirectory+runtime.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension CodeSignCodeDirectory {
12 | public func runtime(in signature: MachOFile.CodeSign) -> Runtime? {
13 | guard isSupportsRuntime else {
14 | return nil
15 | }
16 | let layout: CS_CodeDirectory_Runtime = signature.fileSice.ptr
17 | .advanced(by: offset)
18 | .advanced(by: layoutSize)
19 | .advanced(by: ScatterOffset.layoutSize)
20 | .advanced(by: TeamIdOffset.layoutSize)
21 | .advanced(by: CodeLimit64.layoutSize)
22 | .advanced(by: ExecutableSegment.layoutSize)
23 | .assumingMemoryBound(to: CS_CodeDirectory_Runtime.self)
24 | .pointee
25 | return .init(
26 | layout: signature.isSwapped ? layout.swapped : layout
27 | )
28 | }
29 |
30 | public func runtime(in signature: MachOImage.CodeSign) -> Runtime? {
31 | guard isSupportsRuntime else {
32 | return nil
33 | }
34 | let layout: CS_CodeDirectory_Runtime? = signature.basePointer
35 | .advanced(by: offset)
36 | .advanced(by: layoutSize)
37 | .advanced(by: ScatterOffset.layoutSize)
38 | .advanced(by: TeamIdOffset.layoutSize)
39 | .advanced(by: CodeLimit64.layoutSize)
40 | .advanced(by: ExecutableSegment.layoutSize)
41 | .assumingMemoryBound(to: CS_CodeDirectory_Runtime.self)
42 | .pointee
43 | guard let layout else { return nil }
44 | return .init(
45 | layout: signature.isSwapped ? layout.swapped : layout
46 | )
47 | }
48 | }
49 |
50 | extension CodeSignCodeDirectory {
51 | public func preEncryptHash(
52 | forSlot index: Int,
53 | in signature: MachOFile.CodeSign
54 | ) -> Data? {
55 | guard index >= 0,
56 | index < Int(layout.nCodeSlots),
57 | let runtime = runtime(in: signature),
58 | runtime.preEncryptOffset != 0 else {
59 | return nil
60 | }
61 | let size: Int = numericCast(layout.hashSize)
62 | let offset = offset
63 | + numericCast(runtime.preEncryptOffset)
64 | + index * size
65 | return try! signature.fileSice.readData(
66 | offset: numericCast(offset),
67 | length: size
68 | )
69 | }
70 |
71 | public func preEncryptHash(
72 | forSlot index: Int,
73 | in signature: MachOImage.CodeSign
74 | ) -> Data? {
75 | guard index >= 0,
76 | index < Int(layout.nCodeSlots),
77 | let runtime = runtime(in: signature),
78 | runtime.preEncryptOffset != 0 else {
79 | return nil
80 | }
81 | let size: Int = numericCast(layout.hashSize)
82 | let offset = offset
83 | + numericCast(runtime.preEncryptOffset)
84 | + index * size
85 | return Data(
86 | bytes: signature.basePointer.advanced(by: offset),
87 | count: size
88 | )
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeDirectory/CodeSignCodeDirectory+scatter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignCodeDirectory+scatter.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension CodeSignCodeDirectory {
12 | public func scatterOffset(in signature: MachOFile.CodeSign) -> ScatterOffset? {
13 | guard isSupportsScatter else {
14 | return nil
15 | }
16 | let layout: CS_CodeDirectory_Scatter = signature.fileSice.ptr
17 | .advanced(by: offset)
18 | .advanced(by: layoutSize)
19 | .assumingMemoryBound(to: CS_CodeDirectory_Scatter.self)
20 | .pointee
21 |
22 | return .init(
23 | layout: signature.isSwapped ? layout.swapped : layout
24 | )
25 | }
26 | }
27 |
28 | extension CodeSignCodeDirectory {
29 | public func scatterOffset(in signature: MachOImage.CodeSign) -> ScatterOffset? {
30 | guard isSupportsScatter else {
31 | return nil
32 | }
33 | let layout: CS_CodeDirectory_Scatter? = signature.basePointer
34 | .advanced(by: offset)
35 | .advanced(by: layoutSize)
36 | .assumingMemoryBound(to: CS_CodeDirectory_Scatter.self)
37 | .pointee
38 | guard let layout else { return nil }
39 |
40 | return .init(
41 | layout: signature.isSwapped ? layout.swapped : layout
42 | )
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeDirectory/CodeSignCodeDirectory+teamID.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignCodeDirectory+teamID.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension CodeSignCodeDirectory {
12 | public func teamIdOffset(in signature: MachOFile.CodeSign) -> TeamIdOffset? {
13 | guard isSupportsScatter else { return nil }
14 | let layout: CS_CodeDirectory_TeamID = signature.fileSice.ptr
15 | .advanced(by: offset)
16 | .advanced(by: layoutSize)
17 | .advanced(by: ScatterOffset.layoutSize)
18 | .assumingMemoryBound(to: CS_CodeDirectory_TeamID.self)
19 | .pointee
20 | return .init(
21 | layout: signature.isSwapped ? layout.swapped : layout
22 | )
23 | }
24 |
25 | public func teamId(in signature: MachOFile.CodeSign) -> String? {
26 | guard let teamIdOffset = teamIdOffset(in: signature),
27 | teamIdOffset.teamOffset != 0 else {
28 | return nil
29 | }
30 | let ptr = signature.fileSice.ptr
31 | .advanced(by: offset)
32 | .advanced(by: Int(teamIdOffset.teamOffset))
33 | .assumingMemoryBound(to: CChar.self)
34 | return String(cString: ptr)
35 | }
36 | }
37 |
38 | extension CodeSignCodeDirectory {
39 | public func teamIdOffset(in signature: MachOImage.CodeSign) -> TeamIdOffset? {
40 | guard isSupportsScatter else {
41 | return nil
42 | }
43 | let layout: CS_CodeDirectory_TeamID? = signature.basePointer
44 | .advanced(by: offset)
45 | .advanced(by: layoutSize)
46 | .advanced(by: ScatterOffset.layoutSize)
47 | .assumingMemoryBound(to: CS_CodeDirectory_TeamID.self)
48 | .pointee
49 | guard let layout else { return nil }
50 | return .init(
51 | layout: signature.isSwapped ? layout.swapped : layout
52 | )
53 | }
54 |
55 | public func teamId(in signature: MachOImage.CodeSign) -> String? {
56 | guard let teamIdOffset = teamIdOffset(in: signature),
57 | teamIdOffset.teamOffset != 0 else {
58 | return nil
59 | }
60 | let ptr = signature.basePointer
61 | .advanced(by: offset)
62 | .advanced(by: Int(teamIdOffset.teamOffset))
63 | .assumingMemoryBound(to: CChar.self)
64 | return String(cString: ptr)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeSignBlobIndex.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignBlobIndex.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/03.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct CodeSignBlobIndex: LayoutWrapper {
13 | public typealias Layout = CS_BlobIndex
14 |
15 | public var layout: Layout
16 | }
17 |
18 | extension CodeSignBlobIndex {
19 | public var type: CodeSignSlot! {
20 | .init(rawValue: layout.type)
21 | }
22 | }
23 |
24 | extension CS_BlobIndex {
25 | var swapped: CS_BlobIndex {
26 | .init(
27 | type: type.byteSwapped,
28 | offset: offset.byteSwapped
29 | )
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeSignGenericBlob.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignGenericBlob.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/04.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct CodeSignGenericBlob: LayoutWrapper {
13 | public typealias Layout = CS_GenericBlob
14 |
15 | public var layout: Layout
16 | }
17 |
18 | extension CodeSignGenericBlob {
19 | public var isSwapped: Bool {
20 | layout.isSwapped
21 | }
22 |
23 | public var magic: CodeSignMagic! {
24 | .init(rawValue: isSwapped ? layout.magic.byteSwapped : layout.magic)
25 | }
26 |
27 | public var length: Int {
28 | numericCast(isSwapped ? layout.length.byteSwapped : layout.length)
29 | }
30 | }
31 |
32 | extension CodeSignGenericBlob {
33 | static func load(
34 | from baseAddress: UnsafeRawPointer,
35 | offset: Int,
36 | isSwapped: Bool
37 | ) -> CodeSignGenericBlob? {
38 | let ptr = baseAddress.advanced(by: offset)
39 | var _magic = ptr
40 | .assumingMemoryBound(to: UInt32.self)
41 | .pointee
42 | if isSwapped { _magic = _magic.byteSwapped }
43 | guard CodeSignMagic(rawValue: _magic) != nil else {
44 | return nil
45 | }
46 | let layout = ptr
47 | .assumingMemoryBound(to: CS_GenericBlob.self)
48 | .pointee
49 | return .init(
50 | layout: isSwapped ? layout.swapped : layout
51 | )
52 | }
53 | }
54 |
55 | extension CS_GenericBlob {
56 | var isSwapped: Bool {
57 | magic < 0xfade0000
58 | }
59 |
60 | var swapped: CS_GenericBlob {
61 | var swapped = CS_GenericBlob()
62 | swapped.magic = magic.byteSwapped
63 | swapped.length = length.byteSwapped
64 | return swapped
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeSignHashType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignHashType.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/03.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public enum CodeSignHashType {
13 | case sha1
14 | case sha256
15 | case sha256_truncated
16 | case sha384
17 | }
18 |
19 | extension CodeSignHashType: RawRepresentable {
20 | public typealias RawValue = UInt32
21 |
22 | public init?(rawValue: UInt32) {
23 | switch rawValue {
24 | case CS_HASHTYPE_SHA1: self = .sha1
25 | case CS_HASHTYPE_SHA256: self = .sha256
26 | case CS_HASHTYPE_SHA256_TRUNCATED: self = .sha256_truncated
27 | case CS_HASHTYPE_SHA384: self = .sha384
28 | default:
29 | return nil
30 | }
31 | }
32 |
33 | public var rawValue: UInt32 {
34 | switch self {
35 | case .sha1: CS_HASHTYPE_SHA1
36 | case .sha256: CS_HASHTYPE_SHA256
37 | case .sha256_truncated: CS_HASHTYPE_SHA256_TRUNCATED
38 | case .sha384: CS_HASHTYPE_SHA384
39 | }
40 | }
41 | }
42 |
43 | extension CodeSignHashType: CustomStringConvertible {
44 | public var description: String {
45 | switch self {
46 | case .sha1: "CS_HASHTYPE_SHA1"
47 | case .sha256: "CS_HASHTYPE_SHA256"
48 | case .sha256_truncated: "CS_HASHTYPE_SHA256_TRUNCATED"
49 | case .sha384: "CS_HASHTYPE_SHA384"
50 | }
51 | }
52 | }
53 |
54 | extension CodeSignHashType {
55 | package var priority: Int {
56 | switch self {
57 | case .sha1: 0
58 | case .sha256_truncated: 1
59 | case .sha256: 2
60 | case .sha384: 3
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeSignMagic.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignMagic.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/03.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public enum CodeSignMagic {
13 | /// CSMAGIC_REQUIREMENT
14 | case requirement
15 | /// CSMAGIC_REQUIREMENTS
16 | case requirements
17 | /// CSMAGIC_CODEDIRECTORY
18 | case codedirectory
19 | /// CSMAGIC_EMBEDDED_SIGNATURE
20 | case embedded_signature
21 | /// CSMAGIC_EMBEDDED_SIGNATURE_OLD
22 | case embedded_signature_old
23 | /// CSMAGIC_EMBEDDED_ENTITLEMENTS
24 | case embedded_entitlements
25 | /// CSMAGIC_EMBEDDED_DER_ENTITLEMENTS
26 | case embedded_der_entitlements
27 | /// CSMAGIC_DETACHED_SIGNATURE
28 | case detached_signature
29 | /// CSMAGIC_BLOBWRAPPER
30 | case blobwrapper
31 | /// CSMAGIC_EMBEDDED_LAUNCH_CONSTRAINT
32 | case embedded_launch_constraint
33 | }
34 |
35 | extension CodeSignMagic: RawRepresentable {
36 | public typealias RawValue = UInt32
37 |
38 | public init?(rawValue: RawValue) {
39 | switch rawValue {
40 | case RawValue(CSMAGIC_REQUIREMENT): self = .requirement
41 | case RawValue(CSMAGIC_REQUIREMENTS): self = .requirements
42 | case RawValue(CSMAGIC_CODEDIRECTORY): self = .codedirectory
43 | case RawValue(CSMAGIC_EMBEDDED_SIGNATURE): self = .embedded_signature
44 | case RawValue(CSMAGIC_EMBEDDED_SIGNATURE_OLD): self = .embedded_signature_old
45 | case RawValue(CSMAGIC_EMBEDDED_ENTITLEMENTS): self = .embedded_entitlements
46 | case RawValue(CSMAGIC_EMBEDDED_DER_ENTITLEMENTS): self = .embedded_der_entitlements
47 | case RawValue(CSMAGIC_DETACHED_SIGNATURE): self = .detached_signature
48 | case RawValue(CSMAGIC_BLOBWRAPPER): self = .blobwrapper
49 | case RawValue(CSMAGIC_EMBEDDED_LAUNCH_CONSTRAINT): self = .embedded_launch_constraint
50 | default: return nil
51 | }
52 | }
53 |
54 | public var rawValue: RawValue {
55 | switch self {
56 | case .requirement: RawValue(CSMAGIC_REQUIREMENT)
57 | case .requirements: RawValue(CSMAGIC_REQUIREMENTS)
58 | case .codedirectory: RawValue(CSMAGIC_CODEDIRECTORY)
59 | case .embedded_signature: RawValue(CSMAGIC_EMBEDDED_SIGNATURE)
60 | case .embedded_signature_old: RawValue(CSMAGIC_EMBEDDED_SIGNATURE_OLD)
61 | case .embedded_entitlements: RawValue(CSMAGIC_EMBEDDED_ENTITLEMENTS)
62 | case .embedded_der_entitlements: RawValue(CSMAGIC_EMBEDDED_DER_ENTITLEMENTS)
63 | case .detached_signature: RawValue(CSMAGIC_DETACHED_SIGNATURE)
64 | case .blobwrapper: RawValue(CSMAGIC_BLOBWRAPPER)
65 | case .embedded_launch_constraint: RawValue(CSMAGIC_EMBEDDED_LAUNCH_CONSTRAINT)
66 | }
67 | }
68 | }
69 |
70 | extension CodeSignMagic: CustomStringConvertible {
71 | public var description: String {
72 | switch self {
73 | case .requirement: "CSMAGIC_REQUIREMENT"
74 | case .requirements: "CSMAGIC_REQUIREMENTS"
75 | case .codedirectory: "CSMAGIC_CODEDIRECTORY"
76 | case .embedded_signature: "CSMAGIC_EMBEDDED_SIGNATURE"
77 | case .embedded_signature_old: "CSMAGIC_EMBEDDED_SIGNATURE_OLD"
78 | case .embedded_entitlements: "CSMAGIC_EMBEDDED_ENTITLEMENTS"
79 | case .embedded_der_entitlements: "CSMAGIC_EMBEDDED_DER_ENTITLEMENTS"
80 | case .detached_signature: "CSMAGIC_DETACHED_SIGNATURE"
81 | case .blobwrapper: "CSMAGIC_BLOBWRAPPER"
82 | case .embedded_launch_constraint: "CSMAGIC_EMBEDDED_LAUNCH_CONSTRAINT"
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeSignSpecialSlotType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignSpecialSlotType.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/04.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | /// Special slot in code directory
12 | ///
13 | /// https://github.com/apple-oss-distributions/Security/blob/ef677c3d667a44e1737c1b0245e9ed04d11c51c1/OSX/libsecurity_codesigning/lib/codedirectory.h#L86
14 | public enum CodeSignSpecialSlotType: Int {
15 | /// Info.plist
16 | case infoSlot = 1
17 | /// internal requirements
18 | case requirementsSlot = 2
19 | /// resource directory
20 | case resourceDirSlot = 3
21 | /// Application specific slot
22 | case topDirectorySlot = 4
23 | /// embedded entitlement configuration/
24 | case entitlementSlot = 5
25 | /// for use by disk rep/
26 | case repSpecificSlot = 6
27 | /// DER repreesentation of entitlements/
28 | case entitlementDERSlot = 7
29 | /// DER representation of LWCR on self/
30 | case launchConstraintSelf = 8
31 | /// DER representation of LWCR on the parent/
32 | case launchConstraintParent = 9
33 | /// DER representation of LWCR on the responsible process/
34 | case launchConstraintResponsible = 10
35 | /// DER representation of LWCR on libraries loaded in the process/
36 | case libraryConstraint = 11
37 | // (add further primary slot numbers here)
38 | }
39 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Codesign/CodeSignSuperBlob.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodeSignSuperBlob.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/03/03.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct CodeSignSuperBlob: LayoutWrapper {
13 | public typealias Layout = CS_SuperBlob
14 |
15 | public var layout: Layout
16 | public let offset: Int // offset from start of linkedit_data
17 | }
18 |
19 | extension CodeSignSuperBlob {
20 | public var magic: CodeSignMagic! {
21 | .init(rawValue: layout.magic)
22 | }
23 |
24 | public var count: Int {
25 | numericCast(layout.count)
26 | }
27 | }
28 |
29 | extension CodeSignSuperBlob {
30 | /// Get indices of this SuperBlob
31 | /// - Parameter signature: ``MachOFile.CodeSign`` to which this SuperBlob belongs.
32 | /// - Returns: indices of this superBlob
33 | public func blobIndices(
34 | in signature: MachOFile.CodeSign
35 | ) -> AnyRandomAccessCollection {
36 | let offset = offset + layoutSize
37 |
38 | return AnyRandomAccessCollection(
39 | DataSequence(
40 | data: try! signature.fileSice.readData(
41 | offset: offset,
42 | upToCount: signature.fileSice.size
43 | ),
44 | numberOfElements: count
45 | ).lazy.map {
46 | .init(layout: signature.isSwapped ? $0.swapped : $0)
47 | }
48 | )
49 | }
50 |
51 | /// Get indices of this SuperBlob
52 | /// - Parameter signature: ``MachOImage.CodeSign`` to which this SuperBlob belongs.
53 | /// - Returns: indices of this superBlob
54 | public func blobIndices(
55 | in signature: MachOImage.CodeSign
56 | ) -> AnyRandomAccessCollection {
57 | let offset = offset + layoutSize
58 |
59 | return AnyRandomAccessCollection(
60 | MemorySequence(
61 | basePointer: signature.basePointer
62 | .advanced(by: offset)
63 | .assumingMemoryBound(to: CS_BlobIndex.self),
64 | numberOfElements: count
65 | ).lazy.map {
66 | .init(layout: signature.isSwapped ? $0.swapped : $0)
67 | } // swiftlint:disable:this closure_end_indentation
68 | )
69 | }
70 | }
71 |
72 | extension CS_SuperBlob {
73 | var isSwapped: Bool {
74 | magic < 0xfade0000
75 | }
76 |
77 | var swapped: CS_SuperBlob {
78 | var swapped = CS_SuperBlob()
79 | swapped.magic = magic.byteSwapped
80 | swapped.length = length.byteSwapped
81 | swapped.count = count.byteSwapped
82 | return swapped
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DataInCodeEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataInCodeEntry.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/07.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DataInCodeEntry: LayoutWrapper {
12 | public typealias Layout = data_in_code_entry
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension DataInCodeEntry {
18 | public var kind: Kind? {
19 | .init(rawValue: numericCast(layout.kind))
20 | }
21 | }
22 |
23 | extension DataInCodeEntry {
24 | public enum Kind {
25 | case data
26 | case jumpTable8
27 | case jumpTable16
28 | case jumpTable32
29 | case absJumpTable32
30 | }
31 | }
32 |
33 | extension DataInCodeEntry.Kind: RawRepresentable {
34 | public typealias RawValue = Int32
35 |
36 | public var rawValue: RawValue {
37 | switch self {
38 | case .data: DICE_KIND_DATA
39 | case .jumpTable8: DICE_KIND_JUMP_TABLE8
40 | case .jumpTable16: DICE_KIND_JUMP_TABLE16
41 | case .jumpTable32: DICE_KIND_JUMP_TABLE32
42 | case .absJumpTable32: DICE_KIND_ABS_JUMP_TABLE32
43 | }
44 | }
45 |
46 | public init?(rawValue: RawValue) {
47 | switch rawValue {
48 | case DICE_KIND_DATA: self = .data
49 | case DICE_KIND_JUMP_TABLE8: self = .jumpTable8
50 | case DICE_KIND_JUMP_TABLE16: self = .jumpTable16
51 | case DICE_KIND_JUMP_TABLE32: self = .jumpTable32
52 | case DICE_KIND_ABS_JUMP_TABLE32: self = .absJumpTable32
53 | default: return nil
54 | }
55 | }
56 | }
57 |
58 | extension DataInCodeEntry.Kind: CustomStringConvertible {
59 | public var description: String {
60 | switch self {
61 | case .data: "DICE_KIND_DATA"
62 | case .jumpTable8: "DICE_KIND_JUMP_TABLE8"
63 | case .jumpTable16: "DICE_KIND_JUMP_TABLE16"
64 | case .jumpTable32: "DICE_KIND_JUMP_TABLE32"
65 | case .absJumpTable32: "DICE_KIND_ABS_JUMP_TABLE32"
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DependedDylib.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DependedDylib.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/02/03.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DependedDylib {
12 | public enum DependType {
13 | case load
14 | case weakLoad
15 | case reexport
16 | case upwardLoad
17 | case lazyLoad
18 | }
19 |
20 | public let dylib: Dylib
21 | public let type: DependType
22 | public let useFlags: DylibUseFlags
23 |
24 | init(
25 | dylib: Dylib,
26 | type: DependType,
27 | useFlags: DylibUseFlags = []
28 | ) {
29 | self.dylib = dylib
30 | self.type = type
31 | self.useFlags = useFlags
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCacheDynamicData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheDynamicData.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/02/28
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DyldCacheDynamicData: LayoutWrapper {
12 | public typealias Layout = dyld_cache_dynamic_data_header
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension DyldCacheDynamicData {
18 | public var magic: String {
19 | .init(tuple: layout.magic)
20 | }
21 | }
22 |
23 | #if canImport(Darwin)
24 | extension DyldCacheDynamicData {
25 | public var path: String {
26 | let path: UnsafeMutablePointer = .allocate(capacity: Int(MAXPATHLEN))
27 | var fsid: UInt64 = numericCast(layout.fsId)
28 | return withUnsafeMutablePointer(to: &fsid) { fsid in
29 | fsgetpath(
30 | path,
31 | Int(MAXPATHLEN),
32 | UnsafeMutableRawPointer(fsid).assumingMemoryBound(to: fsid_t.self),
33 | layout.fsObjId
34 | )
35 | return String(cString: path)
36 | }
37 | }
38 | }
39 | #endif
40 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCacheFunctionVariantEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheFunctionVariantEntry.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/05/12
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldCacheFunctionVariantEntry: LayoutWrapper {
13 | public typealias Layout = dyld_cache_function_variant_entry
14 |
15 | public var layout: Layout
16 | }
17 |
18 | extension DyldCacheFunctionVariantEntry {
19 | public var isPACSigned: Bool {
20 | layout.pacAuth != 0
21 | }
22 |
23 | public var sizeOfFunctionVariantTable: Int {
24 | numericCast(layout.functionVariantTableSizeDiv4) * 4
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCacheFunctionVariantInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheFunctionVariantInfo.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/05/12
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldCacheFunctionVariantInfo: LayoutWrapper {
13 | public typealias Layout = dyld_cache_function_variant_info
14 |
15 | public var layout: Layout
16 | public var address: Int
17 | }
18 |
19 | extension DyldCacheFunctionVariantInfo {
20 | public func entries(in cache: DyldCacheLoaded) -> MemorySequence? {
21 | guard let basePointer = UnsafeRawPointer(bitPattern: address) else {
22 | return nil
23 | }
24 | return .init(
25 | basePointer: basePointer
26 | .advanced(by: layoutOffset(of: \.entries))
27 | .assumingMemoryBound(to: DyldCacheFunctionVariantEntry.self),
28 | numberOfElements: numericCast(layout.count)
29 | )
30 | }
31 |
32 | public func entries(in cache: DyldCache) -> DataSequence? {
33 | guard let offset = cache.fileOffset(of: numericCast(address)) else {
34 | return nil
35 | }
36 | return cache.fileHandle.readDataSequence(
37 | offset: offset + numericCast(layoutOffset(of: \.entries)),
38 | numberOfElements: numericCast(layout.count)
39 | )
40 | }
41 | }
42 |
43 | extension DyldCacheFunctionVariantInfo {
44 | public var size: Int {
45 | layoutSize + DyldCacheFunctionVariantEntry.layoutSize * numericCast(layout.count)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCacheImageInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheImageInfo.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/15.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DyldCacheImageInfo: LayoutWrapper {
12 | public typealias Layout = dyld_cache_image_info
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension DyldCacheImageInfo {
18 | /// Path for image
19 | /// - Parameter cache: DyldCache to which this image belongs
20 | /// - Returns: Path for image
21 | public func path(in cache: DyldCache) -> String? {
22 | cache.fileHandle.readString(
23 | offset: numericCast(layout.pathFileOffset)
24 | )
25 | }
26 |
27 | /// Path for image
28 | /// - Parameter cache: DyldCache to which this image belongs
29 | /// - Returns: Path for image
30 | public func path(in cache: DyldCacheLoaded) -> String? {
31 | String(
32 | cString: cache.ptr
33 | .advanced(by: numericCast(layout.pathFileOffset))
34 | .assumingMemoryBound(to: CChar.self)
35 | )
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCacheImageTextInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheImageTextInfo.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/15.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DyldCacheImageTextInfo: LayoutWrapper {
12 | public typealias Layout = dyld_cache_image_text_info
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension DyldCacheImageTextInfo {
18 | /// UUID of this image text
19 | public var uuid: UUID {
20 | .init(uuid: layout.uuid)
21 | }
22 |
23 | /// Path for image text
24 | /// - Parameter cache: DyldCache to which this image belongs
25 | /// - Returns: Path for image text
26 | public func path(in cache: DyldCache) -> String? {
27 | cache.fileHandle.readString(
28 | offset: numericCast(layout.pathOffset)
29 | )
30 | }
31 |
32 | /// Path for image text
33 | /// - Parameter cache: DyldCache to which this image belongs
34 | /// - Returns: Path for image text
35 | public func path(in cache: DyldCacheLoaded) -> String? {
36 | String(
37 | cString: cache.ptr
38 | .advanced(by: numericCast(layout.pathOffset))
39 | .assumingMemoryBound(to: CChar.self)
40 | )
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCacheLocalSymbolsEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheLocalSymbolsEntry.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/15.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DyldCacheLocalSymbolsEntry: LayoutWrapper {
12 | public typealias Layout = dyld_cache_local_symbols_entry
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension DyldCacheLocalSymbolsEntry: DyldCacheLocalSymbolsEntryProtocol {
18 | public var dylibOffset: Int {
19 | numericCast(layout.dylibOffset)
20 | }
21 |
22 | public var nlistStartIndex: Int {
23 | numericCast(layout.nlistStartIndex)
24 | }
25 |
26 | public var nlistCount: Int {
27 | numericCast(layout.nlistCount)
28 | }
29 | }
30 |
31 | public struct DyldCacheLocalSymbolsEntry64: LayoutWrapper {
32 | public typealias Layout = dyld_cache_local_symbols_entry_64
33 |
34 | public var layout: Layout
35 | }
36 |
37 | extension DyldCacheLocalSymbolsEntry64: DyldCacheLocalSymbolsEntryProtocol {
38 | public var dylibOffset: Int {
39 | numericCast(layout.dylibOffset)
40 | }
41 |
42 | public var nlistStartIndex: Int {
43 | numericCast(layout.nlistStartIndex)
44 | }
45 |
46 | public var nlistCount: Int {
47 | numericCast(layout.nlistCount)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCacheMappingInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheMappingInfo.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/15.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DyldCacheMappingInfo: LayoutWrapper {
12 | public typealias Layout = dyld_cache_mapping_info
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension DyldCacheMappingInfo {
18 | /// Max vm protection of this mapping
19 | public var maxProtection: VMProtection {
20 | .init(rawValue: VMProtection.RawValue(bitPattern: layout.maxProt))
21 | }
22 |
23 | /// Initial vm protection of this mapping
24 | public var initialProtection: VMProtection {
25 | .init(rawValue: VMProtection.RawValue(bitPattern: layout.maxProt))
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCachePrewarming.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCachePrewarming.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/05/13
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldCachePrewarming: LayoutWrapper {
13 | public typealias Layout = dyld_prewarming_header
14 |
15 | public var layout: Layout
16 | /// offset from start address of main cache
17 | public let offset: Int
18 | }
19 |
20 | extension DyldCachePrewarming {
21 | public func entries(in cache: DyldCacheLoaded) -> MemorySequence? {
22 | .init(
23 | basePointer: cache.ptr
24 | .advanced(by: offset)
25 | .advanced(by: layoutOffset(of: \.entries))
26 | .assumingMemoryBound(to: DyldCachePrewarmingEntry.self),
27 | numberOfElements: numericCast(layout.count)
28 | )
29 | }
30 |
31 | public func entries(in cache: DyldCache) -> DataSequence? {
32 | let offset = offset + layoutOffset(of: \.entries)
33 | let sharedRegionStart = cache.mainCacheHeader.sharedRegionStart
34 | guard let resolvedOffset = cache.fileOffset(
35 | of: sharedRegionStart + numericCast(offset)
36 | ) else {
37 | return nil
38 | }
39 | return cache.fileHandle.readDataSequence(
40 | offset: resolvedOffset,
41 | numberOfElements: numericCast(layout.count)
42 | )
43 | }
44 | }
45 |
46 | extension DyldCachePrewarming {
47 | public var size: Int {
48 | layoutSize + DyldCachePrewarmingEntry.layoutSize * numericCast(layout.count)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCachePrewarmingEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCachePrewarmingEntry.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/05/13
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldCachePrewarmingEntry: LayoutWrapper {
13 | public typealias Layout = dyld_prewarming_entry
14 |
15 | public var layout: Layout
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldCacheTproMappingInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheTproMappingInfo.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/02/27
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DyldCacheTproMappingInfo: LayoutWrapper {
12 | public typealias Layout = dyld_cache_tpro_mapping_info
13 |
14 | public var layout: Layout
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DyldSubCacheEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldSubCacheEntry.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/15.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum DyldSubCacheEntryType {
12 | case general
13 | case v1
14 |
15 | var layoutSize: Int {
16 | switch self {
17 | case .general:
18 | DyldSubCacheEntryGeneral.layoutSize
19 | case .v1:
20 | DyldSubCacheEntryV1.layoutSize
21 | }
22 | }
23 | }
24 |
25 | public enum DyldSubCacheEntry {
26 | case general(DyldSubCacheEntryGeneral)
27 | case v1(DyldSubCacheEntryV1)
28 |
29 | public var type: DyldSubCacheEntryType {
30 | switch self {
31 | case .general: .general
32 | case .v1: .v1
33 | }
34 | }
35 |
36 | /// UUID of sub cache
37 | public var uuid: UUID {
38 | switch self {
39 | case let .general(info): info.uuid
40 | case let .v1(info): info.uuid
41 | }
42 | }
43 |
44 | /// Offset of this subcache from the main cache base address
45 | public var cacheVMOffset: UInt64 {
46 | switch self {
47 | case let .general(info): info.cacheVMOffset
48 | case let .v1(info): info.cacheVMOffset
49 | }
50 | }
51 |
52 | /// File name suffix of the subCache file
53 | ///
54 | /// e.g. ".25.data", ".03.development"
55 | public var fileSuffix: String {
56 | switch self {
57 | case let .general(info): info.fileSuffix
58 | case let .v1(info): info.fileSuffix
59 | }
60 | }
61 | }
62 |
63 | // cache
64 | extension DyldSubCacheEntry {
65 | public func subcache(for cache: DyldCache) throws -> DyldCache? {
66 | let url = URL(fileURLWithPath: cache.url.path + fileSuffix)
67 | return try DyldCache(subcacheUrl: url, mainCacheHeader: cache.header)
68 | }
69 |
70 | public func subcache(for cache: DyldCacheLoaded) throws -> DyldCacheLoaded? {
71 | try DyldCacheLoaded(
72 | subcachePtr: cache.ptr
73 | .advanced(by: numericCast(cacheVMOffset)),
74 | mainCacheHeader: cache.header
75 | )
76 | }
77 | }
78 |
79 | public struct DyldSubCacheEntryV1: LayoutWrapper {
80 | public typealias Layout = dyld_subcache_entry_v1
81 |
82 | public var layout: Layout
83 | public let index: Int
84 | }
85 |
86 | extension DyldSubCacheEntryV1 {
87 | /// UUID of sub cache
88 | public var uuid: UUID {
89 | .init(uuid: layout.uuid)
90 | }
91 |
92 | /// File name suffix of the subCache file
93 | ///
94 | /// e.g. ".01", ".02"
95 | public var fileSuffix: String {
96 | "." + String(format: "%02d", index)
97 | }
98 | }
99 |
100 | public struct DyldSubCacheEntryGeneral: LayoutWrapper {
101 | public typealias Layout = dyld_subcache_entry
102 |
103 | public var layout: Layout
104 | public let index: Int
105 | }
106 |
107 | extension DyldSubCacheEntryGeneral {
108 | /// UUID of sub cache
109 | public var uuid: UUID {
110 | .init(uuid: layout.uuid)
111 | }
112 |
113 | /// File name suffix of the subCache file
114 | ///
115 | /// e.g. ".25.data", ".03.development"
116 | public var fileSuffix: String {
117 | .init(tuple: layout.fileSuffix)
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DylibIndex.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DylibIndex.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/07
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | /// Index/name pairs, obtained from the Dylibs trie, present in the dyld cache.
12 | ///
13 | /// If an alias for dylib exists, there may be another element with an equal Index in trie.
14 | public struct DylibIndex {
15 | // Dylib name
16 | public let name: String
17 | /// Dylib index
18 | public let index: UInt32
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/DylibsTrieNodeContent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DylibsTrieNodeContent.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/07
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public typealias DylibsTrieEntry = TrieNode
12 |
13 | public struct DylibsTrieNodeContent {
14 | public let index: UInt32
15 | }
16 |
17 | extension DylibsTrieNodeContent: TrieNodeContent {
18 | public static func read(
19 | basePointer: UnsafePointer,
20 | trieSize _: Int,
21 | nextOffset: inout Int
22 | ) -> DylibsTrieNodeContent? {
23 | let (index, ulebOffset) = basePointer
24 | .advanced(by: nextOffset)
25 | .readULEB128()
26 |
27 | nextOffset += ulebOffset
28 |
29 | return .init(index: numericCast(index))
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/Loader/LoaderRef.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoaderRef.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/10
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct LoaderRef: LayoutWrapper {
12 | public typealias Layout = loader_ref
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension LoaderRef {
18 | public var index: Int {
19 | numericCast(layout.index)
20 | }
21 |
22 | public var isApp: Bool {
23 | layout.app == 1
24 | }
25 |
26 | public var isDylib: Bool {
27 | layout.app == 0
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/Loader/ObjCBinaryInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCBinaryInfo.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2024/11/16
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct ObjCBinaryInfo: LayoutWrapper {
12 | public typealias Layout = objc_binary_info
13 |
14 | public var layout: Layout
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PrebuiltLoaderProtocol.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2024/11/09
6 | //
7 | //
8 |
9 |
10 | import Foundation
11 |
12 | public protocol PrebuiltLoaderProtocol {
13 | /// Address where this loader is located.
14 | ///
15 | /// Slides after loading are not included.
16 | var address: Int { get }
17 |
18 | /// magic of loader starts
19 | var magic: String? { get }
20 | /// PrebuiltLoader vs JustInTimeLoader
21 | var isPrebuilt: Bool { get }
22 | var neverUnload: Bool { get }
23 | var isPremapped: Bool { get }
24 |
25 | var ref: LoaderRef { get }
26 |
27 | // Information for all pre-calculated sections that we know about
28 | var sectionLocations: SectionLocations { get }
29 |
30 | /// path for target mach-o image
31 | /// - Parameter cache: DyldCache to which `self` belongs
32 | /// - Returns: path name
33 | func path(in cache: DyldCache) -> String?
34 | /// alternative path for target mach-o image if install_name does not match real path
35 | /// - Parameter cache: DyldCache to which `self` belongs
36 | /// - Returns: path name
37 | func altPath(in cache: DyldCache) -> String?
38 | /// loader reference list of target 's dependencies
39 | /// - Parameter cache: DyldCache to which `self` belongs
40 | /// - Returns: sequence of loader reference
41 | func dependentLoaderRefs(in cache: DyldCache) -> DataSequence?
42 | /// Stores information about the layout of the objc sections in a binary
43 | /// - Parameter cache: DyldCache to which `self` belongs
44 | /// - Returns: binary info for objc
45 | func objcBinaryInfo(in cache: DyldCache) -> ObjCBinaryInfo?
46 |
47 | /// path for target mach-o image
48 | /// - Parameter cache: DyldCacheLoaded to which `self` belongs
49 | /// - Returns: path name
50 | func path(in cache: DyldCacheLoaded) -> String?
51 | /// alternative path for target mach-o image if install_name does not match real path
52 | /// - Parameter cache: DyldCacheLoaded to which `self` belongs
53 | /// - Returns: path name
54 | func altPath(in cache: DyldCacheLoaded) -> String?
55 | /// loader reference list of target 's dependencies
56 | /// - Parameter cache: DyldCacheLoaded to which `self` belongs
57 | /// - Returns: sequence of loader reference
58 | func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence?
59 | /// Stores information about the layout of the objc sections in a binary
60 | /// - Parameter cache: DyldCacheLoaded to which `self` belongs
61 | /// - Returns: binary info for objc
62 | func objcBinaryInfo(in cache: DyldCacheLoaded) -> ObjCBinaryInfo?
63 | }
64 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/Loader/SectionLocations.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SectionLocations.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2024/11/16
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct SectionLocations: LayoutWrapper {
12 | public typealias Layout = section_locations
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension SectionLocations {
18 | // [dyld implementation](https://github.com/apple-oss-distributions/dyld/blob/65bbeed63cec73f313b1d636e63f243964725a9d/include/mach-o/dyld_priv.h#L62)
19 | public enum SectionKind: Int, CaseIterable {
20 | // TEXT:
21 | case text_swift5_protos
22 | case text_swift5_proto
23 | case text_swift5_types
24 | case text_swift5_replace
25 | case text_swift5_replace2
26 | case text_swift5_ac_funcs
27 |
28 | // DATA*:
29 | case objc_image_info
30 | case data_sel_refs
31 | case data_msg_refs
32 | case data_class_refs
33 | case data_super_refs
34 | case data_protocol_refs
35 | case data_class_list
36 | case data_non_lazy_class_list
37 | case data_stub_list
38 | case data_category_list
39 | case data_category_list2
40 | case data_non_lazy_category_list
41 | case data_protocol_list
42 | case data_objc_fork_ok
43 | case data_raw_isa
44 |
45 | // ~~ version 1 ~~
46 | }
47 | }
48 |
49 | extension SectionLocations {
50 | public struct Section {
51 | public let offset: Int
52 | public let size: Int
53 | public let kind: SectionKind
54 | }
55 | }
56 |
57 | extension SectionLocations {
58 | public func section(for kind: SectionKind) -> Section {
59 | var offsets = layout.offsets
60 | var sizes = layout.sizes
61 | let offset = withUnsafePointer(to: &offsets) {
62 | UnsafeRawPointer($0)
63 | .assumingMemoryBound(to: UInt64.self)
64 | .advanced(by: kind.rawValue).pointee
65 | }
66 | let size = withUnsafePointer(to: &sizes) {
67 | UnsafeRawPointer($0)
68 | .assumingMemoryBound(to: UInt64.self)
69 | .advanced(by: kind.rawValue).pointee
70 | }
71 | return .init(
72 | offset: numericCast(offset),
73 | size: numericCast(size),
74 | kind: kind
75 | )
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/ObjCOptimization/ObjCHeaderInfoRW.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ObjCHeaderInfoRW.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/10/14
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol ObjCHeaderInfoRWProtocol {
12 | /// A boolean value that indicates whether objc image is already loaded or not
13 | var isLoaded: Bool { get }
14 | /// A boolean value that indicates whether all objc classes contained in objc image are realized
15 | var isAllClassesRelized: Bool { get }
16 | }
17 |
18 | public struct ObjCHeaderInfoRW64: LayoutWrapper, ObjCHeaderInfoRWProtocol {
19 | public typealias Layout = header_info_rw_64
20 |
21 | public var layout: Layout
22 |
23 | public var isLoaded: Bool { layout.isLoaded == 1 }
24 | public var isAllClassesRelized: Bool { layout.allClassesRealized == 1 }
25 | }
26 |
27 | public struct ObjCHeaderInfoRW32: LayoutWrapper, ObjCHeaderInfoRWProtocol {
28 | public typealias Layout = header_info_rw_32
29 |
30 | public var layout: Layout
31 |
32 | public var isLoaded: Bool { layout.isLoaded == 1 }
33 | public var isAllClassesRelized: Bool { layout.allClassesRealized == 1 }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/ProgramOffset.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProgramOffset.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/09
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct ProgramOffset {
12 | public let name: String
13 | public let offset: UInt32
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/ProgramsTrieNodeContent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProgramsTrieNodeContent.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/09
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public typealias ProgramsTrieEntry = TrieNode
12 |
13 | public struct ProgramsTrieNodeContent {
14 | public let offset: UInt32
15 | }
16 |
17 | extension ProgramsTrieNodeContent: TrieNodeContent {
18 | public static func read(
19 | basePointer: UnsafePointer,
20 | trieSize _: Int,
21 | nextOffset: inout Int
22 | ) -> ProgramsTrieNodeContent? {
23 | let (offset, ulebOffset) = basePointer
24 | .advanced(by: nextOffset)
25 | .readULEB128()
26 |
27 | nextOffset += ulebOffset
28 |
29 | return .init(offset: numericCast(offset))
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/SlideInfo/DyldCacheSlideInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheSlideInfo.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/23
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public enum DyldCacheSlideInfo {
13 | case v1(DyldCacheSlideInfo1)
14 | case v2(DyldCacheSlideInfo2)
15 | case v3(DyldCacheSlideInfo3)
16 | case v4(DyldCacheSlideInfo4)
17 | case v5(DyldCacheSlideInfo5)
18 | }
19 |
20 | extension DyldCacheSlideInfo {
21 | public enum Version: Int {
22 | case none
23 | case v1 = 1, v2, v3, v4, v5
24 | }
25 | }
26 |
27 | extension DyldCacheSlideInfo.Version: Comparable {
28 | public static func < (lhs: DyldCacheSlideInfo.Version, rhs: DyldCacheSlideInfo.Version) -> Bool {
29 | lhs.rawValue < rhs.rawValue
30 | }
31 | }
32 |
33 | extension DyldCacheSlideInfo {
34 | public var version: Version {
35 | switch self {
36 | case .v1: .v1
37 | case .v2: .v2
38 | case .v3: .v3
39 | case .v4: .v4
40 | case .v5: .v5
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/SlideInfo/DyldCacheSlideInfo1.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheSlideInfo1.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/23
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldCacheSlideInfo1: LayoutWrapper {
13 | public typealias Layout = dyld_cache_slide_info
14 |
15 | public var layout: Layout
16 | public var offset: Int
17 | }
18 |
19 | extension DyldCacheSlideInfo1 {
20 | public struct Entry: LayoutWrapper {
21 | public typealias Layout = dyld_cache_slide_info_entry
22 |
23 | public var layout: Layout
24 | }
25 | }
26 |
27 | extension DyldCacheSlideInfo1 {
28 | public var numberOfTableContents: Int {
29 | numericCast(layout.toc_count)
30 | }
31 |
32 | public func toc(in cache: DyldCache) -> DataSequence? {
33 | guard layout.toc_offset > 0 else { return nil }
34 | return cache.fileHandle.readDataSequence(
35 | offset: numericCast(offset) + numericCast(layout.toc_offset),
36 | numberOfElements: numberOfTableContents
37 | )
38 | }
39 | }
40 |
41 | extension DyldCacheSlideInfo1 {
42 | public var numberOfEntries: Int {
43 | numericCast(layout.entries_count)
44 | }
45 |
46 | public func entries(in cache: DyldCache) -> DataSequence? {
47 | precondition(layout.entries_size == Entry.layoutSize)
48 | guard layout.entries_offset > 0 else { return nil }
49 | return cache.fileHandle.readDataSequence(
50 | offset: numericCast(offset) + numericCast(layout.entries_offset),
51 | numberOfElements: numberOfEntries
52 | )
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/SlideInfo/DyldCacheSlideInfo2.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheSlideInfo2.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/23
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldCacheSlideInfo2: LayoutWrapper {
13 | public typealias Layout = dyld_cache_slide_info2
14 |
15 | public var layout: Layout
16 | public var offset: Int
17 | }
18 |
19 | // MARK: - PageStart
20 | extension DyldCacheSlideInfo2 {
21 | public struct PageStart {
22 | public let value: UInt16
23 |
24 | public var isNoRebase: Bool {
25 | value == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE
26 | }
27 |
28 | public var isExtra: Bool {
29 | (value & UInt16(DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA)) > 0
30 | }
31 |
32 | public var extrasStartIndex: Int? {
33 | guard isExtra else { return nil }
34 | return numericCast(value & ~UInt16(DYLD_CACHE_SLIDE_PAGE_ATTRS))
35 | }
36 | }
37 | }
38 |
39 | // MARK: - PageExtra
40 | extension DyldCacheSlideInfo2 {
41 | public struct PageExtra {
42 | public let value: UInt16
43 |
44 | public var isEnd: Bool {
45 | (value & UInt16(DYLD_CACHE_SLIDE_PAGE_ATTR_END)) > 0
46 | }
47 | }
48 | }
49 |
50 | // MARK: - function & proerty
51 | extension DyldCacheSlideInfo2 {
52 | public var pageSize: Int {
53 | numericCast(layout.page_size)
54 | }
55 | }
56 |
57 | extension DyldCacheSlideInfo2 {
58 | public var numberOfPageStarts: Int {
59 | numericCast(layout.page_starts_count)
60 | }
61 |
62 | public func pageStarts(in cache: DyldCache) -> DataSequence? {
63 | guard layout.page_starts_offset > 0 else { return nil }
64 | return cache.fileHandle.readDataSequence(
65 | offset: numericCast(offset) + numericCast(layout.page_starts_offset),
66 | numberOfElements: numberOfPageStarts
67 | )
68 | }
69 | }
70 |
71 | extension DyldCacheSlideInfo2 {
72 | public var numberOfPageExtras: Int {
73 | numericCast(layout.page_extras_count)
74 | }
75 |
76 | public func pageExtras(in cache: DyldCache) -> DataSequence? {
77 | guard layout.page_extras_offset > 0 else { return nil }
78 | return cache.fileHandle.readDataSequence(
79 | offset: numericCast(offset) + numericCast(layout.page_extras_offset),
80 | numberOfElements: numberOfPageExtras
81 | )
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/SlideInfo/DyldCacheSlideInfo3.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheSlideInfo3.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/24
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldCacheSlideInfo3: LayoutWrapper {
13 | public typealias Layout = dyld_cache_slide_info3
14 |
15 | public var layout: Layout
16 | public var offset: Int
17 | }
18 |
19 | // MARK: - PageStart
20 | extension DyldCacheSlideInfo3 {
21 | public struct PageStart {
22 | public let value: UInt16
23 |
24 | public var isNoRebase: Bool {
25 | value == DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE
26 | }
27 | }
28 | }
29 |
30 | // MARK: - function & proerty
31 | extension DyldCacheSlideInfo3 {
32 | public var pageSize: Int {
33 | numericCast(layout.page_size)
34 | }
35 | }
36 |
37 | extension DyldCacheSlideInfo3 {
38 | public var numberOfPageStarts: Int {
39 | numericCast(layout.page_starts_count)
40 | }
41 |
42 | public func pageStarts(in cache: DyldCache) -> DataSequence? {
43 | let pageStartsOffset = layoutSize
44 | return cache.fileHandle.readDataSequence(
45 | offset: numericCast(offset) + numericCast(pageStartsOffset),
46 | numberOfElements: numberOfPageStarts
47 | )
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/SlideInfo/DyldCacheSlideInfo4.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheSlideInfo4.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/24
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldCacheSlideInfo4: LayoutWrapper {
13 | public typealias Layout = dyld_cache_slide_info4
14 |
15 | public var layout: Layout
16 | public var offset: Int
17 | }
18 |
19 | // MARK: - PageStart
20 | extension DyldCacheSlideInfo4 {
21 | public struct PageStart {
22 | public let value: UInt16
23 |
24 | public var isNoRebase: Bool {
25 | value == DYLD_CACHE_SLIDE4_PAGE_NO_REBASE
26 | }
27 |
28 | public var isUseExtra: Bool {
29 | (value & UInt16(DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA)) > 0
30 | }
31 |
32 | public var extrasStartIndex: Int? {
33 | guard isUseExtra else { return nil }
34 | return numericCast(value & UInt16(DYLD_CACHE_SLIDE4_PAGE_INDEX))
35 | }
36 | }
37 | }
38 |
39 | // MARK: - PageExtra
40 | extension DyldCacheSlideInfo4 {
41 | public struct PageExtra {
42 | public let value: UInt16
43 |
44 | public var isEnd: Bool {
45 | (value & UInt16(DYLD_CACHE_SLIDE4_PAGE_EXTRA_END)) > 0
46 | }
47 | }
48 | }
49 |
50 | // MARK: - function & proerty
51 | extension DyldCacheSlideInfo4 {
52 | public var pageSize: Int {
53 | numericCast(layout.page_size)
54 | }
55 | }
56 |
57 | extension DyldCacheSlideInfo4 {
58 | public var numberOfPageStarts: Int {
59 | numericCast(layout.page_starts_count)
60 | }
61 |
62 | public func pageStarts(in cache: DyldCache) -> DataSequence? {
63 | cache.fileHandle.readDataSequence(
64 | offset: numericCast(offset) + numericCast(layout.page_starts_offset),
65 | numberOfElements: numberOfPageStarts
66 | )
67 | }
68 | }
69 |
70 | extension DyldCacheSlideInfo4 {
71 | public var numberOfPageExtras: Int {
72 | numericCast(layout.page_extras_count)
73 | }
74 |
75 | public func pageExtras(in cache: DyldCache) -> DataSequence? {
76 | guard layout.page_extras_offset > 0 else { return nil }
77 | return cache.fileHandle.readDataSequence(
78 | offset: numericCast(offset) + numericCast(layout.page_extras_offset),
79 | numberOfElements: numberOfPageExtras
80 | )
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/SlideInfo/DyldCacheSlideInfo5.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheSlideInfo5.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/25
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldCacheSlideInfo5: LayoutWrapper {
13 | public typealias Layout = dyld_cache_slide_info5
14 |
15 | public var layout: Layout
16 | public var offset: Int
17 | }
18 |
19 | // MARK: - PageStart
20 | extension DyldCacheSlideInfo5 {
21 | public struct PageStart {
22 | public let value: UInt16
23 |
24 | public var isNoRebase: Bool {
25 | value == DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE
26 | }
27 | }
28 | }
29 |
30 | // MARK: - function & proerty
31 | extension DyldCacheSlideInfo5 {
32 | public var pageSize: Int {
33 | numericCast(layout.page_size)
34 | }
35 | }
36 |
37 | extension DyldCacheSlideInfo5 {
38 | public var numberOfPageStarts: Int {
39 | numericCast(layout.page_starts_count)
40 | }
41 |
42 | public func pageStarts(in cache: DyldCache) -> DataSequence? {
43 | let pageStartsOffset = layoutSize
44 | return cache.fileHandle.readDataSequence(
45 | offset: numericCast(offset) + numericCast(pageStartsOffset),
46 | numberOfElements: numberOfPageStarts
47 | )
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldCache/SwiftOptimization.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftOptimization.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/05
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct SwiftOptimization: LayoutWrapper {
13 | public typealias Layout = swift_optimization
14 |
15 | public var layout: Layout
16 | }
17 |
18 | extension SwiftOptimization {
19 | public func hasProperty(_ keyPath: KeyPath) -> Bool {
20 | switch keyPath {
21 | case \.prespecializationDataCacheOffset:
22 | return layout.version >= 2
23 | case \.prespecializedMetadataHashTableCacheOffsets:
24 | return layout.version >= 3
25 | default:
26 | return true
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldChain/DyldChainedFixupsHeader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldChainedFixupsHeader.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/11.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldChainedFixupsHeader: LayoutWrapper {
13 | public typealias Layout = dyld_chained_fixups_header
14 |
15 | public var layout: Layout
16 |
17 | public var importsFormat: DyldChainedImportFormat? {
18 | .init(rawValue: layout.imports_format)
19 | }
20 |
21 | public var symbolsFormat: DyldChainedSymbolsFormat? {
22 | .init(rawValue: layout.symbols_format)
23 | }
24 | }
25 |
26 | extension DyldChainedFixupsHeader {
27 | public var swapped: Self {
28 | var layout = self.layout
29 | layout.fixups_version = layout.fixups_version.byteSwapped
30 | layout.starts_offset = layout.starts_offset.byteSwapped
31 | layout.imports_offset = layout.imports_offset.byteSwapped
32 | layout.symbols_offset = layout.symbols_offset.byteSwapped
33 | layout.imports_count = layout.imports_count.byteSwapped
34 | layout.imports_format = layout.imports_format.byteSwapped
35 | layout.symbols_format = layout.symbols_format.byteSwapped
36 |
37 | return .init(layout: layout)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldChain/DyldChainedImportFormat.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldChainedImportFormat.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum DyldChainedImportFormat: UInt32 {
12 | /// DYLD_CHAINED_IMPORT
13 | case general = 1
14 | /// DYLD_CHAINED_IMPORT_ADDEND
15 | case addend
16 | /// DYLD_CHAINED_IMPORT_ADDEND64
17 | case addend64
18 | }
19 |
20 | extension DyldChainedImportFormat: CustomStringConvertible {
21 | public var description: String {
22 | switch self {
23 | case .general: "DYLD_CHAINED_IMPORT"
24 | case .addend: "DYLD_CHAINED_IMPORT_ADDEND"
25 | case .addend64: "DYLD_CHAINED_IMPORT_ADDEND64"
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldChain/DyldChainedPage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldChainedPage.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/02/17.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DyldChainedPage {
12 | public let offset: UInt16
13 | public let index: Int
14 |
15 | public var isNone: Bool {
16 | offset == DYLD_CHAINED_PTR_START_NONE
17 | }
18 |
19 | public var isMulti: Bool {
20 | offset & UInt16(DYLD_CHAINED_PTR_START_MULTI) > 0
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldChain/DyldChainedStartsInImage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldChainedStartsInImage.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/11.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldChainedStartsInImage: LayoutWrapper {
13 | public typealias Layout = dyld_chained_starts_in_image
14 |
15 | public var layout: Layout
16 | public let offset: Int
17 | }
18 |
19 | extension DyldChainedStartsInImage {
20 | public var swapped: Self {
21 | var layout = self.layout
22 | layout.seg_count = layout.seg_count.byteSwapped
23 | layout.seg_info_offset = layout.seg_info_offset.byteSwapped
24 | return .init(layout: layout, offset: offset)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldChain/DyldChainedStartsInSegment.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldChainedStartsInSegment.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/11.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldChainedStartsInSegment: LayoutWrapper {
13 | public typealias Layout = dyld_chained_starts_in_segment
14 |
15 | public var layout: Layout
16 | public let offset: Int
17 | public let segmentIndex: Int
18 |
19 | public var pointerFormat: DyldChainedFixupPointerFormat? {
20 | .init(rawValue: layout.pointer_format)
21 | }
22 | }
23 |
24 | extension DyldChainedStartsInSegment {
25 | public var swapped: Self {
26 | var layout = self.layout
27 | layout.size = layout.size.byteSwapped
28 | layout.page_size = layout.page_size.byteSwapped
29 | layout.pointer_format = layout.pointer_format.byteSwapped
30 | layout.segment_offset = layout.segment_offset.byteSwapped
31 | layout.max_valid_pointer = layout.max_valid_pointer.byteSwapped
32 | layout.page_count = layout.page_count.byteSwapped
33 | layout.page_start = layout.page_start.byteSwapped
34 | return .init(layout: layout, offset: offset, segmentIndex: segmentIndex)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldChain/DyldChainedStartsOffsets.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldChainedStartsOffsets.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/11.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MachOKitC
11 |
12 | public struct DyldChainedStartsOffsets: LayoutWrapper {
13 | public typealias Layout = dyld_chained_starts_offsets
14 |
15 | public var layout: Layout
16 | }
17 |
18 | extension DyldChainedStartsOffsets {
19 | public var swapped: Self {
20 | var layout = self.layout
21 | layout.pointer_format = layout.pointer_format.byteSwapped
22 | layout.starts_count = layout.starts_count.byteSwapped
23 | layout.chain_starts = layout.chain_starts.byteSwapped
24 | return .init(layout: layout)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/DyldChain/DyldChainedSymbolsFormat.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldChainedSymbolsFormat.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum DyldChainedSymbolsFormat: UInt32 {
12 | case uncompressed
13 | case zlibCompressed
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Export/ExportSymbolFlags.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExportSymbolFlags.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/03.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct ExportSymbolFlags: BitFlags {
12 | public typealias RawValue = Int32
13 |
14 | public let rawValue: RawValue
15 |
16 | public var kind: ExportSymbolKind? {
17 | .init(rawValue: rawValue & EXPORT_SYMBOL_FLAGS_KIND_MASK)
18 | }
19 |
20 | public init(rawValue: RawValue) {
21 | self.rawValue = rawValue
22 | }
23 | }
24 |
25 | extension ExportSymbolFlags {
26 | /// EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
27 | public static let weak_definition = ExportSymbolFlags(
28 | rawValue: Bit.weak_definition.rawValue
29 | )
30 | /// EXPORT_SYMBOL_FLAGS_REEXPORT
31 | public static let reexport = ExportSymbolFlags(
32 | rawValue: Bit.reexport.rawValue
33 | )
34 | /// EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
35 | public static let stub_and_resolver = ExportSymbolFlags(
36 | rawValue: Bit.stub_and_resolver.rawValue
37 | )
38 | /// EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER
39 | public static let static_resolver = ExportSymbolFlags(
40 | rawValue: Bit.static_resolver.rawValue
41 | )
42 | }
43 |
44 | extension ExportSymbolFlags {
45 | public enum Bit: CaseIterable {
46 | /// EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
47 | case weak_definition
48 | /// EXPORT_SYMBOL_FLAGS_REEXPORT
49 | case reexport
50 | /// EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
51 | case stub_and_resolver
52 | /// EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER
53 | case static_resolver
54 | }
55 | }
56 |
57 | extension ExportSymbolFlags.Bit: RawRepresentable {
58 | public typealias RawValue = Int32
59 |
60 | public init?(rawValue: RawValue) {
61 | switch rawValue {
62 | case RawValue(EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION): self = .weak_definition
63 | case RawValue(EXPORT_SYMBOL_FLAGS_REEXPORT): self = .reexport
64 | case RawValue(EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER): self = .stub_and_resolver
65 | case RawValue(EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER): self = .static_resolver
66 | default: return nil
67 | }
68 | }
69 |
70 | public var rawValue: RawValue {
71 | switch self {
72 | case .weak_definition: RawValue(EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION)
73 | case .reexport: RawValue(EXPORT_SYMBOL_FLAGS_REEXPORT)
74 | case .stub_and_resolver: RawValue(EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
75 | case .static_resolver: RawValue(EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER)
76 | }
77 | }
78 | }
79 |
80 | extension ExportSymbolFlags.Bit: CustomStringConvertible {
81 | public var description: String {
82 | switch self {
83 | case .weak_definition: "EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION"
84 | case .reexport: "EXPORT_SYMBOL_FLAGS_REEXPORT"
85 | case .stub_and_resolver: "EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER"
86 | case .static_resolver: "EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER"
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Export/ExportSymbolKind.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExportSymbolKind.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/03.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum ExportSymbolKind {
12 | /// EXPORT_SYMBOL_FLAGS_KIND_REGULAR
13 | case regular
14 | /// EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
15 | case thread_local
16 | /// EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
17 | case absolute
18 | }
19 |
20 | extension ExportSymbolKind: RawRepresentable {
21 | public typealias RawValue = Int32
22 |
23 | public init?(rawValue: RawValue) {
24 | switch rawValue {
25 | case EXPORT_SYMBOL_FLAGS_KIND_REGULAR: self = .regular
26 | case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL: self = .thread_local
27 | case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE: self = .absolute
28 | default: return nil
29 | }
30 | }
31 |
32 | public var rawValue: RawValue {
33 | switch self {
34 | case .regular: EXPORT_SYMBOL_FLAGS_KIND_REGULAR
35 | case .thread_local: EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
36 | case .absolute: EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
37 | }
38 | }
39 | }
40 |
41 | extension ExportSymbolKind: CustomStringConvertible {
42 | public var description: String {
43 | switch self {
44 | case .regular: "EXPORT_SYMBOL_FLAGS_KIND_REGULAR"
45 | case .thread_local: "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL"
46 | case .absolute: "EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE"
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/ExportedSymbol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExportedSymbol.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct ExportedSymbol {
12 | public var name: String
13 | /// Symbol offset from start of mach header (`MachO`)
14 | /// Symbol offset from start of file (`MachOFile`)
15 | public var offset: Int?
16 |
17 | public var flags: ExportSymbolFlags
18 |
19 | public var ordinal: UInt?
20 | public var importedName: String?
21 |
22 | public var stub: UInt?
23 | public var resolverOffset: UInt?
24 | }
25 |
26 | extension ExportedSymbol {
27 | // [dyld implementation](https://github.com/apple-oss-distributions/dyld/blob/66c652a1f1f6b7b5266b8bbfd51cb0965d67cc44/common/MachOLoaded.cpp#L258)
28 | public func resolver(for machO: MachOImage) -> (@convention(c) () -> UInt)? {
29 | guard let resolverOffset else { return nil }
30 | return autoBitCast(
31 | machO.ptr.advanced(by: numericCast(resolverOffset))
32 | )
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/FunctionStart.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FunctionStart.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/07.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct FunctionStart {
12 | /// Offset from start of mach header (`MachO`)
13 | /// File offset from mach header (`MachOFile`)
14 | public let offset: UInt
15 | }
16 |
17 | extension FunctionStart {
18 | internal static func readNext(
19 | basePointer: UnsafePointer,
20 | functionStartsSize: Int,
21 | lastFunctionOffset: UInt,
22 | nextOffset: inout Int
23 | ) -> FunctionStart? {
24 | guard nextOffset < functionStartsSize else { return nil }
25 |
26 | let (additionalOffset, size) = basePointer
27 | .advanced(by: nextOffset)
28 | .readULEB128()
29 | nextOffset += size
30 |
31 | return .init(offset: lastFunctionOffset + additionalOffset)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/IndirectSymbol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IndirectSymbol.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/26.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct IndirectSymbol {
12 | let _value: UInt32
13 | }
14 |
15 | extension IndirectSymbol {
16 | /// index of symbols
17 | public var index: Int? {
18 | guard !isLocal, !isAbsolute else { return nil }
19 | return numericCast(_value)
20 | }
21 |
22 | /// INDIRECT_SYMBOL_LOCAL
23 | public var isLocal: Bool {
24 | _value & ~UInt32(INDIRECT_SYMBOL_ABS) == INDIRECT_SYMBOL_LOCAL
25 | }
26 |
27 | /// INDIRECT_SYMBOL_ABS
28 | public var isAbsolute: Bool {
29 | _value & UInt32(INDIRECT_SYMBOL_ABS) != 0
30 | }
31 | }
32 |
33 | extension IndirectSymbol: CustomStringConvertible {
34 | public var description: String {
35 | if isLocal && isAbsolute {
36 | "INDIRECT_SYMBOL_LOCAL & INDIRECT_SYMBOL_ABS"
37 | } else if isLocal {
38 | "INDIRECT_SYMBOL_LOCAL"
39 | } else if isAbsolute {
40 | "INDIRECT_SYMBOL_ABS"
41 | } else {
42 | "\(_value)"
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Rebase/RebaseOpcode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Rebase.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/02.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum RebaseOpcode {
12 | /// REBASE_OPCODE_DONE
13 | case done
14 | /// REBASE_OPCODE_SET_TYPE_IMM
15 | case set_type_imm
16 | /// REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
17 | case set_segment_and_offset_uleb
18 | /// REBASE_OPCODE_ADD_ADDR_ULEB
19 | case add_addr_uleb
20 | /// REBASE_OPCODE_ADD_ADDR_IMM_SCALED
21 | case add_addr_imm_scaled
22 | /// REBASE_OPCODE_DO_REBASE_IMM_TIMES
23 | case do_rebase_imm_times
24 | /// REBASE_OPCODE_DO_REBASE_ULEB_TIMES
25 | case do_rebase_uleb_times
26 | /// REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
27 | case do_rebase_add_addr_uleb
28 | /// REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
29 | case do_rebase_uleb_times_skipping_uleb
30 | }
31 |
32 | extension RebaseOpcode: RawRepresentable {
33 | public typealias RawValue = Int32
34 |
35 | public init?(rawValue: RawValue) {
36 | switch rawValue {
37 | case REBASE_OPCODE_DONE: self = .done
38 | case REBASE_OPCODE_SET_TYPE_IMM: self = .set_type_imm
39 | case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: self = .set_segment_and_offset_uleb
40 | case REBASE_OPCODE_ADD_ADDR_ULEB: self = .add_addr_uleb
41 | case REBASE_OPCODE_ADD_ADDR_IMM_SCALED: self = .add_addr_imm_scaled
42 | case REBASE_OPCODE_DO_REBASE_IMM_TIMES: self = .do_rebase_imm_times
43 | case REBASE_OPCODE_DO_REBASE_ULEB_TIMES: self = .do_rebase_uleb_times
44 | case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: self = .do_rebase_add_addr_uleb
45 | case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: self = .do_rebase_uleb_times_skipping_uleb
46 | default: return nil
47 | }
48 | }
49 |
50 | public var rawValue: RawValue {
51 | switch self {
52 | case .done: REBASE_OPCODE_DONE
53 | case .set_type_imm: REBASE_OPCODE_SET_TYPE_IMM
54 | case .set_segment_and_offset_uleb: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
55 | case .add_addr_uleb: REBASE_OPCODE_ADD_ADDR_ULEB
56 | case .add_addr_imm_scaled: REBASE_OPCODE_ADD_ADDR_IMM_SCALED
57 | case .do_rebase_imm_times: REBASE_OPCODE_DO_REBASE_IMM_TIMES
58 | case .do_rebase_uleb_times: REBASE_OPCODE_DO_REBASE_ULEB_TIMES
59 | case .do_rebase_add_addr_uleb: REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
60 | case .do_rebase_uleb_times_skipping_uleb: REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
61 | }
62 | }
63 | }
64 |
65 | extension RebaseOpcode: CustomStringConvertible {
66 | public var description: String {
67 | switch self {
68 | case .done: "REBASE_OPCODE_DONE"
69 | case .set_type_imm: "REBASE_OPCODE_SET_TYPE_IMM"
70 | case .set_segment_and_offset_uleb: "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"
71 | case .add_addr_uleb: "REBASE_OPCODE_ADD_ADDR_ULEB"
72 | case .add_addr_imm_scaled: "REBASE_OPCODE_ADD_ADDR_IMM_SCALED"
73 | case .do_rebase_imm_times: "REBASE_OPCODE_DO_REBASE_IMM_TIMES"
74 | case .do_rebase_uleb_times: "REBASE_OPCODE_DO_REBASE_ULEB_TIMES"
75 | case .do_rebase_add_addr_uleb: "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB"
76 | case .do_rebase_uleb_times_skipping_uleb: "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB"
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Rebase/RebaseType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RebaseType.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/03.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum RebaseType {
12 | /// REBASE_TYPE_POINTER
13 | case pointer
14 | /// REBASE_TYPE_TEXT_ABSOLUTE32
15 | case text_absolute32
16 | /// REBASE_TYPE_TEXT_PCREL32
17 | case text_pcrel32
18 | }
19 |
20 | extension RebaseType: RawRepresentable {
21 | public typealias RawValue = Int32
22 |
23 | public init?(rawValue: RawValue) {
24 | switch rawValue {
25 | case REBASE_TYPE_POINTER: self = .pointer
26 | case REBASE_TYPE_TEXT_ABSOLUTE32: self = .text_absolute32
27 | case REBASE_TYPE_TEXT_PCREL32: self = .text_pcrel32
28 | default: return nil
29 | }
30 | }
31 |
32 | public var rawValue: RawValue {
33 | switch self {
34 | case .pointer: REBASE_TYPE_POINTER
35 | case .text_absolute32: REBASE_TYPE_TEXT_ABSOLUTE32
36 | case .text_pcrel32: REBASE_TYPE_TEXT_PCREL32
37 | }
38 | }
39 | }
40 |
41 | extension RebaseType: CustomStringConvertible {
42 | public var description: String {
43 | switch self {
44 | case .pointer: "REBASE_TYPE_POINTER"
45 | case .text_absolute32: "REBASE_TYPE_TEXT_ABSOLUTE32"
46 | case .text_pcrel32: "REBASE_TYPE_TEXT_PCREL32"
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Relocation/Relocation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Relocation.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/10.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct Relocation {
12 | public enum Info {
13 | case general(RelocationInfo)
14 | case scattered(ScatteredRelocationInfo)
15 | }
16 |
17 | public let _data: UInt64
18 |
19 | public var isScattered: Bool {
20 | _data & UInt64(R_SCATTERED) != 0
21 | }
22 |
23 | public var info: Info {
24 | var buffer = _data
25 | if isScattered {
26 | let info: ScatteredRelocationInfo = withUnsafePointer(
27 | to: &buffer, {
28 | let ptr = UnsafeRawPointer($0)
29 | return ptr.autoBoundPointee()
30 | }
31 | )
32 | return .scattered(info)
33 | } else {
34 | let info: RelocationInfo = withUnsafePointer(
35 | to: &buffer, {
36 | let ptr = UnsafeRawPointer($0)
37 | return ptr.autoBoundPointee()
38 | }
39 | )
40 | return .general(info)
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Relocation/RelocationInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RelocationInfo.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/10.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct RelocationInfo: LayoutWrapper {
12 | public typealias Layout = relocation_info
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension RelocationInfo {
18 | public var isRelocatedPCRelative: Bool {
19 | layout.r_pcrel != 0
20 | }
21 |
22 | public var length: RelocationLength? {
23 | .init(rawValue: layout.r_length)
24 | }
25 |
26 | public var isExternal: Bool {
27 | layout.r_extern != 0
28 | }
29 |
30 | public var isScattered: Bool {
31 | UInt32(bitPattern: layout.r_address) & R_SCATTERED != 0
32 | }
33 |
34 | public var symbolIndex: Int? {
35 | isExternal ? numericCast(layout.r_symbolnum) : nil
36 | }
37 |
38 | public var sectionOrdinal: Int? {
39 | isExternal ? nil : numericCast(layout.r_symbolnum)
40 | }
41 |
42 | public func type(for cpuType: CPUType) -> RelocationType? {
43 | .init(rawValue: layout.r_type, for: cpuType)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Relocation/RelocationLength.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RelocationLength.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/10.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum RelocationLength: UInt32 {
12 | case byte
13 | case word
14 | case long
15 | case quad
16 | }
17 |
18 | extension RelocationLength: CustomStringConvertible {
19 | public var description: String {
20 | switch self {
21 | case .byte: "byte"
22 | case .word: "word"
23 | case .long: "long"
24 | case .quad: "quad"
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Relocation/ScatteredRelocationInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScatteredRelocationInfo.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/10.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct ScatteredRelocationInfo: LayoutWrapper {
12 | public typealias Layout = scattered_relocation_info
13 |
14 | public var layout: Layout
15 | }
16 |
17 | extension ScatteredRelocationInfo {
18 | public var isRelocatedPCRelative: Bool {
19 | layout.r_pcrel != 0
20 | }
21 |
22 | public var length: RelocationLength? {
23 | .init(rawValue: layout.r_length)
24 | }
25 |
26 | public var isScattered: Bool {
27 | layout.r_scattered != 0
28 | }
29 |
30 | public func type(for cpuType: CPUType) -> RelocationType? {
31 | .init(rawValue: layout.r_type, for: cpuType)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/StringTableEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringTableEntry.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/04.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct StringTableEntry: Codable, Equatable {
12 | public let string: String
13 | /// Offset from the beginning of the string table
14 | public let offset: Int
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Symbol/Nlist.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Nlist.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/08.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol NlistProtocol: LayoutWrapper {
12 | var flags: SymbolFlags? { get }
13 | var symbolDescription: SymbolDescription? { get }
14 | var sectionNumber: Int? { get }
15 | }
16 |
17 | public struct Nlist: NlistProtocol {
18 | public typealias Layout = nlist
19 |
20 | public var layout: Layout
21 |
22 | public var flags: SymbolFlags? {
23 | .init(rawValue: numericCast(layout.n_type))
24 | }
25 |
26 | public var symbolDescription: SymbolDescription? {
27 | .init(rawValue: numericCast(layout.n_desc))
28 | }
29 |
30 | public var sectionNumber: Int? {
31 | layout.n_sect == NO_SECT ? nil : numericCast(layout.n_sect)
32 | }
33 | }
34 |
35 | public struct Nlist64: NlistProtocol {
36 | public typealias Layout = nlist_64
37 |
38 | public var layout: Layout
39 |
40 | public var flags: SymbolFlags? {
41 | .init(rawValue: numericCast(layout.n_type))
42 | }
43 |
44 | public var symbolDescription: SymbolDescription? {
45 | .init(rawValue: numericCast(layout.n_desc))
46 | }
47 |
48 | public var sectionNumber: Int? {
49 | layout.n_sect == NO_SECT ? nil : numericCast(layout.n_sect)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Symbol/SymbolFlags.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SymbolFlags.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/08.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct SymbolFlags: BitFlags {
12 | public typealias RawValue = Int32
13 |
14 | public let rawValue: RawValue
15 |
16 | public var stab: Stab? {
17 | guard rawValue & N_STAB != 0 else { return nil }
18 | return .init(rawValue: rawValue)
19 | }
20 |
21 | public var type: SymbolType? {
22 | let rawValue = (rawValue & N_TYPE)
23 | return .init(rawValue: rawValue)
24 | }
25 |
26 | public init(rawValue: RawValue) {
27 | self.rawValue = rawValue
28 | }
29 | }
30 |
31 | extension SymbolFlags {
32 | /// N_PEXT
33 | public static let pext = SymbolFlags(
34 | rawValue: Bit.pext.rawValue
35 | )
36 | /// N_EXT
37 | public static let ext = SymbolFlags(
38 | rawValue: Bit.ext.rawValue
39 | )
40 | }
41 |
42 | extension SymbolFlags {
43 | public enum Bit: CaseIterable {
44 | /// N_PEXT
45 | /// private external symbol bit
46 | case pext
47 | /// N_EXT
48 | /// external symbol bit, set for external symbols
49 | case ext
50 | }
51 | }
52 |
53 | extension SymbolFlags.Bit: RawRepresentable {
54 | public typealias RawValue = Int32
55 |
56 | public init?(rawValue: RawValue) {
57 | switch rawValue {
58 | case N_PEXT: self = .pext
59 | case N_EXT: self = .ext
60 | default: return nil
61 | }
62 | }
63 |
64 | public var rawValue: RawValue {
65 | switch self {
66 | case .pext: N_PEXT
67 | case .ext: N_EXT
68 | }
69 | }
70 | }
71 |
72 | extension SymbolFlags.Bit: CustomStringConvertible {
73 | public var description: String {
74 | switch self {
75 | case .pext: "N_PEXT"
76 | case .ext: "N_EXT"
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Symbol/SymbolLibraryOrdinalType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SymbolLibraryOrdinalType.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/08.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum SymbolLibraryOrdinalType {
12 | /// SELF_LIBRARY_ORDINAL
13 | case `self`
14 | /// DYNAMIC_LOOKUP_ORDINAL
15 | case dynamic_lookup_ordinal
16 | /// EXECUTABLE_ORDINAL
17 | case executable_ordinal
18 | }
19 |
20 | extension SymbolLibraryOrdinalType: RawRepresentable {
21 | public typealias RawValue = Int32
22 |
23 | public init?(rawValue: RawValue) {
24 | switch rawValue {
25 | case RawValue(SELF_LIBRARY_ORDINAL): self = .`self`
26 | case RawValue(DYNAMIC_LOOKUP_ORDINAL): self = .dynamic_lookup_ordinal
27 | case RawValue(EXECUTABLE_ORDINAL): self = .executable_ordinal
28 | default: return nil
29 | }
30 | }
31 |
32 | public var rawValue: RawValue {
33 | switch self {
34 | case .`self`: RawValue(SELF_LIBRARY_ORDINAL)
35 | case .dynamic_lookup_ordinal: RawValue(DYNAMIC_LOOKUP_ORDINAL)
36 | case .executable_ordinal: RawValue(EXECUTABLE_ORDINAL)
37 | }
38 | }
39 | }
40 |
41 | extension SymbolLibraryOrdinalType: CustomStringConvertible {
42 | public var description: String {
43 | switch self {
44 | case .self: "SELF_LIBRARY_ORDINAL"
45 | case .dynamic_lookup_ordinal: "DYNAMIC_LOOKUP_ORDINAL"
46 | case .executable_ordinal: "EXECUTABLE_ORDINAL"
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Symbol/SymbolReferenceFlag.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SymbolReferenceFlag.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/08.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum SymbolReferenceFlag {
12 | /// REFERENCE_FLAG_UNDEFINED_NON_LAZY
13 | case undefined_non_lazy
14 | /// REFERENCE_FLAG_UNDEFINED_LAZY
15 | case undefined_lazy
16 | /// REFERENCE_FLAG_DEFINED
17 | case defined
18 | /// REFERENCE_FLAG_PRIVATE_DEFINED
19 | case private_defined
20 | /// REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY
21 | case private_undefined_non_lazy
22 | /// REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY
23 | case private_undefined_lazy
24 | }
25 |
26 | extension SymbolReferenceFlag: RawRepresentable {
27 | public typealias RawValue = Int32
28 |
29 | public init?(rawValue: RawValue) {
30 | switch rawValue {
31 | case RawValue(REFERENCE_FLAG_UNDEFINED_NON_LAZY): self = .undefined_non_lazy
32 | case RawValue(REFERENCE_FLAG_UNDEFINED_LAZY): self = .undefined_lazy
33 | case RawValue(REFERENCE_FLAG_DEFINED): self = .defined
34 | case RawValue(REFERENCE_FLAG_PRIVATE_DEFINED): self = .private_defined
35 | case RawValue(REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY): self = .private_undefined_non_lazy
36 | case RawValue(REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY): self = .private_undefined_lazy
37 | default: return nil
38 | }
39 | }
40 |
41 | public var rawValue: RawValue {
42 | switch self {
43 | case .undefined_non_lazy: RawValue(REFERENCE_FLAG_UNDEFINED_NON_LAZY)
44 | case .undefined_lazy: RawValue(REFERENCE_FLAG_UNDEFINED_LAZY)
45 | case .defined: RawValue(REFERENCE_FLAG_DEFINED)
46 | case .private_defined: RawValue(REFERENCE_FLAG_PRIVATE_DEFINED)
47 | case .private_undefined_non_lazy: RawValue(REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY)
48 | case .private_undefined_lazy: RawValue(REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)
49 | }
50 | }
51 | }
52 |
53 | extension SymbolReferenceFlag: CustomStringConvertible {
54 | public var description: String {
55 | switch self {
56 | case .undefined_non_lazy: "REFERENCE_FLAG_UNDEFINED_NON_LAZY"
57 | case .undefined_lazy: "REFERENCE_FLAG_UNDEFINED_LAZY"
58 | case .defined: "REFERENCE_FLAG_DEFINED"
59 | case .private_defined: "REFERENCE_FLAG_PRIVATE_DEFINED"
60 | case .private_undefined_non_lazy: "REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY"
61 | case .private_undefined_lazy: "REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY"
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Model/Symbol/SymbolType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SymbolType.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/08.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public enum SymbolType {
12 | /// N_UNDF
13 | /// undefined, n_sect == NO_SECT
14 | case undf
15 |
16 | /// N_ABS
17 | /// absolute, n_sect == NO_SECT
18 | case abs
19 |
20 | /// N_SECT
21 | /// defined in section number n_sect
22 | case sect
23 |
24 | /// N_PBUD
25 | /// prebound undefined (defined in a dylib)
26 | case pbud
27 |
28 | /// N_INDR
29 | /// indirect
30 | case indr
31 | }
32 |
33 | extension SymbolType: RawRepresentable {
34 | public typealias RawValue = Int32
35 |
36 | public init?(rawValue: RawValue) {
37 | switch rawValue {
38 | case RawValue(N_UNDF): self = .undf
39 | case RawValue(N_ABS): self = .abs
40 | case RawValue(N_SECT): self = .sect
41 | case RawValue(N_PBUD): self = .pbud
42 | case RawValue(N_INDR): self = .indr
43 | default: return nil
44 | }
45 | }
46 |
47 | public var rawValue: RawValue {
48 | switch self {
49 | case .undf: RawValue(N_UNDF)
50 | case .abs: RawValue(N_ABS)
51 | case .sect: RawValue(N_SECT)
52 | case .pbud: RawValue(N_PBUD)
53 | case .indr: RawValue(N_PBUD)
54 | }
55 | }
56 | }
57 |
58 | extension SymbolType: CustomStringConvertible {
59 | public var description: String {
60 | switch self {
61 | case .undf: "N_UNDF"
62 | case .abs: "N_ABS"
63 | case .sect: "N_SECT"
64 | case .pbud: "N_PBUD"
65 | case .indr: "N_PBUD"
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Protocol/DyldCacheLocalSymbolsEntryProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldCacheLocalSymbolsEntryProtocol.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/20.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol DyldCacheLocalSymbolsEntryProtocol {
12 | /// Offset in cache file of start of dylib
13 | var dylibOffset: Int { get }
14 |
15 | /// Start index of locals for this dylib
16 | var nlistStartIndex: Int { get }
17 |
18 | /// Number of local symbols for this dylib
19 | var nlistCount: Int { get }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Protocol/DyldChainedFixupsProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldChainedFixupsProtocol.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol DyldChainedFixupsProtocol {
12 | var header: DyldChainedFixupsHeader? { get }
13 | var startsInImage: DyldChainedStartsInImage? { get }
14 | var imports: [DyldChainedImport] { get }
15 |
16 | func startsInSegments(
17 | of startsInImage: DyldChainedStartsInImage?
18 | ) -> [DyldChainedStartsInSegment]
19 |
20 | func pages(
21 | of startsInSegment: DyldChainedStartsInSegment?
22 | ) -> [DyldChainedPage]
23 |
24 | func symbolName(for nameOffset: Int) -> String?
25 | func demangledSymbolName(for nameOffset: Int) -> String?
26 | }
27 |
28 | extension DyldChainedFixupsProtocol {
29 | public func demangledSymbolName(for nameOffset: Int) -> String? {
30 | guard let symbolName = symbolName(for: nameOffset) else {
31 | return nil
32 | }
33 | return stdlib_demangleName(symbolName)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Protocol/DyldChainedImportProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DyldChainedImportProtocol.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/11.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol DyldChainedImportProtocol: LayoutWrapper {
12 | var libraryOrdinal: Int { get }
13 | var isWeakImport: Bool { get }
14 | var nameOffset: Int { get }
15 | var addend: Int { get }
16 | }
17 |
18 | extension DyldChainedImportProtocol {
19 | // https://opensource.apple.com/source/cctools/cctools-877.5/otool/dyld_bind_info.c.auto.html
20 | // `ordinalName`
21 | public var libraryOrdinalType: BindSpecial? {
22 | .init(rawValue: numericCast(libraryOrdinal))
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Protocol/LayoutWrapper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LayoutWrapper.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | @dynamicMemberLookup
12 | public protocol LayoutWrapper {
13 | associatedtype Layout
14 |
15 | var layout: Layout { get set }
16 | }
17 |
18 | extension LayoutWrapper {
19 | public subscript(dynamicMember keyPath: KeyPath) -> Value {
20 | layout[keyPath: keyPath]
21 | }
22 | }
23 |
24 | extension LayoutWrapper {
25 | @_spi(Support)
26 | public static var layoutSize: Int {
27 | MemoryLayout.size
28 | }
29 |
30 | @_spi(Support)
31 | public var layoutSize: Int {
32 | MemoryLayout.size
33 | }
34 | }
35 |
36 | extension LayoutWrapper {
37 | @_spi(Support)
38 | public static func layoutOffset(of key: PartialKeyPath) -> Int {
39 | MemoryLayout.offset(of: key)! // swiftlint:disable:this force_unwrapping
40 | }
41 |
42 | @_spi(Support)
43 | public func layoutOffset(of key: PartialKeyPath) -> Int {
44 | MemoryLayout.offset(of: key)! // swiftlint:disable:this force_unwrapping
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Protocol/LoadCommandsProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoadCommandsProtocol.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/04.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol LoadCommandsProtocol: Sequence {}
12 |
13 | extension LoadCommandsProtocol {
14 | public func of(_ type: LoadCommandType) -> AnySequence {
15 | AnySequence(
16 | lazy.filter {
17 | $0.type == type
18 | }
19 | )
20 | }
21 |
22 | public func infos(
23 | of type: @escaping (T) -> LoadCommand
24 | ) -> AnySequence {
25 | AnySequence(
26 | lazy.compactMap { cmd in
27 | guard let info = cmd.info as? T else { return nil }
28 | guard type(info).type == cmd.type else { return nil }
29 | return info
30 | }
31 | )
32 | }
33 |
34 | public func info(
35 | of type: @escaping (T) -> LoadCommand
36 | ) -> T? {
37 | infos(of: type)
38 | .first(where: { _ in true })
39 | }
40 | }
41 |
42 | extension LoadCommandsProtocol {
43 | var text: SegmentCommand? {
44 | infos(of: LoadCommand.segment)
45 | .first {
46 | $0.segname == SEG_TEXT
47 | }
48 | }
49 |
50 | var text64: SegmentCommand64? {
51 | infos(of: LoadCommand.segment64)
52 | .first {
53 | $0.segname == SEG_TEXT
54 | }
55 | }
56 |
57 | var linkedit: SegmentCommand? {
58 | infos(of: LoadCommand.segment)
59 | .first {
60 | $0.segname == SEG_LINKEDIT
61 | }
62 | }
63 |
64 | var linkedit64: SegmentCommand64? {
65 | infos(of: LoadCommand.segment64)
66 | .first {
67 | $0.segname == SEG_LINKEDIT
68 | }
69 | }
70 |
71 | var symtab: LoadCommandInfo? {
72 | info(of: LoadCommand.symtab)
73 | }
74 |
75 | var dysymtab: LoadCommandInfo? {
76 | info(of: LoadCommand.dysymtab)
77 | }
78 |
79 | var functionStarts: LoadCommandInfo? {
80 | info(of: LoadCommand.functionStarts)
81 | }
82 |
83 | var dataInCode: LoadCommandInfo? {
84 | info(of: LoadCommand.dataInCode)
85 | }
86 |
87 | var dyldChainedFixups: LoadCommandInfo? {
88 | info(of: LoadCommand.dyldChainedFixups)
89 | }
90 |
91 | var idDylib: DylibCommand? {
92 | info(of: LoadCommand.idDylib)
93 | }
94 |
95 | var encryptionInfo: EncryptionInfoCommand? {
96 | info(of: LoadCommand.encryptionInfo)
97 | }
98 |
99 | var encryptionInfo64: EncryptionInfoCommand64? {
100 | info(of: LoadCommand.encryptionInfo64)
101 | }
102 |
103 | var codeSignature: LoadCommandInfo? {
104 | info(of: LoadCommand.codeSignature)
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Protocol/StringTable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringTable.swift
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/02/02
6 | //
7 | //
8 |
9 | public protocol StringTable: Sequence {
10 | associatedtype Encoding: _UnicodeEncoding
11 | }
12 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Protocol/SymbolProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Symbol.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/14.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol SymbolProtocol {
12 | var name: String { get }
13 |
14 | /// Offset from start of mach header (`MachO`)
15 | /// File offset from mach header (`MachOFile`)
16 | var offset: Int { get }
17 |
18 | /// Nlist or Nlist64
19 | var nlist: any NlistProtocol { get }
20 | }
21 |
22 | extension SymbolProtocol {
23 | public var demangledName: String {
24 | stdlib_demangleName(name)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/BitFlags.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BitFlags.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/20.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol BitFlags: OptionSet, Sendable {
12 | associatedtype Bit: CaseIterable, RawRepresentable, CustomStringConvertible where Bit.RawValue == RawValue
13 |
14 | associatedtype Element = Self
15 |
16 | var rawValue: RawValue { get }
17 | }
18 |
19 | extension BitFlags where Element == Self {
20 | public var bits: [Bit] {
21 | Bit.allCases
22 | .lazy
23 | .filter {
24 | contains(.init(rawValue: $0.rawValue))
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/Sequence/DataSequence.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataSequence.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/12/06.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DataSequence: Sequence {
12 | public typealias Element = T
13 |
14 | private let data: Data
15 | private let entrySize: Int
16 | private let numberOfElements: Int
17 |
18 | @_spi(Support)
19 | public init(
20 | data: Data,
21 | numberOfElements: Int
22 | ) {
23 | self.data = data
24 | self.entrySize = MemoryLayout.size
25 | self.numberOfElements = numberOfElements
26 | }
27 |
28 | @_spi(Support)
29 | public init(
30 | data: Data,
31 | entrySize: Int
32 | ) {
33 | self.data = data
34 | self.entrySize = entrySize
35 | self.numberOfElements = data.count / entrySize
36 | }
37 |
38 | public func makeIterator() -> Iterator {
39 | Iterator(
40 | data: data,
41 | entrySize: entrySize,
42 | numberOfElements: numberOfElements
43 | )
44 | }
45 | }
46 |
47 | extension DataSequence {
48 | public struct Iterator: IteratorProtocol {
49 | public typealias Element = T
50 |
51 | private let data: Data
52 | private let entrySize: Int
53 | private let numberOfElements: Int
54 |
55 | private var nextIndex: Int = 0
56 | private var nextOffset: Int = 0
57 |
58 | init(
59 | data: Data,
60 | entrySize: Int,
61 | numberOfElements: Int
62 | ) {
63 | self.data = data
64 | self.entrySize = entrySize
65 | self.numberOfElements = numberOfElements
66 | }
67 |
68 | public mutating func next() -> Element? {
69 | guard nextIndex < numberOfElements else { return nil }
70 | guard nextOffset + entrySize <= data.count else { return nil }
71 |
72 | defer {
73 | nextIndex += 1
74 | nextOffset += entrySize
75 | }
76 |
77 | return data.withUnsafeBytes {
78 | guard let baseAddress = $0.baseAddress else { return nil }
79 | return baseAddress.advanced(by: nextOffset).load(as: Element.self)
80 | }
81 | }
82 | }
83 | }
84 |
85 | extension DataSequence: Collection {
86 | public typealias Index = Int
87 |
88 | public var startIndex: Index { 0 }
89 | public var endIndex: Index { numberOfElements }
90 |
91 | public func index(after i: Int) -> Int {
92 | i + 1
93 | }
94 |
95 | public subscript(position: Int) -> Element {
96 | precondition(position >= 0)
97 | precondition(position < endIndex)
98 | precondition(data.count >= (position + 1) * entrySize)
99 | return data.withUnsafeBytes {
100 | guard let baseAddress = $0.baseAddress else {
101 | fatalError("data is empty")
102 | }
103 | return baseAddress
104 | .advanced(by: position * entrySize)
105 | .load(as: Element.self)
106 | }
107 | }
108 | }
109 |
110 | extension DataSequence: RandomAccessCollection {}
111 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/Sequence/MemorySequence.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemorySequence.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct MemorySequence: Sequence {
12 | public typealias Element = T
13 |
14 | private let basePointer: UnsafeRawPointer
15 | private let entrySize: Int
16 | private let numberOfElements: Int
17 |
18 | @_spi(Support)
19 | public init(
20 | basePointer: UnsafePointer,
21 | numberOfElements: Int
22 | ) {
23 | self.basePointer = .init(basePointer)
24 | self.entrySize = MemoryLayout.size
25 | self.numberOfElements = numberOfElements
26 | }
27 |
28 | @_spi(Support)
29 | public init(
30 | basePointer: UnsafePointer,
31 | entrySize: Int,
32 | numberOfElements: Int
33 | ) {
34 | self.basePointer = .init(basePointer)
35 | self.entrySize = entrySize
36 | self.numberOfElements = numberOfElements
37 | }
38 |
39 | public func makeIterator() -> Iterator {
40 | Iterator(
41 | basePointer: basePointer,
42 | entrySize: entrySize,
43 | numberOfElements: numberOfElements
44 | )
45 | }
46 | }
47 |
48 | extension MemorySequence {
49 | public struct Iterator: IteratorProtocol {
50 | public typealias Element = T
51 |
52 | private let basePointer: UnsafeRawPointer
53 | private let entrySize: Int
54 | private let numberOfElements: Int
55 |
56 | private var nextIndex: Int = 0
57 |
58 | init(
59 | basePointer: UnsafeRawPointer,
60 | entrySize: Int,
61 | numberOfElements: Int
62 | ) {
63 | self.basePointer = basePointer
64 | self.entrySize = entrySize
65 | self.numberOfElements = numberOfElements
66 | }
67 |
68 | public mutating func next() -> Element? {
69 | guard nextIndex < numberOfElements else { return nil }
70 | defer { nextIndex += 1 }
71 | return basePointer
72 | .advanced(by: nextIndex * entrySize)
73 | .load(as: Element.self)
74 | }
75 | }
76 | }
77 |
78 | extension MemorySequence: Collection {
79 | public typealias Index = Int
80 |
81 | public var startIndex: Index { 0 }
82 | public var endIndex: Index { numberOfElements }
83 |
84 | public func index(after i: Int) -> Int {
85 | i + 1
86 | }
87 |
88 | public subscript(position: Int) -> Element {
89 | precondition(position >= 0)
90 | precondition(position < endIndex)
91 | return basePointer
92 | .advanced(by: position * entrySize)
93 | .load(as: Element.self)
94 | }
95 | }
96 |
97 | extension MemorySequence: RandomAccessCollection {}
98 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/SwiftDemangle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftDemangle.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/01/05.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | @_silgen_name("swift_demangle")
12 | internal func _stdlib_demangleImpl(
13 | mangledName: UnsafePointer?,
14 | mangledNameLength: UInt,
15 | outputBuffer: UnsafeMutablePointer?,
16 | outputBufferSize: UnsafeMutablePointer?,
17 | flags: UInt32
18 | ) -> UnsafeMutablePointer?
19 |
20 | internal func stdlib_demangleName(
21 | _ mangledName: String
22 | ) -> String {
23 | guard !mangledName.isEmpty else { return mangledName }
24 | return mangledName.utf8CString.withUnsafeBufferPointer { mangledNameUTF8 in
25 | let demangledNamePtr = _stdlib_demangleImpl(
26 | mangledName: mangledNameUTF8.baseAddress,
27 | mangledNameLength: numericCast(mangledNameUTF8.count - 1),
28 | outputBuffer: nil,
29 | outputBufferSize: nil,
30 | flags: 0
31 | )
32 |
33 | if let demangledNamePtr {
34 | return String(cString: demangledNamePtr)
35 | }
36 | return mangledName
37 | }
38 | }
39 |
40 | internal func stdlib_demangleName(
41 | _ mangledName: UnsafePointer
42 | ) -> UnsafePointer {
43 |
44 | let demangledNamePtr = _stdlib_demangleImpl(
45 | mangledName: mangledName,
46 | mangledNameLength: numericCast(strlen(mangledName)),
47 | outputBuffer: nil,
48 | outputBufferSize: nil,
49 | flags: 0
50 | )
51 | if let demangledNamePtr {
52 | return .init(demangledNamePtr)
53 | }
54 | return mangledName
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/TrieTree/DataTrieTree.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataTrieTree.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/05
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct DataTrieTree: TrieTreeProtocol {
12 | public let data: Data
13 |
14 | public var size: Int { data.count }
15 |
16 | @_spi(Support)
17 | public init(data: Data) {
18 | self.data = data
19 | }
20 | }
21 |
22 | extension DataTrieTree {
23 | public func element(atOffset offset: Int) -> TrieNode? {
24 | var nextOffset: Int = offset
25 |
26 | return data.withUnsafeBytes {
27 | guard let basePointer = $0.baseAddress else { return nil }
28 |
29 | return .readNext(
30 | basePointer: basePointer.assumingMemoryBound(to: UInt8.self),
31 | trieSize: data.count,
32 | nextOffset: &nextOffset
33 | )
34 | }
35 | }
36 | }
37 |
38 | extension DataTrieTree: Sequence {
39 | public typealias Element = TrieNode
40 |
41 | public func makeIterator() -> Iterator {
42 | .init(data: data)
43 | }
44 | }
45 |
46 | extension DataTrieTree {
47 | public struct Iterator: IteratorProtocol {
48 | private let data: Data
49 | internal var nextOffset: Int = 0
50 |
51 | @_spi(Support)
52 | public init(data: Data) {
53 | self.data = data
54 | }
55 |
56 | public mutating func next() -> Element? {
57 | guard nextOffset < data.count else { return nil }
58 |
59 | return data.withUnsafeBytes {
60 | guard let basePointer = $0.baseAddress else { return nil }
61 |
62 | return .readNext(
63 | basePointer: basePointer.assumingMemoryBound(to: UInt8.self),
64 | trieSize: data.count,
65 | nextOffset: &nextOffset
66 | )
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/TrieTree/MemoryTrieTree.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemoryTrieTree.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/05
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public struct MemoryTrieTree: TrieTreeProtocol {
12 | public let basePointer: UnsafeRawPointer
13 | public let size: Int
14 |
15 | @_spi(Support)
16 | public init(basePointer: UnsafeRawPointer, size: Int) {
17 | self.basePointer = basePointer
18 | self.size = size
19 | }
20 | }
21 |
22 | extension MemoryTrieTree {
23 | public func element(atOffset offset: Int) -> TrieNode? {
24 | var nextOffset: Int = offset
25 | return .readNext(
26 | basePointer: basePointer.assumingMemoryBound(to: UInt8.self),
27 | trieSize: size,
28 | nextOffset: &nextOffset
29 | )
30 | }
31 | }
32 |
33 | extension MemoryTrieTree: Sequence {
34 | public typealias Element = TrieNode
35 |
36 | public func makeIterator() -> Iterator {
37 | .init(basePointer: basePointer, size: size)
38 | }
39 | }
40 |
41 | extension MemoryTrieTree {
42 | public struct Iterator: IteratorProtocol {
43 | public let basePointer: UnsafeRawPointer
44 | public let size: Int
45 |
46 | internal var nextOffset: Int = 0
47 |
48 | @_spi(Support)
49 | public init(basePointer: UnsafeRawPointer, size: Int) {
50 | self.basePointer = basePointer
51 | self.size = size
52 | }
53 |
54 | public mutating func next() -> Element? {
55 | guard nextOffset < size else { return nil }
56 |
57 | return .readNext(
58 | basePointer: basePointer.assumingMemoryBound(to: UInt8.self),
59 | trieSize: size,
60 | nextOffset: &nextOffset
61 | )
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/TrieTree/Model/TrieNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TrieNode.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/05
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | @dynamicMemberLookup
12 | public struct TrieNode {
13 | public struct Child {
14 | public let label: String
15 | public let offset: UInt
16 | }
17 |
18 | public let offset: Int
19 | public let terminalSize: UInt
20 |
21 | // Content
22 | public var content: Content?
23 |
24 | public var children: [Child]
25 |
26 | @_spi(Support)
27 | public init(
28 | offset: Int,
29 | terminalSize: UInt,
30 | content: Content?,
31 | children: [Child]
32 | ) {
33 | self.offset = offset
34 | self.terminalSize = terminalSize
35 | self.content = content
36 | self.children = children
37 | }
38 | }
39 |
40 | extension TrieNode {
41 | public var isTerminal: Bool {
42 | terminalSize != 0
43 | }
44 | }
45 |
46 | extension TrieNode {
47 | public static func readNext(
48 | basePointer: UnsafePointer,
49 | trieSize: Int,
50 | nextOffset: inout Int
51 | ) -> Self? {
52 | guard nextOffset < trieSize else { return nil }
53 |
54 | let (terminalSize, terminalBytes) = basePointer
55 | .advanced(by: nextOffset)
56 | .readULEB128()
57 | nextOffset += terminalBytes
58 |
59 | var entry = TrieNode(
60 | offset: nextOffset - terminalBytes,
61 | terminalSize: terminalSize,
62 | content: nil,
63 | children: []
64 | )
65 |
66 | var childrenOffset = nextOffset + Int(terminalSize)
67 |
68 | if terminalSize != 0 {
69 | entry.content = .read(
70 | basePointer: basePointer,
71 | trieSize: trieSize,
72 | nextOffset: &nextOffset
73 | )
74 | }
75 |
76 | guard childrenOffset < trieSize else { return entry }
77 |
78 | let numberOfChildren = basePointer
79 | .advanced(by: childrenOffset)
80 | .pointee
81 | childrenOffset += MemoryLayout.size
82 |
83 | for _ in 0..(dynamicMember keyPath: KeyPath) -> Value? {
106 | content?[keyPath: keyPath]
107 | }
108 |
109 | public subscript(dynamicMember keyPath: KeyPath) -> Value? {
110 | content?[keyPath: keyPath]
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/TrieTree/Protocol/TrieNodeContent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TrieNodeContent.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/05
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol TrieNodeContent {
12 | static func read(
13 | basePointer: UnsafePointer,
14 | trieSize: Int,
15 | nextOffset: inout Int
16 | ) -> Self?
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/exported.swift:
--------------------------------------------------------------------------------
1 | //
2 | // exported.swift
3 | //
4 | //
5 | // Created by p-x9 on 2023/11/29.
6 | //
7 | //
8 |
9 | #if canImport(MachO)
10 | @_documentation(visibility: internal)
11 | @_exported
12 | import MachO
13 | #endif
14 |
15 | @_exported
16 | import MachOKitC
17 |
--------------------------------------------------------------------------------
/Sources/MachOKit/Util/global.swift:
--------------------------------------------------------------------------------
1 | //
2 | // global.swift
3 | //
4 | //
5 | // Created by p-x9 on 2024/02/17.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public func autoBitCast(_ x: T) -> U {
12 | unsafeBitCast(x, to: U.self)
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/MachOKitC/include/backports.h:
--------------------------------------------------------------------------------
1 | //
2 | // backports.h
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2024/11/29
6 | //
7 | //
8 |
9 | #ifndef backports_h
10 | #define backports_h
11 |
12 | #ifndef __linux__
13 |
14 | #include
15 | #include
16 |
17 | #ifndef MH_IMPLICIT_PAGEZERO
18 | #define MH_IMPLICIT_PAGEZERO 0x10000000
19 | #endif
20 |
21 | #ifndef DYLIB_USE_MARKER
22 | struct dylib_use_command {
23 | uint32_t cmd; /* LC_LOAD_DYLIB or LC_LOAD_WEAK_DYLIB */
24 | uint32_t cmdsize; /* overall size, including path */
25 | uint32_t nameoff; /* == 28, dylibs's path offset */
26 | uint32_t marker; /* == DYLIB_USE_MARKER */
27 | uint32_t current_version; /* dylib's current version number */
28 | uint32_t compat_version; /* dylib's compatibility version number */
29 | uint32_t flags; /* DYLIB_USE_... flags */
30 | };
31 | #define DYLIB_USE_WEAK_LINK 0x01
32 | #define DYLIB_USE_REEXPORT 0x02
33 | #define DYLIB_USE_UPWARD 0x04
34 | #define DYLIB_USE_DELAYED_INIT 0x08
35 |
36 | #define DYLIB_USE_MARKER 0x1a741800
37 | #endif
38 |
39 | #ifndef PLATFORM_VISIONOS
40 | #define PLATFORM_VISIONOS 11
41 | #endif
42 |
43 | #ifndef PLATFORM_VISIONOSSIMULATOR
44 | #define PLATFORM_VISIONOSSIMULATOR 12
45 | #endif
46 |
47 | #ifndef LC_FUNCTION_VARIANTS
48 | #define LC_FUNCTION_VARIANTS 0x37 /* used with linkedit_data_command */
49 | #endif
50 |
51 | #ifndef LC_FUNCTION_VARIANT_FIXUPS
52 | #define LC_FUNCTION_VARIANT_FIXUPS 0x38 /* used with linkedit_data_command */
53 | #endif
54 |
55 | #ifndef LC_TARGET_TRIPLE
56 | #define LC_TARGET_TRIPLE 0x39 /* target triple used to compile */
57 |
58 | /*
59 | * The target_triple_command contains a string which specifies the
60 | * target triple (e.g. "arm64e-apple-macosx15.0.0") used to compile the code.
61 | */
62 | struct target_triple_command {
63 | uint32_t cmd; /* LC_TARGET_TRIPLE */
64 | uint32_t cmdsize; /* including string */
65 | union lc_str triple; /* target triple string */
66 | };
67 | #endif
68 |
69 | #ifndef PLATFORM_MACOS_EXCLAVECORE
70 | #define PLATFORM_MACOS_EXCLAVECORE 15
71 | #define PLATFORM_MACOS_EXCLAVEKIT 16
72 | #define PLATFORM_IOS_EXCLAVECORE 17
73 | #define PLATFORM_IOS_EXCLAVEKIT 18
74 | #define PLATFORM_TVOS_EXCLAVECORE 19
75 | #define PLATFORM_TVOS_EXCLAVEKIT 20
76 | #define PLATFORM_WATCHOS_EXCLAVECORE 21
77 | #define PLATFORM_WATCHOS_EXCLAVEKIT 22
78 | #define PLATFORM_VISIONOS_EXCLAVECORE 23
79 | #define PLATFORM_VISIONOS_EXCLAVEKIT 24
80 | #endif
81 |
82 | #endif /* __linux__ */
83 |
84 | #endif /* backports_h */
85 |
--------------------------------------------------------------------------------
/Sources/MachOKitC/include/core_foundation.h:
--------------------------------------------------------------------------------
1 | //
2 | // core_foundation.h
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/02/01
6 | //
7 | //
8 |
9 | #ifndef core_foundation_h
10 | #define core_foundation_h
11 |
12 | // ref: https://github.com/apple-oss-distributions/CF/blob/dc54c6bb1c1e5e0b9486c1d26dd5bef110b20bf3/CFRuntime.h#L222-L228
13 | typedef struct __CFRuntimeBase64 {
14 | uint64_t _cfisa;
15 | uint8_t _cfinfo[4];
16 | uint32_t _rc;
17 | } CFRuntimeBase64;
18 |
19 | typedef struct __CFRuntimeBase32 {
20 | uint32_t _cfisa;
21 | uint8_t _cfinfo[4];
22 | } CFRuntimeBase32;
23 |
24 | // ref: https://github.com/apple-oss-distributions/CF/blob/dc54c6bb1c1e5e0b9486c1d26dd5bef110b20bf3/CFInternal.h#L332
25 | struct CF_CONST_STRING64 {
26 | CFRuntimeBase64 _base;
27 | uint64_t _ptr;
28 | uint32_t _length;
29 | };
30 |
31 | struct CF_CONST_STRING32 {
32 | CFRuntimeBase32 _base;
33 | uint32_t _ptr;
34 | uint32_t _length;
35 | };
36 |
37 | #endif /* core_foundation_h */
38 |
--------------------------------------------------------------------------------
/Sources/MachOKitC/include/dyld_cache.h:
--------------------------------------------------------------------------------
1 | //
2 | // dyld_cache.h
3 | //
4 | //
5 | // Created by p-x9 on 2024/10/09
6 | //
7 | //
8 |
9 | #ifndef dyld_cache_h
10 | #define dyld_cache_h
11 |
12 | #ifndef __linux__
13 |
14 | #include
15 | #include
16 |
17 | extern const void* _dyld_get_shared_cache_range(size_t* length);
18 | extern const struct mach_header* dyld_image_header_containing_address(const void* addr);
19 |
20 | #endif
21 |
22 | #endif /* dyld_cache_h */
23 |
--------------------------------------------------------------------------------
/Sources/MachOKitC/include/swift.h:
--------------------------------------------------------------------------------
1 | //
2 | // swift.h
3 | //
4 | //
5 | // Created by p-x9 on 2024/07/05
6 | //
7 | //
8 |
9 | #ifndef swift_h
10 | #define swift_h
11 |
12 | #include
13 |
14 | // ref: https://github.com/apple-oss-distributions/dyld/blob/031f1c6ffb240a094f3f2f85f20dfd9e3f15b664/common/OptimizerSwift.h#L45
15 | struct swift_optimization {
16 | uint32_t version;
17 | uint32_t padding;
18 | uint64_t typeConformanceHashTableCacheOffset;
19 | uint64_t metadataConformanceHashTableCacheOffset;
20 | uint64_t foreignTypeConformanceHashTableCacheOffset;
21 |
22 | uint64_t prespecializationDataCacheOffset; // added in version 2
23 |
24 | // limited space reserved for table offsets, they're not accessed directly
25 | // used for debugging only
26 | uint64_t prespecializedMetadataHashTableCacheOffsets[8]; // added in version 3
27 | };
28 |
29 | #endif /* swift_h */
30 |
--------------------------------------------------------------------------------
/Sources/MachOKitC/include/thread_state.h:
--------------------------------------------------------------------------------
1 | //
2 | // thread_state.h
3 | // MachOKit
4 | //
5 | // Created by p-x9 on 2025/01/13
6 | //
7 | //
8 |
9 | #ifndef thread_state_h
10 | #define thread_state_h
11 |
12 | #include
13 |
14 | // https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/osfmk/mach/arm/_structs.h#L84
15 | struct arm_thread_state {
16 | uint32_t r[13]; /* General purpose register r0-r12 */
17 | uint32_t sp; /* Stack pointer r13 */
18 | uint32_t lr; /* Link register r14 */
19 | uint32_t pc; /* Program counter r15 */
20 | uint32_t cpsr; /* Current program status register */
21 | };
22 |
23 | // https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/osfmk/mach/arm/_structs.h#L101
24 | struct arm_thread_state64 {
25 | uint64_t x[29]; /* General purpose registers x0-x28 */
26 | uint64_t fp; /* Frame pointer x29 */
27 | uint64_t lr; /* Link register x30 */
28 | uint64_t sp; /* Stack pointer x31 */
29 | uint64_t pc; /* Program counter */
30 | uint32_t cpsr; /* Current program status register */
31 | uint32_t flags; /* Flags describing structure format */
32 | };
33 |
34 | // https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/osfmk/mach/i386/_structs.h#L66
35 | struct i386_thread_state {
36 | unsigned int eax;
37 | unsigned int ebx;
38 | unsigned int ecx;
39 | unsigned int edx;
40 | unsigned int edi;
41 | unsigned int esi;
42 | unsigned int ebp;
43 | unsigned int esp;
44 | unsigned int ss;
45 | unsigned int eflags;
46 | unsigned int eip;
47 | unsigned int cs;
48 | unsigned int ds;
49 | unsigned int es;
50 | unsigned int fs;
51 | unsigned int gs;
52 | };
53 |
54 | // https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/osfmk/mach/i386/_structs.h#L738
55 | struct x86_thread_state64 {
56 | uint64_t rax;
57 | uint64_t rbx;
58 | uint64_t rcx;
59 | uint64_t rdx;
60 | uint64_t rdi;
61 | uint64_t rsi;
62 | uint64_t rbp;
63 | uint64_t rsp;
64 | uint64_t r8;
65 | uint64_t r9;
66 | uint64_t r10;
67 | uint64_t r11;
68 | uint64_t r12;
69 | uint64_t r13;
70 | uint64_t r14;
71 | uint64_t r15;
72 | uint64_t rip;
73 | uint64_t rflags;
74 | uint64_t cs;
75 | uint64_t fs;
76 | uint64_t gs;
77 | };
78 |
79 | #endif /* thread_state_h */
80 |
--------------------------------------------------------------------------------
/Sources/MachOKitC/mach-o/fat.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Apple, Inc. All rights reserved.
3 | *
4 | * @APPLE_LICENSE_HEADER_START@
5 | *
6 | * This file contains Original Code and/or Modifications of Original Code
7 | * as defined in and that are subject to the Apple Public Source License
8 | * Version 2.0 (the 'License'). You may not use this file except in
9 | * compliance with the License. Please obtain a copy of the License at
10 | * http://www.opensource.apple.com/apsl/ and read it before using this
11 | * file.
12 | *
13 | * The Original Code and all software distributed under the License are
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 | * Please see the License for the specific language governing rights and
19 | * limitations under the License.
20 | *
21 | * @APPLE_LICENSE_HEADER_END@
22 | */
23 | #ifndef _MACH_O_FAT_H_
24 | #define _MACH_O_FAT_H_
25 | /*
26 | * This header file describes the structures of the file format for "fat"
27 | * architecture specific file (wrapper design). At the begining of the file
28 | * there is one fat_header structure followed by a number of fat_arch
29 | * structures. For each architecture in the file, specified by a pair of
30 | * cputype and cpusubtype, the fat_header describes the file offset, file
31 | * size and alignment in the file of the architecture specific member.
32 | * The padded bytes in the file to place each member on it's specific alignment
33 | * are defined to be read as zeros and can be left as "holes" if the file system
34 | * can support them as long as they read as zeros.
35 | *
36 | * All structures defined here are always written and read to/from disk
37 | * in big-endian order.
38 | */
39 |
40 | /*
41 | * is needed here for the cpu_type_t and cpu_subtype_t types
42 | * and contains the constants for the possible values of these types.
43 | */
44 | #include
45 | #include "../mach/machine.h"
46 | //#include
47 |
48 | #define FAT_MAGIC 0xcafebabe
49 | #define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */
50 |
51 | struct fat_header {
52 | uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
53 | uint32_t nfat_arch; /* number of structs that follow */
54 | };
55 |
56 | struct fat_arch {
57 | int32_t cputype; /* cpu specifier (int) */
58 | int32_t cpusubtype; /* machine specifier (int) */
59 | uint32_t offset; /* file offset to this object file */
60 | uint32_t size; /* size of this object file */
61 | uint32_t align; /* alignment as a power of 2 */
62 | };
63 |
64 | /*
65 | * The support for the 64-bit fat file format described here is a work in
66 | * progress and not yet fully supported in all the Apple Developer Tools.
67 | *
68 | * When a slice is greater than 4mb or an offset to a slice is greater than 4mb
69 | * then the 64-bit fat file format is used.
70 | */
71 | #define FAT_MAGIC_64 0xcafebabf
72 | #define FAT_CIGAM_64 0xbfbafeca /* NXSwapLong(FAT_MAGIC_64) */
73 |
74 | struct fat_arch_64 {
75 | int32_t cputype; /* cpu specifier (int) */
76 | int32_t cpusubtype; /* machine specifier (int) */
77 | uint64_t offset; /* file offset to this object file */
78 | uint64_t size; /* size of this object file */
79 | uint32_t align; /* alignment as a power of 2 */
80 | uint32_t reserved; /* reserved */
81 | };
82 |
83 | #endif /* _MACH_O_FAT_H_ */
84 |
--------------------------------------------------------------------------------
/Tests/MachOKitTests/MachOKitTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import MachOKit
3 |
4 | final class MachOKitTests: XCTestCase {
5 | func testExample() throws {
6 | // XCTest Documentation
7 | // https://developer.apple.com/documentation/xctest
8 |
9 | // Defining Test Cases and Test Methods
10 | // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/scripts/docc-preview.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | TARGET='MachOKit'
4 |
5 | preview_docc() {
6 | mkdir -p docs
7 |
8 | $(xcrun --find docc) preview \
9 | "./${TARGET}.docc" \
10 | --additional-symbol-graph-dir symbol-graphs \
11 | --output-path "docs"
12 | }
13 |
14 | sh ./scripts/generate-symbols.sh
15 |
16 | preview_docc
17 |
--------------------------------------------------------------------------------
/scripts/docc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | TARGET='MachOKit'
4 | REPO_NAME='MachOKit'
5 |
6 | generate_docc() {
7 | mkdir -p docs
8 |
9 | $(xcrun --find docc) convert \
10 | "./${TARGET}.docc" \
11 | --output-path "docs" \
12 | --hosting-base-path "${REPO_NAME}" \
13 | --additional-symbol-graph-dir ./symbol-graphs
14 | }
15 |
16 | sh ./scripts/generate-symbols.sh
17 |
18 | generate_docc
19 |
--------------------------------------------------------------------------------
/scripts/generate-symbols.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SYMBOL_DIR='./symbol-graphs'
4 |
5 | clean_build() {
6 | rm -rf ./.build
7 | }
8 |
9 | clean_xcbuild() {
10 | destination=$1
11 | scheme=$2
12 |
13 | xcodebuild -scheme "$scheme" \
14 | -destination "generic/platform=${destination}" \
15 | clean
16 | }
17 |
18 | clean_symbol() {
19 | rm -rf SYMBOL_DIR
20 | }
21 |
22 | generate_symbol_graphs() {
23 | destination=$1
24 | scheme=$2
25 |
26 | mkdir -p .build/symbol-graphs
27 | mkdir -p "$SYMBOL_DIR"
28 |
29 | xcodebuild clean build -scheme "${scheme}"\
30 | -destination "generic/platform=${destination}" \
31 | OTHER_SWIFT_FLAGS="-emit-extension-block-symbols -emit-symbol-graph -emit-symbol-graph-dir $(pwd)/.build/symbol-graphs"
32 |
33 | mv "./.build/symbol-graphs/${scheme}.symbols.json" "${SYMBOL_DIR}/${scheme}_${destination}.symbols.json"
34 |
35 | if [ -d "./Sources/$scheme/include" ]; then
36 | local HEADERS=$(ls "./Sources/$scheme/include")
37 | while IFS= read -r header; do
38 | xcrun clang \
39 | -extract-api \
40 | --product-name=$scheme \
41 | -o "$SYMBOL_DIR/$scheme-$header.json" \
42 | "$(pwd)/Sources/$scheme/include/$header"
43 | done <<<"$HEADERS"
44 | fi
45 | }
46 |
47 |
48 | clean_build
49 | clean_xcbuild ios MachOKitC
50 | clean_xcbuild ios MachOKit
51 |
52 | clean_symbol
53 |
54 | generate_symbol_graphs ios MachOKitC
55 | generate_symbol_graphs ios MachOKit
56 |
--------------------------------------------------------------------------------