├── .gitignore ├── LICENSE ├── Package.resolved ├── Package.swift ├── README.md ├── Sources ├── Demangle │ ├── Enums │ │ ├── AutoDiffFunctionKind.swift │ │ ├── DemangleFunctionEntityArgs.swift │ │ ├── DemangleGenericRequirementConstraintKind.swift │ │ ├── DemangleGenericRequirementTypeKind.swift │ │ ├── Differentiability.swift │ │ ├── Directness.swift │ │ ├── FunctionSigSpecializationParamKind.swift │ │ ├── SpecializationPass.swift │ │ ├── SugarType.swift │ │ ├── SwiftSymbolParseError.swift │ │ ├── SymbolicReference.swift │ │ ├── TypePrinting.swift │ │ └── ValueWitnessKind.swift │ ├── Main │ │ ├── Demangler.swift │ │ ├── Interface.swift │ │ ├── ScalarScanner.swift │ │ ├── SwiftSymbol.swift │ │ ├── SymbolPrintOptions.swift │ │ └── SymbolPrinter.swift │ └── Utils │ │ ├── Common.swift │ │ └── Extensions.swift ├── MachOExtensions │ ├── BinaryInteger+.swift │ ├── DyldCache+.swift │ ├── DyldCacheLoaded+.swift │ ├── LayoutWrapper+.swift │ ├── LoadCommandsProtocol+.swift │ ├── LocatableLayoutWrapper.swift │ ├── MachOFile+.swift │ ├── MachONamespace.swift │ ├── OptionalProtocol.swift │ ├── SegmentCommandProtocol+.swift │ ├── String+.swift │ └── UnsafeRawPointer+.swift ├── MachOFoundation │ └── Exported.swift ├── MachOMacro │ └── MachOMacro.swift ├── MachOMacroPlugin │ ├── LayoutMacro.swift │ ├── MachOImageMacro.swift │ └── MachOMacroPlugin.swift ├── MachOPointer │ ├── Pointer.swift │ ├── Protocol │ │ ├── PointerProtocol.swift │ │ ├── RelativeDirectPointerProtocol.swift │ │ ├── RelativeIndirectPointerProtocol.swift │ │ ├── RelativeIndirectType.swift │ │ ├── RelativeIndirectablePointerIntPairProtocol.swift │ │ ├── RelativeIndirectablePointerProtocol.swift │ │ └── RelativePointerProtocol.swift │ ├── RelativePointers.swift │ ├── SignedPointer.swift │ ├── Symbol │ │ ├── MachOFile+Symbol.swift │ │ ├── MachOSymbol.swift │ │ └── SymbolOrElement.swift │ ├── SymbolOrElementPointer.swift │ ├── TargetRelativeDirectPointer.swift │ ├── TargetRelativeIndirectPointer.swift │ ├── TargetRelativeIndirectablePointer.swift │ └── TargetRelativeIndirectablePointerIntPair.swift ├── MachOReading │ ├── AnyResolvable.swift │ ├── Models │ │ ├── DataSequence.swift │ │ └── MemorySequence.swift │ ├── Reading │ │ ├── DyldCache+.swift │ │ ├── FileHandle+.swift │ │ ├── FileIO+.swift │ │ ├── MachOFile+Reading.swift │ │ ├── MachOFileReadingError.swift │ │ ├── MachOImage+Reading.swift │ │ └── MachOReadable.swift │ └── Resolvable.swift ├── MachOSwiftSection │ ├── Extensions │ │ ├── Bool+.swift │ │ ├── Data+.swift │ │ ├── SegmentCommandProtocol+.swift │ │ └── String+.swift │ ├── MachOFile+Swift.swift │ ├── MachOImage+Swift.swift │ ├── Models │ │ ├── Anonymous │ │ │ ├── AnonymousContext.swift │ │ │ ├── AnonymousContextDescriptor.swift │ │ │ ├── AnonymousContextDescriptorFlags.swift │ │ │ ├── AnonymousContextDescriptorLayout.swift │ │ │ └── AnonymousContextDescriptorProtocol.swift │ │ ├── AssociatedType │ │ │ ├── AssociatedType.swift │ │ │ ├── AssociatedTypeDescriptor.swift │ │ │ └── AssociatedTypeRecord.swift │ │ ├── BuiltinType │ │ │ ├── BuiltinType.swift │ │ │ └── BuiltinTypeDescriptor.swift │ │ ├── Capture │ │ │ ├── Capture.swift │ │ │ └── CaptureDescriptor.swift │ │ ├── ContextDescriptor │ │ │ ├── ContextDescriptor.swift │ │ │ ├── ContextDescriptorFlags.swift │ │ │ ├── ContextDescriptorKind.swift │ │ │ ├── ContextDescriptorKindSpecificFlags.swift │ │ │ ├── ContextDescriptorLayout.swift │ │ │ ├── ContextDescriptorProtocol.swift │ │ │ ├── ContextDescriptorWrapper.swift │ │ │ ├── NamedContextDescriptorLayout.swift │ │ │ └── NamedContextDescriptorProtocol.swift │ │ ├── ExistentialType │ │ │ ├── ExtendedExistentialTypeShape.swift │ │ │ └── NonUniqueExtendedExistentialTypeShape.swift │ │ ├── Extension │ │ │ ├── ExtensionContext.swift │ │ │ ├── ExtensionContextDescriptor.swift │ │ │ ├── ExtensionContextDescriptorLayout.swift │ │ │ └── ExtensionContextDescriptorProtocol.swift │ │ ├── FieldDescriptor │ │ │ ├── FieldDescriptor.swift │ │ │ └── FieldDescriptorKind.swift │ │ ├── FieldRecord │ │ │ ├── FieldRecord.swift │ │ │ └── FieldRecordFlags.swift │ │ ├── Generic │ │ │ ├── GenericContext.swift │ │ │ ├── GenericContextDescriptorFlags.swift │ │ │ ├── GenericContextDescriptorHeader.swift │ │ │ ├── GenericContextDescriptorHeaderProtocol.swift │ │ │ ├── GenericPackKind.swift │ │ │ ├── GenericPackShapeDescriptor.swift │ │ │ ├── GenericPackShapeHeader.swift │ │ │ ├── GenericParamDescriptor.swift │ │ │ ├── GenericParamKind.swift │ │ │ ├── GenericRequirement.swift │ │ │ ├── GenericRequirementContent.swift │ │ │ ├── GenericRequirementDescriptor.swift │ │ │ ├── GenericRequirementFlags.swift │ │ │ ├── GenericRequirementKind.swift │ │ │ ├── GenericRequirementLayoutKind.swift │ │ │ ├── GenericValueDescriptor.swift │ │ │ ├── GenericValueHeader.swift │ │ │ ├── GenericValueType.swift │ │ │ ├── GenericWitnessTable.swift │ │ │ ├── TypeGenericContext.swift │ │ │ └── TypeGenericContextDescriptorHeader.swift │ │ ├── Mangling │ │ │ └── MangledName.swift │ │ ├── Metadata │ │ │ ├── CanonicalSpecializedMetadataAccessorsListEntry.swift │ │ │ ├── CanonicalSpecializedMetadatasCachingOnceToken.swift │ │ │ ├── CanonicalSpecializedMetadatasListCount.swift │ │ │ ├── CanonicalSpecializedMetadatasListEntry.swift │ │ │ ├── Metadata.swift │ │ │ ├── MetadataBounds.swift │ │ │ ├── MetadataBoundsLayout.swift │ │ │ ├── MetadataBoundsProtocol.swift │ │ │ ├── MetadataInitialization │ │ │ │ ├── ForeignMetadataInitialization.swift │ │ │ │ └── SingletonMetadataInitialization.swift │ │ │ ├── MetadataKind.swift │ │ │ ├── MetadataLayout.swift │ │ │ ├── MetadataProtocol.swift │ │ │ ├── MetadataWrapper.swift │ │ │ └── SingletonMetadataPointer.swift │ │ ├── Module │ │ │ ├── ModuleContextDescriptor.swift │ │ │ ├── ModuleContextDescriptorLayout.swift │ │ │ └── ModuleContextDescriptorProtocol.swift │ │ ├── OpaqueType │ │ │ ├── OpaqueType.swift │ │ │ ├── OpaqueTypeDescriptor.swift │ │ │ ├── OpaqueTypeDescriptorLayout.swift │ │ │ └── OpaqueTypeDescriptorProtocol.swift │ │ ├── Protocol │ │ │ ├── Invertible │ │ │ │ ├── InvertibleProtocolKind.swift │ │ │ │ ├── InvertibleProtocolSet.swift │ │ │ │ └── InvertibleProtocolsRequirementCount.swift │ │ │ ├── ObjC │ │ │ │ ├── ObjCProtocolPrefix.swift │ │ │ │ └── RelativeObjCProtocolPrefix.swift │ │ │ ├── Protocol.swift │ │ │ ├── ProtocolClassConstraint.swift │ │ │ ├── ProtocolContextDescriptorFlags.swift │ │ │ ├── ProtocolDescriptor.swift │ │ │ ├── ProtocolDescriptorLayout.swift │ │ │ ├── ProtocolDescriptorProtocol.swift │ │ │ ├── ProtocolDescriptorRef.swift │ │ │ ├── ProtocolDescriptorWithObjCInterop.swift │ │ │ ├── ProtocolDispatchStrategy.swift │ │ │ ├── ProtocolRequirement.swift │ │ │ ├── ProtocolRequirementFlags.swift │ │ │ ├── ProtocolRequirementKind.swift │ │ │ ├── ProtocolWitnessTable.swift │ │ │ ├── ResilientWitness.swift │ │ │ ├── ResilientWitnessesHeader.swift │ │ │ └── SpecialProtocolKind.swift │ │ ├── ProtocolConformance │ │ │ ├── ProtocolConformance.swift │ │ │ ├── ProtocolConformanceDescriptor.swift │ │ │ └── ProtocolConformanceFlags.swift │ │ ├── Type │ │ │ ├── Class │ │ │ │ ├── Class.swift │ │ │ │ ├── ClassDescriptor.swift │ │ │ │ ├── ClassDescriptorLayout.swift │ │ │ │ ├── ClassFlags.swift │ │ │ │ ├── ExtraClassDescriptorFlags.swift │ │ │ │ ├── Metadata │ │ │ │ │ ├── AnyClassMetadata.swift │ │ │ │ │ ├── ClassMetadata.swift │ │ │ │ │ ├── ClassMetadataBounds.swift │ │ │ │ │ ├── ClassMetadataBoundsLayout.swift │ │ │ │ │ └── ClassMetadataBoundsProtocol.swift │ │ │ │ ├── Method │ │ │ │ │ ├── MethodDefaultOverrideDescriptor.swift │ │ │ │ │ ├── MethodDefaultOverrideTableHeader.swift │ │ │ │ │ ├── MethodDescriptor.swift │ │ │ │ │ ├── MethodDescriptorFlags.swift │ │ │ │ │ ├── MethodDescriptorKind.swift │ │ │ │ │ ├── MethodImplementationPointer.swift │ │ │ │ │ ├── MethodOverrideDescriptor.swift │ │ │ │ │ ├── OverrideTableHeader.swift │ │ │ │ │ └── VTableDescriptorHeader.swift │ │ │ │ └── Resilient │ │ │ │ │ ├── ObjCResilientClassStubInfo.swift │ │ │ │ │ └── ResilientSuperclass.swift │ │ │ ├── Enum │ │ │ │ ├── Enum.swift │ │ │ │ ├── EnumDescriptor.swift │ │ │ │ ├── EnumDescriptorLayout.swift │ │ │ │ └── MultiPayloadEnum │ │ │ │ │ └── MultiPayloadEnumDescriptor.swift │ │ │ ├── Struct │ │ │ │ ├── Struct.swift │ │ │ │ ├── StructDescriptor.swift │ │ │ │ ├── StructDescriptorLayout.swift │ │ │ │ ├── StructMetadata.swift │ │ │ │ └── StructMetadataLayout.swift │ │ │ ├── TypeContextDescriptor.swift │ │ │ ├── TypeContextDescriptorFlags.swift │ │ │ ├── TypeContextDescriptorLayout.swift │ │ │ ├── TypeContextDescriptorProtocol.swift │ │ │ ├── TypeContextDescriptorWrapper.swift │ │ │ ├── TypeReference.swift │ │ │ └── TypeReferenceKind.swift │ │ └── ValueWitnessTable │ │ │ ├── ValueWitnessFlags.swift │ │ │ └── ValueWitnessTable.swift │ ├── Pointer │ │ ├── ContextPointer.swift │ │ ├── RelativePointers.swift │ │ └── RelativeProtocolDescriptorPointer.swift │ ├── Protocols │ │ ├── FlagSet.swift │ │ ├── MutableFlagSet.swift │ │ └── RuntimeProtocol.swift │ └── Utils │ │ ├── AnyLocatableLayoutWrapper.swift │ │ ├── MachOSwiftSectionName.swift │ │ ├── MetadataFinder.swift │ │ ├── MetadataReader.swift │ │ ├── RequiredNonOptional.swift │ │ ├── ResolvableLocatableLayoutWrapper.swift │ │ └── RuntimeLayout.swift └── SwiftDump │ ├── Dumpable+ │ ├── AssociatedType+Dumpable.swift │ ├── Class+Dumpable.swift │ ├── ContextDescriptorWrapper+.swift │ ├── Enum+Dumpable.swift │ ├── GenericContext+Dump.swift │ ├── OpaqueType+Dumpable.swift │ ├── Protocol+Dumpable.swift │ ├── ProtocolConformance+Dumpable.swift │ ├── ResilientSuperclass+.swift │ └── Struct+Dumpable.swift │ ├── Dumpable.swift │ └── Utils │ ├── OffsetEnumeratedSequence.swift │ ├── String+.swift │ └── StringBuilder.swift └── Tests ├── DemangleTests └── DemanglingTests.swift ├── MachOSwiftSectionTests ├── LayoutTests.swift └── TypeContextDescriptorFlagsTests.swift └── SwiftDumpTests ├── DyldCahce+.swift ├── SwiftDumpTests.swift └── SymbolPrintOptions.swift /.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 | .swiftpm 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 MxIris-Reverse-Engineering 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 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "5ff04716ff722fe4bf65c1e124ed976aab3fbf4a2a511fc7c90e2ee2f0d2e423", 3 | "pins" : [ 4 | { 5 | "identity" : "associatedobject", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/MxIris-Library-Forks/AssociatedObject", 8 | "state" : { 9 | "branch" : "main", 10 | "revision" : "c7b9b51d3bc8c6a6b07475275795316129945685" 11 | } 12 | }, 13 | { 14 | "identity" : "machokit-spm", 15 | "kind" : "remoteSourceControl", 16 | "location" : "https://github.com/p-x9/MachOKit-SPM", 17 | "state" : { 18 | "revision" : "c1990f779773ea3430016b2e549ca0e3dd97f164", 19 | "version" : "0.34.0" 20 | } 21 | }, 22 | { 23 | "identity" : "swift-fileio", 24 | "kind" : "remoteSourceControl", 25 | "location" : "https://github.com/p-x9/swift-fileio.git", 26 | "state" : { 27 | "revision" : "23349fe1eb23c6ca2876d461a46ff60c0fa92f9c", 28 | "version" : "0.9.0" 29 | } 30 | }, 31 | { 32 | "identity" : "swift-literal-type-inference", 33 | "kind" : "remoteSourceControl", 34 | "location" : "https://github.com/MxIris-Library-Forks/swift-literal-type-inference.git", 35 | "state" : { 36 | "branch" : "main", 37 | "revision" : "ee038e38d8d540cbef6c457ca1cd464e173dc66f" 38 | } 39 | }, 40 | { 41 | "identity" : "swift-object-association", 42 | "kind" : "remoteSourceControl", 43 | "location" : "https://github.com/p-x9/swift-object-association.git", 44 | "state" : { 45 | "revision" : "93806cfecae1f198c894ed5585b93aff0e2d1f5a", 46 | "version" : "0.5.0" 47 | } 48 | }, 49 | { 50 | "identity" : "swift-syntax", 51 | "kind" : "remoteSourceControl", 52 | "location" : "https://github.com/swiftlang/swift-syntax", 53 | "state" : { 54 | "revision" : "f99ae8aa18f0cf0d53481901f88a0991dc3bd4a2", 55 | "version" : "601.0.1" 56 | } 57 | } 58 | ], 59 | "version" : 3 60 | } 61 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/AutoDiffFunctionKind.swift: -------------------------------------------------------------------------------- 1 | enum AutoDiffFunctionKind: UnicodeScalar { 2 | case forward = "f" 3 | case reverse = "r" 4 | case differential = "d" 5 | case pullback = "p" 6 | 7 | init?(_ uint64: UInt64) { 8 | guard let uint32 = UInt32(exactly: uint64), let scalar = UnicodeScalar(uint32), let value = AutoDiffFunctionKind(rawValue: scalar) else { return nil } 9 | self = value 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/DemangleFunctionEntityArgs.swift: -------------------------------------------------------------------------------- 1 | enum DemangleFunctionEntityArgs { 2 | case none 3 | case typeAndMaybePrivateName 4 | case typeAndIndex 5 | case index 6 | } 7 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/DemangleGenericRequirementConstraintKind.swift: -------------------------------------------------------------------------------- 1 | enum DemangleGenericRequirementConstraintKind { 2 | case `protocol` 3 | case baseClass 4 | case sameType 5 | case sameShape 6 | case layout 7 | case packMarker 8 | case inverse 9 | case valueMarker 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/DemangleGenericRequirementTypeKind.swift: -------------------------------------------------------------------------------- 1 | enum DemangleGenericRequirementTypeKind { 2 | case generic, assoc, compoundAssoc, substitution 3 | } 4 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/Differentiability.swift: -------------------------------------------------------------------------------- 1 | enum Differentiability: UnicodeScalar { 2 | case normal = "d" 3 | case linear = "l" 4 | case forward = "f" 5 | case reverse = "r" 6 | 7 | init?(_ uint64: UInt64) { 8 | guard let uint32 = UInt32(exactly: uint64), let scalar = UnicodeScalar(uint32), let value = Differentiability(rawValue: scalar) else { return nil } 9 | self = value 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/Directness.swift: -------------------------------------------------------------------------------- 1 | public enum Directness: UInt64, CustomStringConvertible { 2 | case direct = 0 3 | case indirect = 1 4 | 5 | public var description: String { 6 | switch self { 7 | case .direct: return "direct" 8 | case .indirect: return "indirect" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/FunctionSigSpecializationParamKind.swift: -------------------------------------------------------------------------------- 1 | enum FunctionSigSpecializationParamKind: UInt64 { 2 | case constantPropFunction = 0 3 | case constantPropGlobal = 1 4 | case constantPropInteger = 2 5 | case constantPropFloat = 3 6 | case constantPropString = 4 7 | case closureProp = 5 8 | case boxToValue = 6 9 | case boxToStack = 7 10 | case inOutToOut = 8 11 | case constantPropKeyPath = 9 12 | 13 | case dead = 64 14 | case ownedToGuaranteed = 128 15 | case sroa = 256 16 | case guaranteedToOwned = 512 17 | case existentialToGeneric = 1024 18 | } 19 | 20 | extension FunctionSigSpecializationParamKind { 21 | var description: String { 22 | switch self { 23 | case .boxToValue: return "Value Promoted from Box" 24 | case .boxToStack: return "Stack Promoted from Box" 25 | case .constantPropFunction: return "Constant Propagated Function" 26 | case .constantPropGlobal: return "Constant Propagated Global" 27 | case .constantPropInteger: return "Constant Propagated Integer" 28 | case .constantPropFloat: return "Constant Propagated Float" 29 | case .constantPropKeyPath: return "Constant Propagated KeyPath" 30 | case .constantPropString: return "Constant Propagated String" 31 | case .closureProp: return "Closure Propagated" 32 | case .existentialToGeneric: return "Existential To Protocol Constrained Generic" 33 | case .dead: return "Dead" 34 | case .inOutToOut: return "InOut Converted to Out" 35 | case .ownedToGuaranteed: return "Owned To Guaranteed" 36 | case .guaranteedToOwned: return "Guaranteed To Owned" 37 | case .sroa: return "Exploded" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/SpecializationPass.swift: -------------------------------------------------------------------------------- 1 | enum SpecializationPass { 2 | case allocBoxToStack 3 | case closureSpecializer 4 | case capturePromotion 5 | case capturePropagation 6 | case functionSignatureOpts 7 | case genericSpecializer 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/SugarType.swift: -------------------------------------------------------------------------------- 1 | enum SugarType { 2 | case none 3 | case optional 4 | case implicitlyUnwrappedOptional 5 | case array 6 | case dictionary 7 | } 8 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/SwiftSymbolParseError.swift: -------------------------------------------------------------------------------- 1 | /// A type for representing the different possible failure conditions when using ScalarScanner 2 | public enum SwiftSymbolParseError: Error { 3 | /// Attempted to convert the buffer to UnicodeScalars but the buffer contained invalid data 4 | case utf8ParseError 5 | 6 | case punycodeParseError 7 | 8 | /// The scalar at the specified index doesn't match the expected grammar 9 | case unexpected(at: Int) 10 | 11 | /// Expected `wanted` at offset `at` 12 | case matchFailed(wanted: String, at: Int) 13 | 14 | /// Expected numerals at offset `at` 15 | case expectedInt(at: Int) 16 | 17 | /// Attempted to read `count` scalars from position `at` but hit the end of the sequence 18 | case endedPrematurely(count: Int, at: Int) 19 | 20 | /// Unable to find search patter `wanted` at or after `after` in the sequence 21 | case searchFailed(wanted: String, after: Int) 22 | 23 | case integerOverflow(at: Int) 24 | 25 | case unimplementedFeature 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/SymbolicReference.swift: -------------------------------------------------------------------------------- 1 | public enum SymbolicReferenceKind: UInt8 { 2 | /// A symbolic reference to a context descriptor, representing the 3 | /// (unapplied generic) context. 4 | case context 5 | /// A symbolic reference to an accessor function, which can be executed in 6 | /// the process to get a pointer to the referenced entity. 7 | case accessorFunctionReference 8 | /// A symbolic reference to a unique extended existential type shape. 9 | case uniqueExtendedExistentialTypeShape 10 | /// A symbolic reference to a non-unique extended existential type shape. 11 | case nonUniqueExtendedExistentialTypeShape 12 | /// A symbolic reference to a objective C protocol ref. 13 | case objectiveCProtocol 14 | } 15 | 16 | enum SymbolicReference { 17 | static func symbolicReference(for rawValue: UInt8) -> (SymbolicReferenceKind, Directness)? { 18 | switch rawValue { 19 | case 0x01: 20 | return (.context, .direct) 21 | case 0x02: 22 | return (.context, .indirect) 23 | case 0x09: 24 | return (.accessorFunctionReference, .direct) 25 | case 0x0A: 26 | return (.uniqueExtendedExistentialTypeShape, .indirect) 27 | case 0x0B: 28 | return (.nonUniqueExtendedExistentialTypeShape, .direct) 29 | case 0x0C: 30 | return (.objectiveCProtocol, .direct) 31 | default: 32 | return nil 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Demangle/Enums/TypePrinting.swift: -------------------------------------------------------------------------------- 1 | enum TypePrinting { 2 | case noType 3 | case withColon 4 | case functionStyle 5 | } 6 | -------------------------------------------------------------------------------- /Sources/Demangle/Main/Interface.swift: -------------------------------------------------------------------------------- 1 | /// This is likely to be the primary entry point to this file. Pass a string containing a Swift mangled symbol or type, get a parsed SwiftSymbol structure which can then be directly examined or printed. 2 | /// 3 | /// - Parameters: 4 | /// - mangled: the string to be parsed ("isType` is false, the string should start with a Swift Symbol prefix, _T, _$S or $S). 5 | /// - isType: if true, no prefix is parsed and, on completion, the first item on the parse stack is returned. 6 | /// - Returns: the successfully parsed result 7 | /// - Throws: a SwiftSymbolParseError error that contains parse position when the error occurred. 8 | package func parseMangledSwiftSymbol(_ mangled: String, isType: Bool = false) throws -> SwiftSymbol { 9 | return try parseMangledSwiftSymbol(mangled.unicodeScalars, isType: isType) 10 | } 11 | 12 | /// Pass a collection of `UnicodeScalars` containing a Swift mangled symbol or type, get a parsed SwiftSymbol structure which can then be directly examined or printed. 13 | /// 14 | /// - Parameters: 15 | /// - mangled: the collection of `UnicodeScalars` to be parsed ("isType` is false, the string should start with a Swift Symbol prefix, _T, _$S or $S). 16 | /// - isType: if true, no prefix is parsed and, on completion, the first item on the parse stack is returned. 17 | /// - Returns: the successfully parsed result 18 | /// - Throws: a SwiftSymbolParseError error that contains parse position when the error occurred. 19 | package func parseMangledSwiftSymbol(_ mangled: C, isType: Bool = false, symbolicReferenceResolver: SymbolicReferenceResolver? = nil) throws -> SwiftSymbol where C.Iterator.Element == UnicodeScalar { 20 | var demangler = Demangler(scalars: mangled) 21 | demangler.symbolicReferenceResolver = symbolicReferenceResolver 22 | if isType { 23 | return try demangler.demangleType() 24 | } else if getManglingPrefixLength(mangled) != 0 { 25 | return try demangler.demangleSymbol() 26 | } else { 27 | return try demangler.demangleSwift3TopLevelSymbol() 28 | } 29 | } 30 | 31 | package typealias SymbolicReferenceResolver = (SymbolicReferenceKind, Directness, Int) -> SwiftSymbol? 32 | -------------------------------------------------------------------------------- /Sources/Demangle/Main/SymbolPrintOptions.swift: -------------------------------------------------------------------------------- 1 | /// These options mimic those used in the Swift project. Check that project for details. 2 | public struct SymbolPrintOptions: OptionSet { 3 | public let rawValue: Int 4 | 5 | public static let synthesizeSugarOnTypes = SymbolPrintOptions(rawValue: 1 << 0) 6 | public static let displayDebuggerGeneratedModule = SymbolPrintOptions(rawValue: 1 << 1) 7 | public static let qualifyEntities = SymbolPrintOptions(rawValue: 1 << 2) 8 | public static let displayExtensionContexts = SymbolPrintOptions(rawValue: 1 << 3) 9 | public static let displayUnmangledSuffix = SymbolPrintOptions(rawValue: 1 << 4) 10 | public static let displayModuleNames = SymbolPrintOptions(rawValue: 1 << 5) 11 | public static let displayGenericSpecializations = SymbolPrintOptions(rawValue: 1 << 6) 12 | public static let displayProtocolConformances = SymbolPrintOptions(rawValue: 1 << 7) 13 | public static let displayWhereClauses = SymbolPrintOptions(rawValue: 1 << 8) 14 | public static let displayEntityTypes = SymbolPrintOptions(rawValue: 1 << 9) 15 | public static let shortenPartialApply = SymbolPrintOptions(rawValue: 1 << 10) 16 | public static let shortenThunk = SymbolPrintOptions(rawValue: 1 << 11) 17 | public static let shortenValueWitness = SymbolPrintOptions(rawValue: 1 << 12) 18 | public static let shortenArchetype = SymbolPrintOptions(rawValue: 1 << 13) 19 | public static let showPrivateDiscriminators = SymbolPrintOptions(rawValue: 1 << 14) 20 | public static let showFunctionArgumentTypes = SymbolPrintOptions(rawValue: 1 << 15) 21 | public static let showAsyncResumePartial = SymbolPrintOptions(rawValue: 1 << 16) 22 | public static let displayStdlibModule = SymbolPrintOptions(rawValue: 1 << 17) 23 | public static let displayObjCModule = SymbolPrintOptions(rawValue: 1 << 18) 24 | public static let printForTypeName = SymbolPrintOptions(rawValue: 1 << 19) 25 | public static let showClosureSignature = SymbolPrintOptions(rawValue: 1 << 20) 26 | 27 | public init(rawValue: Int) { 28 | self.rawValue = rawValue 29 | } 30 | 31 | public static let `default`: SymbolPrintOptions = [.displayDebuggerGeneratedModule, .qualifyEntities, .displayExtensionContexts, .displayUnmangledSuffix, .displayModuleNames, .displayGenericSpecializations, .displayProtocolConformances, .displayWhereClauses, .displayEntityTypes, .showPrivateDiscriminators, .showFunctionArgumentTypes, .showAsyncResumePartial, .displayStdlibModule, .displayObjCModule, .showClosureSignature] 32 | public static let simplified: SymbolPrintOptions = [.synthesizeSugarOnTypes, .qualifyEntities, .shortenPartialApply, .shortenThunk, .shortenValueWitness, .shortenArchetype] 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Demangle/Utils/Extensions.swift: -------------------------------------------------------------------------------- 1 | extension String { 2 | mutating func writeHex(prefix: String? = nil, _ value: UInt64) { 3 | if let prefix = prefix { 4 | write(prefix) 5 | } 6 | write(String(value, radix: 16, uppercase: true)) 7 | } 8 | } 9 | 10 | extension Array { 11 | func at(_ index: Int) -> Element? { 12 | return self.indices.contains(index) ? self[index] : nil 13 | } 14 | func slice(_ from: Int, _ to: Int) -> ArraySlice { 15 | if from > to || from > self.endIndex || to < self.startIndex { 16 | return ArraySlice() 17 | } else { 18 | return self[(from > self.startIndex ? from : self.startIndex)..<(to < self.endIndex ? to : self.endIndex)] 19 | } 20 | } 21 | } 22 | 23 | extension TextOutputStream { 24 | mutating func write(conditional: Bool, _ value: String) { 25 | if conditional { 26 | write(value) 27 | } 28 | } 29 | } 30 | 31 | /// NOTE: This extension is fileprivate to avoid clashing with CwlUtils (from which it is taken). If you want to use these functions outside this file, consider including CwlUtils. 32 | extension UnicodeScalar { 33 | /// Tests if the scalar is within a range 34 | func isInRange(_ range: ClosedRange) -> Bool { 35 | return range.contains(self) 36 | } 37 | 38 | /// Tests if the scalar is a plain ASCII digit 39 | var isDigit: Bool { 40 | return ("0"..."9").contains(self) 41 | } 42 | 43 | /// Tests if the scalar is a plain ASCII English alphabet lowercase letter 44 | var isLower: Bool { 45 | return ("a"..."z").contains(self) 46 | } 47 | 48 | /// Tests if the scalar is a plain ASCII English alphabet uppercase letter 49 | var isUpper: Bool { 50 | return ("A"..."Z").contains(self) 51 | } 52 | 53 | /// Tests if the scalar is a plain ASCII English alphabet letter 54 | var isLetter: Bool { 55 | return isLower || isUpper 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/BinaryInteger+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | 4 | extension BinaryInteger { 5 | package func cast() -> T { 6 | numericCast(self) 7 | } 8 | } 9 | 10 | extension BinaryInteger { 11 | package mutating func offset(of type: T.Type, numbersOfElements: Int = 1) { 12 | self += numericCast(MemoryLayout.size * numbersOfElements) 13 | } 14 | 15 | package mutating func offset(of type: T.Type, numbersOfElements: Int = 1) { 16 | self += numericCast(T.layoutSize * numbersOfElements) 17 | } 18 | 19 | package func offseting(of type: T.Type, numbersOfElements: Int = 1) -> Self { 20 | return self * numericCast(MemoryLayout.size * numbersOfElements) 21 | } 22 | 23 | package func offseting(of type: T.Type, numbersOfElements: Int = 1) -> Self { 24 | return self * numericCast(T.layoutSize * numbersOfElements) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/DyldCache+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | 4 | extension DyldCache { 5 | package var mainCache: DyldCache? { 6 | if url.lastPathComponent.contains(".") { 7 | var url = url 8 | url.deletePathExtension() 9 | return try? .init(url: url) 10 | } else { 11 | return self 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/DyldCacheLoaded+.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | 3 | #if !canImport(Darwin) 4 | extension DyldCacheLoaded { 5 | // FIXME: fallback for linux 6 | package static var current: DyldCacheLoaded? { 7 | return nil 8 | } 9 | } 10 | #endif 11 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/LayoutWrapper+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | 4 | extension LayoutWrapper { 5 | package static var layoutSize: Int { 6 | MemoryLayout.size 7 | } 8 | 9 | package var layoutSize: Int { 10 | MemoryLayout.size 11 | } 12 | } 13 | 14 | extension LayoutWrapper { 15 | package static func layoutOffset(of key: PartialKeyPath) -> Int { 16 | MemoryLayout.offset(of: key)! // swiftlint:disable:this force_unwrapping 17 | } 18 | 19 | package func layoutOffset(of key: PartialKeyPath) -> Int { 20 | MemoryLayout.offset(of: key)! // swiftlint:disable:this force_unwrapping 21 | } 22 | 23 | package func layoutOffset(of keyPath: KeyPath) -> Int { 24 | let pKeyPath: PartialKeyPath = keyPath 25 | return layoutOffset(of: pKeyPath) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/LoadCommandsProtocol+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | 4 | extension LoadCommandsProtocol { 5 | package var text: SegmentCommand? { 6 | infos(of: LoadCommand.segment) 7 | .first { 8 | $0.segname == SEG_TEXT 9 | } 10 | } 11 | 12 | package var text64: SegmentCommand64? { 13 | infos(of: LoadCommand.segment64) 14 | .first { 15 | $0.segname == SEG_TEXT 16 | } 17 | } 18 | 19 | package var data: SegmentCommand? { 20 | infos(of: LoadCommand.segment) 21 | .first { 22 | $0.segname == SEG_DATA 23 | } 24 | } 25 | 26 | package var data64: SegmentCommand64? { 27 | infos(of: LoadCommand.segment64) 28 | .first { 29 | $0.segname == SEG_DATA 30 | } 31 | } 32 | 33 | package var dataConst: SegmentCommand? { 34 | infos(of: LoadCommand.segment) 35 | .first { 36 | $0.segname == "__DATA_CONST" 37 | } 38 | } 39 | 40 | package var dataConst64: SegmentCommand64? { 41 | infos(of: LoadCommand.segment64) 42 | .first { 43 | $0.segname == "__DATA_CONST" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/LocatableLayoutWrapper.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | 3 | public protocol LocatableLayoutWrapper: LayoutWrapper { 4 | var offset: Int { get } 5 | 6 | init(layout: Layout, offset: Int) 7 | } 8 | 9 | extension LocatableLayoutWrapper { 10 | public func offset(of keyPath: KeyPath) -> Int { 11 | return offset + MemoryLayout.offset(of: keyPath)! 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/MachONamespace.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | package struct MachONamespace { 4 | package let base: Base 5 | 6 | package init(_ base: Base) { 7 | self.base = base 8 | } 9 | } 10 | 11 | package protocol MachONamespacing {} 12 | 13 | extension MachONamespacing { 14 | package var machO: MachONamespace { 15 | set {} 16 | get { MachONamespace(self) } 17 | } 18 | 19 | package static var machO: MachONamespace.Type { 20 | set {} 21 | get { MachONamespace.self } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/OptionalProtocol.swift: -------------------------------------------------------------------------------- 1 | public protocol OptionalProtocol: ExpressibleByNilLiteral { 2 | associatedtype Wrapped 3 | static var none: Self { get } 4 | static func some(_ wrappedValue: Wrapped) -> Self 5 | func map(_ transform: (Wrapped) throws(E) -> U) throws(E) -> U? where E: Error, U: ~Copyable 6 | func flatMap(_ transform: (Wrapped) throws(E) -> U?) throws(E) -> U? where E: Error, U: ~Copyable 7 | var unsafelyUnwrapped: Wrapped { get } 8 | } 9 | 10 | extension Optional: OptionalProtocol {} 11 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/SegmentCommandProtocol+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | 4 | extension SegmentCommandProtocol { 5 | package func _section(for name: String, in machOFile: MachOFile) -> SectionType? { 6 | sections(in: machOFile).first( 7 | where: { 8 | $0.sectionName == name 9 | } 10 | ) 11 | } 12 | 13 | package func _section(for name: String, in machOFile: MachOImage) -> SectionType? { 14 | sections(cmdsStart: machOFile.cmdsStartPtr).first( 15 | where: { 16 | $0.sectionName == name 17 | } 18 | ) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/String+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension String { 4 | package typealias CCharTuple16 = (CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar) 5 | 6 | package init(tuple: CCharTuple16) { 7 | self = withUnsafePointer(to: tuple) { 8 | let size = MemoryLayout.size 9 | let data = Data(bytes: $0, count: size) + [0] 10 | return String(cString: data) ?? "" 11 | } 12 | } 13 | } 14 | 15 | extension String { 16 | package 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) 17 | 18 | package init(tuple: CCharTuple32) { 19 | self = withUnsafePointer(to: tuple) { 20 | let size = MemoryLayout.size 21 | let data = Data(bytes: $0, count: size) + [0] 22 | return String(cString: data) ?? "" 23 | } 24 | } 25 | } 26 | 27 | extension String { 28 | package init?(cString data: Data) { 29 | guard !data.isEmpty else { return nil } 30 | let string: String? = data.withUnsafeBytes { 31 | guard let baseAddress = $0.baseAddress else { return nil } 32 | let ptr = baseAddress.assumingMemoryBound(to: CChar.self) 33 | return String(cString: ptr) 34 | } 35 | guard let string else { 36 | return nil 37 | } 38 | self = string 39 | } 40 | } 41 | 42 | extension String { 43 | func isEqual(to tuple: CCharTuple16) -> Bool { 44 | var buffer = tuple 45 | return withUnsafePointer(to: &buffer.0) { tuple in 46 | withCString { str in 47 | strcmp(str, tuple) == 0 48 | } 49 | } 50 | } 51 | 52 | func isEqual(to tuple: CCharTuple32) -> Bool { 53 | var buffer = tuple 54 | return withUnsafePointer(to: &buffer.0) { tuple in 55 | withCString { str in 56 | strcmp(str, tuple) == 0 57 | } 58 | } 59 | } 60 | } 61 | 62 | package func == (string: String, tuple: String.CCharTuple16) -> Bool { 63 | string.isEqual(to: tuple) 64 | } 65 | 66 | package func == (tuple: String.CCharTuple16, string: String) -> Bool { 67 | string.isEqual(to: tuple) 68 | } 69 | 70 | package func == (string: String, tuple: String.CCharTuple32) -> Bool { 71 | string.isEqual(to: tuple) 72 | } 73 | 74 | package func == (tuple: String.CCharTuple32, string: String) -> Bool { 75 | string.isEqual(to: tuple) 76 | } 77 | -------------------------------------------------------------------------------- /Sources/MachOExtensions/UnsafeRawPointer+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension UnsafeRawPointer { 4 | package var uint: UInt { 5 | UInt(bitPattern: self) 6 | } 7 | 8 | package var int: Int { 9 | Int(bitPattern: self) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOFoundation/Exported.swift: -------------------------------------------------------------------------------- 1 | @_exported import MachOExtensions 2 | @_exported import MachOReading 3 | @_exported import MachOPointer 4 | -------------------------------------------------------------------------------- /Sources/MachOMacro/MachOMacro.swift: -------------------------------------------------------------------------------- 1 | @attached(member, names: named(offset)) 2 | @attached(peer, names: suffixed(Field)) 3 | @attached(extension, names: named(offset)) 4 | public macro Layout() = #externalMacro(module: "MachOMacroPlugin", type: "LayoutMacro") 5 | 6 | @attached(peer, names: arbitrary) 7 | public macro MachOImageGenerator() = #externalMacro(module: "MachOMacroPlugin", type: "MachOImageGeneratorMacro") 8 | 9 | @attached(member, names: arbitrary) 10 | public macro MachOImageAllMembersGenerator() = #externalMacro(module: "MachOMacroPlugin", type: "MachOImageAllMembersGeneratorMacro") 11 | -------------------------------------------------------------------------------- /Sources/MachOMacroPlugin/MachOMacroPlugin.swift: -------------------------------------------------------------------------------- 1 | import SwiftCompilerPlugin 2 | import SwiftSyntaxMacros 3 | 4 | @main 5 | struct MachOMacroPlugin: CompilerPlugin { 6 | let providingMacros: [Macro.Type] = [ 7 | LayoutMacro.self, 8 | MachOImageGeneratorMacro.self, 9 | MachOImageAllMembersGeneratorMacro.self, 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Pointer.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOReading 3 | import MachOExtensions 4 | 5 | public struct Pointer: RelativeIndirectType, PointerProtocol { 6 | public typealias Resolved = Pointee 7 | 8 | public let address: UInt64 9 | 10 | public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self { 11 | if let rebase = machOFile.resolveRebase(fileOffset: fileOffset.cast()) { 12 | return .init(address: rebase) 13 | } else { 14 | return try machOFile.readElement(offset: fileOffset) 15 | } 16 | } 17 | 18 | public init(address: UInt64) { 19 | self.address = address 20 | } 21 | } 22 | 23 | public typealias RawPointer = Pointer 24 | 25 | public typealias MetadataPointer = Pointer 26 | 27 | public typealias ConstMetadataPointer = MetadataPointer 28 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Protocol/PointerProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOReading 4 | import MachOExtensions 5 | 6 | public protocol PointerProtocol: Resolvable { 7 | associatedtype Pointee: Resolvable 8 | 9 | var address: UInt64 { get } 10 | 11 | func resolve(in machOFile: MachOFile) throws -> Pointee 12 | func resolveAny(in machOFile: MachOFile) throws -> T 13 | func resolveOffset(in machOFile: MachOFile) -> Int 14 | 15 | func resolve(in machOImage: MachOImage) throws -> Pointee 16 | func resolveAny(in machOImage: MachOImage) throws -> T 17 | func resolveOffset(in machOImage: MachOImage) -> Int 18 | } 19 | 20 | @MachOImageAllMembersGenerator 21 | extension PointerProtocol { 22 | public func resolveAny(in machOFile: MachOFile) throws -> T { 23 | return try T.resolve(from: resolveOffset(in: machOFile), in: machOFile) 24 | } 25 | 26 | public func resolve(in machOFile: MachOFile) throws -> Pointee { 27 | return try Pointee.resolve(from: resolveOffset(in: machOFile), in: machOFile) 28 | } 29 | 30 | } 31 | 32 | extension PointerProtocol { 33 | public func resolveOffset(in machOFile: MachOFile) -> Int { 34 | numericCast(machOFile.fileOffset(of: address)) 35 | } 36 | 37 | public func resolveOffset(in machOImage: MachOImage) -> Int { 38 | Int(address) - machOImage.ptr.int 39 | } 40 | } 41 | 42 | extension PointerProtocol where Pointee: OptionalProtocol { 43 | func resolve(in machOFile: MachOFile) throws -> Pointee { 44 | guard address != 0 else { return nil } 45 | return try Pointee.resolve(from: resolveOffset(in: machOFile), in: machOFile) 46 | } 47 | } 48 | 49 | extension PointerProtocol where Pointee: OptionalProtocol { 50 | func resolve(in machOImage: MachOImage) throws -> Pointee { 51 | guard address != 0 else { return nil } 52 | return try Pointee.resolve(from: resolveOffset(in: machOImage), in: machOImage) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Protocol/RelativeDirectPointerProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOReading 4 | import MachOExtensions 5 | 6 | public protocol RelativeDirectPointerProtocol: RelativePointerProtocol {} 7 | 8 | @MachOImageAllMembersGenerator 9 | extension RelativeDirectPointerProtocol { 10 | public func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 11 | return try resolveDirect(from: fileOffset, in: machOFile) 12 | } 13 | 14 | func resolveDirect(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 15 | return try Pointee.resolve(from: resolveDirectOffset(from: fileOffset), in: machOFile) 16 | } 17 | 18 | public func resolveAny(from fileOffset: Int, in machOFile: MachOFile) throws -> T { 19 | return try resolveDirect(from: fileOffset, in: machOFile) 20 | } 21 | 22 | func resolveDirect(from fileOffset: Int, in machOFile: MachOFile) throws -> T { 23 | return try T.resolve(from: resolveDirectOffset(from: fileOffset), in: machOFile) 24 | } 25 | } 26 | 27 | extension RelativeDirectPointerProtocol where Pointee: OptionalProtocol { 28 | public func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 29 | guard isValid else { return nil } 30 | return try resolve(from: fileOffset, in: machOFile) 31 | } 32 | } 33 | 34 | extension RelativeDirectPointerProtocol where Pointee: OptionalProtocol { 35 | public func resolve(from imageOffset: Int, in machOImage: MachOImage) throws -> Pointee { 36 | guard isValid else { return nil } 37 | return try resolve(from: imageOffset, in: machOImage) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Protocol/RelativeIndirectPointerProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOReading 4 | import MachOExtensions 5 | 6 | public protocol RelativeIndirectPointerProtocol: RelativePointerProtocol { 7 | associatedtype IndirectType: RelativeIndirectType where IndirectType.Resolved == Pointee 8 | 9 | func resolveIndirectOffset(from fileOffset: Int, in machOFile: MachOFile) throws -> Int 10 | 11 | func resolveIndirectOffset(from imageOffset: Int, in machOImage: MachOImage) throws -> Int 12 | } 13 | 14 | @MachOImageAllMembersGenerator 15 | extension RelativeIndirectPointerProtocol { 16 | public func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 17 | return try resolveIndirect(from: fileOffset, in: machOFile) 18 | } 19 | 20 | func resolveIndirect(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 21 | return try resolveIndirectType(from: fileOffset, in: machOFile).resolve(in: machOFile) 22 | } 23 | 24 | public func resolveAny(from fileOffset: Int, in machOFile: MachOFile) throws -> T { 25 | return try resolveIndirect(from: fileOffset, in: machOFile) 26 | } 27 | 28 | func resolveIndirect(from fileOffset: Int, in machOFile: MachOFile) throws -> T { 29 | return try resolveIndirectType(from: fileOffset, in: machOFile).resolveAny(in: machOFile) 30 | } 31 | 32 | public func resolveIndirectType(from fileOffset: Int, in machOFile: MachOFile) throws -> IndirectType { 33 | return try .resolve(from: resolveDirectOffset(from: fileOffset), in: machOFile) 34 | } 35 | 36 | public func resolveIndirectOffset(from fileOffset: Int, in machOFile: MachOFile) throws -> Int { 37 | return try resolveIndirectType(from: fileOffset, in: machOFile).resolveOffset(in: machOFile) 38 | } 39 | } 40 | 41 | extension RelativeIndirectPointerProtocol where Pointee: OptionalProtocol { 42 | public func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 43 | guard isValid else { return nil } 44 | return try resolve(from: fileOffset, in: machOFile) 45 | } 46 | } 47 | 48 | extension RelativeIndirectPointerProtocol where Pointee: OptionalProtocol { 49 | public func resolve(from fileOffset: Int, in machOFile: MachOImage) throws -> Pointee { 50 | guard isValid else { return nil } 51 | return try resolve(from: fileOffset, in: machOFile) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Protocol/RelativeIndirectType.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOReading 3 | import MachOExtensions 4 | 5 | public protocol RelativeIndirectType: Resolvable { 6 | associatedtype Resolved: Resolvable 7 | 8 | func resolve(in machOFile: MachOFile) throws -> Resolved 9 | func resolveAny(in machOFile: MachOFile) throws -> T 10 | func resolveOffset(in machOFile: MachOFile) -> Int 11 | 12 | func resolve(in machOImage: MachOImage) throws -> Resolved 13 | func resolveAny(in machOImage: MachOImage) throws -> T 14 | func resolveOffset(in machOImage: MachOImage) -> Int 15 | } 16 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Protocol/RelativeIndirectablePointerIntPairProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOReading 3 | import MachOExtensions 4 | 5 | public protocol RelativeIndirectablePointerIntPairProtocol: RelativeIndirectablePointerProtocol { 6 | typealias Integer = Value.RawValue 7 | associatedtype Value: RawRepresentable where Value.RawValue: FixedWidthInteger 8 | var relativeOffsetPlusIndirectAndInt: Offset { get } 9 | var isIndirect: Bool { get } 10 | } 11 | 12 | extension RelativeIndirectablePointerIntPairProtocol { 13 | public var relativeOffsetPlusIndirect: Offset { 14 | relativeOffsetPlusIndirectAndInt & ~mask 15 | } 16 | 17 | public var relativeOffset: Offset { 18 | (relativeOffsetPlusIndirectAndInt & ~mask) & ~1 19 | } 20 | 21 | public var mask: Offset { 22 | Offset(MemoryLayout.alignment - 1) & ~1 23 | } 24 | 25 | public var intValue: Integer { 26 | numericCast((relativeOffsetPlusIndirectAndInt & mask) >> 1) 27 | } 28 | 29 | public var isIndirect: Bool { 30 | return relativeOffsetPlusIndirectAndInt & 1 == 1 31 | } 32 | 33 | public var value: Value { 34 | return Value(rawValue: intValue)! 35 | } 36 | } 37 | 38 | extension RelativeIndirectablePointerIntPairProtocol where Pointee: OptionalProtocol { 39 | public func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 40 | guard isValid else { return nil } 41 | return try resolve(from: fileOffset, in: machOFile) 42 | } 43 | } 44 | 45 | extension RelativeIndirectablePointerIntPairProtocol where Pointee: OptionalProtocol { 46 | public func resolve(from fileOffset: Int, in machOFile: MachOImage) throws -> Pointee { 47 | guard isValid else { return nil } 48 | return try resolve(from: fileOffset, in: machOFile) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Protocol/RelativeIndirectablePointerProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOReading 4 | import MachOExtensions 5 | 6 | public protocol RelativeIndirectablePointerProtocol: RelativeDirectPointerProtocol, RelativeIndirectPointerProtocol { 7 | var relativeOffsetPlusIndirect: Offset { get } 8 | var isIndirect: Bool { get } 9 | func resolveIndirectableOffset(from fileOffset: Int, in machOFile: MachOFile) throws -> Int 10 | func resolveIndirectableOffset(from imageOffset: Int, in machOFile: MachOImage) throws -> Int 11 | } 12 | 13 | extension RelativeIndirectablePointerProtocol { 14 | public var relativeOffset: Offset { 15 | relativeOffsetPlusIndirect & ~1 16 | } 17 | 18 | public var isIndirect: Bool { 19 | return relativeOffsetPlusIndirect & 1 == 1 20 | } 21 | } 22 | 23 | @MachOImageAllMembersGenerator 24 | extension RelativeIndirectablePointerProtocol { 25 | public func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 26 | return try resolveIndirectable(from: fileOffset, in: machOFile) 27 | } 28 | 29 | public func resolveAny(from fileOffset: Int, in machOFile: MachOFile) throws -> T { 30 | return try resolveIndirectableAny(from: fileOffset, in: machOFile) 31 | } 32 | 33 | func resolveIndirectable(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 34 | if isIndirect { 35 | return try resolveIndirect(from: fileOffset, in: machOFile) 36 | } else { 37 | return try resolveDirect(from: fileOffset, in: machOFile) 38 | } 39 | } 40 | 41 | public func resolveIndirectableType(from fileOffset: Int, in machOFile: MachOFile) throws -> IndirectType? { 42 | guard isIndirect else { return nil } 43 | return try resolveIndirectableType(from: fileOffset, in: machOFile) 44 | } 45 | 46 | func resolveIndirectableAny(from fileOffset: Int, in machOFile: MachOFile) throws -> T { 47 | if isIndirect { 48 | return try resolveIndirect(from: fileOffset, in: machOFile) 49 | } else { 50 | return try resolveDirect(from: fileOffset, in: machOFile) 51 | } 52 | } 53 | 54 | public func resolveIndirectableOffset(from fileOffset: Int, in machOFile: MachOFile) throws -> Int { 55 | guard let indirectType = try resolveIndirectableType(from: fileOffset, in: machOFile) else { return resolveDirectOffset(from: fileOffset) } 56 | return indirectType.resolveOffset(in: machOFile) 57 | } 58 | } 59 | 60 | extension RelativeIndirectablePointerProtocol where Pointee: OptionalProtocol { 61 | public func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee { 62 | guard isValid else { return nil } 63 | return try resolve(from: fileOffset, in: machOFile) 64 | } 65 | } 66 | 67 | extension RelativeIndirectablePointerProtocol where Pointee: OptionalProtocol { 68 | public func resolve(from fileOffset: Int, in machOFile: MachOImage) throws -> Pointee { 69 | guard isValid else { return nil } 70 | return try resolve(from: fileOffset, in: machOFile) 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Protocol/RelativePointerProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOReading 3 | import MachOExtensions 4 | 5 | public protocol RelativePointerProtocol { 6 | associatedtype Pointee: Resolvable 7 | associatedtype Offset: FixedWidthInteger & SignedInteger 8 | 9 | var relativeOffset: Offset { get } 10 | 11 | func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Pointee 12 | func resolve(from imageOffset: Int, in machOImage: MachOImage) throws -> Pointee 13 | 14 | func resolveAny(from fileOffset: Int, in machOFile: MachOFile) throws -> T 15 | func resolveAny(from imageOffset: Int, in machOImage: MachOImage) throws -> T 16 | 17 | func resolveDirectOffset(from offset: Int) -> Int 18 | } 19 | 20 | extension RelativePointerProtocol { 21 | public func resolveDirectOffset(from offset: Int) -> Int { 22 | return Int(offset) + Int(relativeOffset) 23 | } 24 | 25 | public var isNull: Bool { 26 | return relativeOffset == 0 27 | } 28 | 29 | public var isValid: Bool { 30 | return relativeOffset != 0 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/MachOPointer/RelativePointers.swift: -------------------------------------------------------------------------------- 1 | import MachOReading 2 | import MachOExtensions 3 | 4 | public typealias RelativeOffset = Int32 5 | 6 | public typealias RelativeDirectPointer = TargetRelativeDirectPointer 7 | 8 | public typealias RelativeDirectRawPointer = TargetRelativeDirectPointer 9 | 10 | public typealias RelativeIndirectPointer = TargetRelativeIndirectPointer where Pointee == IndirectType.Resolved 11 | 12 | public typealias RelativeIndirectRawPointer = TargetRelativeIndirectPointer> 13 | 14 | public typealias RelativeIndirectablePointer = TargetRelativeIndirectablePointer where Pointee == IndirectType.Resolved 15 | 16 | public typealias RelativeIndirectableRawPointer = TargetRelativeIndirectablePointer> 17 | 18 | public typealias RelativeIndirectablePointerIntPair = TargetRelativeIndirectablePointerIntPair where Pointee == IndirectType.Resolved, Integer.RawValue: FixedWidthInteger 19 | 20 | public typealias RelativeIndirectableRawPointerIntPair = TargetRelativeIndirectablePointerIntPair> where Integer.RawValue: FixedWidthInteger 21 | 22 | public typealias RelativeSymbolOrElementPointer = RelativeIndirectablePointer, SymbolOrElementPointer> 23 | 24 | public typealias RelativeIndirectSymbolOrElementPointer = RelativeIndirectPointer, SymbolOrElementPointer> 25 | 26 | public typealias RelativeSymbolOrElementPointerIntPair = RelativeIndirectablePointerIntPair, Value, SymbolOrElementPointer> where Value.RawValue: FixedWidthInteger 27 | -------------------------------------------------------------------------------- /Sources/MachOPointer/SignedPointer.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOReading 3 | import MachOExtensions 4 | 5 | //public struct SignedPointer: RelativeIndirectType, PointerProtocol { 6 | // public let address: UInt64 7 | // 8 | // public init(address: UInt64) { 9 | // self.address = address 10 | // } 11 | // 12 | // public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self { 13 | // if let rebase = machOFile.resolveRebase(fileOffset: fileOffset.cast()) { 14 | // return .init(address: rebase) 15 | // } else { 16 | // return try machOFile.readElement(offset: fileOffset) 17 | // } 18 | // } 19 | //} 20 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Symbol/MachOFile+Symbol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOExtensions 3 | import AssociatedObject 4 | 5 | private class SymbolCache { 6 | var symbolByOffset: [Int: MachOSymbol] = [:] 7 | } 8 | 9 | extension MachOFile { 10 | @AssociatedObject(.retain(.nonatomic)) 11 | private var symbolCache: SymbolCache = .init() 12 | 13 | private func buildSymbolByOffsetIfNeeded() { 14 | guard symbolCache.symbolByOffset.isEmpty else { return } 15 | guard let symbols64 else { return } 16 | var symbolByOffset: [Int: MachOSymbol] = [:] 17 | for symbol in symbols64 where !symbol.name.isEmpty { 18 | var offset = symbol.offset 19 | if let cache { 20 | offset -= cache.mainCacheHeader.sharedRegionStart.cast() 21 | } 22 | symbolByOffset[offset] = .init(offset: offset, stringValue: symbol.name) 23 | } 24 | 25 | for exportedSymbol in exportedSymbols { 26 | if var offset = exportedSymbol.offset { 27 | if let cache { 28 | offset -= cache.mainCacheHeader.sharedRegionStart.cast() 29 | } 30 | symbolByOffset[offset] = .init(offset: offset, stringValue: exportedSymbol.name) 31 | } 32 | } 33 | symbolCache.symbolByOffset = symbolByOffset 34 | } 35 | 36 | package func findSymbol(offset: Int) -> MachOSymbol? { 37 | buildSymbolByOffsetIfNeeded() 38 | return symbolCache.symbolByOffset[offset] 39 | } 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /Sources/MachOPointer/Symbol/MachOSymbol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOExtensions 4 | import MachOReading 5 | 6 | public struct MachOSymbol: Resolvable { 7 | enum Error: Swift.Error { 8 | case symbolNotFound 9 | } 10 | 11 | public let offset: Int 12 | 13 | public let stringValue: String 14 | 15 | public init(offset: Int, stringValue: String) { 16 | self.offset = offset 17 | self.stringValue = stringValue 18 | } 19 | 20 | @MachOImageGenerator 21 | public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self { 22 | guard let symbol = try resolve(from: fileOffset, in: machOFile) else { throw Error.symbolNotFound } 23 | return symbol 24 | } 25 | 26 | public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self? { 27 | guard let symbol = machOFile.findSymbol(offset: fileOffset) else { return nil } 28 | return symbol 29 | } 30 | 31 | public static func resolve(from imageOffset: Int, in machOImage: MachOImage) throws -> Self? { 32 | guard let symbol = machOImage.symbol(for: imageOffset) else { return nil } 33 | return .init(offset: symbol.offset, stringValue: symbol.name) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/MachOPointer/SymbolOrElementPointer.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOReading 3 | 4 | public enum SymbolOrElementPointer: RelativeIndirectType { 5 | public typealias Resolved = SymbolOrElement 6 | 7 | case symbol(MachOSymbol) 8 | case address(UInt64) 9 | 10 | public func resolveOffset(in machOFile: MachOFile) -> Int { 11 | switch self { 12 | case .symbol(let unsolvedSymbol): 13 | return unsolvedSymbol.offset 14 | case .address(let address): 15 | return numericCast(machOFile.fileOffset(of: address)) 16 | } 17 | } 18 | 19 | public func resolve(in machOFile: MachOFile) throws -> Resolved { 20 | switch self { 21 | case .symbol(let unsolvedSymbol): 22 | return .symbol(unsolvedSymbol) 23 | case .address: 24 | return try .element(Context.resolve(from: resolveOffset(in: machOFile), in: machOFile)) 25 | } 26 | } 27 | 28 | public func resolveOffset(in machOImage: MachOImage) -> Int { 29 | switch self { 30 | case .symbol(let unsolvedSymbol): 31 | unsolvedSymbol.offset 32 | case .address(let address): 33 | Int(address) - machOImage.ptr.int 34 | } 35 | } 36 | 37 | public func resolve(in machOImage: MachOImage) throws -> Resolved { 38 | switch self { 39 | case .symbol(let unsolvedSymbol): 40 | return .symbol(unsolvedSymbol) 41 | case .address: 42 | return try .element(Context.resolve(from: resolveOffset(in: machOImage), in: machOImage)) 43 | } 44 | } 45 | 46 | public func resolveAny(in machOFile: MachOFile) throws -> T { 47 | fatalError() 48 | } 49 | 50 | public func resolveAny(in machOImage: MachOImage) throws -> T { 51 | fatalError() 52 | } 53 | 54 | public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self { 55 | if let symbol = machOFile.resolveBind(fileOffset: fileOffset) { 56 | return .symbol(.init(offset: fileOffset, stringValue: symbol)) 57 | } else { 58 | let resolvedFileOffset = fileOffset 59 | if let rebase = machOFile.resolveRebase(fileOffset: resolvedFileOffset) { 60 | return .address(rebase) 61 | } else { 62 | return try .address(machOFile.readElement(offset: resolvedFileOffset)) 63 | } 64 | } 65 | } 66 | 67 | public static func resolve(from imageOffset: Int, in machOImage: MachOImage) throws -> Self { 68 | return try .address(machOImage.readElement(offset: imageOffset)) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Sources/MachOPointer/TargetRelativeDirectPointer.swift: -------------------------------------------------------------------------------- 1 | import MachOReading 2 | import MachOExtensions 3 | 4 | public struct TargetRelativeDirectPointer: RelativeDirectPointerProtocol { 5 | public typealias Element = Pointee 6 | public let relativeOffset: Offset 7 | public init(relativeOffset: Offset) { 8 | self.relativeOffset = relativeOffset 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/MachOPointer/TargetRelativeIndirectPointer.swift: -------------------------------------------------------------------------------- 1 | import MachOReading 2 | import MachOExtensions 3 | 4 | public struct TargetRelativeIndirectPointer: RelativeIndirectPointerProtocol where Pointee == IndirectType.Resolved { 5 | public typealias Element = Pointee 6 | public let relativeOffset: Offset 7 | 8 | public init(relativeOffset: Offset) { 9 | self.relativeOffset = relativeOffset 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOPointer/TargetRelativeIndirectablePointer.swift: -------------------------------------------------------------------------------- 1 | import MachOReading 2 | import MachOExtensions 3 | 4 | public struct TargetRelativeIndirectablePointer: RelativeIndirectablePointerProtocol where Pointee == IndirectType.Resolved { 5 | public let relativeOffsetPlusIndirect: Offset 6 | 7 | public init(relativeOffsetPlusIndirect: Offset) { 8 | self.relativeOffsetPlusIndirect = relativeOffsetPlusIndirect 9 | } 10 | 11 | public func withIntPairPointer(_ integer: Integer.Type = Integer.self) -> TargetRelativeIndirectablePointerIntPair { 12 | return .init(relativeOffsetPlusIndirectAndInt: relativeOffsetPlusIndirect) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/MachOPointer/TargetRelativeIndirectablePointerIntPair.swift: -------------------------------------------------------------------------------- 1 | import MachOReading 2 | import MachOExtensions 3 | 4 | public struct TargetRelativeIndirectablePointerIntPair: RelativeIndirectablePointerIntPairProtocol where Value.RawValue: FixedWidthInteger, Pointee == IndirectType.Resolved { 5 | public let relativeOffsetPlusIndirectAndInt: Offset 6 | 7 | public init(relativeOffsetPlusIndirectAndInt: Offset) { 8 | self.relativeOffsetPlusIndirectAndInt = relativeOffsetPlusIndirectAndInt 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/MachOReading/AnyResolvable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AnyResolvable: Resolvable { 4 | public let wrappedValue: UInt8 5 | } 6 | -------------------------------------------------------------------------------- /Sources/MachOReading/Models/DataSequence.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | package struct DataSequence: Sequence { 4 | package typealias Element = T 5 | 6 | private let data: Data 7 | private let entrySize: Int 8 | private let numberOfElements: Int 9 | 10 | init( 11 | data: Data, 12 | numberOfElements: Int 13 | ) { 14 | self.data = data 15 | self.entrySize = MemoryLayout.size 16 | self.numberOfElements = numberOfElements 17 | } 18 | 19 | init( 20 | data: Data, 21 | entrySize: Int 22 | ) { 23 | self.data = data 24 | self.entrySize = entrySize 25 | self.numberOfElements = data.count / entrySize 26 | } 27 | 28 | package func makeIterator() -> Iterator { 29 | Iterator( 30 | data: data, 31 | entrySize: entrySize, 32 | numberOfElements: numberOfElements 33 | ) 34 | } 35 | } 36 | 37 | extension DataSequence { 38 | package struct Iterator: IteratorProtocol { 39 | public typealias Element = T 40 | 41 | private let data: Data 42 | private let entrySize: Int 43 | private let numberOfElements: Int 44 | 45 | private var nextIndex: Int = 0 46 | private var nextOffset: Int = 0 47 | 48 | init( 49 | data: Data, 50 | entrySize: Int, 51 | numberOfElements: Int 52 | ) { 53 | self.data = data 54 | self.entrySize = entrySize 55 | self.numberOfElements = numberOfElements 56 | } 57 | 58 | public mutating func next() -> Element? { 59 | guard nextIndex < numberOfElements else { return nil } 60 | guard nextOffset + entrySize <= data.count else { return nil } 61 | 62 | defer { 63 | nextIndex += 1 64 | nextOffset += entrySize 65 | } 66 | 67 | return data.withUnsafeBytes { 68 | guard let baseAddress = $0.baseAddress else { return nil } 69 | return baseAddress.advanced(by: nextOffset).load(as: Element.self) 70 | } 71 | } 72 | } 73 | } 74 | 75 | extension DataSequence: Collection { 76 | package typealias Index = Int 77 | 78 | package var startIndex: Index { 0 } 79 | package var endIndex: Index { numberOfElements } 80 | 81 | package func index(after i: Int) -> Int { 82 | i + 1 83 | } 84 | 85 | package subscript(position: Int) -> Element { 86 | precondition(position >= 0) 87 | precondition(position < endIndex) 88 | precondition(data.count >= (position + 1) * entrySize) 89 | return data.withUnsafeBytes { 90 | guard let baseAddress = $0.baseAddress else { 91 | fatalError("data is empty") 92 | } 93 | return baseAddress 94 | .advanced(by: position * entrySize) 95 | .load(as: Element.self) 96 | } 97 | } 98 | } 99 | 100 | extension DataSequence: RandomAccessCollection {} 101 | -------------------------------------------------------------------------------- /Sources/MachOReading/Models/MemorySequence.swift: -------------------------------------------------------------------------------- 1 | package struct MemorySequence: Sequence { 2 | public typealias Element = T 3 | 4 | private let basePointer: UnsafeRawPointer 5 | private let entrySize: Int 6 | private let numberOfElements: Int 7 | 8 | package init( 9 | basePointer: UnsafePointer, 10 | numberOfElements: Int 11 | ) { 12 | self.basePointer = .init(basePointer) 13 | self.entrySize = MemoryLayout.size 14 | self.numberOfElements = numberOfElements 15 | } 16 | 17 | package init( 18 | basePointer: UnsafePointer, 19 | entrySize: Int, 20 | numberOfElements: Int 21 | ) { 22 | self.basePointer = .init(basePointer) 23 | self.entrySize = entrySize 24 | self.numberOfElements = numberOfElements 25 | } 26 | 27 | package func makeIterator() -> Iterator { 28 | Iterator( 29 | basePointer: basePointer, 30 | entrySize: entrySize, 31 | numberOfElements: numberOfElements 32 | ) 33 | } 34 | } 35 | 36 | extension MemorySequence { 37 | package struct Iterator: IteratorProtocol { 38 | public typealias Element = T 39 | 40 | private let basePointer: UnsafeRawPointer 41 | private let entrySize: Int 42 | private let numberOfElements: Int 43 | 44 | private var nextIndex: Int = 0 45 | 46 | init( 47 | basePointer: UnsafeRawPointer, 48 | entrySize: Int, 49 | numberOfElements: Int 50 | ) { 51 | self.basePointer = basePointer 52 | self.entrySize = entrySize 53 | self.numberOfElements = numberOfElements 54 | } 55 | 56 | public mutating func next() -> Element? { 57 | guard nextIndex < numberOfElements else { return nil } 58 | defer { nextIndex += 1 } 59 | return basePointer 60 | .advanced(by: nextIndex * entrySize) 61 | .load(as: Element.self) 62 | } 63 | } 64 | } 65 | 66 | extension MemorySequence: Collection { 67 | package typealias Index = Int 68 | 69 | package var startIndex: Index { 0 } 70 | package var endIndex: Index { numberOfElements } 71 | 72 | package func index(after i: Int) -> Int { 73 | i + 1 74 | } 75 | 76 | package subscript(position: Int) -> Element { 77 | precondition(position >= 0) 78 | precondition(position < endIndex) 79 | return basePointer 80 | .advanced(by: position * entrySize) 81 | .load(as: Element.self) 82 | } 83 | } 84 | 85 | extension MemorySequence: RandomAccessCollection {} 86 | -------------------------------------------------------------------------------- /Sources/MachOReading/Reading/DyldCache+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import FileIO 4 | 5 | extension DyldCache { 6 | var fileHandle: FileHandle { 7 | try! .init(forReadingFrom: url) 8 | } 9 | 10 | var fileIO: MemoryMappedFile { 11 | try! .open(url: url, isWritable: false) 12 | } 13 | 14 | package var fileStartOffset: UInt64 { 15 | numericCast( 16 | header.sharedRegionStart - mainCacheHeader.sharedRegionStart 17 | ) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/MachOReading/Reading/MachOFileReadingError.swift: -------------------------------------------------------------------------------- 1 | import MachOExtensions 2 | 3 | package enum MachOFileReadingError: Error { 4 | case invalidDataSize 5 | case invalidLayoutSize 6 | } 7 | 8 | extension MachONamespace { 9 | func throwIfInvalid(_ isValid: Bool, error: MachOFileReadingError) throws { 10 | if !isValid { 11 | throw error 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/MachOReading/Reading/MachOImage+Reading.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOExtensions 3 | 4 | extension MachOImage: MachOReadable { 5 | package func readElement( 6 | offset: Int 7 | ) throws -> Element { 8 | let pointer = ptr + offset 9 | return pointer.assumingMemoryBound(to: Element.self).pointee 10 | } 11 | 12 | package func readElement( 13 | offset: Int 14 | ) throws -> Element where Element: LocatableLayoutWrapper { 15 | return try readWrapperElement(offset: offset) 16 | } 17 | 18 | package func readWrapperElement(offset: Int) throws -> Element where Element : LocatableLayoutWrapper { 19 | let pointer = ptr + offset 20 | let layout: Element.Layout = pointer.assumingMemoryBound(to: Element.Layout.self).pointee 21 | return .init(layout: layout, offset: offset) 22 | } 23 | 24 | package func readElements( 25 | offset: Int, 26 | numberOfElements: Int 27 | ) throws -> [Element] { 28 | let pointer = ptr + offset 29 | return MemorySequence(basePointer: pointer.assumingMemoryBound(to: Element.self), numberOfElements: numberOfElements).map { $0 } 30 | } 31 | 32 | package func readElements( 33 | offset: Int, 34 | numberOfElements: Int 35 | ) throws -> [Element] where Element: LocatableLayoutWrapper { 36 | return try readWrapperElements(offset: offset, numberOfElements: numberOfElements) 37 | } 38 | 39 | package func readWrapperElements(offset: Int, numberOfElements: Int) throws -> [Element] where Element : LocatableLayoutWrapper { 40 | let pointer = ptr + offset 41 | var currentOffset = offset 42 | let elements = MemorySequence(basePointer: pointer.assumingMemoryBound(to: Element.Layout.self), numberOfElements: numberOfElements).map { (layout: Element.Layout) -> Element in 43 | let element = Element(layout: layout, offset: currentOffset) 44 | currentOffset += Element.layoutSize 45 | return element 46 | } 47 | return elements 48 | } 49 | 50 | package func readString(offset: Int) throws -> String { 51 | let pointer = ptr + offset 52 | return .init(cString: pointer.assumingMemoryBound(to: CChar.self)) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/MachOReading/Reading/MachOReadable.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOExtensions 3 | 4 | package protocol MachOReadable { 5 | func readElement(offset: Int) throws -> Element 6 | 7 | func readWrapperElement(offset: Int) throws -> Element where Element: LocatableLayoutWrapper 8 | 9 | func readElements(offset: Int, numberOfElements: Int) throws -> [Element] 10 | 11 | func readWrapperElements(offset: Int, numberOfElements: Int) throws -> [Element] where Element: LocatableLayoutWrapper 12 | 13 | func readString(offset: Int) throws -> String 14 | } 15 | 16 | -------------------------------------------------------------------------------- /Sources/MachOReading/Resolvable.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOExtensions 3 | import MachOMacro 4 | 5 | public protocol Resolvable { 6 | static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self 7 | static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self? 8 | 9 | static func resolve(from imageOffset: Int, in machOImage: MachOImage) throws -> Self 10 | static func resolve(from imageOffset: Int, in machOImage: MachOImage) throws -> Self? 11 | } 12 | 13 | @MachOImageAllMembersGenerator 14 | extension Resolvable { 15 | public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self { 16 | return try machOFile.readElement(offset: fileOffset) 17 | } 18 | 19 | public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self? { 20 | let result: Self = try resolve(from: fileOffset, in: machOFile) 21 | return .some(result) 22 | } 23 | } 24 | 25 | @MachOImageAllMembersGenerator 26 | extension Optional: Resolvable where Wrapped: Resolvable { 27 | public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self { 28 | let result: Wrapped? = try Wrapped.resolve(from: fileOffset, in: machOFile) 29 | if let result { 30 | return .some(result) 31 | } else { 32 | return .none 33 | } 34 | } 35 | } 36 | 37 | @MachOImageAllMembersGenerator 38 | extension String: Resolvable { 39 | public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self { 40 | return try machOFile.readString(offset: fileOffset) 41 | } 42 | } 43 | 44 | extension Resolvable where Self: LocatableLayoutWrapper { 45 | public static func resolve(from fileOffset: Int, in machOFile: MachOFile) throws -> Self { 46 | try machOFile.readElement(offset: fileOffset) 47 | } 48 | } 49 | 50 | extension Resolvable where Self: LocatableLayoutWrapper { 51 | public static func resolve(from imageOffset: Int, in machOImage: MachOImage) throws -> Self { 52 | try machOImage.readElement(offset: imageOffset) 53 | } 54 | } 55 | 56 | extension Int: Resolvable {} 57 | extension UInt: Resolvable {} 58 | extension Int8: Resolvable {} 59 | extension UInt8: Resolvable {} 60 | extension Int16: Resolvable {} 61 | extension UInt16: Resolvable {} 62 | extension Int32: Resolvable {} 63 | extension UInt32: Resolvable {} 64 | extension Int64: Resolvable {} 65 | extension UInt64: Resolvable {} 66 | extension Float: Resolvable {} 67 | extension Double: Resolvable {} 68 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Extensions/Bool+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Bool: @retroactive RawRepresentable { 4 | public var rawValue: UInt8 { self ? 1 : 0 } 5 | public init?(rawValue: UInt8) { 6 | self = rawValue != 0 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Extensions/Data+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Data {} 4 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Extensions/SegmentCommandProtocol+.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | 3 | extension SegmentCommandProtocol { 4 | func _section(for swiftSection: MachOSwiftSectionName, in machOFile: MachOFile) -> SectionType? { 5 | _section(for: swiftSection.rawValue, in: machOFile) 6 | } 7 | 8 | func _section(for swiftSection: MachOSwiftSectionName, in machOFile: MachOImage) -> SectionType? { 9 | _section(for: swiftSection.rawValue, in: machOFile) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Extensions/String+.swift: -------------------------------------------------------------------------------- 1 | extension String { 2 | var countedString: String { 3 | guard !isEmpty else { return "" } 4 | return "\(count)\(self)" 5 | } 6 | 7 | var stripProtocolDescriptorMangle: String { 8 | replacingOccurrences(of: "Mp", with: "") 9 | } 10 | 11 | var stripNominalTypeDescriptorMangle: String { 12 | replacingOccurrences(of: "Mn", with: "") 13 | } 14 | 15 | var stripManglePrefix: String { 16 | guard isStartWithManglePrefix else { return self } 17 | return replacingOccurrences(of: "_$s", with: "") 18 | } 19 | 20 | var insertManglePrefix: String { 21 | guard !isStartWithManglePrefix else { return self } 22 | return "_$s" + self 23 | } 24 | 25 | var isStartWithManglePrefix: Bool { 26 | hasPrefix("_$s") || hasPrefix("$s") 27 | } 28 | 29 | var stripProtocolMangleType: String { 30 | replacingOccurrences(of: "_p", with: "") 31 | } 32 | 33 | var stripDuplicateProtocolMangleType: String { 34 | replacingOccurrences(of: "_p_p", with: "_p") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/MachOImage+Swift.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | 5 | extension MachOImage { 6 | public struct Swift { 7 | private let machOImage: MachOImage 8 | 9 | fileprivate init(machOImage: MachOImage) { 10 | self.machOImage = machOImage 11 | } 12 | } 13 | 14 | public var swift: Swift { 15 | .init(machOImage: self) 16 | } 17 | } 18 | 19 | extension MachOImage.Swift { 20 | public var protocolDescriptors: [ProtocolDescriptor]? { 21 | return _readDescriptors(from: .__swift5_protos, in: machOImage) 22 | } 23 | 24 | public var protocolConformanceDescriptors: [ProtocolConformanceDescriptor]? { 25 | return _readDescriptors(from: .__swift5_proto, in: machOImage) 26 | } 27 | 28 | public var typeContextDescriptors: [ContextDescriptorWrapper]? { 29 | return _readDescriptors(from: .__swift5_types, in: machOImage) + _readDescriptors(from: .__swift5_types2, in: machOImage) 30 | } 31 | } 32 | 33 | extension MachOImage.Swift { 34 | private func _section(for swiftMachOSection: MachOSwiftSectionName, in machOImage: MachOImage) -> (any SectionProtocol)? { 35 | let loadCommands = machOImage.loadCommands 36 | let swiftSection: any SectionProtocol 37 | if let text = loadCommands.text64, 38 | let section = text._section(for: swiftMachOSection, in: machOImage) { 39 | swiftSection = section 40 | } else if let text = loadCommands.text, 41 | let section = text._section(for: swiftMachOSection, in: machOImage) { 42 | swiftSection = section 43 | } else { 44 | return nil 45 | } 46 | guard swiftSection.align * 2 == 4 else { 47 | return nil 48 | } 49 | return swiftSection 50 | } 51 | 52 | private func _readDescriptors(from swiftMachOSection: MachOSwiftSectionName, in machOImage: MachOImage) -> [Descriptor]? { 53 | guard let section = _section(for: swiftMachOSection, in: machOImage) else { return nil } 54 | return try? _readDescriptors(from: section, in: machOImage) 55 | } 56 | 57 | private func _readDescriptors(from section: any SectionProtocol, in machO: MachOImage) throws -> [Descriptor]? { 58 | guard let vmaddrSlide = machO.vmaddrSlide else { return nil } 59 | guard let start = UnsafeRawPointer( 60 | bitPattern: section.address + vmaddrSlide 61 | ) else { return nil } 62 | 63 | let offset = start.int - machO.ptr.int 64 | 65 | let pointerSize: Int = MemoryLayout>.size 66 | 67 | let data: [AnyLocatableLayoutWrapper>] = try machO.readElements(offset: offset, numberOfElements: section.size / pointerSize) 68 | 69 | return try data.map { try $0.layout.resolve(from: $0.offset, in: machO) } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Anonymous/AnonymousContext.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | import MachOMacro 5 | 6 | public struct AnonymousContext { 7 | public let descriptor: AnonymousContextDescriptor 8 | public let genericContext: GenericContext? 9 | public let mangledName: MangledName? 10 | 11 | @MachOImageGenerator 12 | public init(descriptor: AnonymousContextDescriptor, in machOFile: MachOFile) throws { 13 | self.descriptor = descriptor 14 | var currentOffset = descriptor.offset + descriptor.layoutSize 15 | 16 | let genericContext = try descriptor.genericContext(in: machOFile) 17 | 18 | if let genericContext { 19 | currentOffset += genericContext.size 20 | } 21 | self.genericContext = genericContext 22 | 23 | if descriptor.hasMangledName { 24 | let mangledNamePointer: RelativeDirectPointer = try machOFile.readElement(offset: currentOffset) 25 | self.mangledName = try mangledNamePointer.resolve(from: currentOffset, in: machOFile) 26 | currentOffset += MemoryLayout>.size 27 | } else { 28 | self.mangledName = nil 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Anonymous/AnonymousContextDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | 5 | public struct AnonymousContextDescriptor: AnonymousContextDescriptorProtocol { 6 | public struct Layout: AnonymousContextDescriptorLayout { 7 | public let flags: ContextDescriptorFlags 8 | public let parent: RelativeContextPointer 9 | } 10 | 11 | public let offset: Int 12 | 13 | public var layout: Layout 14 | 15 | public init(layout: Layout, offset: Int) { 16 | self.offset = offset 17 | self.layout = layout 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Anonymous/AnonymousContextDescriptorFlags.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AnonymousContextDescriptorFlags: FlagSet { 4 | public let rawValue: UInt16 5 | 6 | public init(rawValue: UInt16) { 7 | self.rawValue = rawValue 8 | } 9 | 10 | private enum Bits { 11 | static let hasMangledName = 0 12 | } 13 | 14 | public var hasMangledName: Bool { 15 | flag(bit: Bits.hasMangledName) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Anonymous/AnonymousContextDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | public protocol AnonymousContextDescriptorLayout: ContextDescriptorLayout {} 2 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Anonymous/AnonymousContextDescriptorProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOFoundation 3 | import MachOMacro 4 | 5 | public protocol AnonymousContextDescriptorProtocol: ContextDescriptorProtocol where Layout: AnonymousContextDescriptorLayout {} 6 | 7 | @MachOImageAllMembersGenerator 8 | extension AnonymousContextDescriptorProtocol { 9 | public func mangledName(in machOFile: MachOFile) throws -> MangledName? { 10 | guard hasMangledName else { 11 | return nil 12 | } 13 | var currentOffset = offset + layoutSize 14 | if let genericContext = try genericContext(in: machOFile) { 15 | currentOffset += genericContext.size 16 | } 17 | let mangledNamePointer: RelativeDirectPointer = try machOFile.readElement(offset: currentOffset) 18 | return try mangledNamePointer.resolve(from: currentOffset, in: machOFile) 19 | } 20 | 21 | public var hasMangledName: Bool { 22 | guard let kindSpecificFlags = layout.flags.kindSpecificFlags, case .anonymous(let anonymousContextDescriptorFlags) = kindSpecificFlags else { 23 | return false 24 | } 25 | return anonymousContextDescriptorFlags.hasMangledName 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/AssociatedType/AssociatedType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | 5 | public struct AssociatedType { 6 | public let descriptor: AssociatedTypeDescriptor 7 | 8 | public let conformingTypeName: MangledName 9 | 10 | public let protocolTypeName: MangledName 11 | 12 | public let records: [AssociatedTypeRecord] 13 | 14 | @MachOImageGenerator 15 | public init(descriptor: AssociatedTypeDescriptor, in machOFile: MachOFile) throws { 16 | self.descriptor = descriptor 17 | self.conformingTypeName = try descriptor.conformingTypeName(in: machOFile) 18 | self.protocolTypeName = try descriptor.protocolTypeName(in: machOFile) 19 | self.records = try descriptor.associatedTypeRecords(in: machOFile) 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/AssociatedType/AssociatedTypeDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | import MachOMacro 5 | 6 | public struct AssociatedTypeDescriptor: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let conformingTypeName: RelativeDirectPointer 9 | public let protocolTypeName: RelativeDirectPointer 10 | public let numAssociatedTypes: UInt32 11 | public let associatedTypeRecordSize: UInt32 12 | } 13 | 14 | public var layout: Layout 15 | public let offset: Int 16 | 17 | public init(layout: Layout, offset: Int) { 18 | self.offset = offset 19 | self.layout = layout 20 | } 21 | } 22 | 23 | 24 | @MachOImageAllMembersGenerator 25 | extension AssociatedTypeDescriptor { 26 | 27 | public func conformingTypeName(in machOFile: MachOFile) throws -> MangledName { 28 | return try layout.conformingTypeName.resolve(from: offset(of: \.conformingTypeName), in: machOFile) 29 | } 30 | 31 | //@MachOImageGenerator 32 | public func protocolTypeName(in machOFile: MachOFile) throws -> MangledName { 33 | return try layout.protocolTypeName.resolve(from: offset(of: \.protocolTypeName), in: machOFile) 34 | } 35 | 36 | //@MachOImageGenerator 37 | public func associatedTypeRecords(in machOFile: MachOFile) throws -> [AssociatedTypeRecord] { 38 | return try machOFile.readElements(offset: offset + layoutSize, numberOfElements: layout.numAssociatedTypes.cast()) 39 | } 40 | 41 | public var size: Int { 42 | layoutSize + (layout.numAssociatedTypes * layout.associatedTypeRecordSize).cast() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/AssociatedType/AssociatedTypeRecord.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | import MachOMacro 5 | 6 | public struct AssociatedTypeRecord: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let name: RelativeDirectPointer 9 | public let substitutedTypeName: RelativeDirectPointer 10 | } 11 | 12 | public var layout: Layout 13 | 14 | public var offset: Int 15 | 16 | public init(layout: Layout, offset: Int) { 17 | self.layout = layout 18 | self.offset = offset 19 | } 20 | } 21 | 22 | @MachOImageAllMembersGenerator 23 | extension AssociatedTypeRecord { 24 | public func name(in machOFile: MachOFile) throws -> String { 25 | return try layout.name.resolve(from: offset(of: \.name), in: machOFile) 26 | } 27 | 28 | public func substitutedTypeName(in machOFile: MachOFile) throws -> MangledName { 29 | return try layout.substitutedTypeName.resolve(from: offset(of: \.substitutedTypeName), in: machOFile) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/BuiltinType/BuiltinType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/BuiltinType/BuiltinTypeDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct BuiltinTypeDescriptor: ResolvableLocatableLayoutWrapper { 5 | public struct Layout { 6 | public let typeName: RelativeDirectPointer 7 | public let size: UInt32 8 | public let alignmentAndFlags: UInt32 9 | public let stride: UInt32 10 | public let numExtraInhabitants: UInt32 11 | } 12 | 13 | public var layout: Layout 14 | 15 | public let offset: Int 16 | 17 | public init(layout: Layout, offset: Int) { 18 | self.layout = layout 19 | self.offset = offset 20 | } 21 | } 22 | 23 | extension BuiltinTypeDescriptor { 24 | public var isBitwiseTakable: Bool { 25 | return (layout.alignmentAndFlags >> 16) & 0x1 != 0 26 | } 27 | 28 | public var alignment: Int { 29 | (layout.alignmentAndFlags & 0xFFFF).cast() 30 | } 31 | 32 | public var hasMangledName: Bool { 33 | layout.typeName.isNull == false 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Capture/Capture.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Capture/CaptureDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ContextDescriptor/ContextDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | 5 | public struct ContextDescriptor: ContextDescriptorProtocol { 6 | public struct Layout: ContextDescriptorLayout { 7 | public let flags: ContextDescriptorFlags 8 | public let parent: RelativeContextPointer 9 | } 10 | 11 | public let offset: Int 12 | 13 | public var layout: Layout 14 | 15 | public init(layout: Layout, offset: Int) { 16 | self.offset = offset 17 | self.layout = layout 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ContextDescriptor/ContextDescriptorFlags.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // https://github.com/apple/swift/blob/main/include/swift/ABI/MetadataValues.h#L1849 4 | public struct ContextDescriptorFlags: OptionSet { 5 | public let rawValue: UInt32 6 | 7 | public init(rawValue: UInt32) { 8 | self.rawValue = rawValue 9 | } 10 | 11 | /// The kind of context this descriptor describes. 12 | public var kind: ContextDescriptorKind { 13 | if let kind = ContextDescriptorKind(rawValue: UInt8(rawValue & 0x1F)) { 14 | return kind 15 | } 16 | return ContextDescriptorKind.unknown 17 | } 18 | 19 | /// Whether the context has information about invertible protocols, which 20 | /// will show up as a trailing field in the context descriptor. 21 | public static let hasInvertibleProtocols = ContextDescriptorFlags(rawValue: 0x20) 22 | 23 | /// Whether this is a unique record describing the referenced context. 24 | public static let isUnique = ContextDescriptorFlags(rawValue: 0x40) 25 | 26 | /// Whether the context being described is generic. 27 | public static let isGeneric = ContextDescriptorFlags(rawValue: 0x80) 28 | 29 | /// The format version of the descriptor. Higher version numbers may have 30 | /// additional fields that aren't present in older versions. 31 | public var version: UInt8 { 32 | return UInt8((rawValue >> 8) & 0xFF) 33 | } 34 | 35 | public var kindSpecificFlagsRawValue: UInt16 { 36 | return UInt16((rawValue >> 16) & 0xFFFF) 37 | } 38 | 39 | /// The most significant two bytes of the flags word, which can have 40 | /// kind-specific meaning. 41 | public var kindSpecificFlags: ContextDescriptorKindSpecificFlags? { 42 | let rawValue = kindSpecificFlagsRawValue 43 | switch kind { 44 | case .anonymous: 45 | return .anonymous(.init(rawValue: rawValue)) 46 | case .protocol: 47 | return .protocol(.init(rawValue: rawValue)) 48 | case .class, 49 | .struct, 50 | .enum: 51 | return .type(.init(rawValue: rawValue)) 52 | default: 53 | return nil 54 | } 55 | } 56 | 57 | public var hasInvertibleProtocols: Bool { 58 | contains(.hasInvertibleProtocols) 59 | } 60 | 61 | public var isUnique: Bool { 62 | contains(.isUnique) 63 | } 64 | 65 | public var isGeneric: Bool { 66 | contains(.isGeneric) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ContextDescriptor/ContextDescriptorKind.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // https://github.com/apple/swift/blob/main/include/swift/ABI/MetadataValues.h#L1183 4 | public enum ContextDescriptorKind: UInt8, CustomStringConvertible { 5 | /// This context descriptor represents a module. 6 | case module = 0 7 | 8 | /// This context descriptor represents an extension. 9 | case `extension` = 1 10 | 11 | /// This context descriptor represents an anonymous possibly-generic context 12 | /// such as a function body. 13 | case anonymous = 2 14 | 15 | /// This context descriptor represents a protocol context. 16 | case `protocol` = 3 17 | 18 | /// This context descriptor represents an opaque type alias. 19 | case opaqueType = 4 20 | 21 | /// First kind that represents a type of any sort. 22 | // case Type_First = 16 23 | 24 | /// This context descriptor represents a class. 25 | case `class` = 16 // Type_First 26 | 27 | /// This context descriptor represents a struct. 28 | case `struct` = 17 // Type_First + 1 29 | 30 | /// This context descriptor represents an enum. 31 | case `enum` = 18 // Type_First + 2 32 | 33 | /// Last kind that represents a type of any sort. 34 | case typeLast = 31 35 | 36 | /// It's not in swift source, this value only used for dump 37 | case unknown = 0xFF 38 | 39 | public var description: String { 40 | switch self { 41 | case .module: return "module" 42 | case .extension: return "extension" 43 | case .anonymous: return "anonymous" 44 | case .protocol: return "protocol" 45 | case .opaqueType: return "opaque type" 46 | case .class: return "class" 47 | case .struct: return "struct" 48 | case .enum: return "enum" 49 | case .typeLast: return "typeLast" 50 | case .unknown: return "unknown" 51 | } 52 | } 53 | 54 | public var mangledType: String { 55 | switch self { 56 | case .module: 57 | "" 58 | case .extension: 59 | "" 60 | case .anonymous: 61 | "" 62 | case .protocol: 63 | "P" 64 | case .opaqueType: 65 | "" 66 | case .class: 67 | "C" 68 | case .struct: 69 | "V" 70 | case .enum: 71 | "O" 72 | case .typeLast: 73 | "" 74 | case .unknown: 75 | "XY" 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ContextDescriptor/ContextDescriptorKindSpecificFlags.swift: -------------------------------------------------------------------------------- 1 | public enum ContextDescriptorKindSpecificFlags { 2 | case `protocol`(ProtocolContextDescriptorFlags) 3 | case type(TypeContextDescriptorFlags) 4 | case anonymous(AnonymousContextDescriptorFlags) 5 | 6 | 7 | public var protocolFlags: ProtocolContextDescriptorFlags? { 8 | switch self { 9 | case .protocol(let flags): 10 | return flags 11 | default: 12 | return nil 13 | } 14 | } 15 | 16 | public var typeFlags: TypeContextDescriptorFlags? { 17 | switch self { 18 | case .type(let flags): 19 | return flags 20 | default: 21 | return nil 22 | } 23 | } 24 | 25 | public var anonymousFlags: AnonymousContextDescriptorFlags? { 26 | switch self { 27 | case .anonymous(let flags): 28 | return flags 29 | default: 30 | return nil 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ContextDescriptor/ContextDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOMacro 3 | import MachOFoundation 4 | 5 | @Layout 6 | public protocol ContextDescriptorLayout { 7 | var flags: ContextDescriptorFlags { get } 8 | var parent: RelativeContextPointer { get } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ContextDescriptor/ContextDescriptorProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOFoundation 3 | import MachOMacro 4 | 5 | public protocol ContextDescriptorProtocol: ResolvableLocatableLayoutWrapper where Layout: ContextDescriptorLayout {} 6 | 7 | @MachOImageAllMembersGenerator 8 | extension ContextDescriptorProtocol { 9 | public func parent(in machOFile: MachOFile) throws -> SymbolOrElement? { 10 | guard layout.flags.kind != .module else { return nil } 11 | return try layout.parent.resolve(from: offset + layout.offset(of: .parent), in: machOFile).asOptional 12 | } 13 | 14 | public func genericContext(in machOFile: MachOFile) throws -> GenericContext? { 15 | guard layout.flags.isGeneric else { return nil } 16 | return try GenericContext(contextDescriptor: self, in: machOFile) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ContextDescriptor/NamedContextDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOMacro 3 | import MachOFoundation 4 | 5 | @Layout 6 | public protocol NamedContextDescriptorLayout: ContextDescriptorLayout { 7 | var name: RelativeDirectPointer { get } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ContextDescriptor/NamedContextDescriptorProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOFoundation 4 | 5 | public protocol NamedContextDescriptorProtocol: ContextDescriptorProtocol where Layout: NamedContextDescriptorLayout {} 6 | 7 | @MachOImageAllMembersGenerator 8 | extension NamedContextDescriptorProtocol { 9 | public func name(in machOFile: MachOFile) throws -> String { 10 | try layout.name.resolve(from: offset + layout.offset(of: .name), in: machOFile) 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ExistentialType/ExtendedExistentialTypeShape.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | import MachOMacro 5 | 6 | public struct ExtendedExistentialTypeShape: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let flags: ExtendedExistentialTypeShapeFlags 9 | public let existentialType: RelativeDirectPointer 10 | public let requirementSignatureHeader: GenericContextDescriptorHeader.Layout 11 | } 12 | 13 | public let offset: Int 14 | 15 | public var layout: Layout 16 | 17 | public init(layout: Layout, offset: Int) { 18 | self.offset = offset 19 | self.layout = layout 20 | } 21 | } 22 | 23 | extension ExtendedExistentialTypeShape { 24 | @MachOImageGenerator 25 | public func existentialType(in machOFile: MachOFile) throws -> MangledName { 26 | try layout.existentialType.resolve(from: offset(of: \.existentialType), in: machOFile) 27 | } 28 | } 29 | 30 | public struct ExtendedExistentialTypeShapeFlags: OptionSet { 31 | public let rawValue: UInt32 32 | 33 | public init(rawValue: UInt32) { 34 | self.rawValue = rawValue 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ExistentialType/NonUniqueExtendedExistentialTypeShape.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | import MachOMacro 5 | 6 | public struct NonUniqueExtendedExistentialTypeShape: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let uniqueCache: RelativeDirectPointer> 9 | public let localCopy: ExtendedExistentialTypeShape.Layout 10 | } 11 | 12 | public var layout: Layout 13 | 14 | public let offset: Int 15 | 16 | public init(layout: Layout, offset: Int) { 17 | self.layout = layout 18 | self.offset = offset 19 | } 20 | } 21 | 22 | extension NonUniqueExtendedExistentialTypeShape { 23 | @MachOImageGenerator 24 | public func existentialType(in machOFile: MachOFile) throws -> MangledName { 25 | try layout.localCopy.existentialType.resolve(from: offset(of: \.localCopy.existentialType), in: machOFile) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Extension/ExtensionContext.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | 5 | public struct ExtensionContext { 6 | public let descriptor: ExtensionContextDescriptor 7 | 8 | public let genericContext: GenericContext? 9 | 10 | public let extendedContextMangledName: MangledName? 11 | 12 | @MachOImageGenerator 13 | public init(descriptor: ExtensionContextDescriptor, in machOFile: MachOFile) throws { 14 | self.descriptor = descriptor 15 | self.extendedContextMangledName = try descriptor.extendedContext(in: machOFile) 16 | self.genericContext = try descriptor.genericContext(in: machOFile) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Extension/ExtensionContextDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct ExtensionContextDescriptor: ExtensionContextDescriptorProtocol { 7 | public struct Layout: ExtensionContextDescriptorLayout { 8 | public let flags: ContextDescriptorFlags 9 | public let parent: RelativeContextPointer 10 | public let extendedContext: RelativeDirectPointer 11 | } 12 | 13 | public let offset: Int 14 | 15 | public var layout: Layout 16 | 17 | public init(layout: Layout, offset: Int) { 18 | self.offset = offset 19 | self.layout = layout 20 | } 21 | } 22 | 23 | @MachOImageAllMembersGenerator 24 | extension ExtensionContextDescriptorProtocol { 25 | public func extendedContext(in machOFile: MachOFile) throws -> MangledName? { 26 | try layout.extendedContext.resolve(from: offset + 8, in: machOFile) 27 | } 28 | } 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Extension/ExtensionContextDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | import MachOFoundation 2 | 3 | public protocol ExtensionContextDescriptorLayout: ContextDescriptorLayout { 4 | var extendedContext: RelativeDirectPointer { get } 5 | } 6 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Extension/ExtensionContextDescriptorProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | 3 | public protocol ExtensionContextDescriptorProtocol: ContextDescriptorProtocol where Layout: ExtensionContextDescriptorLayout {} 4 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/FieldDescriptor/FieldDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | import MachOMacro 5 | 6 | public struct FieldDescriptor: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let mangledTypeName: RelativeDirectPointer 9 | public let superclass: RelativeOffset 10 | public let kind: UInt16 11 | public let fieldRecordSize: UInt16 12 | public let numFields: UInt32 13 | } 14 | 15 | public let offset: Int 16 | 17 | public var layout: Layout 18 | 19 | public init(layout: Layout, offset: Int) { 20 | self.offset = offset 21 | self.layout = layout 22 | } 23 | } 24 | 25 | @MachOImageAllMembersGenerator 26 | extension FieldDescriptor { 27 | 28 | public var kind: FieldDescriptorKind { .init(rawValue: layout.kind)! } 29 | 30 | public func mangledTypeName(in machOFile: MachOFile) throws -> MangledName { 31 | return try layout.mangledTypeName.resolve(from: offset(of: \.mangledTypeName), in: machOFile) 32 | } 33 | 34 | public func records(in machOFile: MachOFile) throws -> [FieldRecord] { 35 | guard layout.fieldRecordSize != 0 else { return [] } 36 | let offset = offset + MemoryLayout.size 37 | return try machOFile.readElements(offset: offset, numberOfElements: layout.numFields.cast()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/FieldDescriptor/FieldDescriptorKind.swift: -------------------------------------------------------------------------------- 1 | public enum FieldDescriptorKind: UInt16 { 2 | case `struct` 3 | case `class` 4 | case `enum` 5 | case multiPayloadEnum 6 | case `protocol` 7 | case classProtocol 8 | case objCProtocol 9 | case objCClass 10 | case unknown = 0xFFFF 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/FieldRecord/FieldRecord.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct FieldRecord: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let flags: FieldRecordFlags 9 | public let mangledTypeName: RelativeDirectPointer 10 | public let fieldName: RelativeDirectPointer 11 | } 12 | 13 | public let offset: Int 14 | 15 | public var layout: Layout 16 | 17 | public init(layout: Layout, offset: Int) { 18 | self.offset = offset 19 | self.layout = layout 20 | } 21 | } 22 | 23 | @MachOImageAllMembersGenerator 24 | extension FieldRecord { 25 | public func mangledTypeName(in machOFile: MachOFile) throws -> MangledName { 26 | return try layout.mangledTypeName.resolve(from: offset(of: \.mangledTypeName), in: machOFile) 27 | } 28 | 29 | public func fieldName(in machOFile: MachOFile) throws -> String { 30 | return try layout.fieldName.resolve(from: offset(of: \.fieldName), in: machOFile) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/FieldRecord/FieldRecordFlags.swift: -------------------------------------------------------------------------------- 1 | public struct FieldRecordFlags: OptionSet { 2 | public let rawValue: UInt32 3 | 4 | public init(rawValue: UInt32) { 5 | self.rawValue = rawValue 6 | } 7 | 8 | public static let isIndirectCase = FieldRecordFlags(rawValue: 1 << 0) 9 | public static let isVariadic = FieldRecordFlags(rawValue: 1 << 1) 10 | public static let isArtificial = FieldRecordFlags(rawValue: 1 << 2) 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericContextDescriptorFlags.swift: -------------------------------------------------------------------------------- 1 | public struct GenericContextDescriptorFlags: OptionSet { 2 | public let rawValue: UInt16 3 | 4 | public init(rawValue: UInt16) { 5 | self.rawValue = rawValue 6 | } 7 | 8 | public static let hasTypePacks = GenericContextDescriptorFlags(rawValue: 1 << 0) 9 | public static let hasConditionalInvertedProtocols = GenericContextDescriptorFlags(rawValue: 1 << 1) 10 | public static let hasValues = GenericContextDescriptorFlags(rawValue: 1 << 2) 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericContextDescriptorHeader.swift: -------------------------------------------------------------------------------- 1 | public struct GenericContextDescriptorHeader: GenericContextDescriptorHeaderProtocol { 2 | public struct Layout: GenericContextDescriptorHeaderLayout { 3 | public let numParams: UInt16 4 | public let numRequirements: UInt16 5 | public let numKeyArguments: UInt16 6 | public let flags: GenericContextDescriptorFlags 7 | } 8 | 9 | public let offset: Int 10 | public var layout: Layout 11 | public init(layout: Layout, offset: Int) { 12 | self.offset = offset 13 | self.layout = layout 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericContextDescriptorHeaderProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | 4 | public protocol GenericContextDescriptorHeaderProtocol: ResolvableLocatableLayoutWrapper where Layout: GenericContextDescriptorHeaderLayout {} 5 | 6 | public protocol GenericContextDescriptorHeaderLayout { 7 | var numParams: UInt16 { get } 8 | var numRequirements: UInt16 { get } 9 | var numKeyArguments: UInt16 { get } 10 | var flags: GenericContextDescriptorFlags { get } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericPackKind.swift: -------------------------------------------------------------------------------- 1 | public enum GenericPackKind: UInt16 { 2 | case metadata 3 | case witnessTable 4 | } 5 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericPackShapeDescriptor.swift: -------------------------------------------------------------------------------- 1 | public struct GenericPackShapeDescriptor: ResolvableLocatableLayoutWrapper { 2 | public struct Layout { 3 | public let kind: UInt16 4 | public let index: UInt16 5 | public let shapeClass: UInt16 6 | public let unused: UInt16 7 | } 8 | 9 | public let offset: Int 10 | public var layout: Layout 11 | public init(layout: Layout, offset: Int) { 12 | self.offset = offset 13 | self.layout = layout 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericPackShapeHeader.swift: -------------------------------------------------------------------------------- 1 | public struct GenericPackShapeHeader: ResolvableLocatableLayoutWrapper { 2 | public struct Layout { 3 | public let numPacks: UInt16 4 | public let numShapeClasses: UInt16 5 | } 6 | 7 | public let offset: Int 8 | public var layout: Layout 9 | public init(layout: Layout, offset: Int) { 10 | self.offset = offset 11 | self.layout = layout 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericParamDescriptor.swift: -------------------------------------------------------------------------------- 1 | public struct GenericParamDescriptor: ResolvableLocatableLayoutWrapper { 2 | public struct Layout { 3 | public let rawValue: UInt8 4 | } 5 | 6 | public let offset: Int 7 | public var layout: Layout 8 | 9 | public init(layout: Layout, offset: Int) { 10 | self.offset = offset 11 | self.layout = layout 12 | } 13 | 14 | public var hasKeyArgument: Bool { 15 | layout.rawValue & 0x80 != 0 16 | } 17 | 18 | public var kind: GenericParamKind { 19 | .init(rawValue: layout.rawValue & 0x3F)! 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericParamKind.swift: -------------------------------------------------------------------------------- 1 | public enum GenericParamKind: UInt8 { 2 | case type 3 | case typePack 4 | case value 5 | case max = 0x3F 6 | } 7 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericRequirement.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | 5 | public struct GenericRequirement { 6 | public let descriptor: GenericRequirementDescriptor 7 | 8 | public var flags: GenericRequirementFlags { descriptor.flags } 9 | 10 | public var paramManagledName: MangledName 11 | 12 | public var content: ResolvedGenericRequirementContent 13 | 14 | @MachOImageGenerator 15 | public init(descriptor: GenericRequirementDescriptor, in machOFile: MachOFile) throws { 16 | self.descriptor = descriptor 17 | self.paramManagledName = try descriptor.paramManagedName(in: machOFile) 18 | self.content = try descriptor.resolvedContent(in: machOFile) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericRequirementContent.swift: -------------------------------------------------------------------------------- 1 | import MachOFoundation 2 | 3 | public enum GenericRequirementContent { 4 | public struct InvertedProtocols { 5 | public let genericParamIndex: UInt16 6 | public let protocols: InvertibleProtocolSet 7 | } 8 | 9 | case type(RelativeDirectPointer) 10 | case `protocol`(RelativeProtocolDescriptorPointer) 11 | case layout(GenericRequirementLayoutKind) 12 | case conformance(RelativeIndirectablePointer>) 13 | case invertedProtocols(GenericRequirementContent.InvertedProtocols) 14 | } 15 | 16 | public enum ResolvedGenericRequirementContent { 17 | case type(MangledName) 18 | case `protocol`(SymbolOrElement) 19 | case layout(GenericRequirementLayoutKind) 20 | case conformance(ProtocolConformanceDescriptor) 21 | case invertedProtocols(GenericRequirementContent.InvertedProtocols) 22 | } 23 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericRequirementDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | import MachOMacro 5 | 6 | public struct GenericRequirementDescriptor: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let flags: GenericRequirementFlags 9 | public let param: RelativeDirectPointer 10 | public let content: RelativeOffset 11 | } 12 | 13 | public var layout: Layout 14 | 15 | public let offset: Int 16 | 17 | public init(layout: Layout, offset: Int) { 18 | self.offset = offset 19 | self.layout = layout 20 | } 21 | } 22 | 23 | 24 | @MachOImageAllMembersGenerator 25 | extension GenericRequirementDescriptor { 26 | //@MachOImageGenerator 27 | public func paramManagedName(in machOFile: MachOFile) throws -> MangledName { 28 | return try layout.param.resolve(from: offset(of: \.param), in: machOFile) 29 | } 30 | 31 | //@MachOImageGenerator 32 | public func type(in machOFile: MachOFile) throws -> MangledName { 33 | return try RelativeDirectPointer(relativeOffset: layout.content).resolve(from: offset(of: \.content), in: machOFile) 34 | } 35 | 36 | public var content: GenericRequirementContent { 37 | switch layout.flags.kind { 38 | case .protocol: 39 | let ptr = RelativeIndirectableRawPointerIntPair(relativeOffsetPlusIndirectAndInt: layout.content) 40 | if ptr.value { 41 | return .protocol(.objcPointer(.init(relativeOffsetPlusIndirectAndInt: layout.content))) 42 | } else { 43 | return .protocol(.swiftPointer(.init(relativeOffsetPlusIndirectAndInt: layout.content))) 44 | } 45 | case .sameType, 46 | .baseClass, 47 | .sameShape: 48 | return .type(.init(relativeOffset: layout.content)) 49 | case .sameConformance: 50 | return .conformance(.init(relativeOffsetPlusIndirect: layout.content)) 51 | case .invertedProtocols: 52 | var value = layout.content 53 | return .invertedProtocols(withUnsafeBytes(of: &value) { 54 | $0.load(as: GenericRequirementContent.InvertedProtocols.self) 55 | }) 56 | case .layout: 57 | return .layout(.init(rawValue: layout.content.cast())!) 58 | } 59 | } 60 | 61 | //@MachOImageGenerator 62 | public func resolvedContent(in machOFile: MachOFile) throws -> ResolvedGenericRequirementContent { 63 | let offset = offset(of: \.content) 64 | switch content { 65 | case .type(let relativeDirectPointer): 66 | return try .type(relativeDirectPointer.resolve(from: offset, in: machOFile)) 67 | case .protocol(let relativeProtocolDescriptorPointer): 68 | return try .protocol(relativeProtocolDescriptorPointer.resolve(from: offset, in: machOFile)) 69 | case .layout(let genericRequirementLayoutKind): 70 | return .layout(genericRequirementLayoutKind) 71 | case .conformance(let relativeIndirectablePointer): 72 | return try .conformance(relativeIndirectablePointer.resolve(from: offset, in: machOFile)) 73 | case .invertedProtocols(let invertedProtocols): 74 | return .invertedProtocols(invertedProtocols) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericRequirementFlags.swift: -------------------------------------------------------------------------------- 1 | public struct GenericRequirementFlags: OptionSet { 2 | public let rawValue: UInt32 3 | 4 | public init(rawValue: UInt32) { 5 | self.rawValue = rawValue 6 | } 7 | 8 | public static let isPackRequirement = GenericRequirementFlags(rawValue: 0x20) 9 | public static let hasKeyArgument = GenericRequirementFlags(rawValue: 0x80) 10 | public static let isValueRequirement = GenericRequirementFlags(rawValue: 0x100) 11 | 12 | public var kind: GenericRequirementKind { 13 | .init(rawValue: UInt8(rawValue & 0x1F))! 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericRequirementKind.swift: -------------------------------------------------------------------------------- 1 | public enum GenericRequirementKind: UInt8 { 2 | case `protocol` 3 | case sameType 4 | case baseClass 5 | case sameConformance 6 | case sameShape 7 | case invertedProtocols 8 | case layout = 0x1F 9 | } 10 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericRequirementLayoutKind.swift: -------------------------------------------------------------------------------- 1 | public enum GenericRequirementLayoutKind: UInt32 { 2 | case `class` 3 | } 4 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericValueDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct GenericValueDescriptor: ResolvableLocatableLayoutWrapper { 4 | public struct Layout { 5 | public let type: UInt32 6 | } 7 | 8 | public let offset: Int 9 | public var layout: Layout 10 | public init(layout: Layout, offset: Int) { 11 | self.offset = offset 12 | self.layout = layout 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericValueHeader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct GenericValueHeader: ResolvableLocatableLayoutWrapper { 4 | public struct Layout { 5 | public let numValues: UInt32 6 | } 7 | 8 | public let offset: Int 9 | 10 | public var layout: Layout 11 | 12 | public init(layout: Layout, offset: Int) { 13 | self.offset = offset 14 | self.layout = layout 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericValueType.swift: -------------------------------------------------------------------------------- 1 | public enum GenericValueType: UInt32 { 2 | case int 3 | } 4 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/GenericWitnessTable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct GenericWitnessTable: ResolvableLocatableLayoutWrapper { 5 | public struct Layout { 6 | public let witnessTableSizeInWords: UInt16 7 | public let witnessTablePrivateSizeInWordsAndRequiresInstantiation: UInt16 8 | public let instantiator: RelativeDirectRawPointer 9 | public let privateData: RelativeDirectRawPointer 10 | } 11 | 12 | public let offset: Int 13 | 14 | public var layout: Layout 15 | 16 | public init(layout: Layout, offset: Int) { 17 | self.offset = offset 18 | self.layout = layout 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/TypeGenericContext.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | //public struct TypeGenericContext { 4 | // public let offset: Int 5 | // public let header: TypeGenericContextDescriptorHeader 6 | // public let parameters: [GenericParamDescriptor] 7 | // public let requirements: [GenericRequirementDescriptor] 8 | // public let typePacks: [GenericPackShapeDescriptor] 9 | //} 10 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Generic/TypeGenericContextDescriptorHeader.swift: -------------------------------------------------------------------------------- 1 | import MachOFoundation 2 | 3 | public struct TypeGenericContextDescriptorHeader: GenericContextDescriptorHeaderProtocol { 4 | public struct Layout: GenericContextDescriptorHeaderLayout { 5 | public let instantiationCache: RelativeOffset 6 | public let defaultInstantiationPattern: RelativeOffset 7 | public let base: GenericContextDescriptorHeader.Layout 8 | 9 | public var numParams: UInt16 { base.numParams } 10 | public var numRequirements: UInt16 { base.numRequirements } 11 | public var numKeyArguments: UInt16 { base.numKeyArguments } 12 | public var flags: GenericContextDescriptorFlags { base.flags } 13 | } 14 | 15 | public let offset: Int 16 | public var layout: Layout 17 | 18 | public init(layout: Layout, offset: Int) { 19 | self.offset = offset 20 | self.layout = layout 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/CanonicalSpecializedMetadataAccessorsListEntry.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct CanonicalSpecializedMetadataAccessorsListEntry: ResolvableLocatableLayoutWrapper { 5 | public struct Layout { 6 | public let accessor: RelativeDirectRawPointer 7 | } 8 | 9 | public var layout: Layout 10 | 11 | public let offset: Int 12 | 13 | public init(layout: Layout, offset: Int) { 14 | self.layout = layout 15 | self.offset = offset 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/CanonicalSpecializedMetadatasCachingOnceToken.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public typealias SwiftOnceToken = intptr_t 5 | 6 | public struct CanonicalSpecializedMetadatasCachingOnceToken: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | let token: RelativeDirectPointer 9 | } 10 | 11 | public var layout: Layout 12 | 13 | public let offset: Int 14 | 15 | public init(layout: Layout, offset: Int) { 16 | self.layout = layout 17 | self.offset = offset 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/CanonicalSpecializedMetadatasListCount.swift: -------------------------------------------------------------------------------- 1 | public struct CanonicalSpecializedMetadatasListCount: RawRepresentable { 2 | public let rawValue: UInt32 3 | public init(rawValue: UInt32) { 4 | self.rawValue = rawValue 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/CanonicalSpecializedMetadatasListEntry.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct CanonicalSpecializedMetadatasListEntry: ResolvableLocatableLayoutWrapper { 5 | public struct Layout { 6 | let metadata: RelativeDirectPointer 7 | } 8 | 9 | public var layout: Layout 10 | 11 | public let offset: Int 12 | 13 | public init(layout: Layout, offset: Int) { 14 | self.layout = layout 15 | self.offset = offset 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/Metadata.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Metadata: MetadataProtocol { 4 | public struct Layout: MetadataLayout { 5 | /// The kind. Only valid for non-class metadata; getKind() must be used to get 6 | /// the kind value. 7 | public let kind: StoredPointer 8 | } 9 | 10 | public let offset: Int 11 | public var layout: Layout 12 | 13 | public init(layout: Layout, offset: Int) { 14 | self.offset = offset 15 | self.layout = layout 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/MetadataBounds.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct MetadataBounds: MetadataBoundsProtocol { 4 | public struct Layout: MetadataBoundsLayout { 5 | public let negativeSizeInWords: UInt32 6 | public let positiveSizeInWords: UInt32 7 | } 8 | 9 | public var layout: Layout 10 | 11 | public let offset: Int 12 | 13 | public init(layout: Layout, offset: Int) { 14 | self.layout = layout 15 | self.offset = offset 16 | } 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/MetadataBoundsLayout.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOMacro 3 | 4 | @Layout 5 | public protocol MetadataBoundsLayout { 6 | var negativeSizeInWords: UInt32 { get } 7 | var positiveSizeInWords: UInt32 { get } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/MetadataBoundsProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOExtensions 4 | import MachOReading 5 | 6 | public protocol MetadataBoundsProtocol: LocatableLayoutWrapper where Layout: MetadataBoundsLayout {} 7 | 8 | extension MetadataBoundsProtocol { 9 | public var totalSizeInBytes: StoredSize { 10 | return (StoredSize(layout.negativeSizeInWords) + StoredSize(layout.positiveSizeInWords)) * MemoryLayout.size.cast() 11 | } 12 | 13 | public var addressPointInBytes: StoredSize { 14 | return StoredSize(layout.negativeSizeInWords) * MemoryLayout.size.cast() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/MetadataInitialization/ForeignMetadataInitialization.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct ForeignMetadataInitialization: ResolvableLocatableLayoutWrapper { 5 | public struct Layout { 6 | public let completionFunction: RelativeDirectRawPointer 7 | } 8 | 9 | public let offset: Int 10 | public var layout: Layout 11 | 12 | public init(layout: Layout, offset: Int) { 13 | self.offset = offset 14 | self.layout = layout 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/MetadataInitialization/SingletonMetadataInitialization.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct SingletonMetadataInitialization: ResolvableLocatableLayoutWrapper { 5 | public struct Layout { 6 | public let initializationCacheOffset: RelativeOffset 7 | public let incompleteMetadata: RelativeOffset 8 | public let completionFunction: RelativeOffset 9 | } 10 | 11 | public let offset: Int 12 | public var layout: Layout 13 | 14 | public init(layout: Layout, offset: Int) { 15 | self.offset = offset 16 | self.layout = layout 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/MetadataKind.swift: -------------------------------------------------------------------------------- 1 | public enum MetadataKind: UInt32 { 2 | static let isNonType: UInt32 = 0x400 3 | static let isNonHeap: UInt32 = 0x200 4 | static let isRuntimePrivate: UInt32 = 0x100 5 | 6 | case `class` = 0 7 | /// 0 | Self.isNonHeap 8 | case `struct` = 0x200 9 | /// 1 | Self.isNonHeap 10 | case `enum` = 0x201 11 | /// 2 | Self.isNonHeap 12 | case `optional` = 0x202 13 | /// 3 | Self.isNonHeap 14 | case foreignClass = 0x203 15 | /// 4 | Self.isNonHeap 16 | case foreignReferenceType = 0x204 17 | /// 0 | Self.isNonHeap | Self.isRuntimePrivate 18 | case opaque = 0x300 19 | /// 1 | Self.isNonHeap | Self.isRuntimePrivate 20 | case tuple = 0x301 21 | /// 2 | Self.isNonHeap | Self.isRuntimePrivate 22 | case function = 0x302 23 | /// 3 | Self.isNonHeap | Self.isRuntimePrivate 24 | case existential = 0x303 25 | /// 4 | Self.isNonHeap | Self.isRuntimePrivate 26 | case metatype = 0x304 27 | /// 5 | Self.isNonHeap | Self.isRuntimePrivate 28 | case objcClassWrapper = 0x305 29 | /// 6 | Self.isNonHeap | Self.isRuntimePrivate 30 | case existentialMetatype = 0x306 31 | /// 7 | Self.isNonHeap | Self.isRuntimePrivate 32 | case extendedExistential = 0x307 33 | /// 8 | Self.isNonHeap | Self.isRuntimePrivate 34 | case fixedArray = 0x308 35 | /// 0 | Self.isNonType 36 | case heapLocalVariable = 0x400 37 | /// 1 | Self.isNonType | Self.isRuntimePrivate 38 | case errorObject = 0x501 39 | /// 2 | Self.isNonType | Self.isRuntimePrivate 40 | case task = 0x502 41 | /// 3 | Self.isNonType | Self.isRuntimePrivate 42 | case job = 0x503 43 | 44 | /// The largest possible non-isa-pointer metadata kind value. 45 | /// 46 | /// This is included in the enumeration to prevent against attempts to 47 | /// exhaustively match metadata kinds. Future Swift runtimes or compilers 48 | /// may introduce new metadata kinds, so for forward compatibility, the 49 | /// runtime must tolerate metadata with unknown kinds. 50 | /// This specific value is not mapped to a valid metadata kind at this time, 51 | /// however. 52 | case lastEnumerated = 0x7FF 53 | 54 | var isHeap: Bool { 55 | rawValue & Self.isNonHeap == 0 56 | } 57 | 58 | var isType: Bool { 59 | rawValue & Self.isNonType == 0 60 | } 61 | 62 | var isRuntimePrivate: Bool { 63 | rawValue & Self.isRuntimePrivate != 0 64 | } 65 | 66 | static func enumeratedMetadataKind(_ kind: UInt64) -> Self { 67 | if kind.cast() > lastEnumerated.rawValue { 68 | return .class 69 | } else { 70 | return .init(rawValue: kind.cast()) ?? .lastEnumerated 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/MetadataLayout.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOMacro 3 | 4 | @Layout 5 | public protocol MetadataLayout { 6 | var kind: StoredPointer { get } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/MetadataProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOExtensions 4 | import MachOReading 5 | 6 | public protocol MetadataProtocol: ResolvableLocatableLayoutWrapper where Layout: MetadataLayout {} 7 | 8 | extension MetadataProtocol { 9 | public var kind: MetadataKind { 10 | .enumeratedMetadataKind(layout.kind) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/MetadataWrapper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public enum MetadataWrapper: Resolvable { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Metadata/SingletonMetadataPointer.swift: -------------------------------------------------------------------------------- 1 | import MachOFoundation 2 | 3 | public struct SingletonMetadataPointer: ResolvableLocatableLayoutWrapper { 4 | public struct Layout { 5 | let metadata: RelativeDirectPointer 6 | } 7 | 8 | public var layout: Layout 9 | 10 | public let offset: Int 11 | 12 | public init(layout: Layout, offset: Int) { 13 | self.layout = layout 14 | self.offset = offset 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Module/ModuleContextDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | 5 | public struct ModuleContextDescriptor: ModuleContextDescriptorProtocol { 6 | public struct Layout: ModuleContextDescriptorLayout { 7 | public let flags: ContextDescriptorFlags 8 | public let parent: RelativeContextPointer 9 | public let name: RelativeDirectPointer 10 | } 11 | 12 | public let offset: Int 13 | 14 | public var layout: Layout 15 | 16 | public init(layout: Layout, offset: Int) { 17 | self.offset = offset 18 | self.layout = layout 19 | } 20 | 21 | public func offset(of keyPath: KeyPath) -> Int { 22 | return offset + layoutOffset(of: keyPath) 23 | } 24 | } 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Module/ModuleContextDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | public protocol ModuleContextDescriptorLayout: NamedContextDescriptorLayout {} 2 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Module/ModuleContextDescriptorProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | 3 | public protocol ModuleContextDescriptorProtocol: NamedContextDescriptorProtocol where Layout: ModuleContextDescriptorLayout {} 4 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/OpaqueType/OpaqueType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct OpaqueType { 7 | public let descriptor: OpaqueTypeDescriptor 8 | 9 | public let genericContext: GenericContext? 10 | 11 | public let underlyingTypeArgumentMangledNames: [MangledName] 12 | 13 | public let invertedProtocols: InvertibleProtocolSet? 14 | 15 | @MachOImageGenerator 16 | public init(descriptor: OpaqueTypeDescriptor, in machOFile: MachOFile) throws { 17 | self.descriptor = descriptor 18 | var currentOffset = descriptor.offset + descriptor.layoutSize 19 | 20 | let genericContext = try descriptor.genericContext(in: machOFile) 21 | 22 | if let genericContext { 23 | currentOffset += genericContext.size 24 | } 25 | self.genericContext = genericContext 26 | 27 | if descriptor.numUnderlyingTypeArugments > 0 { 28 | let underlyingTypeArgumentMangledNamePointers: [RelativeDirectPointer] = try machOFile.readElements(offset: currentOffset, numberOfElements: descriptor.numUnderlyingTypeArugments) 29 | var underlyingTypeArgumentMangledNames: [MangledName] = [] 30 | for underlyingTypeArgumentMangledNamePointer in underlyingTypeArgumentMangledNamePointers { 31 | try underlyingTypeArgumentMangledNames.append(underlyingTypeArgumentMangledNamePointer.resolve(from: currentOffset, in: machOFile)) 32 | currentOffset += MemoryLayout>.size 33 | } 34 | self.underlyingTypeArgumentMangledNames = underlyingTypeArgumentMangledNames 35 | } else { 36 | self.underlyingTypeArgumentMangledNames = [] 37 | } 38 | 39 | if descriptor.flags.contains(.hasInvertibleProtocols) { 40 | self.invertedProtocols = try machOFile.readElement(offset: currentOffset) 41 | currentOffset.offset(of: InvertibleProtocolSet.self) 42 | } else { 43 | self.invertedProtocols = nil 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/OpaqueType/OpaqueTypeDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | 5 | public struct OpaqueTypeDescriptor: OpaqueTypeDescriptorProtocol { 6 | public struct Layout: OpaqueTypeDescriptorLayout { 7 | public let flags: ContextDescriptorFlags 8 | public let parent: RelativeContextPointer 9 | } 10 | 11 | public let offset: Int 12 | 13 | public var layout: Layout 14 | 15 | public init(layout: Layout, offset: Int) { 16 | self.offset = offset 17 | self.layout = layout 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/OpaqueType/OpaqueTypeDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | public protocol OpaqueTypeDescriptorLayout: ContextDescriptorLayout {} 2 | 3 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/OpaqueType/OpaqueTypeDescriptorProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | 3 | public protocol OpaqueTypeDescriptorProtocol: ContextDescriptorProtocol where Layout: OpaqueTypeDescriptorLayout {} 4 | 5 | extension OpaqueTypeDescriptorProtocol { 6 | public var numUnderlyingTypeArugments: Int { 7 | layout.flags.kindSpecificFlagsRawValue.cast() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/Invertible/InvertibleProtocolKind.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum InvertibleProtocolKind: UInt8 { 4 | case copyable 5 | case escapable 6 | } 7 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/Invertible/InvertibleProtocolSet.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct InvertibleProtocolSet: OptionSet { 4 | public let rawValue: UInt16 5 | 6 | public init(rawValue: UInt16) { 7 | self.rawValue = rawValue 8 | } 9 | 10 | public static let copyable = InvertibleProtocolSet(rawValue: 1 << InvertibleProtocolKind.copyable.rawValue) 11 | 12 | public static let escapable = InvertibleProtocolSet(rawValue: 1 << InvertibleProtocolKind.escapable.rawValue) 13 | 14 | public var hasCopyable: Bool { 15 | contains(.copyable) 16 | } 17 | 18 | public var hasEscapable: Bool { 19 | contains(.escapable) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/Invertible/InvertibleProtocolsRequirementCount.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct InvertibleProtocolsRequirementCount: RawRepresentable { 4 | public let rawValue: UInt16 5 | 6 | public init(rawValue: UInt16) { 7 | self.rawValue = rawValue 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ObjC/ObjCProtocolPrefix.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct ObjCProtocolPrefix: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let isa: RawPointer 9 | public let name: Pointer 10 | } 11 | 12 | public let offset: Int 13 | 14 | public var layout: Layout 15 | 16 | public init(layout: Layout, offset: Int) { 17 | self.offset = offset 18 | self.layout = layout 19 | } 20 | } 21 | 22 | @MachOImageAllMembersGenerator 23 | extension ObjCProtocolPrefix { 24 | //@MachOImageGenerator 25 | public func name(in machOFile: MachOFile) throws -> String { 26 | try layout.name.resolve(in: machOFile) 27 | } 28 | 29 | //@MachOImageGenerator 30 | public func mangledName(in machOFile: MachOFile) throws -> MangledName { 31 | try Pointer(address: layout.name.address).resolve(in: machOFile) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ObjC/RelativeObjCProtocolPrefix.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct RelativeObjCProtocolPrefix: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let isa: RelativeDirectRawPointer 9 | public let mangledName: RelativeDirectPointer 10 | } 11 | 12 | public let offset: Int 13 | 14 | public var layout: Layout 15 | 16 | public init(layout: Layout, offset: Int) { 17 | self.offset = offset 18 | self.layout = layout 19 | } 20 | } 21 | 22 | @MachOImageAllMembersGenerator 23 | extension RelativeObjCProtocolPrefix { 24 | func mangledName(in machOFile: MachOFile) throws -> MangledName { 25 | return try layout.mangledName.resolve(from: offset(of: \.mangledName), in: machOFile) 26 | } 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/Protocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | 5 | // using TrailingObjects 6 | // = swift::ABI::TrailingObjects< 7 | // TargetProtocolDescriptor, 8 | // TargetGenericRequirementDescriptor, 9 | // TargetProtocolRequirement>; 10 | 11 | public struct Protocol { 12 | public enum Error: Swift.Error { 13 | case invalidProtocolDescriptor 14 | } 15 | 16 | public let descriptor: ProtocolDescriptor 17 | 18 | public let requirementInSignatures: [GenericRequirementDescriptor] 19 | 20 | public let requirements: [ProtocolRequirement] 21 | 22 | public let protocolFlags: ProtocolContextDescriptorFlags 23 | 24 | public let name: String 25 | 26 | public var numberOfRequirements: Int { 27 | descriptor.numRequirements.cast() 28 | } 29 | 30 | public var numberOfRequirementsInSignature: Int { 31 | descriptor.numRequirementsInSignature.cast() 32 | } 33 | 34 | @MachOImageGenerator 35 | public init(descriptor: ProtocolDescriptor, in machOFile: MachOFile) throws { 36 | guard let protocolFlags = descriptor.flags.kindSpecificFlags?.protocolFlags else { 37 | throw Error.invalidProtocolDescriptor 38 | } 39 | self.descriptor = descriptor 40 | self.protocolFlags = protocolFlags 41 | self.name = try descriptor.name(in: machOFile) 42 | var currentOffset = descriptor.offset + descriptor.layoutSize 43 | 44 | if descriptor.numRequirementsInSignature > 0 { 45 | self.requirementInSignatures = try machOFile.readElements(offset: currentOffset, numberOfElements: descriptor.numRequirementsInSignature.cast()) 46 | currentOffset.offset(of: GenericRequirementDescriptor.self, numbersOfElements: descriptor.numRequirementsInSignature.cast()) 47 | currentOffset = align(address: currentOffset.cast(), alignment: 4).cast() 48 | } else { 49 | self.requirementInSignatures = [] 50 | } 51 | 52 | if descriptor.numRequirements > 0 { 53 | self.requirements = try machOFile.readElements(offset: currentOffset, numberOfElements: descriptor.numRequirements.cast()) 54 | currentOffset.offset(of: ProtocolRequirement.self, numbersOfElements: descriptor.numRequirements.cast()) 55 | } else { 56 | self.requirements = [] 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolClassConstraint.swift: -------------------------------------------------------------------------------- 1 | public enum ProtocolClassConstraint: UInt8 { 2 | case `class` 3 | case any 4 | } 5 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolContextDescriptorFlags.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct ProtocolContextDescriptorFlags: FlagSet { 4 | public let rawValue: UInt16 5 | 6 | public init(rawValue: UInt16) { 7 | self.rawValue = rawValue 8 | } 9 | 10 | private enum Bits { 11 | static let hasClassConstraint = 0 12 | static let hasClassConstraintWidth = 1 13 | static let isResilient = 1 14 | static let specialProtocolKind = 2 15 | static let specialProtocolKindWidth = 6 16 | } 17 | 18 | public var isResilient: Bool { 19 | return flag(bit: Bits.isResilient) 20 | } 21 | 22 | public var classConstraint: ProtocolClassConstraint { 23 | .init(rawValue: field(firstBit: Bits.hasClassConstraint, bitWidth: Bits.hasClassConstraintWidth, fieldType: UInt8.self))! 24 | } 25 | 26 | public var specialProtocolKind: SpecialProtocolKind { 27 | .init(rawValue: field(firstBit: Bits.specialProtocolKind, bitWidth: Bits.specialProtocolKindWidth, fieldType: UInt8.self))! 28 | } 29 | } 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | /// A protocol descriptor. 7 | /// 8 | /// Protocol descriptors contain information about the contents of a protocol: 9 | /// it's name, requirements, requirement signature, context, and so on. They 10 | /// are used both to identify a protocol and to reason about its contents. 11 | /// 12 | /// Only Swift protocols are defined by a protocol descriptor, whereas 13 | /// Objective-C (including protocols defined in Swift as @objc) use the 14 | /// Objective-C protocol layout. 15 | public struct ProtocolDescriptor: ProtocolDescriptorProtocol { 16 | public struct Layout: ProtocolDescriptorLayout { 17 | public let flags: ContextDescriptorFlags 18 | public let parent: RelativeContextPointer 19 | public var name: RelativeDirectPointer 20 | public var numRequirementsInSignature: UInt32 21 | public var numRequirements: UInt32 22 | public var associatedTypes: RelativeDirectPointer 23 | } 24 | 25 | public var offset: Int 26 | public var layout: Layout 27 | 28 | public init(layout: Layout, offset: Int) { 29 | self.offset = offset 30 | self.layout = layout 31 | } 32 | 33 | public func offset(of keyPath: KeyPath) -> Int { 34 | return offset + layoutOffset(of: keyPath) 35 | } 36 | } 37 | 38 | @MachOImageAllMembersGenerator 39 | extension ProtocolDescriptor { 40 | public func associatedTypes(in machOFile: MachOFile) throws -> [String] { 41 | guard layout.associatedTypes.isValid else { return [] } 42 | return try layout.associatedTypes.resolve(from: offset(of: \.associatedTypes), in: machOFile).components(separatedBy: " ") 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | import MachOFoundation 2 | 3 | public protocol ProtocolDescriptorLayout: NamedContextDescriptorLayout { 4 | var numRequirementsInSignature: UInt32 { get } 5 | var numRequirements: UInt32 { get } 6 | var associatedTypes: RelativeDirectPointer { get } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolDescriptorProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | 3 | public protocol ProtocolDescriptorProtocol: NamedContextDescriptorProtocol where Layout: ProtocolDescriptorLayout {} 4 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolDescriptorRef.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct ProtocolDescriptorRef { 7 | public let storage: StoredPointer 8 | 9 | private enum Bits { 10 | static let isObjC: UInt64 = 0x1 11 | } 12 | 13 | public var dispatchStrategy: ProtocolDispatchStrategy { 14 | if isObjC { 15 | return .objc 16 | } else { 17 | return .swift 18 | } 19 | } 20 | 21 | @MachOImageGenerator 22 | public func swiftProtocol(in machOFile: MachOFile) throws -> ProtocolDescriptor { 23 | try Pointer(address: storage).resolve(in: machOFile) 24 | } 25 | 26 | @MachOImageGenerator 27 | public func objcProtocol(in machOFile: MachOFile) throws -> ObjCProtocolPrefix { 28 | try Pointer(address: storage & ~Bits.isObjC).resolve(in: machOFile) 29 | } 30 | 31 | public var isObjC: Bool { 32 | storage & Bits.isObjC != 0 33 | } 34 | 35 | @MachOImageGenerator 36 | public func name(in machOFile: MachOFile) throws -> String { 37 | if isObjC { 38 | return try objcProtocol(in: machOFile).name(in: machOFile) 39 | } else { 40 | return try swiftProtocol(in: machOFile).name(in: machOFile) 41 | } 42 | } 43 | 44 | public static func forObjC(_ storage: StoredPointer) -> Self { 45 | .init(storage: storage | Bits.isObjC) 46 | } 47 | 48 | public static func forSwift(_ storage: StoredPointer) -> Self { 49 | .init(storage: storage) 50 | } 51 | } 52 | 53 | 54 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolDescriptorWithObjCInterop.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public enum ProtocolDescriptorWithObjCInterop: Resolvable { 5 | case objc(ObjCProtocolPrefix) 6 | case swift(ProtocolDescriptor) 7 | } 8 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolDispatchStrategy.swift: -------------------------------------------------------------------------------- 1 | public enum ProtocolDispatchStrategy: UInt8 { 2 | case objc 3 | case swift 4 | } 5 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolRequirement.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOFoundation 4 | 5 | public struct ProtocolRequirement: ResolvableLocatableLayoutWrapper { 6 | public struct Layout { 7 | public let flags: ProtocolRequirementFlags 8 | public let defaultImplementation: RelativeDirectPointer 9 | } 10 | 11 | public let offset: Int 12 | 13 | public var layout: Layout 14 | 15 | public init(layout: Layout, offset: Int) { 16 | self.offset = offset 17 | self.layout = layout 18 | } 19 | } 20 | 21 | @MachOImageAllMembersGenerator 22 | extension ProtocolRequirement { 23 | public func defaultImplementationSymbol(in machOFile: MachOFile) throws -> MachOSymbol? { 24 | guard layout.defaultImplementation.isValid else { return nil } 25 | return try layout.defaultImplementation.resolve(from: offset(of: \.defaultImplementation), in: machOFile) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolRequirementFlags.swift: -------------------------------------------------------------------------------- 1 | public struct ProtocolRequirementFlags: OptionSet { 2 | public let rawValue: UInt32 3 | 4 | public init(rawValue: UInt32) { 5 | self.rawValue = rawValue 6 | } 7 | 8 | public static let isInstance = ProtocolRequirementFlags(rawValue: 0x10) 9 | public static let maybeAsync = ProtocolRequirementFlags(rawValue: 0x20) 10 | 11 | public var kind: ProtocolRequirementKind { 12 | return ProtocolRequirementKind(rawValue: UInt8(rawValue & 0x0F))! 13 | } 14 | 15 | public var isCoroutine: Bool { 16 | switch kind { 17 | case .baseProtocol, 18 | .method, 19 | .`init`, 20 | .getter, 21 | .setter, 22 | .associatedTypeAccessFunction, 23 | .associatedConformanceAccessFunction: 24 | return false 25 | case .readCoroutine, 26 | .modifyCoroutine: 27 | return true 28 | } 29 | } 30 | 31 | public var isAsync: Bool { 32 | return !isCoroutine && contains(.maybeAsync) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolRequirementKind.swift: -------------------------------------------------------------------------------- 1 | public enum ProtocolRequirementKind: UInt8 { 2 | case baseProtocol 3 | case method 4 | case `init` 5 | case getter 6 | case setter 7 | case readCoroutine 8 | case modifyCoroutine 9 | case associatedTypeAccessFunction 10 | case associatedConformanceAccessFunction 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ProtocolWitnessTable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct ProtocolWitnessTable: ResolvableLocatableLayoutWrapper { 5 | public struct Layout { 6 | public let descriptor: Pointer 7 | } 8 | 9 | public var layout: Layout 10 | 11 | public var offset: Int 12 | 13 | public init(layout: Layout, offset: Int) { 14 | self.layout = layout 15 | self.offset = offset 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ResilientWitness.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct ResilientWitness: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let requirement: RelativeProtocolRequirementPointer 9 | public let implementation: RelativeDirectPointer 10 | } 11 | 12 | public let offset: Int 13 | 14 | public var layout: Layout 15 | 16 | public init(layout: Layout, offset: Int) { 17 | self.offset = offset 18 | self.layout = layout 19 | } 20 | } 21 | 22 | 23 | @MachOImageAllMembersGenerator 24 | extension ResilientWitness { 25 | public func requirement(in machOFile: MachOFile) throws -> SymbolOrElement? { 26 | return try layout.requirement.resolve(from: offset(of: \.requirement), in: machOFile).asOptional 27 | } 28 | 29 | public func implementationSymbol(in machOFile: MachOFile) throws -> MachOSymbol? { 30 | return try layout.implementation.resolve(from: offset(of: \.implementation), in: machOFile) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/ResilientWitnessesHeader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct ResilientWitnessesHeader: ResolvableLocatableLayoutWrapper { 4 | public struct Layout { 5 | public let numWitnesses: UInt32 6 | } 7 | 8 | public let offset: Int 9 | 10 | public var layout: Layout 11 | 12 | public init(layout: Layout, offset: Int) { 13 | self.offset = offset 14 | self.layout = layout 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Protocol/SpecialProtocolKind.swift: -------------------------------------------------------------------------------- 1 | public enum SpecialProtocolKind: UInt8 { 2 | case none 3 | case error 4 | } 5 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ProtocolConformance/ProtocolConformanceDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct ProtocolConformanceDescriptor: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let protocolDescriptor: RelativeSymbolOrElementPointer 9 | public let typeReference: RelativeOffset 10 | public let witnessTablePattern: RelativeDirectPointer 11 | public let flags: ProtocolConformanceFlags 12 | } 13 | 14 | public let offset: Int 15 | 16 | public var layout: Layout 17 | 18 | public init(layout: Layout, offset: Int) { 19 | self.offset = offset 20 | self.layout = layout 21 | } 22 | } 23 | 24 | @MachOImageAllMembersGenerator 25 | extension ProtocolConformanceDescriptor { 26 | public func protocolDescriptor(in machOFile: MachOFile) throws -> SymbolOrElement? { 27 | try layout.protocolDescriptor.resolve(from: offset(of: \.protocolDescriptor), in: machOFile).asOptional 28 | } 29 | 30 | public var typeReference: TypeReference { 31 | return .forKind(layout.flags.typeReferenceKind, at: layout.typeReference) 32 | } 33 | 34 | public func resolvedTypeReference(in machOFile: MachOFile) throws -> ResolvedTypeReference { 35 | let offset = offset(of: \.typeReference) 36 | return try typeReference.resolve(at: offset, in: machOFile) 37 | } 38 | 39 | public func witnessTablePattern(in machOFile: MachOFile) throws -> ProtocolWitnessTable? { 40 | try layout.witnessTablePattern.resolve(from: offset(of: \.witnessTablePattern), in: machOFile) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/ClassDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOMacro 3 | import MachOFoundation 4 | 5 | @Layout 6 | public protocol ClassDescriptorLayout: TypeContextDescriptorLayout { 7 | var superclassType: RelativeDirectPointer { get } 8 | var metadataNegativeSizeInWordsOrResilientMetadataBounds: UInt32 { get } 9 | var metadataPositiveSizeInWordsOrExtraClassFlags: UInt32 { get } 10 | var numImmediateMembers: UInt32 { get } 11 | var numFields: UInt32 { get } 12 | var fieldOffsetVectorOffset: UInt32 { get } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/ClassFlags.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Swift class flags. 4 | /// These flags are valid only when isTypeMetadata(). 5 | /// When !isTypeMetadata() these flags will collide with other Swift ABIs. 6 | public enum ClassFlags: UInt32 { 7 | /// Is this a Swift class from the Darwin pre-stable ABI? 8 | /// This bit is clear in stable ABI Swift classes. 9 | /// The Objective-C runtime also reads this bit. 10 | case isSwiftPreStableABI = 0x1 11 | /// Does this class use Swift refcounting? 12 | case usesSwiftRefcounting = 0x2 13 | /// Has this class a custom name, specified with the @objc attribute? 14 | case hasCustomObjCName = 0x4 15 | /// Whether this metadata is a specialization of a generic metadata pattern 16 | /// which was created during compilation. 17 | case isStaticSpecialization = 0x8 18 | /// Whether this metadata is a specialization of a generic metadata pattern 19 | /// which was created during compilation and made to be canonical by 20 | /// modifying the metadata accessor. 21 | case isCanonicalStaticSpecialization = 0x10 22 | } 23 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/ExtraClassDescriptorFlags.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct ExtraClassDescriptorFlags: FlagSet { 4 | public typealias RawValue = UInt32 5 | 6 | public let rawValue: RawValue 7 | 8 | public init(rawValue: RawValue) { 9 | self.rawValue = rawValue 10 | } 11 | 12 | private enum Bits { 13 | static let hasObjCResilientClassStub = 0 14 | } 15 | 16 | public var hasObjCResilientClassStub: Bool { 17 | flag(bit: Bits.hasObjCResilientClassStub) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Metadata/AnyClassMetadata.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct AnyClassMetadata: MetadataProtocol { 5 | public struct Layout: AnyClassMetadataLayout { 6 | public let kind: StoredPointer 7 | public let superclass: StoredPointer 8 | } 9 | 10 | public var layout: Layout 11 | 12 | public let offset: Int 13 | 14 | public init(layout: Layout, offset: Int) { 15 | self.layout = layout 16 | self.offset = offset 17 | } 18 | } 19 | 20 | public struct AnyClassMetadataObjCInterop: MetadataProtocol { 21 | public struct Layout: AnyClassMetadataObjCInteropLayout { 22 | public let kind: StoredPointer 23 | public let superclass: StoredPointer 24 | public let cache: RawPointer 25 | public let vtable: RawPointer 26 | public let data: StoredSize 27 | } 28 | 29 | public var layout: Layout 30 | 31 | public let offset: Int 32 | 33 | public init(layout: Layout, offset: Int) { 34 | self.layout = layout 35 | self.offset = offset 36 | } 37 | } 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Metadata/ClassMetadataBounds.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct ClassMetadataBounds: ClassMetadataBoundsProtocol { 4 | public struct Layout: ClassMetadataBoundsLayout { 5 | public let negativeSizeInWords: UInt32 6 | public let positiveSizeInWords: UInt32 7 | public let immediateMembersOffset: StoredPointerDifference 8 | } 9 | 10 | public var layout: Layout 11 | 12 | public let offset: Int 13 | 14 | public init(layout: Layout, offset: Int) { 15 | self.layout = layout 16 | self.offset = offset 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Metadata/ClassMetadataBoundsLayout.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOMacro 3 | 4 | 5 | @Layout 6 | public protocol ClassMetadataBoundsLayout: MetadataBoundsLayout { 7 | var immediateMembersOffset: StoredPointerDifference { get } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Metadata/ClassMetadataBoundsProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | 4 | public protocol ClassMetadataBoundsProtocol: MetadataBoundsProtocol where Layout: ClassMetadataBoundsLayout {} 5 | 6 | extension ClassMetadataBoundsProtocol { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Method/MethodDefaultOverrideDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct MethodDefaultOverrideDescriptor: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let replacement: RelativeMethodDescriptorPointer 9 | public let original: RelativeMethodDescriptorPointer 10 | public let implementation: RelativeDirectPointer 11 | } 12 | 13 | public var layout: Layout 14 | 15 | public let offset: Int 16 | 17 | public init(layout: Layout, offset: Int) { 18 | self.layout = layout 19 | self.offset = offset 20 | } 21 | } 22 | 23 | @MachOImageAllMembersGenerator 24 | extension MethodDefaultOverrideDescriptor { 25 | //@MachOImageGenerator 26 | public func implementationSymbol(in machOFile: MachOFile) throws -> MachOSymbol? { 27 | return try layout.implementation.resolve(from: offset(of: \.implementation), in: machOFile) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Method/MethodDefaultOverrideTableHeader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct MethodDefaultOverrideTableHeader: ResolvableLocatableLayoutWrapper { 4 | public struct Layout { 5 | public let numEntries: UInt32 6 | } 7 | 8 | public var layout: Layout 9 | 10 | public let offset: Int 11 | 12 | public init(layout: Layout, offset: Int) { 13 | self.layout = layout 14 | self.offset = offset 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Method/MethodDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct MethodDescriptor: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let flags: MethodDescriptorFlags 9 | public let implementation: RelativeDirectPointer 10 | } 11 | 12 | public var layout: Layout 13 | 14 | public let offset: Int 15 | 16 | public init(layout: Layout, offset: Int) { 17 | self.layout = layout 18 | self.offset = offset 19 | } 20 | } 21 | 22 | @MachOImageAllMembersGenerator 23 | extension MethodDescriptor { 24 | //@MachOImageGenerator 25 | public func implementationSymbol(in machOFile: MachOFile) throws -> MachOSymbol? { 26 | return try layout.implementation.resolve(from: offset(of: \.implementation), in: machOFile) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Method/MethodDescriptorFlags.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct MethodDescriptorFlags: RawRepresentable { 4 | public typealias RawValue = UInt32 5 | 6 | public let rawValue: RawValue 7 | 8 | public init(rawValue: RawValue) { 9 | self.rawValue = rawValue 10 | } 11 | 12 | private static let kindMask: RawValue = 0x0F 13 | private static let isInstanceMask: RawValue = 0x10 14 | private static let isDynamicMask: RawValue = 0x20 15 | private static let isAsyncMask: RawValue = 0x40 16 | private static let extraDiscriminatorShift: RawValue = 16 17 | private static let extraDiscriminatorMask: RawValue = 0xFFFF0000 18 | 19 | public var kind: MethodDescriptorKind { 20 | .init(rawValue: .init(rawValue & Self.kindMask))! 21 | } 22 | 23 | public var isDynamic: Bool { 24 | rawValue & Self.isDynamicMask != 0 25 | } 26 | 27 | public var isInstance: Bool { 28 | rawValue & Self.isInstanceMask != 0 29 | } 30 | 31 | public var _hasAsyncBitSet: Bool { 32 | rawValue & Self.isAsyncMask != 0 33 | } 34 | 35 | public var isAsync: Bool { 36 | !isCoroutine && _hasAsyncBitSet 37 | } 38 | 39 | public var isCoroutine: Bool { 40 | switch kind { 41 | case .method, 42 | .`init`, 43 | .getter, 44 | .setter: 45 | return false 46 | case .modifyCoroutine, 47 | .readCoroutine: 48 | return true 49 | } 50 | } 51 | 52 | public var isCalleeAllocatedCoroutine: Bool { 53 | isCoroutine && _hasAsyncBitSet 54 | } 55 | 56 | public var isData: Bool { 57 | isAsync || isCalleeAllocatedCoroutine 58 | } 59 | 60 | public var extraDiscriminator: UInt16 { 61 | .init(rawValue >> Self.extraDiscriminatorShift) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Method/MethodDescriptorKind.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum MethodDescriptorKind: UInt8, CaseIterable, CustomStringConvertible { 4 | case method 5 | case `init` 6 | case getter 7 | case setter 8 | case modifyCoroutine 9 | case readCoroutine 10 | 11 | public var description: String { 12 | switch self { 13 | case .method: 14 | return "Method" 15 | case .`init`: 16 | return "Init" 17 | case .getter: 18 | return "Getter" 19 | case .setter: 20 | return "Setter" 21 | case .modifyCoroutine: 22 | return "Modify" 23 | case .readCoroutine: 24 | return "Read" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Method/MethodImplementationPointer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public enum MethodImplementationPointer { 5 | case implementation(RelativeDirectRawPointer) 6 | case asyncImplementation(RelativeDirectRawPointer) 7 | case coroutineImplementation(RelativeDirectRawPointer) 8 | } 9 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Method/MethodOverrideDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct MethodOverrideDescriptor: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let `class`: RelativeContextPointer 9 | public let method: RelativeMethodDescriptorPointer 10 | public let implementation: RelativeDirectPointer 11 | } 12 | 13 | public var layout: Layout 14 | 15 | public let offset: Int 16 | 17 | public init(layout: Layout, offset: Int) { 18 | self.layout = layout 19 | self.offset = offset 20 | } 21 | } 22 | 23 | @MachOImageAllMembersGenerator 24 | extension MethodOverrideDescriptor { 25 | //@MachOImageGenerator 26 | public func implementationSymbol(in machOFile: MachOFile) throws -> MachOSymbol? { 27 | return try layout.implementation.resolve(from: offset(of: \.implementation), in: machOFile) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Method/OverrideTableHeader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct OverrideTableHeader: ResolvableLocatableLayoutWrapper { 4 | public struct Layout { 5 | public let numEntries: UInt32 6 | } 7 | 8 | public var layout: Layout 9 | 10 | public let offset: Int 11 | 12 | public init(layout: Layout, offset: Int) { 13 | self.layout = layout 14 | self.offset = offset 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Method/VTableDescriptorHeader.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct VTableDescriptorHeader: ResolvableLocatableLayoutWrapper { 4 | public struct Layout { 5 | public let vTableOffset: UInt32 6 | public let vTableSize: UInt32 7 | } 8 | 9 | public var layout: Layout 10 | 11 | public let offset: Int 12 | 13 | public init(layout: Layout, offset: Int) { 14 | self.layout = layout 15 | self.offset = offset 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Resilient/ObjCResilientClassStubInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct ObjCResilientClassStubInfo: ResolvableLocatableLayoutWrapper { 5 | public struct Layout { 6 | public let stub: RelativeDirectRawPointer 7 | } 8 | 9 | public var layout: Layout 10 | 11 | public let offset: Int 12 | 13 | public init(layout: Layout, offset: Int) { 14 | self.layout = layout 15 | self.offset = offset 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Class/Resilient/ResilientSuperclass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct ResilientSuperclass: ResolvableLocatableLayoutWrapper { 7 | public struct Layout { 8 | public let superclass: RelativeDirectRawPointer 9 | } 10 | 11 | public var layout: Layout 12 | 13 | public let offset: Int 14 | 15 | public init(layout: Layout, offset: Int) { 16 | self.layout = layout 17 | self.offset = offset 18 | } 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Enum/EnumDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public struct EnumDescriptor: TypeContextDescriptorProtocol { 5 | public struct Layout: EnumDescriptorLayout { 6 | public let flags: ContextDescriptorFlags 7 | public let parent: RelativeContextPointer 8 | public let name: RelativeDirectPointer 9 | public let accessFunctionPtr: RelativeOffset 10 | public let fieldDescriptor: RelativeDirectPointer 11 | public let numPayloadCasesAndPayloadSizeOffset: UInt32 12 | public let numEmptyCases: UInt32 13 | } 14 | 15 | public let offset: Int 16 | 17 | public var layout: Layout 18 | 19 | public init(layout: Layout, offset: Int) { 20 | self.offset = offset 21 | self.layout = layout 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Enum/EnumDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOMacro 3 | 4 | @Layout 5 | public protocol EnumDescriptorLayout: TypeContextDescriptorLayout { 6 | var numPayloadCasesAndPayloadSizeOffset: UInt32 { get } 7 | var numEmptyCases: UInt32 { get } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Enum/MultiPayloadEnum/MultiPayloadEnumDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Struct/StructDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOFoundation 4 | 5 | public struct StructDescriptor: TypeContextDescriptorProtocol { 6 | public struct Layout: StructDescriptorLayout { 7 | public let flags: ContextDescriptorFlags 8 | public let parent: RelativeContextPointer 9 | public let name: RelativeDirectPointer 10 | public let accessFunctionPtr: RelativeOffset 11 | public let fieldDescriptor: RelativeDirectPointer 12 | public let numFields: UInt32 13 | public let fieldOffsetVector: UInt32 14 | } 15 | 16 | public let offset: Int 17 | 18 | public var layout: Layout 19 | 20 | public init(layout: Layout, offset: Int) { 21 | self.offset = offset 22 | self.layout = layout 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Struct/StructDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOMacro 3 | 4 | @Layout 5 | public protocol StructDescriptorLayout: TypeContextDescriptorLayout { 6 | var numFields: UInt32 { get } 7 | var fieldOffsetVector: UInt32 { get } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Struct/StructMetadata.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOFoundation 4 | 5 | public struct StructMetadata: TypeMetadataProtocol { 6 | public struct Layout: StructMetadataLayout { 7 | public let kind: StoredPointer 8 | public let descriptor: Pointer 9 | } 10 | 11 | public var layout: Layout 12 | 13 | public let offset: Int 14 | 15 | public init(layout: Layout, offset: Int) { 16 | self.layout = layout 17 | self.offset = offset 18 | } 19 | 20 | public static var descriptorOffset: Int { Layout.offset(of: .descriptor) } 21 | } 22 | 23 | @MachOImageAllMembersGenerator 24 | extension StructMetadata { 25 | public func fieldOffsets(for descriptor: StructDescriptor? = nil, in machOFile: MachOFile) throws -> [UInt32] { 26 | let descriptor = try descriptor ?? layout.descriptor.resolve(in: machOFile) 27 | guard descriptor.fieldOffsetVector != .zero else { return [] } 28 | let offset = offset + descriptor.fieldOffsetVector.cast() * MemoryLayout.size 29 | return try machOFile.readElements(offset: offset, numberOfElements: descriptor.numFields.cast()) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/Struct/StructMetadataLayout.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | @Layout 7 | public protocol StructMetadataLayout: MetadataLayout { 8 | var descriptor: Pointer { get } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/TypeContextDescriptor.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOMacro 4 | import MachOFoundation 5 | 6 | public struct TypeContextDescriptor: TypeContextDescriptorProtocol { 7 | public struct Layout: TypeContextDescriptorLayout { 8 | public let flags: ContextDescriptorFlags 9 | public let parent: RelativeContextPointer 10 | public let name: RelativeDirectPointer 11 | public let accessFunctionPtr: RelativeOffset 12 | public let fieldDescriptor: RelativeDirectPointer 13 | } 14 | 15 | public let offset: Int 16 | 17 | public var layout: Layout 18 | 19 | public init(layout: Layout, offset: Int) { 20 | self.offset = offset 21 | self.layout = layout 22 | } 23 | } 24 | 25 | 26 | @MachOImageAllMembersGenerator 27 | extension TypeContextDescriptor { 28 | public func enumDescriptor(in machOFile: MachOFile) throws -> EnumDescriptor? { 29 | guard layout.flags.kind == .enum else { return nil } 30 | return try machOFile.readElement(offset: offset) as EnumDescriptor 31 | } 32 | 33 | public func structDescriptor(in machOFile: MachOFile) throws -> StructDescriptor? { 34 | guard layout.flags.kind == .struct else { return nil } 35 | return try machOFile.readElement(offset: offset) as StructDescriptor 36 | } 37 | 38 | public func classDescriptor(in machOFile: MachOFile) throws -> ClassDescriptor? { 39 | guard layout.flags.kind == .class else { return nil } 40 | return try machOFile.readElement(offset: offset) as ClassDescriptor 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/TypeContextDescriptorFlags.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct TypeContextDescriptorFlags: FlagSet { 4 | public let rawValue: UInt16 5 | 6 | public init(rawValue: UInt16) { 7 | self.rawValue = rawValue 8 | } 9 | 10 | private enum Bits { 11 | static let metadataInitialization = 0 12 | static let metadataInitializationWidth = 2 13 | static let hasImportInfo = 2 14 | static let hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer = 3 15 | static let hasLayoutString = 4 16 | static let classHasDefaultOverrideTable = 6 17 | static let classIsActor = 7 18 | static let classIsDefaultActor = 8 19 | static let classResilientSuperclassReferenceKind = 9 20 | static let classResilientSuperclassReferenceKindWidth = 3 21 | static let classAreImmdiateMembersNegative = 12 22 | static let classHasResilientSuperclass = 13 23 | static let classHasOverrideTable = 14 24 | static let classHasVTable = 15 25 | } 26 | 27 | public var noMetadataInitialization: Bool { 28 | field(firstBit: Bits.metadataInitialization, bitWidth: Bits.metadataInitializationWidth, fieldType: UInt8.self) == 0 29 | } 30 | 31 | public var hasSingletonMetadataInitialization: Bool { 32 | field(firstBit: Bits.metadataInitialization, bitWidth: Bits.metadataInitializationWidth, fieldType: UInt8.self) == 1 33 | } 34 | 35 | public var hasForeignMetadataInitialization: Bool { 36 | field(firstBit: Bits.metadataInitialization, bitWidth: Bits.metadataInitializationWidth, fieldType: UInt8.self) == 2 37 | } 38 | 39 | public var hasImportInfo: Bool { 40 | flag(bit: Bits.hasImportInfo) 41 | } 42 | 43 | public var hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer: Bool { 44 | flag(bit: Bits.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer) 45 | } 46 | 47 | public var hasLayoutString: Bool { 48 | flag(bit: Bits.hasLayoutString) 49 | } 50 | 51 | public var classHasDefaultOverrideTable: Bool { 52 | flag(bit: Bits.classHasDefaultOverrideTable) 53 | } 54 | 55 | public var classIsActor: Bool { 56 | flag(bit: Bits.classIsActor) 57 | } 58 | 59 | public var classIsDefaultActor: Bool { 60 | flag(bit: Bits.classIsDefaultActor) 61 | } 62 | 63 | public var classResilientSuperclassReferenceKind: TypeReferenceKind { 64 | let rawValue = field(firstBit: Bits.classResilientSuperclassReferenceKind, bitWidth: Bits.classResilientSuperclassReferenceKindWidth, fieldType: UInt8.self) 65 | return .init(rawValue: rawValue)! 66 | } 67 | 68 | public var classAreImmdiateMembersNegative: Bool { 69 | flag(bit: Bits.classAreImmdiateMembersNegative) 70 | } 71 | 72 | public var classHasResilientSuperclass: Bool { 73 | flag(bit: Bits.classHasResilientSuperclass) 74 | } 75 | 76 | public var classHasOverrideTable: Bool { 77 | flag(bit: Bits.classHasOverrideTable) 78 | } 79 | 80 | public var classHasVTable: Bool { 81 | flag(bit: Bits.classHasVTable) 82 | } 83 | } 84 | 85 | 86 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/TypeContextDescriptorLayout.swift: -------------------------------------------------------------------------------- 1 | import MachOMacro 2 | import MachOFoundation 3 | 4 | @Layout 5 | public protocol TypeContextDescriptorLayout: NamedContextDescriptorLayout { 6 | var accessFunctionPtr: RelativeOffset { get } 7 | var fieldDescriptor: RelativeDirectPointer { get } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/TypeContextDescriptorProtocol.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOFoundation 4 | 5 | public protocol TypeContextDescriptorProtocol: NamedContextDescriptorProtocol where Layout: TypeContextDescriptorLayout {} 6 | 7 | @MachOImageAllMembersGenerator 8 | extension TypeContextDescriptorProtocol { 9 | 10 | public func accessFunction(in machOFile: MachOFile) throws -> MachOSymbol? { 11 | let ptr = RelativeDirectPointer(relativeOffset: layout.accessFunctionPtr) 12 | return try ptr.resolve(from: offset + layout.offset(of: .accessFunctionPtr), in: machOFile) 13 | } 14 | 15 | public func fieldDescriptor(in machOFile: MachOFile) throws -> FieldDescriptor { 16 | try layout.fieldDescriptor.resolve(from: offset + layout.offset(of: .fieldDescriptor), in: machOFile) 17 | } 18 | 19 | public func genericContext(in machO: MachOFile) throws -> GenericContext? { 20 | guard layout.flags.isGeneric else { return nil } 21 | return try typeGenericContext(in: machO)?.asGenericContext() 22 | } 23 | 24 | public func typeGenericContext(in machOFile: MachOFile) throws -> TypeGenericContext? { 25 | guard layout.flags.isGeneric else { return nil } 26 | return try .init(contextDescriptor: self, in: machOFile) 27 | } 28 | 29 | public var hasSingletonMetadataInitialization: Bool { 30 | return layout.flags.kindSpecificFlags?.typeFlags?.hasSingletonMetadataInitialization ?? false 31 | } 32 | 33 | public var hasForeignMetadataInitialization: Bool { 34 | return layout.flags.kindSpecificFlags?.typeFlags?.hasForeignMetadataInitialization ?? false 35 | } 36 | 37 | public var hasImportInfo: Bool { 38 | return layout.flags.kindSpecificFlags?.typeFlags?.hasImportInfo ?? false 39 | } 40 | 41 | public var hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer: Bool { 42 | return layout.flags.kindSpecificFlags?.typeFlags?.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer ?? false 43 | } 44 | 45 | public var hasLayoutString: Bool { 46 | return layout.flags.kindSpecificFlags?.typeFlags?.hasLayoutString ?? false 47 | } 48 | 49 | public var hasCanonicalMetadataPrespecializations: Bool { 50 | return layout.flags.contains(.isGeneric) && hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer 51 | } 52 | 53 | public var hasSingletonMetadataPointer: Bool { 54 | return !layout.flags.contains(.isGeneric) && hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer 55 | } 56 | } 57 | 58 | func align(address: UInt64, alignment: UInt64) -> UInt64 { 59 | (address + alignment - 1) & ~(alignment - 1) 60 | } 61 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/TypeContextDescriptorWrapper.swift: -------------------------------------------------------------------------------- 1 | public enum TypeContextDescriptorWrapper { 2 | case `enum`(EnumDescriptor) 3 | case `struct`(StructDescriptor) 4 | case `class`(ClassDescriptor) 5 | 6 | public var contextDescriptor: any ContextDescriptorProtocol { 7 | switch self { 8 | case .enum(let enumDescriptor): 9 | return enumDescriptor 10 | case .struct(let structDescriptor): 11 | return structDescriptor 12 | case .class(let classDescriptor): 13 | return classDescriptor 14 | } 15 | } 16 | 17 | public var namedContextDescriptor: any NamedContextDescriptorProtocol { 18 | switch self { 19 | case .enum(let enumDescriptor): 20 | return enumDescriptor 21 | case .struct(let structDescriptor): 22 | return structDescriptor 23 | case .class(let classDescriptor): 24 | return classDescriptor 25 | } 26 | } 27 | 28 | public var typeContextDescriptor: any TypeContextDescriptorProtocol { 29 | switch self { 30 | case .enum(let enumDescriptor): 31 | return enumDescriptor 32 | case .struct(let structDescriptor): 33 | return structDescriptor 34 | case .class(let classDescriptor): 35 | return classDescriptor 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/TypeReference.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOFoundation 4 | 5 | public enum TypeReference { 6 | case directTypeDescriptor(RelativeDirectPointer) 7 | case indirectTypeDescriptor(RelativeDirectPointer) 8 | case directObjCClassName(RelativeDirectPointer) 9 | case indirectObjCClass(RelativeDirectPointer>) 10 | 11 | public static func forKind(_ kind: TypeReferenceKind, at relativeOffset: RelativeOffset) -> TypeReference { 12 | switch kind { 13 | case .directTypeDescriptor: 14 | return .directTypeDescriptor(.init(relativeOffset: relativeOffset)) 15 | case .indirectTypeDescriptor: 16 | return .indirectTypeDescriptor(.init(relativeOffset: relativeOffset)) 17 | case .directObjCClassName: 18 | return .directObjCClassName(.init(relativeOffset: relativeOffset)) 19 | case .indirectObjCClass: 20 | return .indirectObjCClass(.init(relativeOffset: relativeOffset)) 21 | } 22 | } 23 | 24 | 25 | @MachOImageGenerator 26 | public func resolve(at fileOffset: Int, in machOFile: MachOFile) throws -> ResolvedTypeReference { 27 | switch self { 28 | case let .directTypeDescriptor(relativeDirectPointer): 29 | return try .directTypeDescriptor(relativeDirectPointer.resolve(from: fileOffset, in: machOFile)) 30 | case let .indirectTypeDescriptor(relativeIndirectPointer): 31 | return try .indirectTypeDescriptor(relativeIndirectPointer.resolve(from: fileOffset, in: machOFile).resolve(in: machOFile).asOptional) 32 | case let .directObjCClassName(relativeDirectPointer): 33 | return try .directObjCClassName(relativeDirectPointer.resolve(from: fileOffset, in: machOFile)) 34 | case let .indirectObjCClass(relativeIndirectPointer): 35 | return try .indirectObjCClass(relativeIndirectPointer.resolve(from: fileOffset, in: machOFile).resolve(in: machOFile).asOptional) 36 | } 37 | } 38 | } 39 | 40 | public enum ResolvedTypeReference { 41 | case directTypeDescriptor(ContextDescriptorWrapper?) 42 | case indirectTypeDescriptor(SymbolOrElement?) 43 | case directObjCClassName(String?) 44 | case indirectObjCClass(SymbolOrElement?) 45 | } 46 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/Type/TypeReferenceKind.swift: -------------------------------------------------------------------------------- 1 | public enum TypeReferenceKind: UInt8 { 2 | case directTypeDescriptor 3 | case indirectTypeDescriptor 4 | case directObjCClassName 5 | case indirectObjCClass 6 | } 7 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ValueWitnessTable/ValueWitnessFlags.swift: -------------------------------------------------------------------------------- 1 | public struct ValueWitnessFlags: OptionSet { 2 | public typealias RawValue = UInt32 3 | 4 | public let rawValue: RawValue 5 | 6 | public init(rawValue: RawValue) { 7 | self.rawValue = rawValue 8 | } 9 | 10 | public static let isNonPOD = ValueWitnessFlags(rawValue: 0x00010000) 11 | public static let isNonInline = ValueWitnessFlags(rawValue: 0x00020000) 12 | public static let hasSpareBits = ValueWitnessFlags(rawValue: 0x00080000) 13 | public static let isNonBitwiseTakable = ValueWitnessFlags(rawValue: 0x00100000) 14 | public static let hasEnumWitnesses = ValueWitnessFlags(rawValue: 0x00200000) 15 | public static let inComplete = ValueWitnessFlags(rawValue: 0x00400000) 16 | public static let isNonCopyable = ValueWitnessFlags(rawValue: 0x00800000) 17 | public static let isNonBitwiseBorrowable = ValueWitnessFlags(rawValue: 0x01000000) 18 | 19 | public static let alignmentMask: UInt32 = 0x000000FF 20 | public static let maxNumExtraInhabitants: UInt32 = 0x7FFFFFFF 21 | 22 | 23 | public var alignmentMask: StoredSize { 24 | numericCast(rawValue & Self.alignmentMask) 25 | } 26 | 27 | public var alignment: StoredSize { 28 | alignmentMask + 1 29 | } 30 | 31 | public var isPOD: Bool { 32 | !contains(.isNonPOD) 33 | } 34 | 35 | public var isInlineStorage: Bool { 36 | !contains(.isNonInline) 37 | } 38 | 39 | public var isBitwiseTakable: Bool { 40 | !contains(.isNonBitwiseTakable) 41 | } 42 | 43 | public var isBitwiseBorrowable: Bool { 44 | !contains(.isNonBitwiseBorrowable) && isBitwiseTakable 45 | } 46 | 47 | public var isCopyable: Bool { 48 | !contains(.isNonCopyable) 49 | } 50 | 51 | public var hasEnumWitnesses: Bool { 52 | contains(.hasEnumWitnesses) 53 | } 54 | 55 | public var isIncomplete: Bool { 56 | contains(.inComplete) 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Models/ValueWitnessTable/ValueWitnessTable.swift: -------------------------------------------------------------------------------- 1 | public struct ValueWitnessTable: ResolvableLocatableLayoutWrapper { 2 | public struct Layout { 3 | public let size: StoredSize 4 | public let stride: StoredSize 5 | public let flags: ValueWitnessFlags 6 | public let numExtraInhabitants: UInt32 7 | } 8 | 9 | public var layout: Layout 10 | 11 | public let offset: Int 12 | 13 | public init(layout: Layout, offset: Int) { 14 | self.layout = layout 15 | self.offset = offset 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Pointer/ContextPointer.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOFoundation 3 | 4 | public typealias ContextPointer = SymbolOrElementPointer 5 | 6 | 7 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Pointer/RelativePointers.swift: -------------------------------------------------------------------------------- 1 | import MachOFoundation 2 | 3 | public typealias RelativeMethodDescriptorPointer = RelativeSymbolOrElementPointer 4 | 5 | public typealias RelativeProtocolRequirementPointer = RelativeSymbolOrElementPointer 6 | 7 | public typealias RelativeContextPointer = RelativeSymbolOrElementPointer 8 | 9 | public typealias RelativeContextPointerIntPair = RelativeSymbolOrElementPointerIntPair where Value.RawValue: FixedWidthInteger 10 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Pointer/RelativeProtocolDescriptorPointer.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | import MachOMacro 3 | import MachOFoundation 4 | 5 | public enum RelativeProtocolDescriptorPointer { 6 | case objcPointer(RelativeSymbolOrElementPointerIntPair) 7 | case swiftPointer(RelativeSymbolOrElementPointerIntPair) 8 | 9 | public var isObjC: Bool { 10 | switch self { 11 | case .objcPointer(let relativeIndirectablePointerIntPair): 12 | return relativeIndirectablePointerIntPair.value 13 | case .swiftPointer: 14 | return false 15 | } 16 | } 17 | 18 | public var rawPointer: RelativeIndirectableRawPointerIntPair { 19 | switch self { 20 | case .objcPointer(let relativeIndirectablePointerIntPair): 21 | return .init(relativeOffsetPlusIndirectAndInt: relativeIndirectablePointerIntPair.relativeOffsetPlusIndirectAndInt) 22 | case .swiftPointer(let relativeContextPointerIntPair): 23 | return .init(relativeOffsetPlusIndirectAndInt: relativeContextPointerIntPair.relativeOffsetPlusIndirectAndInt) 24 | } 25 | } 26 | 27 | @MachOImageGenerator 28 | public func protocolDescriptorRef(from offset: Int, in machOFile: MachOFile) throws -> ProtocolDescriptorRef { 29 | let storedPointer = try rawPointer.resolveIndirectType(from: offset, in: machOFile).address 30 | if isObjC { 31 | return .forObjC(storedPointer) 32 | } else { 33 | return .forSwift(storedPointer) 34 | } 35 | } 36 | 37 | @MachOImageGenerator 38 | public func resolve(from offset: Int, in machOFile: MachOFile) throws -> SymbolOrElement { 39 | switch self { 40 | case .objcPointer(let relativeIndirectablePointerIntPair): 41 | return try relativeIndirectablePointerIntPair.resolve(from: offset, in: machOFile).map { .objc($0) } 42 | case .swiftPointer(let relativeContextPointerIntPair): 43 | return try relativeContextPointerIntPair.resolve(from: offset, in: machOFile).map { .swift($0) } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Protocols/FlagSet.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol FlagSet: Equatable, RawRepresentable where RawValue: FixedWidthInteger { 4 | func flag(bit: Int) -> Bool 5 | 6 | func field( 7 | firstBit: Int, 8 | bitWidth: Int, 9 | fieldType: FieldType.Type 10 | ) -> FieldType where FieldType.Magnitude == FieldType 11 | } 12 | 13 | extension FlagSet { 14 | @inline(__always) 15 | static func lowMask(forBitWidth bitWidth: Int) -> RawValue { 16 | precondition(bitWidth >= 0 && bitWidth <= RawValue.bitWidth, "Bit width must be between 0 and the storage type's bit width.") 17 | if bitWidth == RawValue.bitWidth { 18 | return ~RawValue(0) // All bits set 19 | } 20 | if bitWidth == 0 { 21 | return 0 22 | } 23 | let mask = (RawValue(1) << bitWidth) &- 1 24 | return mask 25 | } 26 | 27 | @inline(__always) 28 | static func mask(forFirstBit firstBit: Int, bitWidth: Int = 1) -> RawValue { 29 | precondition(firstBit >= 0, "First bit index cannot be negative.") 30 | precondition(bitWidth >= 1, "Bit width must be at least 1.") 31 | precondition(firstBit + bitWidth <= RawValue.bitWidth, "Field extends beyond the storage type's bit width.") 32 | return lowMask(forBitWidth: bitWidth) << firstBit 33 | } 34 | 35 | @inline(__always) 36 | public func flag(bit: Int) -> Bool { 37 | precondition(bit >= 0 && bit < RawValue.bitWidth, "Bit index out of range.") 38 | return (rawValue & Self.mask(forFirstBit: bit)) != 0 39 | } 40 | 41 | @inline(__always) 42 | public func field( 43 | firstBit: Int, 44 | bitWidth: Int, 45 | fieldType: FieldType.Type = FieldType.self 46 | ) -> FieldType where FieldType.Magnitude == FieldType { 47 | precondition(bitWidth > 0, "Bit width must be positive.") 48 | precondition(firstBit >= 0 && (firstBit + bitWidth) <= RawValue.bitWidth, "Field range is out of bounds for the storage type.") 49 | precondition(FieldType.bitWidth >= bitWidth, "The requested FieldType is too small to represent a value of the specified bitWidth.") 50 | 51 | let mask = Self.lowMask(forBitWidth: bitWidth) 52 | let shiftedValue = rawValue >> firstBit 53 | let isolatedValue = shiftedValue & mask 54 | return FieldType(truncatingIfNeeded: isolatedValue) 55 | } 56 | 57 | public static func == (lhs: Self, rhs: Self) -> Bool { 58 | return lhs.rawValue == rhs.rawValue 59 | } 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Protocols/MutableFlagSet.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol MutableFlagSet: FlagSet { 4 | var rawValue: RawValue { get set } 5 | 6 | mutating func setFlag(_ value: Bool, bit: Int) 7 | 8 | mutating func setField( 9 | _ value: FieldType, 10 | firstBit: Int, 11 | bitWidth: Int 12 | ) 13 | } 14 | 15 | extension MutableFlagSet { 16 | @inline(__always) 17 | public mutating func setFlag(_ value: Bool, bit: Int) { 18 | precondition(bit >= 0 && bit < RawValue.bitWidth, "Bit index out of range.") 19 | let mask = Self.mask(forFirstBit: bit) 20 | if value { 21 | rawValue |= mask 22 | } else { 23 | rawValue &= ~mask 24 | } 25 | } 26 | 27 | @inline(__always) 28 | public mutating func setField( 29 | _ value: FieldType, 30 | firstBit: Int, 31 | bitWidth: Int 32 | ) { 33 | precondition(bitWidth > 0, "Bit width must be positive.") 34 | precondition(firstBit >= 0 && (firstBit + bitWidth) <= RawValue.bitWidth, "Field range is out of bounds for the storage type.") 35 | 36 | let valueMask = Self.lowMask(forBitWidth: bitWidth) 37 | let rawValueEquivalent = RawValue(truncatingIfNeeded: value) 38 | 39 | precondition((rawValueEquivalent & ~valueMask) == 0, "Value \(value) is too large to fit in a field of width \(bitWidth).") 40 | 41 | let fieldMask = Self.mask(forFirstBit: firstBit, bitWidth: bitWidth) 42 | rawValue &= ~fieldMask 43 | rawValue |= (rawValueEquivalent << firstBit) & fieldMask 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Protocols/RuntimeProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol RuntimeProtocol { 4 | associatedtype StoredPointer: FixedWidthInteger 5 | associatedtype StoredSignedPointer: FixedWidthInteger 6 | associatedtype StoredSize: FixedWidthInteger 7 | associatedtype StoredPointerDifference: FixedWidthInteger 8 | static var pointerSize: Int { get } 9 | } 10 | 11 | 12 | public enum RuntimeTarget32: RuntimeProtocol { 13 | public typealias StoredPointer = UInt32 14 | public typealias StoredSignedPointer = UInt32 15 | public typealias StoredSize = UInt32 16 | public typealias StoredPointerDifference = Int32 17 | public static var pointerSize: Int { 4 } 18 | } 19 | 20 | public enum RuntimeTarget64: RuntimeProtocol { 21 | public typealias StoredPointer = UInt64 22 | public typealias StoredSignedPointer = Int64 23 | public typealias StoredSize = UInt64 24 | public typealias StoredPointerDifference = Int64 25 | public static var pointerSize: Int { 8 } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Utils/AnyLocatableLayoutWrapper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AnyLocatableLayoutWrapper: ResolvableLocatableLayoutWrapper { 4 | public var layout: Layout 5 | public let offset: Int 6 | 7 | public init(layout: Layout, offset: Int) { 8 | self.offset = offset 9 | self.layout = layout 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Utils/MachOSwiftSectionName.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum MachOSwiftSectionName: String { 4 | case __swift5_types 5 | case __swift5_types2 6 | case __swift5_builtin 7 | case __swift5_fieldmd 8 | case __swift5_assocty 9 | case __swift5_protos 10 | case __swift5_proto 11 | case __swift5_reflstr 12 | case __swift5_capture 13 | case __swift5_typeref 14 | case __swift5_mpenum 15 | case __constg_swiftt 16 | case __swift5_replace 17 | case __swift5_replac2 18 | case __swift5_acfuncs 19 | case __swift5_entry 20 | } 21 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Utils/RequiredNonOptional.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | package enum RequiredNonOptionalError: Error { 4 | case requiredNonOptional 5 | } 6 | 7 | package func required(_ optional: T?, error: Error? = nil) throws -> T { 8 | guard let optional else { throw error ?? RequiredNonOptionalError.requiredNonOptional } 9 | return optional 10 | } 11 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Utils/ResolvableLocatableLayoutWrapper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOFoundation 3 | 4 | public typealias ResolvableLocatableLayoutWrapper = LocatableLayoutWrapper & Resolvable 5 | -------------------------------------------------------------------------------- /Sources/MachOSwiftSection/Utils/RuntimeLayout.swift: -------------------------------------------------------------------------------- 1 | public typealias StoredPointer = RuntimeTarget64.StoredPointer 2 | public typealias StoredSize = RuntimeTarget64.StoredSize 3 | public typealias StoredPointerDifference = RuntimeTarget64.StoredPointerDifference 4 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Dumpable+/AssociatedType+Dumpable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOSwiftSection 4 | import MachOMacro 5 | 6 | extension AssociatedType: Dumpable { 7 | @MachOImageGenerator 8 | @StringBuilder 9 | public func dump(using options: SymbolPrintOptions, in machOFile: MachOFile) throws -> String { 10 | try "extension \(MetadataReader.demangleSymbol(for: conformingTypeName, in: machOFile).print(using: options)): \(MetadataReader.demangleSymbol(for: protocolTypeName, in: machOFile).print(using: options)) {" 11 | for (offset, record) in records.offsetEnumerated() { 12 | BreakLine() 13 | 14 | Indent(level: 1) 15 | 16 | try "typealias \(record.name(in: machOFile)) = \(MetadataReader.demangleSymbol(for: record.substitutedTypeName(in: machOFile), in: machOFile).print(using: options))" 17 | 18 | if offset.isEnd { 19 | BreakLine() 20 | } 21 | } 22 | 23 | "}" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Dumpable+/ContextDescriptorWrapper+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOSwiftSection 4 | import MachOMacro 5 | 6 | extension ContextDescriptorWrapper { 7 | @MachOImageGenerator 8 | func dumpName(using options: SymbolPrintOptions, in machOFile: MachOFile) throws -> String { 9 | try MetadataReader.demangleContext(for: self, in: machOFile).print(using: options) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Dumpable+/Enum+Dumpable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOSwiftSection 4 | import MachOMacro 5 | 6 | extension Enum: Dumpable { 7 | @MachOImageGenerator 8 | @StringBuilder 9 | public func dump(using options: SymbolPrintOptions, in machOFile: MachOFile) throws -> String { 10 | try "enum \(MetadataReader.demangleContext(for: .type(.enum(descriptor)), in: machOFile).print(using: options))" 11 | 12 | if let genericContext { 13 | try genericContext.dumpGenericParameters(in: machOFile) 14 | if genericContext.requirements.count > 0 { 15 | " where " 16 | try genericContext.dumpGenericRequirements(using: options, in: machOFile) 17 | } 18 | } 19 | 20 | " {" 21 | for (offset, fieldRecord) in try descriptor.fieldDescriptor(in: machOFile).records(in: machOFile).offsetEnumerated() { 22 | BreakLine() 23 | 24 | Indent(level: 1) 25 | 26 | if fieldRecord.flags.contains(.isIndirectCase) { 27 | "indirect case " 28 | } else { 29 | "case " 30 | } 31 | 32 | try "\(fieldRecord.fieldName(in: machOFile))" 33 | 34 | let mangledName = try fieldRecord.mangledTypeName(in: machOFile) 35 | 36 | if !mangledName.isEmpty { 37 | try MetadataReader.demangleType(for: mangledName, in: machOFile).print(using: options).insertBracketIfNeeded 38 | } 39 | 40 | if offset.isEnd { 41 | BreakLine() 42 | } 43 | } 44 | 45 | "}" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Dumpable+/OpaqueType+Dumpable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOSwiftSection 4 | import MachOMacro 5 | 6 | //extension OpaqueType: Dumpable { 7 | // @MachOImageGenerator 8 | // @StringBuilder 9 | // public func dump(using options: SymbolPrintOptions, in machOFile: MachOFile) throws -> String { 10 | // try "opaquetype \(descriptor.dumpFullname(using: options, in: machOFile))" 11 | // for underlyingTypeArgumentMangledName in self.underlyingTypeArgumentMangledNames { 12 | // try MetadataReader.demangleType(for: underlyingTypeArgumentMangledName, in: machOFile).print(using: options) 13 | // } 14 | // } 15 | // 16 | // 17 | // 18 | //} 19 | // 20 | //@MachOImageAllMembersGenerator 21 | //extension OpaqueTypeDescriptorProtocol { 22 | // func dumpFullname(using options: SymbolPrintOptions, in machOFile: MachOFile) throws -> String { 23 | // var name = "" 24 | // var parent = try parent(in: machOFile) 25 | // findParent: while let currnetParent = parent { 26 | // switch currnetParent { 27 | // case .symbol(let unsolvedSymbol): 28 | // name = unsolvedSymbol.stringValue + "." + name 29 | // break findParent 30 | // case .element(let element): 31 | // if let parentName = try element.dumpName(using: options, in: machOFile) { 32 | // name = parentName + "." + name 33 | // } 34 | // parent = try element.contextDescriptor.parent(in: machOFile) 35 | // } 36 | // } 37 | // return name 38 | // } 39 | //} 40 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Dumpable+/Protocol+Dumpable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOSwiftSection 4 | import MachOMacro 5 | 6 | extension MachOSwiftSection.`Protocol`: Dumpable { 7 | @MachOImageGenerator 8 | @StringBuilder 9 | public func dump(using options: SymbolPrintOptions, in machOFile: MachOFile) throws -> String { 10 | try "protocol \(MetadataReader.demangleContext(for: .protocol(descriptor), in: machOFile).print(using: options))" 11 | 12 | if numberOfRequirementsInSignature > 0 { 13 | " where " 14 | 15 | for (offset, requirement) in requirementInSignatures.offsetEnumerated() { 16 | try requirement.dump(using: options, in: machOFile) 17 | if !offset.isEnd { 18 | ", " 19 | } 20 | } 21 | } 22 | 23 | " {" 24 | 25 | let associatedTypes = try descriptor.associatedTypes(in: machOFile) 26 | 27 | if !associatedTypes.isEmpty { 28 | for (offset, associatedType) in associatedTypes.offsetEnumerated() { 29 | BreakLine() 30 | Indent(level: 1) 31 | "associatedtype \(associatedType)" 32 | if offset.isEnd { 33 | BreakLine() 34 | } 35 | } 36 | } 37 | 38 | for (offset, requirement) in requirements.offsetEnumerated() { 39 | BreakLine() 40 | Indent(level: 1) 41 | if let symbol = try requirement.defaultImplementationSymbol(in: machOFile) { 42 | "[Default Implementation] " 43 | try MetadataReader.demangleSymbol(for: symbol, in: machOFile).print(using: options) 44 | } else { 45 | "[Stripped Symbol]" 46 | } 47 | if offset.isEnd { 48 | BreakLine() 49 | } 50 | } 51 | 52 | "}" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Dumpable+/ResilientSuperclass+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOSwiftSection 4 | import MachOMacro 5 | 6 | extension ResilientSuperclass { 7 | @MachOImageGenerator 8 | func dumpSuperclass(using options: SymbolPrintOptions, for kind: TypeReferenceKind, in machOFile: MachOFile) throws -> String? { 9 | let typeReference = TypeReference.forKind(kind, at: layout.superclass.relativeOffset) 10 | let resolvedTypeReference = try typeReference.resolve(at: offset(of: \.superclass), in: machOFile) 11 | switch resolvedTypeReference { 12 | case .directTypeDescriptor(let contextDescriptorWrapper): 13 | return try contextDescriptorWrapper?.dumpName(using: options, in: machOFile) 14 | case .indirectTypeDescriptor(let resolvableElement): 15 | switch resolvableElement { 16 | case .symbol(let unsolvedSymbol): 17 | return try MetadataReader.demangleSymbol(for: unsolvedSymbol, in: machOFile).print(using: options) 18 | case .element(let element): 19 | return try element.dumpName(using: options, in: machOFile) 20 | case nil: 21 | return nil 22 | } 23 | case .directObjCClassName(let string): 24 | return string 25 | case .indirectObjCClass(let resolvableElement): 26 | switch resolvableElement { 27 | case .symbol(let unsolvedSymbol): 28 | return try MetadataReader.demangleSymbol(for: unsolvedSymbol, in: machOFile).print(using: options) 29 | case .element(let element): 30 | return try MetadataReader.demangleContext(for: .type(.class(element.descriptor.resolve(in: machOFile))), in: machOFile).print(using: options) 31 | case nil: 32 | return nil 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Dumpable+/Struct+Dumpable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOKit 3 | import MachOSwiftSection 4 | import MachOMacro 5 | 6 | extension Struct: Dumpable { 7 | @MachOImageGenerator 8 | @StringBuilder 9 | public func dump(using options: SymbolPrintOptions, in machOFile: MachOFile) throws -> String { 10 | try "struct \(MetadataReader.demangleContext(for: .type(.struct(descriptor)), in: machOFile).print(using: options))" 11 | 12 | if let genericContext { 13 | try genericContext.dumpGenericParameters(in: machOFile) 14 | if genericContext.requirements.count > 0 { 15 | " where " 16 | try genericContext.dumpGenericRequirements(using: options, in: machOFile) 17 | } 18 | } 19 | 20 | " {" 21 | 22 | for (offset, fieldRecord) in try descriptor.fieldDescriptor(in: machOFile).records(in: machOFile).offsetEnumerated() { 23 | 24 | BreakLine() 25 | 26 | Indent(level: 1) 27 | 28 | let demangledTypeName = try MetadataReader.demangleType(for: fieldRecord.mangledTypeName(in: machOFile), in: machOFile).print(using: options) 29 | 30 | let fieldName = try fieldRecord.fieldName(in: machOFile) 31 | 32 | if fieldRecord.flags.contains(.isVariadic) { 33 | if demangledTypeName.hasWeakPrefix { 34 | "weak var " 35 | } else if fieldName.hasLazyPrefix { 36 | "lazy var " 37 | } else { 38 | "var " 39 | } 40 | } else { 41 | "let " 42 | } 43 | 44 | "\(fieldName.stripLazyPrefix): \(demangledTypeName.stripWeakPrefix)" 45 | 46 | if offset.isEnd { 47 | BreakLine() 48 | } 49 | } 50 | 51 | "}" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Dumpable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Demangle 3 | import MachOKit 4 | 5 | public typealias SymbolPrintOptions = Demangle.SymbolPrintOptions 6 | 7 | public protocol Dumpable { 8 | func dump(using options: SymbolPrintOptions, in machOFile: MachOFile) throws -> String 9 | func dump(using options: SymbolPrintOptions, in machOImage: MachOImage) throws -> String 10 | } 11 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Utils/OffsetEnumeratedSequence.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct OffsetEnumeratedSequence: Sequence { 4 | struct OffsetInfo { 5 | let index: Int 6 | let isStart: Bool 7 | let isEnd: Bool 8 | 9 | init(index: Int, isStart: Bool, isEnd: Bool) { 10 | self.index = index 11 | self.isStart = isStart 12 | self.isEnd = isEnd 13 | } 14 | } 15 | 16 | typealias Element = (offset: OffsetInfo, element: Base.Element) 17 | 18 | struct Iterator: IteratorProtocol { 19 | typealias Element = (offset: OffsetInfo, element: BaseIterator.Element) 20 | 21 | private var baseIterator: BaseIterator 22 | private var currentIndex: Int 23 | private let totalCount: Int 24 | 25 | init(baseIterator: BaseIterator, count: Int) { 26 | self.baseIterator = baseIterator 27 | self.currentIndex = 0 28 | self.totalCount = count 29 | } 30 | 31 | mutating func next() -> Element? { 32 | guard let element = baseIterator.next() else { 33 | return nil 34 | } 35 | 36 | if totalCount == 0 { 37 | return nil 38 | } 39 | 40 | let isFirstElement = (currentIndex == 0) 41 | let isLastElement = (currentIndex == totalCount - 1) 42 | 43 | let offset = OffsetInfo( 44 | index: currentIndex, 45 | isStart: isFirstElement, 46 | isEnd: isLastElement 47 | ) 48 | 49 | let result = (offset: offset, element: element) 50 | currentIndex += 1 51 | return result 52 | } 53 | } 54 | 55 | private let base: Base 56 | 57 | init(_ base: Base) { 58 | self.base = base 59 | } 60 | 61 | func makeIterator() -> Iterator { 62 | return Iterator(baseIterator: base.makeIterator(), count: base.count) 63 | } 64 | } 65 | 66 | extension Collection { 67 | func offsetEnumerated() -> OffsetEnumeratedSequence { 68 | return OffsetEnumeratedSequence(self) 69 | } 70 | } 71 | 72 | extension OffsetEnumeratedSequence.OffsetInfo: CustomStringConvertible { 73 | var description: String { 74 | var parts = ["index: \(index)"] 75 | if isStart { parts.append("isStart") } 76 | if isEnd { parts.append("isEnd") } 77 | return "Offset(\(parts.joined(separator: ", ")))" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Utils/String+.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension String { 4 | var hasLazyPrefix: Bool { 5 | hasPrefix("$__lazy_storage_$_") 6 | } 7 | 8 | var stripLazyPrefix: String { 9 | replacingOccurrences(of: "$__lazy_storage_$_", with: "") 10 | } 11 | 12 | var hasWeakPrefix: Bool { 13 | hasPrefix("weak ") 14 | } 15 | 16 | var stripWeakPrefix: String { 17 | replacingOccurrences(of: "weak ", with: "") 18 | } 19 | 20 | var insertBracketIfNeeded: String { 21 | if hasPrefix("("), hasSuffix(")") { 22 | return self 23 | } else { 24 | return "(\(self))" 25 | } 26 | } 27 | } 28 | extension String? { 29 | var valueOrEmpty: String { 30 | self ?? "" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/SwiftDump/Utils/StringBuilder.swift: -------------------------------------------------------------------------------- 1 | @resultBuilder 2 | internal enum StringBuilder { 3 | internal static func buildBlock() -> String { 4 | "" 5 | } 6 | 7 | internal static func buildBlock(_ components: String...) -> [String] { 8 | components 9 | } 10 | 11 | internal static func buildBlock(_ components: CustomStringConvertible...) -> [String] { 12 | components.map { $0.description } 13 | } 14 | 15 | internal static func buildBlock(_ components: [String]...) -> [String] { 16 | components.flatMap { $0 } 17 | } 18 | 19 | internal static func buildBlock(_ components: [CustomStringConvertible]...) -> [String] { 20 | components.flatMap { $0.map { $0.description } } 21 | } 22 | 23 | internal static func buildFinalResult(_ components: [String]) -> String { 24 | components.joined() 25 | } 26 | } 27 | 28 | extension StringBuilder { 29 | internal static func buildPartialBlock(first: CustomStringConvertible) -> [String] { 30 | [first.description] 31 | } 32 | 33 | internal static func buildPartialBlock(accumulated: [String], next: CustomStringConvertible) -> [String] { 34 | accumulated + [next.description] 35 | } 36 | 37 | internal static func buildPartialBlock(first: String) -> [String] { 38 | [first] 39 | } 40 | 41 | internal static func buildPartialBlock(accumulated: [String], next: String) -> [String] { 42 | accumulated + [next] 43 | } 44 | 45 | internal static func buildPartialBlock(first: [String]) -> [String] { 46 | first 47 | } 48 | 49 | internal static func buildPartialBlock(accumulated: [String], next: [String]) -> [String] { 50 | accumulated + next 51 | } 52 | } 53 | 54 | extension StringBuilder { 55 | internal static func buildOptional(_ component: [String]?) -> [String] { 56 | component ?? [] 57 | } 58 | } 59 | 60 | extension StringBuilder { 61 | internal static func buildEither(first component: [String]) -> [String] { 62 | component 63 | } 64 | 65 | internal static func buildEither(second component: [String]) -> [String] { 66 | component 67 | } 68 | } 69 | 70 | extension StringBuilder { 71 | internal static func buildArray(_ components: [[String]]) -> [String] { 72 | components.flatMap { 73 | $0 74 | } 75 | } 76 | } 77 | 78 | struct Indent: CustomStringConvertible { 79 | let level: Int 80 | 81 | var description: String { 82 | String(repeating: " ", count: level * 4) 83 | } 84 | } 85 | 86 | struct BreakLine: CustomStringConvertible { 87 | var description: String { 88 | "\n" 89 | } 90 | } 91 | 92 | struct Space: CustomStringConvertible { 93 | var description: String { 94 | " " 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Tests/DemangleTests/DemanglingTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Testing 3 | @testable import Demangle 4 | 5 | struct DemanglingTests { 6 | @Test func test() async throws { 7 | var demangler = Demangler(scalars: "_$ss8RangeSetV7SwiftUISxRzSZ6StrideRpzrlE13IndexSequenceV8IteratorVySi__G".unicodeScalars) 8 | print(try demangler.demangleSymbol().print()) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/MachOSwiftSectionTests/LayoutTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Testing 3 | @testable import MachOSwiftSection 4 | 5 | @Suite 6 | struct LayoutTests { 7 | 8 | @Test func contextDescriptor() async throws { 9 | #expect(ContextDescriptor.Layout.offset(of: .flags) == 0) 10 | #expect(ContextDescriptor.Layout.offset(of: .parent) == 4) 11 | } 12 | 13 | @Test func typeContextDescriptor() async throws { 14 | #expect(TypeContextDescriptor.Layout.offset(of: .name) == 8) 15 | #expect(TypeContextDescriptor.Layout.offset(of: .accessFunctionPtr) == 12) 16 | #expect(TypeContextDescriptor.Layout.offset(of: .fieldDescriptor) == 16) 17 | print(ClassMetadataObjCInterop.Layout.offset(of: .instanceAddressPoint)) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/MachOSwiftSectionTests/TypeContextDescriptorFlagsTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Testing 3 | @testable import MachOSwiftSection 4 | 5 | @Suite 6 | struct TypeContextDescriptorFlagsTests { 7 | @Test func create() async throws { 8 | let flag = TypeContextDescriptorFlags(rawValue: 0b0000_0000_0000_0010) 9 | #expect(flag.hasSingletonMetadataInitialization == false) 10 | #expect(flag.hasForeignMetadataInitialization == true) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/SwiftDumpTests/DyldCahce+.swift: -------------------------------------------------------------------------------- 1 | import MachOKit 2 | 3 | enum FrameworkNamed: String { 4 | case AppKit 5 | case UIKit 6 | case SwiftUI 7 | case SwiftUICore 8 | case AttributeGraph 9 | case Foundation 10 | case CoreFoundation 11 | case CodableSwiftUI 12 | case AAAFoundationSwift 13 | 14 | var stringValue: String { 15 | "/\(rawValue)" 16 | } 17 | } 18 | 19 | extension DyldCache { 20 | func machOFile(named: FrameworkNamed) -> MachOFile? { 21 | if let found = machOFiles().first(where: { $0.imagePath.contains(named.stringValue) }) { 22 | return found 23 | } 24 | 25 | guard let mainCache else { return nil } 26 | 27 | if let found = mainCache.machOFiles().first(where: { $0.imagePath.contains(named.stringValue) }) { 28 | return found 29 | } 30 | 31 | if let subCaches { 32 | for subCacheEntry in subCaches { 33 | if let subCache = try? subCacheEntry.subcache(for: mainCache), let found = subCache.machOFiles().first(where: { $0.imagePath.contains(named.stringValue) }) { 34 | return found 35 | } 36 | } 37 | } 38 | return nil 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Tests/SwiftDumpTests/SymbolPrintOptions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import MachOSwiftSection 3 | import SwiftDump 4 | 5 | let printOptions: SymbolPrintOptions = { 6 | var options = SymbolPrintOptions.default 7 | options.remove(.displayObjCModule) 8 | options.insert(.synthesizeSugarOnTypes) 9 | options.remove(.displayWhereClauses) 10 | options.remove(.displayExtensionContexts) 11 | options.remove(.showPrivateDiscriminators) 12 | return options 13 | }() 14 | --------------------------------------------------------------------------------