├── .github └── workflows │ └── docc.yml ├── .gitignore ├── .spi.yml ├── .swiftlint.yml ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── LICENSE ├── Makefile ├── Package.swift ├── README.md ├── Sources ├── ELFKit │ ├── Documentation.docc │ │ └── ELFKit.md │ ├── ELFFile+Dynamics.swift │ ├── ELFFile+Strings.swift │ ├── ELFFile.swift │ ├── ELFImage+Dynamics.swift │ ├── ELFImage+Strings.swift │ ├── ELFImage+static.swift │ ├── ELFImage.swift │ ├── ELFKit.swift │ ├── ELFKitError.swift │ ├── Extension │ │ ├── ELFDynamic+.swift │ │ ├── ELFFile+Dynamics32+.swift │ │ ├── ELFFile+Dynamics64+.swift │ │ ├── ELFImage+Dynamics32+.swift │ │ ├── ELFImage+Dynamics64+.swift │ │ ├── FileHandle.swift │ │ ├── String+.swift │ │ ├── UnsafePointer+.swift │ │ └── UnsafeRawPointer+.swift │ ├── Header │ │ ├── ELFHeader │ │ │ ├── ELF32Header.swift │ │ │ ├── ELF64Header.swift │ │ │ └── ELFHeader.swift │ │ ├── Model │ │ │ ├── ELFClass.swift │ │ │ ├── ELFData.swift │ │ │ ├── ELFMachine.swift │ │ │ ├── ELFOSABI.swift │ │ │ ├── ELFType.swift │ │ │ ├── HeaderIdentifier.swift │ │ │ ├── ProgramFlags.swift │ │ │ ├── ProgramType.swift │ │ │ ├── SectionFlags.swift │ │ │ └── SectionType.swift │ │ ├── NoteHeader │ │ │ ├── ELF32NoteHeader.swift │ │ │ └── ELF64NoteHeader.swift │ │ ├── ProgramHeader │ │ │ ├── ELF32ProgramHeader.swift │ │ │ └── ELF64ProgramHeader.swift │ │ └── SectionHeader │ │ │ ├── ELF32SectionHeader.swift │ │ │ └── ELF64SectionHeader.swift │ ├── Model │ │ ├── Dynamic │ │ │ ├── DynamicFlags.swift │ │ │ ├── DynamicFlags1.swift │ │ │ ├── DynamicTag.swift │ │ │ ├── ELF32Dynamic.swift │ │ │ └── ELF64Dynamic.swift │ │ ├── GnuHash │ │ │ ├── ELFGnuHashTable.swift │ │ │ └── ELFGnuHashTableHeader.swift │ │ ├── Hash │ │ │ ├── ELFHashTable.swift │ │ │ └── ELFHashTableHeader.swift │ │ ├── Note │ │ │ ├── ELF32Note.swift │ │ │ ├── ELF64Note.swift │ │ │ ├── ELFNotes.swift │ │ │ └── GNU │ │ │ │ ├── GnuABITag.swift │ │ │ │ ├── GnuHardwareCapabilities.swift │ │ │ │ ├── GnuNoteContent.swift │ │ │ │ └── GnuNoteType.swift │ │ ├── Relocation │ │ │ ├── ELF32Relocation.swift │ │ │ ├── ELF32RelocationInfo.swift │ │ │ ├── ELF64Relocation.swift │ │ │ └── ELF64RelocationInfo.swift │ │ ├── StringTableEntry.swift │ │ ├── Symbol │ │ │ ├── ELFSymbol.swift │ │ │ ├── SpecialSectionIndex.swift │ │ │ ├── SymbolBinding.swift │ │ │ ├── SymbolType.swift │ │ │ └── SymbolVisibility.swift │ │ ├── SymbolInfo │ │ │ ├── ELFSymbolInfo.swift │ │ │ ├── SymbolInfoFlags.swift │ │ │ └── SymbolInfoSpecialBound.swift │ │ ├── Version.swift │ │ └── Version │ │ │ ├── VersionDef │ │ │ ├── ELFVersionDef.swift │ │ │ └── ELFVersionDefAux.swift │ │ │ ├── VersionFlags.swift │ │ │ ├── VersionNeed │ │ │ ├── ELFVersionNeed.swift │ │ │ └── ELFVersionNeedAux.swift │ │ │ └── VersionSym │ │ │ └── ELFVersionSym.swift │ ├── Protocol │ │ ├── ELFDynamicProtocol.swift │ │ ├── ELFDynamicsSequence.swift │ │ ├── ELFFileDynamicsSequence.swift │ │ ├── ELFHashTableProtocol.swift │ │ ├── ELFImageDynamicsSequence.swift │ │ ├── ELFNoteHeaderProtocol.swift │ │ ├── ELFNoteProtocol.swift │ │ ├── ELFProgramHeaderProtocol.swift │ │ ├── ELFRelocationProtocol.swift │ │ ├── ELFRepresentable.swift │ │ ├── ELFSectionHeaderProtocol.swift │ │ ├── ELFSymbolInfoProtocol.swift │ │ ├── ELFSymbolProtocol.swift │ │ ├── ELFVersionDefAuxProtocol.swift │ │ ├── ELFVersionDefProtocol.swift │ │ ├── ELFVersionNeedAuxProtocol.swift │ │ ├── ELFVersionNeedProtocol.swift │ │ ├── ELFVersionSymProtocol.swift │ │ └── LayoutWrapper.swift │ ├── Sections.swift │ ├── Segments.swift │ └── Util │ │ ├── BitFlags.swift │ │ ├── ConditionalBitFlags.swift │ │ ├── Sequence │ │ ├── DataSequence.swift │ │ └── MemorySequence.swift │ │ ├── SwiftDemangle.swift │ │ └── exported.swift └── ELFKitC │ ├── dummy.c │ └── include │ ├── additional.h │ ├── elf32.h │ ├── elf64.h │ ├── elf_common.h │ └── elf_linux.h ├── Tests └── ELFKitTests │ ├── ELFFilePrintTests.swift │ ├── ELFImagePrintTests.swift │ ├── ELFKitTests.swift │ └── Util │ └── Linux.swift └── scripts ├── docc-preview.sh ├── docc.sh └── generate-symbols.sh /.github/workflows/docc.yml: -------------------------------------------------------------------------------- 1 | name: DocC 2 | 3 | on: 4 | workflow_call: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | build: 9 | name: Generate DocC 10 | runs-on: macos-15 11 | steps: 12 | - uses: actions/checkout@v3 13 | 14 | - name: Select Xcode 16 15 | run: sudo xcode-select -s /Applications/Xcode_16.0.app 16 | 17 | - name: Build DocC 18 | run: | 19 | make docc 20 | 21 | - uses: actions/upload-pages-artifact@v3 22 | with: 23 | path: docs 24 | 25 | deploy: 26 | needs: build 27 | permissions: 28 | pages: write 29 | id-token: write 30 | environment: 31 | name: github-pages 32 | url: ${{ steps.deployment.outputs.page_url }} 33 | runs-on: macos-15 34 | steps: 35 | - name: Deploy to GitHub Pages 36 | id: deployment 37 | uses: actions/deploy-pages@v4 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | 10 | # DocC 11 | docs 12 | symbol-graphs 13 | -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | external_links: 3 | documentation: "https://p-x9.github.io/ELFKit/documentation/elfkit/" 4 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 p-x9 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: docc 2 | docc: 3 | bash scripts/docc.sh 4 | 5 | .PHONY: docc-preview 6 | docc-preview: 7 | bash scripts/docc-preview.sh 8 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.9 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "ELFKit", 7 | products: [ 8 | .library( 9 | name: "ELFKit", 10 | targets: ["ELFKit"] 11 | ), 12 | ], 13 | targets: [ 14 | .target( 15 | name: "ELFKit", 16 | dependencies: [ 17 | "ELFKitC" 18 | ] 19 | ), 20 | .target( 21 | name: "ELFKitC" 22 | ), 23 | .testTarget( 24 | name: "ELFKitTests", 25 | dependencies: ["ELFKit"] 26 | ), 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ELFKit 2 | 3 | Library for parsing ELF files to obtain various information. 4 | 5 | 6 | 7 | [![Github issues](https://img.shields.io/github/issues/p-x9/ELFKit)](https://github.com/p-x9/ELFKit/issues) 8 | [![Github forks](https://img.shields.io/github/forks/p-x9/ELFKit)](https://github.com/p-x9/ELFKit/network/members) 9 | [![Github stars](https://img.shields.io/github/stars/p-x9/ELFKit)](https://github.com/p-x9/ELFKit/stargazers) 10 | [![Github top language](https://img.shields.io/github/languages/top/p-x9/ELFKit)](https://github.com/p-x9/ELFKit/) 11 | 12 | ## Features 13 | 14 | - parse segments 15 | - parse sections 16 | - parse dynamics 17 | - symbol list 18 | - get all cstrings 19 | - rebase infos 20 | - notes 21 | - ... 22 | 23 | ## Usage 24 | 25 | ### Load from file 26 | 27 | For reading from file, use the `ELFFile` structure. 28 | 29 | Reading from a file can be as follows. 30 | 31 | ```swift 32 | let path = "Path to MachO file" 33 | let url = URL(string: path) 34 | 35 | let elf = try ELFFile(url: url) 36 | ``` 37 | 38 | ### Example Codes 39 | 40 | There are a variety of uses, but most show a basic example that prints output to the Test directory. 41 | 42 | #### Load from file 43 | 44 | The following file contains sample code. 45 | [ELFFilePrintTests](./Tests/ELFKitTests/ELFFilePrintTests.swift) 46 | 47 | ## Related Projects 48 | 49 | - [MachOKit](https://github.com/p-x9/MachOKit) 50 | A swift library for parsing MachO binaries 51 | 52 | ## License 53 | 54 | ELFKit is released under the MIT License. See [LICENSE](./LICENSE) 55 | -------------------------------------------------------------------------------- /Sources/ELFKit/Documentation.docc/ELFKit.md: -------------------------------------------------------------------------------- 1 | # ``ELFKit`` 2 | 3 | 🔬 A Swift library for parsing ELF files to obtain various information. 4 | -------------------------------------------------------------------------------- /Sources/ELFKit/ELFFile+Dynamics.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFFile+Dynamics.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/02 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | extension ELFFile { 13 | public struct Dynamics32: ELFFileDynamicsSequence { 14 | public typealias Dynamic = ELF32Dynamic 15 | 16 | public typealias Element = ELF32Dynamic 17 | public typealias Iterator = DataSequence.Iterator 18 | 19 | public let sequence: WrappedSequence 20 | 21 | public init(_ sequence: WrappedSequence) { 22 | self.sequence = sequence 23 | } 24 | } 25 | 26 | public struct Dynamics64: ELFFileDynamicsSequence { 27 | public typealias Dynamic = ELF64Dynamic 28 | public typealias Element = ELF64Dynamic 29 | public typealias Iterator = DataSequence.Iterator 30 | 31 | public let sequence: WrappedSequence 32 | 33 | public init(_ sequence: WrappedSequence) { 34 | self.sequence = sequence 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/ELFKit/ELFFile+Strings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFFile+Strings.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol StringTable: Sequence { 12 | associatedtype Encoding: _UnicodeEncoding 13 | } 14 | 15 | extension ELFFile { 16 | public typealias Strings = UnicodeStrings 17 | 18 | public struct UnicodeStrings: StringTable { 19 | public let data: Data 20 | 21 | /// file offset of string table start 22 | public let offset: Int 23 | 24 | /// size of string table 25 | public let size: Int 26 | 27 | public let isLittleEndian: Bool 28 | 29 | public func makeIterator() -> Iterator { 30 | .init(data: data, isLittleEndian: isLittleEndian) 31 | } 32 | } 33 | } 34 | 35 | extension ELFFile.UnicodeStrings { 36 | init( 37 | elf: ELFFile, 38 | offset: Int, 39 | size: Int, 40 | isLittleEndian: Bool = false 41 | ) { 42 | let data = elf.fileHandle.readData( 43 | offset: numericCast(offset), 44 | size: size 45 | ) 46 | self.init( 47 | data: data, 48 | offset: offset, 49 | size: size, 50 | isLittleEndian: isLittleEndian 51 | ) 52 | } 53 | } 54 | 55 | extension ELFFile.UnicodeStrings { 56 | public struct Iterator: IteratorProtocol { 57 | public typealias Element = StringTableEntry 58 | 59 | private let data: Data 60 | private let tableSize: Int 61 | private let isLittleEndian: Bool 62 | 63 | private var nextOffset: Int 64 | 65 | init(data: Data, isLittleEndian: Bool) { 66 | self.data = data 67 | self.tableSize = data.count 68 | self.isLittleEndian = isLittleEndian 69 | self.nextOffset = 0 70 | } 71 | 72 | public mutating func next() -> Element? { 73 | data.withUnsafeBytes { 74 | if nextOffset >= tableSize { return nil } 75 | guard let baseAddress = $0.baseAddress else { return nil } 76 | 77 | let ptr = baseAddress 78 | .advanced(by: nextOffset) 79 | .assumingMemoryBound(to: Encoding.CodeUnit.self) 80 | var (string, offset) = ptr.readString(as: Encoding.self) 81 | 82 | if isLittleEndian { 83 | let data = Data(bytes: ptr, count: offset) 84 | string = data.withUnsafeBytes { 85 | let baseAddress = $0.baseAddress! 86 | .assumingMemoryBound(to: Encoding.CodeUnit.self) 87 | return .init( 88 | decodingCString: baseAddress, 89 | as: Encoding.self 90 | ) 91 | } 92 | } 93 | 94 | let result = Element(string: string, offset: nextOffset) 95 | 96 | nextOffset += offset 97 | 98 | return result 99 | } 100 | } 101 | } 102 | } 103 | 104 | extension ELFFile.Strings { 105 | func string(at offset: Int) -> Element? { 106 | guard data.count >= offset else { return nil } 107 | guard let string = String( 108 | cString: data.advanced(by: offset) 109 | ) else { 110 | return nil 111 | } 112 | return .init(string: string, offset: offset) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Sources/ELFKit/ELFImage+Dynamics.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFImage+Dynamics.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/07 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | extension ELFImage { 13 | public struct Dynamics32: ELFImageDynamicsSequence { 14 | public typealias Dynamic = ELF32Dynamic 15 | 16 | public typealias Element = ELF32Dynamic 17 | public typealias Iterator = MemorySequence.Iterator 18 | 19 | public let sequence: WrappedSequence 20 | 21 | public init(_ sequence: WrappedSequence) { 22 | self.sequence = sequence 23 | } 24 | } 25 | 26 | public struct Dynamics64: ELFImageDynamicsSequence { 27 | public typealias Dynamic = ELF64Dynamic 28 | public typealias Element = ELF64Dynamic 29 | public typealias Iterator = MemorySequence.Iterator 30 | 31 | public let sequence: WrappedSequence 32 | 33 | public init(_ sequence: WrappedSequence) { 34 | self.sequence = sequence 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/ELFKit/ELFImage+Strings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFImage+Strings.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/07 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | extension ELFImage { 12 | public typealias Strings = UnicodeStrings 13 | 14 | public struct UnicodeStrings: StringTable { 15 | public let basePointer: UnsafePointer 16 | public let tableSize: Int 17 | 18 | public let isLittleEndian: Bool 19 | 20 | init( 21 | basePointer: UnsafePointer, 22 | tableSize: Int, 23 | isLittleEndian: Bool = false 24 | ) { 25 | self.basePointer = basePointer 26 | self.tableSize = tableSize 27 | self.isLittleEndian = isLittleEndian 28 | } 29 | 30 | public func makeIterator() -> Iterator { 31 | Iterator( 32 | basePointer: basePointer, 33 | tableSize: tableSize, 34 | isLittleEndian: isLittleEndian 35 | ) 36 | } 37 | } 38 | } 39 | 40 | extension ELFImage.UnicodeStrings { 41 | public struct Iterator: IteratorProtocol { 42 | public typealias Element = StringTableEntry 43 | 44 | private let basePointer: UnsafePointer 45 | private let tableSize: Int 46 | private let isLittleEndian: Bool 47 | 48 | private var nextPointer: UnsafePointer 49 | 50 | init( 51 | basePointer: UnsafePointer, 52 | tableSize: Int, 53 | isLittleEndian: Bool 54 | ) { 55 | self.basePointer = basePointer 56 | self.tableSize = tableSize 57 | self.isLittleEndian = isLittleEndian 58 | self.nextPointer = basePointer 59 | } 60 | 61 | public mutating func next() -> Element? { 62 | let offset = Int(bitPattern: nextPointer) - Int(bitPattern: basePointer) 63 | if offset >= tableSize { 64 | return nil 65 | } 66 | var (string, nextOffset) = nextPointer.readString( 67 | as: Encoding.self 68 | ) 69 | 70 | if isLittleEndian { 71 | let data = Data(bytes: nextPointer, count: offset) 72 | string = data.withUnsafeBytes { 73 | let baseAddress = $0.baseAddress! 74 | .assumingMemoryBound(to: Encoding.CodeUnit.self) 75 | return .init( 76 | decodingCString: baseAddress, 77 | as: Encoding.self 78 | ) 79 | } 80 | } 81 | 82 | nextPointer = nextPointer.advanced( 83 | by: nextOffset / MemoryLayout.size 84 | ) 85 | 86 | return .init(string: string, offset: offset) 87 | } 88 | } 89 | } 90 | 91 | extension ELFImage.Strings { 92 | func string(at offset: Int) -> Element? { 93 | guard tableSize >= offset else { return nil } 94 | let string = String( 95 | cString: UnsafeRawPointer(basePointer) 96 | .advanced(by: offset) 97 | .assumingMemoryBound(to: CChar.self) 98 | ) 99 | return .init(string: string, offset: offset) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Sources/ELFKit/ELFImage+static.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFImage+static.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/07 6 | // 7 | // 8 | 9 | #if os(Linux) 10 | 11 | import Foundation 12 | 13 | public typealias IteratePhdrCallback = @convention(c) (_ info: UnsafeMutablePointer?, _ size: Int, _ data: UnsafeMutableRawPointer?) -> Int32 14 | 15 | extension ELFImage { 16 | public static var images: [ELFImage] { 17 | var images = Ref(values: []) 18 | 19 | let callback: IteratePhdrCallback = { info, size, _images in 20 | guard let info = info?.pointee else { return 0 } 21 | guard let ptr = UnsafeRawPointer(bitPattern: UInt(info.dlpi_addr)) else { 22 | return 0 23 | } 24 | guard let elf = try? ELFImage(ptr: ptr) else { return 0 } 25 | 26 | if let _images { 27 | let images = _images.assumingMemoryBound(to: Ref.self) 28 | images.pointee.append(elf) 29 | } 30 | 31 | return 0 32 | } 33 | 34 | dl_iterate_phdr(callback, &images) 35 | 36 | return images.values 37 | } 38 | } 39 | 40 | fileprivate class Ref { 41 | private(set) var values: [T] 42 | 43 | init(values: [T]) { 44 | self.values = values 45 | } 46 | 47 | func append(_ value: T) { 48 | values.append(value) 49 | } 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /Sources/ELFKit/ELFImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFImage.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/07 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public struct ELFImage: ELFRepresentable { 12 | /// Address of ELF header start 13 | public let ptr: UnsafeRawPointer 14 | 15 | /// A boolean value that indicates whether ELF is a 64-bit architecture. 16 | public var is64Bit: Bool { header.identifier.class == ._64 } 17 | 18 | /// Size of ELF header. [byte] 19 | public var headerSize: Int { 20 | is64Bit ? ELF64Header.layoutSize : ELF32Header.layoutSize 21 | } 22 | 23 | /// ELF header 24 | public let header: ELFHeader 25 | 26 | public init(ptr: UnsafeRawPointer) throws { 27 | self.ptr = .init(ptr) 28 | 29 | guard let identifier: HeaderIdentifier = .init( 30 | layout: ptr.autoBoundPointee() 31 | ) else { throw ELFKitError.invalidPointer } 32 | 33 | let header: ELFHeader 34 | switch identifier.class { 35 | case ._32: 36 | let _header: ELF32Header = ptr.autoBoundPointee() 37 | header = ._32(_header) 38 | case ._64: 39 | let _header: ELF64Header = ptr.autoBoundPointee() 40 | header = ._64(_header) 41 | default: 42 | throw ELFKitError.invalidPointer 43 | } 44 | 45 | self.header = header 46 | } 47 | } 48 | 49 | #if os(Linux) 50 | extension ELFImage { 51 | public init?(name: String) { 52 | var image = Ref(targetName: name, value: nil) 53 | 54 | let callback: IteratePhdrCallback = { info, size, _image in 55 | guard let info = info?.pointee else { return 0 } 56 | guard let path = info.dlpi_name.flatMap({ String(cString: $0) }) else { 57 | return 0 58 | } 59 | let imageName = path 60 | .components(separatedBy: "/") 61 | .last? 62 | .components(separatedBy: ".") 63 | .first 64 | 65 | guard let _image else { return 1 } 66 | let image = _image.assumingMemoryBound(to: Ref.self) 67 | 68 | guard imageName == image.pointee.targetName else { return 0 } 69 | 70 | guard let ptr = UnsafeRawPointer(bitPattern: UInt(info.dlpi_addr)) else { 71 | return 1 // stop iterate 72 | } 73 | guard let elf = try? ELFImage(ptr: ptr) else { return 1 } 74 | image.pointee.set(elf) 75 | 76 | return 1 77 | } 78 | 79 | dl_iterate_phdr(callback, &image) 80 | 81 | guard let image = image.value else { return nil } 82 | self = image 83 | } 84 | } 85 | 86 | fileprivate class Ref { 87 | let targetName: String 88 | private(set) var value: T 89 | 90 | init(targetName: String, value: T) { 91 | self.targetName = targetName 92 | self.value = value 93 | } 94 | 95 | func set(_ value: T) { 96 | self.value = value 97 | } 98 | } 99 | #endif 100 | 101 | extension ELFImage { 102 | public var programs32: MemorySequence? { 103 | guard !is64Bit else { return nil } 104 | return .init( 105 | basePointer: ptr 106 | .advanced(by: header.programTableOffset) 107 | .assumingMemoryBound(to: ELF32ProgramHeader.self), 108 | numberOfElements: header.numberOfPrograms 109 | ) 110 | } 111 | 112 | public var programs64: MemorySequence? { 113 | guard is64Bit else { return nil } 114 | return .init( 115 | basePointer: ptr 116 | .advanced(by: header.programTableOffset) 117 | .assumingMemoryBound(to: ELF64ProgramHeader.self), 118 | numberOfElements: header.numberOfPrograms 119 | ) 120 | } 121 | } 122 | 123 | extension ELFImage { 124 | public var dynamics64: Dynamics64? { 125 | guard is64Bit else { return nil } 126 | if let dynamic = programs64?._dynamic, 127 | let wrapped = dynamic._dynamics(in: self) { 128 | return .init(wrapped) 129 | } 130 | return nil 131 | } 132 | 133 | public var dynamics32: Dynamics32? { 134 | guard !is64Bit else { return nil } 135 | if let dynamic = programs32?._dynamic, 136 | let wrapped = dynamic._dynamics(in: self) { 137 | return .init(wrapped) 138 | } 139 | return nil 140 | } 141 | } 142 | 143 | extension ELFImage { 144 | public var dynamicSymbols32: MemorySequence? { 145 | guard !is64Bit else { return nil } 146 | return dynamics32?.symbols(in: self) 147 | } 148 | 149 | public var dynamicSymbols64: MemorySequence? { 150 | guard is64Bit else { return nil} 151 | return dynamics64?.symbols(in: self) 152 | } 153 | } 154 | 155 | extension ELFImage { 156 | public var dynamicStringTable: Strings? { 157 | if let dynamics64 { 158 | return dynamics64.strings(in: self) 159 | } else if let dynamics32 { 160 | return dynamics32.strings(in: self) 161 | } 162 | return nil 163 | } 164 | } 165 | 166 | extension ELFImage { 167 | /// List of runpaths 168 | public var rpaths: [String] { 169 | if let dynamics64 { 170 | let rpaths = dynamics64.rpaths(in: self) 171 | let runpaths = dynamics64.runpaths(in: self) 172 | return rpaths + runpaths 173 | } 174 | if let dynamics32 { 175 | let rpaths = dynamics32.rpaths(in: self) 176 | let runpaths = dynamics32.runpaths(in: self) 177 | return rpaths + runpaths 178 | } 179 | return [] 180 | } 181 | } 182 | 183 | extension ELFImage { 184 | /// List of depended shared objects. 185 | public var dependencies: [String] { 186 | if let dynamics64 { 187 | return dynamics64.neededs(in: self) 188 | } 189 | if let dynamics32 { 190 | return dynamics32.neededs(in: self) 191 | } 192 | return [] 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /Sources/ELFKit/ELFKit.swift: -------------------------------------------------------------------------------- 1 | // The Swift Programming Language 2 | // https://docs.swift.org/swift-book 3 | -------------------------------------------------------------------------------- /Sources/ELFKit/ELFKitError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFKitError.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/12 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public enum ELFKitError: Error { 12 | case invalidFile 13 | case invalidPointer 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ELFKit/Extension/ELFDynamic+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFDynamic+.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/28 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | extension Sequence where Element: ELFDynamicProtocol { 12 | var _neededs: [Element] { filter { $0._commonTag == .needed } } 13 | var _soname: Element? { first(where: { $0._commonTag == .soname }) } 14 | 15 | var _strtab: Element? { first(where: { $0._commonTag == .strtab }) } 16 | var _strsiz: Element? { first(where: { $0._commonTag == .strsz }) } 17 | 18 | var _hash: Element? { first(where: { $0._commonTag == .hash }) } 19 | func _gnu_hash(inELF header: ELFHeader) -> Element? { 20 | first(where: { $0.tag(inELF: header) == .gnu_hash }) 21 | } 22 | 23 | var _symtab: Element? { first(where: { $0._commonTag == .symtab }) } 24 | var _syment: Element? { first(where: { $0._commonTag == .syment }) } 25 | 26 | var _rela: Element? { first(where: { $0._commonTag == .rela }) } 27 | var _relasz: Element? { first(where: { $0._commonTag == .relasz }) } 28 | var _relacount: Element? { first(where: { $0._commonTag == .relacount }) } 29 | var _relaent: Element? { first(where: { $0._commonTag == .relaent }) } 30 | var _rel: Element? { first(where: { $0._commonTag == .rel }) } 31 | var _relsz: Element? { first(where: { $0._commonTag == .relsz }) } 32 | var _relcount: Element? { first(where: { $0._commonTag == .relcount }) } 33 | var _relent: Element? { first(where: { $0._commonTag == .relent }) } 34 | 35 | var _rpath: [Element] { filter { $0._commonTag == .rpath } } 36 | var _runpath: [Element] { filter { $0._commonTag == .runpath } } 37 | 38 | var _flags: Element? { first(where: { $0._commonTag == .flags }) } 39 | var _flags_1: Element? { first(where: { $0._commonTag == .flags_1 }) } 40 | 41 | var _syminfo: Element? { first(where: { $0._commonTag == .syminfo }) } 42 | var _syminsz: Element? { first(where: { $0._commonTag == .syminsz }) } 43 | 44 | var _verdef: Element? { first(where: { $0._commonTag == .verdef }) } 45 | var _verdefnum: Element? { first(where: { $0._commonTag == .verdefnum }) } 46 | 47 | var _verneed: Element? { first(where: { $0._commonTag == .verneed }) } 48 | var _verneednum: Element? { first(where: { $0._commonTag == .verneednum }) } 49 | 50 | var _versym: Element? { first(where: { $0._commonTag == .versym }) } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/ELFKit/Extension/ELFFile+Dynamics32+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFFile+Dynamics32+.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/02 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | // MARK: - Relocations 13 | extension ELFFile.Dynamics32 { 14 | public func relocations(in elf: ELFFile) -> AnyRandomAccessCollection? { 15 | if let _rel, let relcount { 16 | guard let offset = elf.fileOffset(of: _rel.pointer) else { 17 | return nil 18 | } 19 | let sequence: DataSequence = elf.fileHandle.readDataSequence( 20 | offset: numericCast(offset), 21 | numberOfElements: relcount 22 | ) 23 | return AnyRandomAccessCollection( 24 | sequence.map { .general($0) } 25 | ) 26 | } 27 | 28 | if let _rela, let relacount { 29 | guard let offset = elf.fileOffset(of: _rela.pointer) else { 30 | return nil 31 | } 32 | let sequence: DataSequence = elf.fileHandle.readDataSequence( 33 | offset: numericCast(offset), 34 | numberOfElements: relacount 35 | ) 36 | return AnyRandomAccessCollection( 37 | sequence.map { .addend($0) } 38 | ) 39 | } 40 | return nil 41 | } 42 | } 43 | 44 | // MARK: - Version Defs 45 | extension ELFFile.Dynamics32 { 46 | public func _versionDef(in elf: ELFFile) -> ELF32VersionDef? { 47 | guard let _verdef else { return nil } 48 | guard let offset = elf.fileOffset(of: _verdef.pointer) else { 49 | return nil 50 | } 51 | let layout: ELF32VersionDef.Layout = elf.fileHandle.read( 52 | offset: numericCast(offset) 53 | ) 54 | return .init( 55 | layout: layout, 56 | _index: 0, 57 | _offset: numericCast(offset) 58 | ) 59 | } 60 | } 61 | 62 | // MARK: - Version Needs 63 | extension ELFFile.Dynamics32 { 64 | public func _versionNeed(in elf: ELFFile) -> ELF32VersionNeed? { 65 | guard let _verneed else { return nil } 66 | guard let offset = elf.fileOffset(of: _verneed.pointer) else { 67 | return nil 68 | } 69 | let layout: ELF32VersionNeed.Layout = elf.fileHandle.read( 70 | offset: numericCast(offset) 71 | ) 72 | return .init( 73 | layout: layout, 74 | _index: 0, 75 | _offset: numericCast(offset) 76 | ) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Sources/ELFKit/Extension/ELFFile+Dynamics64+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFFile+Dynamics64+.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/02 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | // MARK: - Relocations 13 | extension ELFFile.Dynamics64 { 14 | public func relocations(in elf: ELFFile) -> AnyRandomAccessCollection? { 15 | if let _rel, let relcount { 16 | guard let offset = elf.fileOffset(of: _rel.pointer) else { 17 | return nil 18 | } 19 | let sequence: DataSequence = elf.fileHandle.readDataSequence( 20 | offset: numericCast(offset), 21 | numberOfElements: relcount 22 | ) 23 | return AnyRandomAccessCollection( 24 | sequence.map { .general($0) } 25 | ) 26 | } 27 | 28 | if let _rela, let relacount { 29 | guard let offset = elf.fileOffset(of: _rela.pointer) else { 30 | return nil 31 | } 32 | let sequence: DataSequence = elf.fileHandle.readDataSequence( 33 | offset: numericCast(offset), 34 | numberOfElements: relacount 35 | ) 36 | return AnyRandomAccessCollection( 37 | sequence.map { .addend($0) } 38 | ) 39 | } 40 | return nil 41 | } 42 | } 43 | 44 | // MARK: - Version Defs 45 | extension ELFFile.Dynamics64 { 46 | public func _versionDef(in elf: ELFFile) -> ELF64VersionDef? { 47 | guard let _verdef else { return nil } 48 | guard let offset = elf.fileOffset(of: _verdef.pointer) else { 49 | return nil 50 | } 51 | let layout: ELF64VersionDef.Layout = elf.fileHandle.read( 52 | offset: numericCast(offset) 53 | ) 54 | return .init( 55 | layout: layout, 56 | _index: 0, 57 | _offset: numericCast(offset) 58 | ) 59 | } 60 | } 61 | 62 | // MARK: - Version Needs 63 | extension ELFFile.Dynamics64 { 64 | public func _versionNeed(in elf: ELFFile) -> ELF64VersionNeed? { 65 | guard let _verneed else { return nil } 66 | guard let offset = elf.fileOffset(of: _verneed.pointer) else { 67 | return nil 68 | } 69 | let layout: ELF64VersionNeed.Layout = elf.fileHandle.read( 70 | offset: numericCast(offset) 71 | ) 72 | return .init( 73 | layout: layout, 74 | _index: 0, 75 | _offset: numericCast(offset) 76 | ) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Sources/ELFKit/Extension/ELFImage+Dynamics32+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFImage+Dynamics32+.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/08 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | // MARK: - Relocations 13 | extension ELFImage.Dynamics32 { 14 | public func relocations(in elf: ELFImage) -> AnyRandomAccessCollection? { 15 | if let _rel, let relcount { 16 | guard let pointer = _rel.pointer(for: elf) else { 17 | return nil 18 | } 19 | let sequence: MemorySequence = .init( 20 | basePointer: pointer 21 | .assumingMemoryBound(to: ELF32RelocationInfo.self), 22 | numberOfElements: relcount 23 | ) 24 | return AnyRandomAccessCollection( 25 | sequence.map { .general($0) } 26 | ) 27 | } 28 | 29 | if let _rela, let relacount { 30 | guard let pointer = _rela.pointer(for: elf) else { 31 | return nil 32 | } 33 | let sequence: MemorySequence = .init( 34 | basePointer: pointer 35 | .assumingMemoryBound(to: ELF32RelocationAddendInfo.self), 36 | numberOfElements: relacount 37 | ) 38 | return AnyRandomAccessCollection( 39 | sequence.map { .addend($0) } 40 | ) 41 | } 42 | return nil 43 | } 44 | } 45 | 46 | // MARK: - Version Defs 47 | extension ELFImage.Dynamics32 { 48 | public func _versionDef(in elf: ELFImage) -> ELF32VersionDef? { 49 | guard let _verdef else { return nil } 50 | guard let pointer = _verdef.pointer(for: elf) else { 51 | return nil 52 | } 53 | let layout: ELF32VersionDef.Layout = pointer.autoBoundPointee() 54 | return .init( 55 | layout: layout, 56 | _index: 0, 57 | _offset: Int(bitPattern: pointer) - Int(bitPattern: elf.ptr) 58 | ) 59 | } 60 | } 61 | 62 | // MARK: - Version Needs 63 | extension ELFImage.Dynamics32 { 64 | public func _versionNeed(in elf: ELFImage) -> ELF32VersionNeed? { 65 | guard let _verneed else { return nil } 66 | guard let pointer = _verneed.pointer(for: elf) else { 67 | return nil 68 | } 69 | let layout: ELF32VersionNeed.Layout = pointer.autoBoundPointee() 70 | return .init( 71 | layout: layout, 72 | _index: 0, 73 | _offset: Int(bitPattern: pointer) - Int(bitPattern: elf.ptr) 74 | ) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sources/ELFKit/Extension/ELFImage+Dynamics64+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFImage+Dynamics64+.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/08 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | // MARK: - Relocations 13 | extension ELFImage.Dynamics64 { 14 | public func relocations(in elf: ELFImage) -> AnyRandomAccessCollection? { 15 | if let _rel, let relcount { 16 | guard let pointer = _rel.pointer(for: elf) else { 17 | return nil 18 | } 19 | let sequence: MemorySequence = .init( 20 | basePointer: pointer 21 | .assumingMemoryBound(to: ELF64RelocationInfo.self), 22 | numberOfElements: relcount 23 | ) 24 | return AnyRandomAccessCollection( 25 | sequence.map { .general($0) } 26 | ) 27 | } 28 | 29 | if let _rela, let relacount { 30 | guard let pointer = _rela.pointer(for: elf) else { 31 | return nil 32 | } 33 | let sequence: MemorySequence = .init( 34 | basePointer: pointer 35 | .assumingMemoryBound(to: ELF64RelocationAddendInfo.self), 36 | numberOfElements: relacount 37 | ) 38 | return AnyRandomAccessCollection( 39 | sequence.map { .addend($0) } 40 | ) 41 | } 42 | return nil 43 | } 44 | } 45 | 46 | // MARK: - Version Defs 47 | extension ELFImage.Dynamics64 { 48 | public func _versionDef(in elf: ELFImage) -> ELF64VersionDef? { 49 | guard let _verdef else { return nil } 50 | guard let pointer = _verdef.pointer(for: elf) else { 51 | return nil 52 | } 53 | let layout: ELF64VersionDef.Layout = pointer.autoBoundPointee() 54 | return .init( 55 | layout: layout, 56 | _index: 0, 57 | _offset: Int(bitPattern: pointer) - Int(bitPattern: elf.ptr) 58 | ) 59 | } 60 | } 61 | 62 | // MARK: - Version Needs 63 | extension ELFImage.Dynamics64 { 64 | public func _versionNeed(in elf: ELFImage) -> ELF64VersionNeed? { 65 | guard let _verneed else { return nil } 66 | guard let pointer = _verneed.pointer(for: elf) else { 67 | return nil 68 | } 69 | let layout: ELF64VersionNeed.Layout = pointer.autoBoundPointee() 70 | return .init( 71 | layout: layout, 72 | _index: 0, 73 | _offset: Int(bitPattern: pointer) - Int(bitPattern: elf.ptr) 74 | ) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sources/ELFKit/Extension/FileHandle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FileHandle+.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/01/20. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | extension FileHandle { 12 | @_spi(Support) 13 | public func readDataSequence( 14 | offset: UInt64, 15 | numberOfElements: Int, 16 | swapHandler: ((inout Data) -> Void)? = nil 17 | ) -> DataSequence where Element: LayoutWrapper { 18 | seek(toFileOffset: offset) 19 | let size = Element.layoutSize * numberOfElements 20 | var data = readData( 21 | ofLength: size 22 | ) 23 | precondition( 24 | Element.layoutSize == MemoryLayout.size, 25 | "Invalid Layout Size" 26 | ) 27 | precondition( 28 | data.count >= size, 29 | "Invalid Data Size" 30 | ) 31 | if let swapHandler { swapHandler(&data) } 32 | return .init( 33 | data: data, 34 | numberOfElements: numberOfElements 35 | ) 36 | } 37 | 38 | @_spi(Support) 39 | @_disfavoredOverload 40 | public func readDataSequence( 41 | offset: UInt64, 42 | numberOfElements: Int, 43 | swapHandler: ((inout Data) -> Void)? = nil 44 | ) -> DataSequence { 45 | seek(toFileOffset: offset) 46 | let size = MemoryLayout.size * numberOfElements 47 | var data = readData( 48 | ofLength: size 49 | ) 50 | precondition( 51 | data.count >= size, 52 | "Invalid Data Size" 53 | ) 54 | if let swapHandler { swapHandler(&data) } 55 | return .init( 56 | data: data, 57 | numberOfElements: numberOfElements 58 | ) 59 | } 60 | 61 | @_spi(Support) 62 | public func readDataSequence( 63 | offset: UInt64, 64 | entrySize: Int, 65 | numberOfElements: Int, 66 | swapHandler: ((inout Data) -> Void)? = nil 67 | ) -> DataSequence where Element: LayoutWrapper { 68 | seek(toFileOffset: offset) 69 | let size = entrySize * numberOfElements 70 | var data = readData( 71 | ofLength: size 72 | ) 73 | precondition( 74 | Element.layoutSize == MemoryLayout.size, 75 | "Invalid Layout Size" 76 | ) 77 | precondition( 78 | data.count >= size, 79 | "Invalid Data Size" 80 | ) 81 | if let swapHandler { swapHandler(&data) } 82 | return .init( 83 | data: data, 84 | entrySize: entrySize 85 | ) 86 | } 87 | 88 | @_spi(Support) 89 | @_disfavoredOverload 90 | public func readDataSequence( 91 | offset: UInt64, 92 | entrySize: Int, 93 | numberOfElements: Int, 94 | swapHandler: ((inout Data) -> Void)? = nil 95 | ) -> DataSequence { 96 | seek(toFileOffset: offset) 97 | let size = entrySize * numberOfElements 98 | var data = readData( 99 | ofLength: size 100 | ) 101 | precondition( 102 | data.count >= size, 103 | "Invalid Data Size" 104 | ) 105 | if let swapHandler { swapHandler(&data) } 106 | return .init( 107 | data: data, 108 | entrySize: entrySize 109 | ) 110 | } 111 | } 112 | 113 | extension FileHandle { 114 | @_spi(Support) 115 | public func read( 116 | offset: UInt64, 117 | swapHandler: ((inout Data) -> Void)? = nil 118 | ) -> Optional where Element: LayoutWrapper { 119 | seek(toFileOffset: offset) 120 | var data = readData( 121 | ofLength: Element.layoutSize 122 | ) 123 | precondition( 124 | Element.layoutSize == MemoryLayout.size, 125 | "Invalid Layout Size" 126 | ) 127 | precondition( 128 | data.count >= Element.layoutSize, 129 | "Invalid Data Size" 130 | ) 131 | if let swapHandler { swapHandler(&data) } 132 | return data.withUnsafeBytes { 133 | $0.load(as: Element.self) 134 | } 135 | } 136 | 137 | @_spi(Support) 138 | public func read( 139 | offset: UInt64, 140 | swapHandler: ((inout Data) -> Void)? = nil 141 | ) -> Optional { 142 | seek(toFileOffset: offset) 143 | var data = readData( 144 | ofLength: MemoryLayout.size 145 | ) 146 | precondition( 147 | data.count >= MemoryLayout.size, 148 | "Invalid Data Size" 149 | ) 150 | if let swapHandler { swapHandler(&data) } 151 | return data.withUnsafeBytes { 152 | $0.load(as: Element.self) 153 | } 154 | } 155 | 156 | @_spi(Support) 157 | public func read( 158 | offset: UInt64, 159 | swapHandler: ((inout Data) -> Void)? = nil 160 | ) -> Element where Element: LayoutWrapper { 161 | seek(toFileOffset: offset) 162 | var data = readData( 163 | ofLength: Element.layoutSize 164 | ) 165 | precondition( 166 | Element.layoutSize == MemoryLayout.size, 167 | "Invalid Layout Size" 168 | ) 169 | precondition( 170 | data.count >= Element.layoutSize, 171 | "Invalid Data Size" 172 | ) 173 | if let swapHandler { swapHandler(&data) } 174 | return data.withUnsafeBytes { 175 | $0.load(as: Element.self) 176 | } 177 | } 178 | 179 | @_spi(Support) 180 | public func read( 181 | offset: UInt64, 182 | swapHandler: ((inout Data) -> Void)? = nil 183 | ) -> Element { 184 | seek(toFileOffset: offset) 185 | var data = readData( 186 | ofLength: MemoryLayout.size 187 | ) 188 | precondition( 189 | data.count >= MemoryLayout.size, 190 | "Invalid Data Size" 191 | ) 192 | if let swapHandler { swapHandler(&data) } 193 | return data.withUnsafeBytes { 194 | $0.load(as: Element.self) 195 | } 196 | } 197 | } 198 | 199 | extension FileHandle { 200 | @_spi(Support) 201 | public func readString( 202 | offset: UInt64, 203 | size: Int 204 | ) -> String? { 205 | let data = readData( 206 | offset: offset, 207 | size: size 208 | ) 209 | return String(cString: data) 210 | } 211 | 212 | @_spi(Support) 213 | public func readString( 214 | offset: UInt64, 215 | step: UInt64 = 10 216 | ) -> String? { 217 | var data = Data() 218 | var offset = offset 219 | while true { 220 | let new = readData(offset: offset, size: Int(step)) 221 | if new.isEmpty { break } 222 | data.append(new) 223 | if new.contains(0) { break } 224 | offset += UInt64(new.count) 225 | } 226 | 227 | return String(cString: data) 228 | } 229 | 230 | @_spi(Support) 231 | public func readData( 232 | offset: UInt64, 233 | size: Int 234 | ) -> Data { 235 | seek(toFileOffset: offset) 236 | return readData( 237 | ofLength: size 238 | ) 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /Sources/ELFKit/Extension/String+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | typealias UInt8Tuple16 = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) 13 | 14 | init(tuple: UInt8Tuple16) { 15 | self = withUnsafePointer(to: tuple) { 16 | let size = MemoryLayout.size 17 | let data = Data(bytes: $0, count: size) + [0] 18 | return String(cString: data) ?? "" 19 | } 20 | } 21 | } 22 | 23 | extension String { 24 | init?(cString data: Data) { 25 | guard !data.isEmpty else { return nil } 26 | self = data.withUnsafeBytes { 27 | let ptr = $0.baseAddress!.assumingMemoryBound(to: CChar.self) 28 | return String(cString: ptr) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/ELFKit/Extension/UnsafePointer+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UnsafePointer+.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/07 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | extension UnsafePointer { 12 | func readString() -> (String, Int) { 13 | let offset = Int(bitPattern: strchr(self, 0)) + 1 - Int(bitPattern: self) 14 | let string = String(cString: self) 15 | 16 | return (string, offset) 17 | } 18 | } 19 | 20 | extension UnsafePointer { 21 | func readString() -> (String, Int) { 22 | let offset = Int(bitPattern: strchr(self, 0)) + 1 - Int(bitPattern: self) 23 | let string = String(cString: self) 24 | 25 | return (string, offset) 26 | } 27 | } 28 | 29 | extension UnsafePointer where Pointee: FixedWidthInteger { 30 | func findNullTerminator() -> UnsafePointer { 31 | var ptr = self 32 | while ptr.pointee != 0 { 33 | ptr = ptr.advanced(by: 1) 34 | } 35 | return ptr 36 | } 37 | 38 | func readString( 39 | as encoding: Encoding.Type 40 | ) -> (String, Int) where Pointee == Encoding.CodeUnit { 41 | let nullTerminator = findNullTerminator() 42 | let offset = Int(bitPattern: nullTerminator) + MemoryLayout.size - Int(bitPattern: self) 43 | let string = String(decodingCString: self, as: Encoding.self) 44 | 45 | return (string, offset) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/ELFKit/Extension/UnsafeRawPointer+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UnsafeRawPointer+.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/07 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | extension UnsafeRawPointer { 12 | func autoBoundPointee() -> Out { 13 | bindMemory(to: Out.self, capacity: 1).pointee 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/ELFHeader/ELF32Header.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF32Header.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32Header: LayoutWrapper { 13 | public typealias Layout = Elf32_Ehdr 14 | public var layout: Layout 15 | } 16 | 17 | extension ELF32Header { 18 | public var identifier: HeaderIdentifier! { 19 | .init(layout: layout.e_ident) 20 | } 21 | 22 | public var type: ELFType! { 23 | .init(rawValue: layout.e_type) 24 | } 25 | 26 | public var machine: ELFMachine! { 27 | .init(rawValue: numericCast(layout.e_machine)) 28 | } 29 | 30 | public var osABI: ELFOSABI! { 31 | .init( 32 | rawValue: identifier.layout.7, // EI_OSABI 33 | machine: machine 34 | ) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/ELFHeader/ELF64Header.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF64Header.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF64Header: LayoutWrapper { 13 | public var layout: Elf64_Ehdr 14 | } 15 | 16 | extension ELF64Header { 17 | public var identifier: HeaderIdentifier! { 18 | .init(layout: layout.e_ident) 19 | } 20 | 21 | public var type: ELFType { 22 | .init(rawValue: layout.e_type)! 23 | } 24 | 25 | public var machine: ELFMachine! { 26 | .init(rawValue: numericCast(layout.e_machine)) 27 | } 28 | 29 | public var osABI: ELFOSABI! { 30 | .init( 31 | rawValue: identifier.layout.7, // EI_OSABI 32 | machine: machine 33 | ) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/ELFHeader/ELFHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFHeader.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public enum ELFHeader { 12 | case _32(ELF32Header) 13 | case _64(ELF64Header) 14 | } 15 | 16 | extension ELFHeader { 17 | public var identifier: HeaderIdentifier! { 18 | switch self { 19 | case ._32(let v): v.identifier 20 | case ._64(let v): v.identifier 21 | } 22 | } 23 | 24 | public var type: ELFType! { 25 | switch self { 26 | case ._32(let v): v.type 27 | case ._64(let v): v.type 28 | } 29 | } 30 | 31 | public var machine: ELFMachine! { 32 | switch self { 33 | case ._32(let v): v.machine 34 | case ._64(let v): v.machine 35 | } 36 | } 37 | 38 | public var osABI: ELFOSABI! { 39 | switch self { 40 | case ._32(let v): v.osABI 41 | case ._64(let v): v.osABI 42 | } 43 | } 44 | } 45 | 46 | extension ELFHeader { 47 | public var sectionTableOffset: Int { 48 | switch self { 49 | case ._32(let v): numericCast(v.e_shoff) 50 | case ._64(let v): numericCast(v.e_shoff) 51 | } 52 | } 53 | 54 | public var sectionTableEntrySize: Int { 55 | switch self { 56 | case ._32(let v): numericCast(v.e_shentsize) 57 | case ._64(let v): numericCast(v.e_shentsize) 58 | } 59 | } 60 | 61 | public var numberOfSections: Int { 62 | switch self { 63 | case ._32(let v): numericCast(v.e_shnum) 64 | case ._64(let v): numericCast(v.e_shnum) 65 | } 66 | } 67 | 68 | public var sectionNameStringTableIndex: Int { 69 | switch self { 70 | case ._32(let v): numericCast(v.e_shstrndx) 71 | case ._64(let v): numericCast(v.e_shstrndx) 72 | } 73 | } 74 | } 75 | 76 | extension ELFHeader { 77 | public var programTableOffset: Int { 78 | switch self { 79 | case ._32(let v): numericCast(v.e_phoff) 80 | case ._64(let v): numericCast(v.e_phoff) 81 | } 82 | } 83 | 84 | public var programTableEntrySize: Int { 85 | switch self { 86 | case ._32(let v): numericCast(v.e_phentsize) 87 | case ._64(let v): numericCast(v.e_phentsize) 88 | } 89 | } 90 | 91 | public var numberOfPrograms: Int { 92 | switch self { 93 | case ._32(let v): numericCast(v.e_phnum) 94 | case ._64(let v): numericCast(v.e_phnum) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/Model/ELFClass.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFClass.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public enum ELFClass: UInt8 { 13 | /// ELFCLASSNONE 14 | case none = 0 15 | /// ELFCLASS32 16 | case _32 = 1 17 | /// ELFCLASS64 18 | case _64 = 2 19 | } 20 | 21 | extension ELFClass: CustomStringConvertible { 22 | public var description: String { 23 | switch self { 24 | case .none: "ELFCLASSNONE" 25 | case ._32: "ELFCLASS32" 26 | case ._64: "ELFCLASS64" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/Model/ELFData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFData.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public enum ELFData: UInt8 { 13 | /// ELFDATANONE 14 | case none = 0 15 | /// ELFDATA2LSB 16 | case _2lsb = 1 17 | /// ELFDATA2MSB 18 | case _2msb = 2 19 | } 20 | 21 | extension ELFData: CustomStringConvertible { 22 | public var description: String { 23 | switch self { 24 | case .none: "ELFDATANONE" 25 | case ._2lsb: "ELFDATA2LSB" 26 | case ._2msb: "ELFDATA2MSB" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/Model/ELFOSABI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFOSABI.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/28 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public enum ELFOSABI: CaseIterable { 12 | /// ELFOSABI_NONE 13 | case none 14 | /// ELFOSABI_HPUX 15 | case hpux 16 | /// ELFOSABI_NETBSD 17 | case netbsd 18 | // /// ELFOSABI_GNU 19 | // case gnu 20 | /// ELFOSABI_LINUX 21 | case linux 22 | /// ELFOSABI_HURD 23 | case hurd 24 | /// ELFOSABI_86OPEN 25 | case _86open 26 | /// ELFOSABI_SOLARIS 27 | case solaris 28 | /// ELFOSABI_AIX 29 | case aix 30 | /// ELFOSABI_IRIX 31 | case irix 32 | /// ELFOSABI_FREEBSD 33 | case freebsd 34 | /// ELFOSABI_TRU64 35 | case tru64 36 | /// ELFOSABI_MODESTO 37 | case modesto 38 | /// ELFOSABI_OPENBSD 39 | case openbsd 40 | /// ELFOSABI_OPENVMS 41 | case openvms 42 | /// ELFOSABI_NSK 43 | case nsk 44 | /// ELFOSABI_AROS 45 | case aros 46 | /// ELFOSABI_FENIXOS 47 | case fenixos 48 | /// ELFOSABI_CLOUDABI 49 | case cloudabi 50 | /// ELFOSABI_OPENVOS 51 | case openvos 52 | /// ELFOSABI_C6000_ELFABI 53 | case c6000_elfabi 54 | /// ELFOSABI_AMDGPU_HSA 55 | case amdgpu_hsa 56 | /// ELFOSABI_C6000_LINUX 57 | case c6000_linux 58 | /// ELFOSABI_AMDGPU_PAL 59 | case amdgpu_pal 60 | /// ELFOSABI_ARM_FDPIC 61 | case arm_fdpic 62 | /// ELFOSABI_AMDGPU_MESA3D 63 | case amdgpu_mesa3d 64 | /// ELFOSABI_ARM 65 | case arm 66 | /// ELFOSABI_STANDALONE 67 | case standalone 68 | } 69 | 70 | extension ELFOSABI/*: RawRepresentable*/ { 71 | public typealias RawValue = UInt8 72 | 73 | public init?(rawValue: RawValue, machine: ELFMachine) { 74 | switch rawValue { 75 | case 0: self = .none 76 | case 1: self = .hpux 77 | case 2: self = .netbsd 78 | // case 3: self = .gnu 79 | case 3: self = .linux 80 | case 4: self = .hurd 81 | case 5: self = ._86open 82 | case 6: self = .solaris 83 | case 7: self = .aix 84 | case 8: self = .irix 85 | case 9: self = .freebsd 86 | case 10: self = .tru64 87 | case 11: self = .modesto 88 | case 12: self = .openbsd 89 | case 13: self = .openvms 90 | case 14: self = .nsk 91 | case 15: self = .aros 92 | case 16: self = .fenixos 93 | case 17: self = .cloudabi 94 | case 18: self = .openvos 95 | case _ where machine == .amdgpu: 96 | switch rawValue { 97 | case 64: self = .amdgpu_hsa 98 | case 65: self = .amdgpu_pal 99 | case 66: self = .amdgpu_mesa3d 100 | default: return nil 101 | } 102 | case _ where machine == .arm: 103 | switch rawValue { 104 | case 65: self = .arm_fdpic 105 | case 97: self = .arm 106 | default: return nil 107 | } 108 | case _ where [.msp430, .visium].contains(machine): 109 | switch rawValue { 110 | case 0xff: self = .standalone 111 | default: return nil 112 | } 113 | case _ where machine == .ti_c6000: 114 | switch rawValue { 115 | case 64: self = .c6000_elfabi 116 | case 65: self = .c6000_linux 117 | default: return nil 118 | } 119 | default: return nil 120 | } 121 | } 122 | public var rawValue: RawValue { 123 | switch self { 124 | case .none: 0 125 | case .hpux: 1 126 | case .netbsd: 2 127 | // case .gnu: 3 128 | case .linux: 3 129 | case .hurd: 4 130 | case ._86open: 5 131 | case .solaris: 6 132 | case .aix: 7 133 | case .irix: 8 134 | case .freebsd: 9 135 | case .tru64: 10 136 | case .modesto: 11 137 | case .openbsd: 12 138 | case .openvms: 13 139 | case .nsk: 14 140 | case .aros: 15 141 | case .fenixos: 16 142 | case .cloudabi: 17 143 | case .openvos: 18 144 | case .c6000_elfabi: 64 145 | case .amdgpu_hsa: 64 146 | case .c6000_linux: 65 147 | case .amdgpu_pal: 65 148 | case .arm_fdpic: 65 149 | case .amdgpu_mesa3d: 66 150 | case .arm: 97 151 | case .standalone: 0xff 152 | } 153 | } 154 | } 155 | extension ELFOSABI: CustomStringConvertible { 156 | public var description: String { 157 | switch self { 158 | case .none: "ELFOSABI_NONE" 159 | case .hpux: "ELFOSABI_HPUX" 160 | case .netbsd: "ELFOSABI_NETBSD" 161 | // case .gnu: "ELFOSABI_GNU" 162 | case .linux: "ELFOSABI_LINUX" 163 | case .hurd: "ELFOSABI_HURD" 164 | case ._86open: "ELFOSABI_86OPEN" 165 | case .solaris: "ELFOSABI_SOLARIS" 166 | case .aix: "ELFOSABI_AIX" 167 | case .irix: "ELFOSABI_IRIX" 168 | case .freebsd: "ELFOSABI_FREEBSD" 169 | case .tru64: "ELFOSABI_TRU64" 170 | case .modesto: "ELFOSABI_MODESTO" 171 | case .openbsd: "ELFOSABI_OPENBSD" 172 | case .openvms: "ELFOSABI_OPENVMS" 173 | case .nsk: "ELFOSABI_NSK" 174 | case .aros: "ELFOSABI_AROS" 175 | case .fenixos: "ELFOSABI_FENIXOS" 176 | case .cloudabi: "ELFOSABI_CLOUDABI" 177 | case .openvos: "ELFOSABI_OPENVOS" 178 | case .c6000_elfabi: "ELFOSABI_C6000_ELFABI" 179 | case .amdgpu_hsa: "ELFOSABI_AMDGPU_HSA" 180 | case .c6000_linux: "ELFOSABI_C6000_LINUX" 181 | case .amdgpu_pal: "ELFOSABI_AMDGPU_PAL" 182 | case .arm_fdpic: "ELFOSABI_ARM_FDPIC" 183 | case .amdgpu_mesa3d: "ELFOSABI_AMDGPU_MESA3D" 184 | case .arm: "ELFOSABI_ARM" 185 | case .standalone: "ELFOSABI_STANDALONE" 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/Model/ELFType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFType.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public enum ELFType: UInt16, CaseIterable { 13 | /// ET_NONE 14 | case none = 0 15 | /// ET_REL 16 | case rel = 1 17 | /// ET_EXEC 18 | case exec = 2 19 | /// ET_DYN 20 | case dyn = 3 21 | /// ET_CORE 22 | case core = 4 23 | } 24 | 25 | extension ELFType: CustomStringConvertible { 26 | public var description: String { 27 | switch self { 28 | case .none: "ET_NONE" 29 | case .rel: "ET_REL" 30 | case .exec: "ET_EXEC" 31 | case .dyn: "ET_DYN" 32 | case .core: "ET_CORE" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/Model/HeaderIdentifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeaderIdentifier.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct HeaderIdentifier: LayoutWrapper { 13 | public typealias Layout = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) 14 | 15 | public var layout: Layout 16 | 17 | init?(layout: Layout) { 18 | guard layout.0 == 0x7f, /* EI_MAG0 */ 19 | layout.1 == UInt8(ascii: "E") /* EI_MAG1 */, 20 | layout.2 == UInt8(ascii: "L") /* EI_MAG2 */, 21 | layout.3 == UInt8(ascii: "F") /* EI_MAG3 */ else { 22 | return nil 23 | } 24 | self.layout = layout 25 | } 26 | } 27 | 28 | extension HeaderIdentifier { 29 | public var `class`: ELFClass! { 30 | .init(rawValue: layout.4) /* EI_CLASS */ 31 | } 32 | 33 | public var data: ELFData! { 34 | .init(rawValue: layout.5) /* EI_DATA */ 35 | } 36 | 37 | public var version: UInt8 { 38 | layout.6 /* EI_VERSION */ 39 | } 40 | 41 | /* OSABI */ 42 | // EI_OSABI 43 | // Not defined here because OSABI needs to take into account the value of the `machine` in the header. 44 | 45 | public var abiVersion: UInt8 { 46 | layout.8 // EI_ABIVERSION 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/Model/ProgramFlags.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProgramFlags.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ProgramFlags: ConditionalBitFlags { 13 | public typealias RawValue = UInt32 14 | 15 | public var rawValue: RawValue 16 | public var _bits: Set 17 | 18 | public init(rawValue: RawValue, _bits: Set) { 19 | self.rawValue = rawValue 20 | self._bits = _bits 21 | } 22 | 23 | public init( 24 | rawValue: RawValue, 25 | osabi: ELFOSABI, 26 | machine: ELFMachine 27 | ) { 28 | self.rawValue = rawValue 29 | 30 | var bits: [Bit] = [] 31 | var mask: RawValue = 1 32 | for _ in 0.. 0 52 | } 53 | 54 | public var isProcessorSpecific: Bool { 55 | let PF_MASKPROC = 0xf0000000 56 | return (rawValue & numericCast(PF_MASKPROC)) > 0 57 | } 58 | } 59 | 60 | extension ProgramFlags { 61 | public enum Bit: CaseIterable { 62 | /// PF_X 63 | case x 64 | /// PF_W 65 | case w 66 | /// PF_R 67 | case r 68 | /// PF_ARM_SB 69 | case arm_sb 70 | /// PF_ARM_PI 71 | case arm_pi 72 | /// PF_ARM_ABS 73 | case arm_abs 74 | /// PF_HP_CODE 75 | case hp_code 76 | /// PF_HP_MODIFY 77 | case hp_modify 78 | /// PF_HP_PAGE_SIZE 79 | case hp_page_size 80 | /// PF_HP_FAR_SHARED 81 | case hp_far_shared 82 | /// PF_HP_NEAR_SHARED 83 | case hp_near_shared 84 | /// PF_HP_LAZYSWAP 85 | case hp_lazyswap 86 | /// PF_HP_CODE_DEPR 87 | case hp_code_depr 88 | /// PF_HP_MODIFY_DEPR 89 | case hp_modify_depr 90 | /// PF_HP_LAZYSWAP_DEPR 91 | case hp_lazyswap_depr 92 | /// PF_PARISC_SBP 93 | case parisc_sbp 94 | /// PF_HP_SBP 95 | case hp_sbp 96 | /// PF_IA_64_NORECOV 97 | case ia_64_norecov 98 | /// PF_PPC_VLE 99 | case ppc_vle 100 | /// PF_OVERLAY 101 | case overlay 102 | } 103 | } 104 | 105 | extension ProgramFlags.Bit: RawRepresentable { 106 | public typealias RawValue = UInt32 107 | 108 | public init?(rawValue: RawValue) { 109 | self.init( 110 | rawValue: rawValue, 111 | osabi: .none, 112 | machine: .none 113 | ) 114 | } 115 | 116 | public init?( 117 | rawValue: RawValue, 118 | osabi: ELFOSABI, 119 | machine: ELFMachine 120 | ) { 121 | switch rawValue { 122 | case 0x00000001: self = .x 123 | case 0x00000002: self = .w 124 | case 0x00000004: self = .r 125 | default: 126 | switch (osabi, machine, rawValue) { 127 | case (_, .arm, 0x10000000): self = .arm_sb 128 | case (_, .arm, 0x20000000): self = .arm_pi 129 | case (_, .arm, 0x40000000): self = .arm_abs 130 | case (.hpux, _, 0x01000000): self = .hp_code 131 | case (.hpux, _, 0x02000000): self = .hp_modify 132 | case (.hpux, _, 0x00100000): self = .hp_page_size 133 | case (.hpux, _, 0x00200000): self = .hp_far_shared 134 | case (.hpux, _, 0x00400000): self = .hp_near_shared 135 | case (.hpux, _, 0x04000000): self = .hp_lazyswap 136 | case (.hpux, _, 0x01000000): self = .hp_code_depr 137 | case (.hpux, _, 0x02000000): self = .hp_modify_depr 138 | case (.hpux, _, 0x04000000): self = .hp_lazyswap_depr 139 | case (.hpux, .parisc, 0x08000000): self = .parisc_sbp 140 | case (.hpux, _, 0x08000000): self = .hp_sbp 141 | case (_, .ia_64, 0x80000000): self = .ia_64_norecov 142 | case (_, .ppc, 0x10000000): self = .ppc_vle 143 | case (_, .spu, 0x08000000): self = .overlay 144 | default: return nil 145 | } 146 | } 147 | } 148 | 149 | public var rawValue: RawValue { 150 | switch self { 151 | case .x: 0x00000001 152 | case .w: 0x00000002 153 | case .r: 0x00000004 154 | case .arm_sb: 0x10000000 155 | case .arm_pi: 0x20000000 156 | case .arm_abs: 0x40000000 157 | case .hp_code: 0x01000000 158 | case .hp_modify: 0x02000000 159 | case .hp_page_size: 0x00100000 160 | case .hp_far_shared: 0x00200000 161 | case .hp_near_shared: 0x00400000 162 | case .hp_lazyswap: 0x04000000 163 | case .hp_code_depr: 0x01000000 164 | case .hp_modify_depr: 0x02000000 165 | case .hp_lazyswap_depr: 0x04000000 166 | case .parisc_sbp: 0x08000000 167 | case .hp_sbp: 0x08000000 168 | case .ia_64_norecov: 0x80000000 169 | case .ppc_vle: 0x10000000 170 | case .overlay: 0x08000000 171 | } 172 | } 173 | } 174 | 175 | extension ProgramFlags.Bit: CustomStringConvertible { 176 | public var description: String { 177 | switch self { 178 | case .x: "PF_X" 179 | case .w: "PF_W" 180 | case .r: "PF_R" 181 | case .arm_sb: "PF_ARM_SB" 182 | case .arm_pi: "PF_ARM_PI" 183 | case .arm_abs: "PF_ARM_ABS" 184 | case .hp_code: "PF_HP_CODE" 185 | case .hp_modify: "PF_HP_MODIFY" 186 | case .hp_page_size: "PF_HP_PAGE_SIZE" 187 | case .hp_far_shared: "PF_HP_FAR_SHARED" 188 | case .hp_near_shared: "PF_HP_NEAR_SHARED" 189 | case .hp_lazyswap: "PF_HP_LAZYSWAP" 190 | case .hp_code_depr: "PF_HP_CODE_DEPR" 191 | case .hp_modify_depr: "PF_HP_MODIFY_DEPR" 192 | case .hp_lazyswap_depr: "PF_HP_LAZYSWAP_DEPR" 193 | case .parisc_sbp: "PF_PARISC_SBP" 194 | case .hp_sbp: "PF_HP_SBP" 195 | case .ia_64_norecov: "PF_IA_64_NORECOV" 196 | case .ppc_vle: "PF_PPC_VLE" 197 | case .overlay: "PF_OVERLAY" 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/NoteHeader/ELF32NoteHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF32NoteHeader.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32NoteHeader: LayoutWrapper { 13 | public typealias Layout = Elf32_Nhdr 14 | 15 | public var layout: Layout 16 | } 17 | 18 | extension ELF32NoteHeader: ELFNoteHeaderProtocol { 19 | public var nameSize: Int { 20 | numericCast(layout.n_namesz) 21 | } 22 | 23 | public var descriptionSize: Int { 24 | numericCast(layout.n_descsz) 25 | } 26 | 27 | public var type: Int { 28 | numericCast(layout.n_type) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/NoteHeader/ELF64NoteHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF64NoteHeader.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF64NoteHeader: LayoutWrapper { 13 | public typealias Layout = Elf64_Nhdr 14 | 15 | public var layout: Layout 16 | } 17 | 18 | extension ELF64NoteHeader: ELFNoteHeaderProtocol { 19 | public var nameSize: Int { 20 | numericCast(layout.n_namesz) 21 | } 22 | 23 | public var descriptionSize: Int { 24 | numericCast(layout.n_descsz) 25 | } 26 | 27 | public var type: Int { 28 | numericCast(layout.n_type) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/ProgramHeader/ELF32ProgramHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF32ProgramHeader.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32ProgramHeader: LayoutWrapper { 13 | public typealias Layout = Elf32_Phdr 14 | 15 | public var layout: Layout 16 | } 17 | 18 | extension ELF32ProgramHeader: ELFProgramHeaderProtocol { 19 | public typealias Relocation = ELF32Relocation 20 | public typealias Note = ELF32Note 21 | public typealias Dynamic = ELF32Dynamic 22 | 23 | public var _commonType: ProgramType? { 24 | .init( 25 | rawValue: layout.p_type, 26 | osabi: .none, 27 | machine: .none 28 | ) 29 | } 30 | 31 | public func type(inELF header: ELFHeader) -> ProgramType? { 32 | .init( 33 | rawValue: layout.p_type, 34 | osabi: header.osABI ?? .none, 35 | machine: header.machine ?? .none 36 | ) 37 | } 38 | 39 | public var _commonFlags: ProgramFlags { 40 | .init( 41 | rawValue: numericCast(layout.p_flags), 42 | osabi: .none, 43 | machine: .none 44 | ) 45 | } 46 | 47 | public func flags(inELF header: ELFHeader) -> ProgramFlags { 48 | .init( 49 | rawValue: numericCast(layout.p_flags), 50 | osabi: header.osABI ?? .none, 51 | machine: header.machine ?? .none 52 | ) 53 | } 54 | 55 | public var offset: Int { numericCast(layout.p_offset) } 56 | public var virtualAddress: Int { numericCast(layout.p_vaddr) } 57 | public var physicalAddress: Int { numericCast(layout.p_paddr) } 58 | public var fileSize: Int { numericCast(layout.p_filesz) } 59 | public var memorySize: Int { numericCast(layout.p_memsz) } 60 | public var align: Int { numericCast(layout.p_align) } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/ProgramHeader/ELF64ProgramHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF64ProgramHeader.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF64ProgramHeader: LayoutWrapper { 13 | public typealias Layout = Elf64_Phdr 14 | 15 | public var layout: Layout 16 | } 17 | 18 | extension ELF64ProgramHeader: ELFProgramHeaderProtocol { 19 | public typealias Relocation = ELF64Relocation 20 | public typealias Note = ELF64Note 21 | public typealias Dynamic = ELF64Dynamic 22 | 23 | public var _commonType: ProgramType? { 24 | .init( 25 | rawValue: layout.p_type, 26 | osabi: .none, 27 | machine: .none 28 | ) 29 | } 30 | 31 | public func type(inELF header: ELFHeader) -> ProgramType? { 32 | .init( 33 | rawValue: layout.p_type, 34 | osabi: header.osABI ?? .none, 35 | machine: header.machine ?? .none 36 | ) 37 | } 38 | 39 | public var _commonFlags: ProgramFlags { 40 | .init( 41 | rawValue: numericCast(layout.p_flags), 42 | osabi: .none, 43 | machine: .none 44 | ) 45 | } 46 | 47 | public func flags(inELF header: ELFHeader) -> ProgramFlags { 48 | .init( 49 | rawValue: numericCast(layout.p_flags), 50 | osabi: header.osABI ?? .none, 51 | machine: header.machine ?? .none 52 | ) 53 | } 54 | 55 | public var offset: Int { numericCast(layout.p_offset) } 56 | public var virtualAddress: Int { numericCast(layout.p_vaddr) } 57 | public var physicalAddress: Int { numericCast(layout.p_paddr) } 58 | public var fileSize: Int { numericCast(layout.p_filesz) } 59 | public var memorySize: Int { numericCast(layout.p_memsz) } 60 | public var align: Int { numericCast(layout.p_align) } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/SectionHeader/ELF32SectionHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF32SectionHeader.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32SectionHeader: LayoutWrapper { 13 | public typealias Layout = Elf32_Shdr 14 | 15 | public var layout: Layout 16 | } 17 | 18 | extension ELF32SectionHeader: ELFSectionHeaderProtocol { 19 | public typealias Relocation = ELF32Relocation 20 | public typealias Note = ELF32Note 21 | public typealias Dynamic = ELF32Dynamic 22 | 23 | public var nameOffset: Int { numericCast(layout.sh_name) } 24 | 25 | public var _commonType: SectionType? { 26 | .init( 27 | rawValue: layout.sh_type, 28 | osabi: .none, 29 | machine: .none 30 | ) 31 | } 32 | 33 | public func type(inELF header: ELFHeader) -> SectionType? { 34 | .init( 35 | rawValue: layout.sh_type, 36 | osabi: header.osABI ?? .none, 37 | machine: header.machine ?? .none 38 | ) 39 | } 40 | 41 | public var _commonFlags: SectionFlags { 42 | .init( 43 | rawValue: numericCast(layout.sh_flags), 44 | osabi: .none, 45 | machine: .none 46 | ) 47 | } 48 | 49 | public func flags(inELF header: ELFHeader) -> SectionFlags { 50 | .init( 51 | rawValue: numericCast(layout.sh_flags), 52 | osabi: header.osABI ?? .none, 53 | machine: header.machine ?? .none 54 | ) 55 | } 56 | 57 | public var address: Int { numericCast(layout.sh_addr) } 58 | public var offset: Int { numericCast(layout.sh_offset) } 59 | public var size: Int { numericCast(layout.sh_size) } 60 | public var link: Int { numericCast(layout.sh_link) } 61 | public var addressAlignment: Int { numericCast(layout.sh_addralign) } 62 | public var entrySize: Int { numericCast(layout.sh_entsize) } 63 | } 64 | 65 | extension ELF32SectionHeader { 66 | public func _relocations(in elf: ELFFile) -> AnyRandomAccessCollection? { 67 | switch type(inELF: elf.header) { 68 | case .rel: 69 | let count = size / ELF32RelocationInfo.layoutSize 70 | let sequence: DataSequence = elf.fileHandle.readDataSequence( 71 | offset: numericCast(offset), 72 | numberOfElements: count 73 | ) 74 | return AnyRandomAccessCollection( 75 | sequence 76 | .map { 77 | .general($0) 78 | } 79 | ) 80 | case .rela: 81 | let count = size / ELF32RelocationAddendInfo.layoutSize 82 | let sequence: DataSequence = elf.fileHandle.readDataSequence( 83 | offset: numericCast(offset), 84 | numberOfElements: count 85 | ) 86 | return AnyRandomAccessCollection( 87 | sequence 88 | .map { 89 | .addend($0) 90 | } 91 | ) 92 | default: 93 | return nil 94 | } 95 | } 96 | } 97 | 98 | // MARK: - Version Defs 99 | extension ELF32SectionHeader { 100 | public func _versionDef(in elf: ELFFile) -> ELF32VersionDef? { 101 | guard [.gnu_verdef, .sunw_verdef].contains(type(inELF: elf.header)) else { 102 | return nil 103 | } 104 | let layout: ELF32VersionDef.Layout = elf.fileHandle.read( 105 | offset: numericCast(offset) 106 | ) 107 | return .init( 108 | layout: layout, 109 | _index: 0, 110 | _offset: offset 111 | ) 112 | } 113 | } 114 | 115 | // MARK: - Verson Needs 116 | extension ELF32SectionHeader { 117 | public func _versionNeed(in elf: ELFFile) -> ELF32VersionNeed? { 118 | guard [.gnu_verneed, .sunw_verneed].contains(type(inELF: elf.header)) else { 119 | return nil 120 | } 121 | let layout: ELF32VersionNeed.Layout = elf.fileHandle.read( 122 | offset: numericCast(offset) 123 | ) 124 | return .init( 125 | layout: layout, 126 | _index: 0, 127 | _offset: offset 128 | ) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Sources/ELFKit/Header/SectionHeader/ELF64SectionHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF64SectionHeader.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF64SectionHeader: LayoutWrapper { 13 | public typealias Layout = Elf64_Shdr 14 | 15 | public var layout: Layout 16 | } 17 | 18 | extension ELF64SectionHeader: ELFSectionHeaderProtocol { 19 | public typealias Relocation = ELF64Relocation 20 | public typealias Note = ELF64Note 21 | public typealias Dynamic = ELF64Dynamic 22 | 23 | public var nameOffset: Int { numericCast(layout.sh_name) } 24 | 25 | public var _commonType: SectionType? { 26 | .init( 27 | rawValue: layout.sh_type, 28 | osabi: .none, 29 | machine: .none 30 | ) 31 | } 32 | 33 | public func type(inELF header: ELFHeader) -> SectionType? { 34 | .init( 35 | rawValue: layout.sh_type, 36 | osabi: header.osABI ?? .none, 37 | machine: header.machine ?? .none 38 | ) 39 | } 40 | 41 | public var _commonFlags: SectionFlags { 42 | .init( 43 | rawValue: numericCast(layout.sh_flags), 44 | osabi: .none, 45 | machine: .none 46 | ) 47 | } 48 | 49 | public func flags(inELF header: ELFHeader) -> SectionFlags { 50 | .init( 51 | rawValue: numericCast(layout.sh_flags), 52 | osabi: header.osABI ?? .none, 53 | machine: header.machine ?? .none 54 | ) 55 | } 56 | 57 | public var address: Int { numericCast(layout.sh_addr) } 58 | public var offset: Int { numericCast(layout.sh_offset) } 59 | public var size: Int { numericCast(layout.sh_size) } 60 | public var link: Int { numericCast(layout.sh_link) } 61 | public var addressAlignment: Int { numericCast(layout.sh_addralign) } 62 | public var entrySize: Int { numericCast(layout.sh_entsize) } 63 | } 64 | 65 | extension ELF64SectionHeader { 66 | public func _relocations(in elf: ELFFile) -> AnyRandomAccessCollection? { 67 | switch type(inELF: elf.header) { 68 | case .rel: 69 | let count = size / ELF64RelocationInfo.layoutSize 70 | let sequence: DataSequence = elf.fileHandle.readDataSequence( 71 | offset: numericCast(offset), 72 | numberOfElements: count 73 | ) 74 | return AnyRandomAccessCollection( 75 | sequence.map { .general($0) } 76 | ) 77 | case .rela: 78 | let count = size / ELF64RelocationAddendInfo.layoutSize 79 | let sequence: DataSequence = elf.fileHandle.readDataSequence( 80 | offset: numericCast(offset), 81 | numberOfElements: count 82 | ) 83 | return AnyRandomAccessCollection( 84 | sequence.map { .addend($0) } 85 | ) 86 | default: 87 | return nil 88 | } 89 | } 90 | } 91 | 92 | // MARK: - Version Defs 93 | extension ELF64SectionHeader { 94 | public func _versionDef(in elf: ELFFile) -> ELF64VersionDef? { 95 | // name: .gnu.* or .SUNW_* 96 | guard [.gnu_verdef, .sunw_verdef].contains(type(inELF: elf.header)) else { 97 | return nil 98 | } 99 | let layout: ELF64VersionDef.Layout = elf.fileHandle.read( 100 | offset: numericCast(offset) 101 | ) 102 | return .init( 103 | layout: layout, 104 | _index: 0, 105 | _offset: offset 106 | ) 107 | } 108 | } 109 | 110 | // MARK: - Verson Needs 111 | extension ELF64SectionHeader { 112 | public func _versionNeed(in elf: ELFFile) -> ELF64VersionNeed? { 113 | guard [.gnu_verneed, .sunw_verneed].contains(type(inELF: elf.header)) else { 114 | return nil 115 | } 116 | let layout: ELF64VersionNeed.Layout = elf.fileHandle.read( 117 | offset: numericCast(offset) 118 | ) 119 | return .init( 120 | layout: layout, 121 | _index: 0, 122 | _offset: offset 123 | ) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Dynamic/DynamicFlags.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicFlags.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct DynamicFlags: BitFlags { 13 | public typealias RawValue = UInt32 14 | 15 | public var rawValue: RawValue 16 | 17 | public init(rawValue: RawValue) { 18 | self.rawValue = rawValue 19 | } 20 | } 21 | 22 | extension DynamicFlags { 23 | /// DF_ORIGIN 24 | public static let origin = DynamicFlags( 25 | rawValue: Bit.origin.rawValue 26 | ) 27 | /// DF_SYMBOLIC 28 | public static let symbolic = DynamicFlags( 29 | rawValue: Bit.symbolic.rawValue 30 | ) 31 | /// DF_TEXTREL 32 | public static let textrel = DynamicFlags( 33 | rawValue: Bit.textrel.rawValue 34 | ) 35 | /// DF_BIND_NOW 36 | public static let bind_now = DynamicFlags( 37 | rawValue: Bit.bind_now.rawValue 38 | ) 39 | /// DF_STATIC_TLS 40 | public static let static_tls = DynamicFlags( 41 | rawValue: Bit.static_tls.rawValue 42 | ) 43 | } 44 | 45 | extension DynamicFlags { 46 | public enum Bit: UInt32, CaseIterable { 47 | /// DF_ORIGIN 48 | case origin = 1 49 | /// DF_SYMBOLIC 50 | case symbolic = 2 51 | /// DF_TEXTREL 52 | case textrel = 4 53 | /// DF_BIND_NOW 54 | case bind_now = 8 55 | /// DF_STATIC_TLS 56 | case static_tls = 0x10 57 | } 58 | } 59 | 60 | extension DynamicFlags.Bit: CustomStringConvertible { 61 | public var description: String { 62 | switch self { 63 | case .origin: "DF_ORIGIN" 64 | case .symbolic: "DF_SYMBOLIC" 65 | case .textrel: "DF_TEXTREL" 66 | case .bind_now: "DF_BIND_NOW" 67 | case .static_tls: "DF_STATIC_TLS" 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Dynamic/ELF32Dynamic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF32Dynamic.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/28 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32Dynamic: LayoutWrapper { 13 | public typealias Layout = Elf32_Dyn 14 | 15 | public typealias HashTable = ELF32HashTable 16 | public typealias GnuHashTable = ELF32GnuHashTable 17 | public typealias Symbol = ELF32Symbol 18 | public typealias Relocation = ELF32Relocation 19 | public typealias SymbolInfo = ELF32SymbolInfo 20 | public typealias VersionDef = ELF32VersionDef 21 | public typealias VersionNeed = ELF32VersionNeed 22 | public typealias VersionSym = ELF32VersionSym 23 | 24 | public var layout: Layout 25 | } 26 | 27 | extension ELF32Dynamic: ELFDynamicProtocol { 28 | public var _commonTag: DynamicTag? { 29 | .init( 30 | rawValue: numericCast(layout.d_tag), 31 | osabi: .none, 32 | machine: .none 33 | ) 34 | } 35 | 36 | public func tag(inELF header: ELFHeader) -> DynamicTag? { 37 | .init( 38 | rawValue: numericCast(layout.d_tag), 39 | osabi: header.osABI ?? .none, 40 | machine: header.machine ?? .none 41 | ) 42 | } 43 | 44 | public var value: Int { 45 | numericCast(layout.d_un.d_val) 46 | } 47 | 48 | public var pointer: Int { 49 | numericCast(layout.d_un.d_ptr) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Dynamic/ELF64Dynamic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF64Dynamic.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/28 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF64Dynamic: LayoutWrapper { 13 | public typealias Layout = Elf64_Dyn 14 | 15 | public typealias HashTable = ELF64HashTable 16 | public typealias GnuHashTable = ELF64GnuHashTable 17 | public typealias Symbol = ELF64Symbol 18 | public typealias Relocation = ELF64Relocation 19 | public typealias SymbolInfo = ELF64SymbolInfo 20 | public typealias VersionDef = ELF64VersionDef 21 | public typealias VersionNeed = ELF64VersionNeed 22 | public typealias VersionSym = ELF64VersionSym 23 | 24 | public var layout: Layout 25 | } 26 | 27 | extension ELF64Dynamic: ELFDynamicProtocol { 28 | public var _commonTag: DynamicTag? { 29 | .init( 30 | rawValue: numericCast(layout.d_tag), 31 | osabi: .none, 32 | machine: .none 33 | ) 34 | } 35 | 36 | public func tag(inELF header: ELFHeader) -> DynamicTag? { 37 | .init( 38 | rawValue: numericCast(layout.d_tag), 39 | osabi: header.osABI ?? .none, 40 | machine: header.machine ?? .none 41 | ) 42 | } 43 | 44 | public var value: Int { 45 | numericCast(layout.d_un.d_val) 46 | } 47 | 48 | public var pointer: Int { 49 | numericCast(layout.d_un.d_ptr) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/GnuHash/ELFGnuHashTable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFGnuHashTable.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/29 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32GnuHashTable: ELFGnuHashTableProtocol { 13 | public typealias Hashelt = Elf32_Hashelt 14 | public typealias Bloom = UInt32 15 | public typealias Symbol = ELF32Symbol 16 | 17 | public let header: ELFGnuHashTableHeader 18 | 19 | public let bloom: [Bloom] 20 | public let buckets: [Hashelt] 21 | // public let chains: [Hashelt] 22 | public let chainsOffset: Int 23 | 24 | public init( 25 | header: ELFGnuHashTableHeader, 26 | bloom: [Bloom], 27 | buckets: [Hashelt], 28 | chainsOffset: Int 29 | ) { 30 | self.header = header 31 | self.bloom = bloom 32 | self.buckets = buckets 33 | self.chainsOffset = chainsOffset 34 | } 35 | } 36 | 37 | public struct ELF64GnuHashTable: ELFGnuHashTableProtocol { 38 | public typealias Hashelt = Elf64_Hashelt 39 | public typealias Bloom = UInt64 40 | public typealias Symbol = ELF64Symbol 41 | 42 | public let header: ELFGnuHashTableHeader 43 | 44 | public let bloom: [Bloom] 45 | public let buckets: [Hashelt] 46 | // public let chains: [Hashelt] 47 | public let chainsOffset: Int 48 | 49 | public init( 50 | header: ELFGnuHashTableHeader, 51 | bloom: [Bloom], 52 | buckets: [Hashelt], 53 | chainsOffset: Int 54 | ) { 55 | self.header = header 56 | self.bloom = bloom 57 | self.buckets = buckets 58 | self.chainsOffset = chainsOffset 59 | } 60 | } 61 | 62 | extension ELF32GnuHashTable { 63 | public func findSymbol( 64 | named symbol: String, 65 | in elf: ELFFile 66 | ) -> Symbol? { 67 | guard let dynamics = elf.dynamics32, 68 | let symbols = dynamics.symbols(in: elf) else { 69 | return nil 70 | } 71 | return _findSymbol( 72 | named: symbol, 73 | in: elf, 74 | bits: 32, 75 | symbols: symbols 76 | ) 77 | } 78 | 79 | public func findSymbol( 80 | named symbol: String, 81 | in elf: ELFImage 82 | ) -> Symbol? { 83 | guard let dynamics = elf.dynamics32, 84 | let symbols = dynamics.symbols(in: elf) else { 85 | return nil 86 | } 87 | return _findSymbol( 88 | named: symbol, 89 | in: elf, 90 | bits: 32, 91 | symbols: symbols 92 | ) 93 | } 94 | } 95 | 96 | extension ELF64GnuHashTable { 97 | public func findSymbol( 98 | named symbol: String, 99 | in elf: ELFFile 100 | ) -> Symbol? { 101 | guard let dynamics = elf.dynamics64, 102 | let symbols = dynamics.symbols(in: elf) else { 103 | return nil 104 | } 105 | return _findSymbol( 106 | named: symbol, 107 | in: elf, 108 | bits: 64, 109 | symbols: symbols 110 | ) 111 | } 112 | 113 | public func findSymbol( 114 | named symbol: String, 115 | in elf: ELFImage 116 | ) -> Symbol? { 117 | guard let dynamics = elf.dynamics64, 118 | let symbols = dynamics.symbols(in: elf) else { 119 | return nil 120 | } 121 | return _findSymbol( 122 | named: symbol, 123 | in: elf, 124 | bits: 64, 125 | symbols: symbols 126 | ) 127 | } 128 | } 129 | 130 | fileprivate extension ELFGnuHashTableProtocol { 131 | // ref: https://flapenguin.me/elf-dt-gnu-hash 132 | // ref: https://github.com/bminor/glibc/blob/ea73eb5f581ef5931fd67005aa0c526ba43366c9/elf/dl-lookup.c#L340 133 | func _findSymbol( 134 | named symbol: String, 135 | in elf: ELFFile, 136 | bits: Int, 137 | symbols: DataSequence 138 | ) -> Symbol? { 139 | let hashTable = self 140 | let header = hashTable.header 141 | 142 | let hash = Self.hash(for: symbol) 143 | 144 | let word = hashTable.bloom[(hash / bits) % numericCast(header.gh_maskwords)] 145 | let mask: Bloom = 0 | 1 << (hash % bits) | 1 << ((hash >> Bloom(header.gh_shift2)) % bits) 146 | 147 | if (word & mask) != mask { 148 | // Symbol Not Found" 149 | return nil 150 | } 151 | 152 | var symix = hashTable.buckets[hash % numericCast(header.gh_nbuckets)] 153 | if symix < numericCast(header.gh_symndx) { 154 | // Symbol Not Found 155 | return nil 156 | } 157 | 158 | while true { 159 | let current = symbols[Int(symix)] 160 | let name = current.name(in: elf, isDynamic: true) 161 | let nhash: UInt32 = elf.fileHandle.read( 162 | offset: numericCast( hashTable.chainsOffset) + numericCast(MemoryLayout.size) * numericCast(UInt32(symix) - header.gh_symndx)) 163 | if (hash | 1) == (nhash | 1) && name == symbol { 164 | return current 165 | } 166 | if (hash & 1) != 0 { break } 167 | symix += 1 168 | } 169 | 170 | return nil 171 | } 172 | 173 | func _findSymbol( 174 | named symbol: String, 175 | in elf: ELFImage, 176 | bits: Int, 177 | symbols: MemorySequence 178 | ) -> Symbol? { 179 | let hashTable = self 180 | let header = hashTable.header 181 | 182 | let hash = Self.hash(for: symbol) 183 | 184 | let word = hashTable.bloom[(hash / bits) % numericCast(header.gh_maskwords)] 185 | let mask: Bloom = 0 | 1 << (hash % bits) | 1 << ((hash >> Bloom(header.gh_shift2)) % bits) 186 | 187 | if (word & mask) != mask { 188 | // Symbol Not Found" 189 | return nil 190 | } 191 | 192 | var symix = hashTable.buckets[hash % numericCast(header.gh_nbuckets)] 193 | if symix < numericCast(header.gh_symndx) { 194 | // Symbol Not Found 195 | return nil 196 | } 197 | 198 | while true { 199 | let current = symbols[Int(symix)] 200 | let name = current.name(in: elf, isDynamic: true) 201 | let nhash: UInt32 = elf.ptr 202 | .advanced( 203 | by: numericCast( hashTable.chainsOffset) + numericCast(MemoryLayout.size) * numericCast(UInt32(symix) - header.gh_symndx) 204 | ) 205 | .autoBoundPointee() 206 | if (hash | 1) == (nhash | 1) && name == symbol { 207 | return current 208 | } 209 | if (hash & 1) != 0 { break } 210 | symix += 1 211 | } 212 | 213 | return nil 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/GnuHash/ELFGnuHashTableHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFGnuHashTableHeader.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/29 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public struct ELFGnuHashTableHeader: LayoutWrapper { 12 | public typealias Layout = Elf_GNU_Hash_Header 13 | public var layout: Layout 14 | } 15 | 16 | extension ELFGnuHashTableHeader { 17 | func _readContent( 18 | in elf: ELFFile, 19 | at offset: Int 20 | ) -> Table { 21 | var header: Self { self } 22 | let bloomsStart: Int = numericCast(offset) + numericCast(header.layoutSize) 23 | let blooms: DataSequence = elf.fileHandle.readDataSequence( 24 | offset: numericCast(bloomsStart), 25 | numberOfElements: numericCast(header.gh_maskwords) 26 | ) 27 | 28 | let bucketsStart: Int = bloomsStart + blooms.size 29 | let buckets: DataSequence = elf.fileHandle.readDataSequence( 30 | offset: numericCast(bucketsStart), 31 | numberOfElements: numericCast(header.gh_nbuckets) 32 | ) 33 | 34 | let chainsOffset = bucketsStart + buckets.size 35 | 36 | return .init( 37 | header: header, 38 | bloom: Array(blooms), 39 | buckets: Array(buckets), 40 | chainsOffset: chainsOffset 41 | ) 42 | } 43 | 44 | func _readContent( 45 | in elf: ELFImage, 46 | at offset: Int 47 | ) -> Table { 48 | var header: Self { self } 49 | let bloomsStart: Int = numericCast(offset) + numericCast(header.layoutSize) 50 | let blooms: MemorySequence = .init( 51 | basePointer: elf.ptr 52 | .advanced(by: bloomsStart) 53 | .assumingMemoryBound(to: Table.Bloom.self), 54 | numberOfElements: numericCast(header.gh_maskwords) 55 | ) 56 | 57 | let bucketsStart: Int = bloomsStart + blooms.size 58 | let buckets: MemorySequence = .init( 59 | basePointer: elf.ptr 60 | .advanced(by: bucketsStart) 61 | .assumingMemoryBound(to: Table.Hashelt.self), 62 | numberOfElements: numericCast(header.gh_nbuckets) 63 | ) 64 | 65 | let chainsOffset = bucketsStart + buckets.size 66 | 67 | return .init( 68 | header: header, 69 | bloom: Array(blooms), 70 | buckets: Array(buckets), 71 | chainsOffset: chainsOffset 72 | ) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Hash/ELFHashTable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF32HashTable.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/29 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32HashTable: ELFHashTableProtocol { 13 | public typealias Header = ELF32HashTableHeader 14 | public typealias Hashelt = Elf32_Hashelt 15 | public typealias Symbol = ELF32Symbol 16 | 17 | public let header: Header 18 | 19 | public let buckets: [Hashelt] 20 | public let chains: [Hashelt] 21 | 22 | public init( 23 | header: Header, 24 | buckets: [Hashelt], 25 | chains: [Hashelt] 26 | ) { 27 | self.header = header 28 | self.buckets = buckets 29 | self.chains = chains 30 | } 31 | } 32 | 33 | public struct ELF64HashTable: ELFHashTableProtocol { 34 | public typealias Header = ELF64HashTableHeader 35 | public typealias Hashelt = Elf64_Hashelt 36 | public typealias Symbol = ELF64Symbol 37 | 38 | public let header: Header 39 | 40 | public let buckets: [Hashelt] 41 | public let chains: [Hashelt] 42 | 43 | public init( 44 | header: Header, 45 | buckets: [Hashelt], 46 | chains: [Hashelt] 47 | ) { 48 | self.header = header 49 | self.buckets = buckets 50 | self.chains = chains 51 | } 52 | } 53 | 54 | extension ELF32HashTable { 55 | public func findSymbol( 56 | named symbol: String, 57 | in elf: ELFFile 58 | ) -> Symbol? { 59 | guard let dynamics = elf.dynamics32, 60 | let symbols = dynamics.symbols(in: elf) else { 61 | return nil 62 | } 63 | return _findSymbol( 64 | named: symbol, 65 | in: elf, 66 | symbols: symbols 67 | ) 68 | } 69 | 70 | public func findSymbol( 71 | named symbol: String, 72 | in elf: ELFImage 73 | ) -> Symbol? { 74 | guard let dynamics = elf.dynamics32, 75 | let symbols = dynamics.symbols(in: elf) else { 76 | return nil 77 | } 78 | return _findSymbol( 79 | named: symbol, 80 | in: elf, 81 | symbols: symbols 82 | ) 83 | } 84 | } 85 | 86 | extension ELF64HashTable { 87 | public func findSymbol( 88 | named symbol: String, 89 | in elf: ELFFile 90 | ) -> Symbol? { 91 | guard let dynamics = elf.dynamics64, 92 | let symbols = dynamics.symbols(in: elf) else { 93 | return nil 94 | } 95 | return _findSymbol( 96 | named: symbol, 97 | in: elf, 98 | symbols: symbols 99 | ) 100 | } 101 | 102 | public func findSymbol( 103 | named symbol: String, 104 | in elf: ELFImage 105 | ) -> Symbol? { 106 | guard let dynamics = elf.dynamics64, 107 | let symbols = dynamics.symbols(in: elf) else { 108 | return nil 109 | } 110 | return _findSymbol( 111 | named: symbol, 112 | in: elf, 113 | symbols: symbols 114 | ) 115 | } 116 | } 117 | 118 | extension ELFHashTableProtocol { 119 | // ref: https://flapenguin.me/elf-dt-hash 120 | fileprivate func _findSymbol( 121 | named symbol: String, 122 | in elf: ELFFile, 123 | symbols: DataSequence 124 | ) -> Symbol? { 125 | let hashTable = self 126 | let header = hashTable.header 127 | 128 | let hash = Self.hash(for: symbol) 129 | 130 | var symix = hashTable.buckets[hash % header.numberOfBuckets] 131 | while true { 132 | let current = symbols[Int(symix)] 133 | let name = current.name(in: elf, isDynamic: true) 134 | if name == symbol { 135 | return current 136 | } 137 | if current._commonSpecialSection == .undef { 138 | break 139 | } 140 | symix = hashTable.chains[Int(symix)] 141 | } 142 | return nil 143 | } 144 | 145 | fileprivate func _findSymbol( 146 | named symbol: String, 147 | in elf: ELFImage, 148 | symbols: MemorySequence 149 | ) -> Symbol? { 150 | let hashTable = self 151 | let header = hashTable.header 152 | 153 | let hash = Self.hash(for: symbol) 154 | 155 | var symix = hashTable.buckets[hash % header.numberOfBuckets] 156 | while true { 157 | let current = symbols[Int(symix)] 158 | let name = current.name(in: elf, isDynamic: true) 159 | if name == symbol { 160 | return current 161 | } 162 | if current._commonSpecialSection == .undef { 163 | break 164 | } 165 | symix = hashTable.chains[Int(symix)] 166 | } 167 | return nil 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Hash/ELFHashTableHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFHashTableHeader.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/29 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32HashTableHeader: LayoutWrapper { 13 | public struct Layout { 14 | public let nbuckets: Elf32_Hashelt 15 | public let nchain: Elf32_Hashelt 16 | } 17 | public var layout: Layout 18 | } 19 | 20 | public struct ELF64HashTableHeader: LayoutWrapper { 21 | public struct Layout { 22 | public let nbuckets: Elf64_Hashelt 23 | public let nchain: Elf64_Hashelt 24 | } 25 | public var layout: Layout 26 | } 27 | 28 | extension ELF32HashTableHeader: ELFHashTableHeaderProtocol { 29 | public var numberOfBuckets: Int { 30 | numericCast(layout.nbuckets) 31 | } 32 | 33 | public var numberOfChains: Int { 34 | numericCast(layout.nchain) 35 | } 36 | } 37 | 38 | extension ELF64HashTableHeader: ELFHashTableHeaderProtocol { 39 | public var numberOfBuckets: Int { 40 | numericCast(layout.nbuckets) 41 | } 42 | 43 | public var numberOfChains: Int { 44 | numericCast(layout.nchain) 45 | } 46 | } 47 | 48 | extension ELFHashTableHeaderProtocol where Self: LayoutWrapper { 49 | func _readContent( 50 | in elf: ELFFile, 51 | at offset: Int 52 | ) -> Table where Table.Header == Self { 53 | var header: Self { self } 54 | 55 | let bucketStart: Int = numericCast(offset) + numericCast(header.layoutSize) 56 | let buckets: DataSequence = elf.fileHandle.readDataSequence( 57 | offset: numericCast(bucketStart), 58 | numberOfElements: header.numberOfBuckets 59 | ) 60 | 61 | let chainStart: Int = bucketStart + buckets.size 62 | let chains: DataSequence = elf.fileHandle.readDataSequence( 63 | offset: numericCast(chainStart), 64 | numberOfElements: header.numberOfChains 65 | ) 66 | return .init( 67 | header: header, 68 | buckets: Array(buckets), 69 | chains: Array(chains) 70 | ) 71 | } 72 | 73 | func _readContent( 74 | in elf: ELFImage, 75 | at offset: Int 76 | ) -> Table where Table.Header == Self { 77 | var header: Self { self } 78 | 79 | let bucketStart: Int = numericCast(offset) + numericCast(header.layoutSize) 80 | 81 | let buckets: MemorySequence = .init( 82 | basePointer: elf.ptr 83 | .advanced(by: bucketStart) 84 | .assumingMemoryBound(to: Table.Hashelt.self), 85 | numberOfElements: header.numberOfBuckets 86 | ) 87 | 88 | let chainStart: Int = bucketStart + buckets.size 89 | let chains: MemorySequence = .init( 90 | basePointer: elf.ptr 91 | .advanced(by: chainStart) 92 | .assumingMemoryBound(to: Table.Hashelt.self), 93 | numberOfElements: header.numberOfChains 94 | ) 95 | 96 | return .init( 97 | header: header, 98 | buckets: Array(buckets), 99 | chains: Array(chains) 100 | ) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Note/ELF32Note.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF32Note.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/28 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32Note { 13 | public let data: Data 14 | public let header: ELF32NoteHeader 15 | 16 | public init?(data: Data) { 17 | guard data.count >= ELF32NoteHeader.layoutSize else { 18 | return nil 19 | } 20 | self.data = data 21 | self.header = data.withUnsafeBytes { 22 | let laytou = $0.load(as: ELF32NoteHeader.Layout.self) 23 | return .init(layout: laytou) 24 | } 25 | } 26 | } 27 | 28 | extension ELF32Note: ELFNoteProtocol { 29 | public var name: String? { 30 | let data = data.advanced(by: header.layoutSize) 31 | return String(cString: data) 32 | } 33 | 34 | public var descriptionData: Data? { 35 | let offset = header.layoutSize + header.nameSize 36 | let size = header.descriptionSize 37 | guard data.count >= offset + size else { 38 | return nil 39 | } 40 | return data[offset..= ELF64NoteHeader.layoutSize else { 18 | return nil 19 | } 20 | self.data = data 21 | self.header = data.withUnsafeBytes { 22 | let laytou = $0.load(as: ELF64NoteHeader.Layout.self) 23 | return .init(layout: laytou) 24 | } 25 | } 26 | } 27 | 28 | extension ELF64Note: ELFNoteProtocol { 29 | public var name: String? { 30 | let data = data.advanced(by: header.layoutSize) 31 | return String(cString: data) 32 | } 33 | 34 | public var descriptionData: Data? { 35 | let offset = header.layoutSize + header.nameSize 36 | let size = header.descriptionSize 37 | guard data.count >= offset + size else { 38 | return nil 39 | } 40 | return data[offset.. 12 | public typealias ELF64Notes = _ELFNotes 13 | 14 | public struct _ELFNotes: Sequence { 15 | let data: Data 16 | 17 | public func makeIterator() -> Iterator { 18 | .init(data: data) 19 | } 20 | } 21 | 22 | extension _ELFNotes { 23 | public struct Iterator: IteratorProtocol { 24 | public typealias Element = Note 25 | 26 | private let data: Data 27 | private var nextOffset: Int = 0 28 | 29 | init(data: Data) { 30 | self.data = data 31 | } 32 | 33 | public mutating func next() -> Element? { 34 | guard nextOffset < data.count else { return nil } 35 | 36 | let note = Note( 37 | data: data.advanced(by: nextOffset) 38 | ) 39 | 40 | if let note { 41 | nextOffset += note.layoutSize + note.padding 42 | } 43 | 44 | return note 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Note/GNU/GnuABITag.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GnuABITag.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/05 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public struct GnuABITag: LayoutWrapper { 12 | public struct Layout { 13 | let os: UInt32 14 | let major, minor, patch: UInt32 15 | } 16 | 17 | public var layout: Layout 18 | } 19 | 20 | extension GnuABITag { 21 | init?(data: Data) { 22 | guard data.count >= Self.layoutSize else { 23 | return nil 24 | } 25 | let data = Array(data) 26 | let os = data[0..<4] 27 | .withUnsafeBytes({ $0.load(as: UInt32.self) }) 28 | let major = data[4..<8] 29 | .withUnsafeBytes({ $0.load(as: UInt32.self) }) 30 | let minor = data[8..<12] 31 | .withUnsafeBytes({ $0.load(as: UInt32.self) }) 32 | let subminor = data[12..<16] 33 | .withUnsafeBytes({ $0.load(as: UInt32.self) }) 34 | self.init( 35 | layout: .init( 36 | os: os, 37 | major: major, 38 | minor: minor, 39 | patch: subminor 40 | ) 41 | ) 42 | } 43 | } 44 | 45 | extension GnuABITag { 46 | public var os: OS! { 47 | .init(rawValue: layout.os) 48 | } 49 | 50 | public var version: Version { 51 | .init( 52 | major: numericCast(layout.major), 53 | minor: numericCast(layout.minor), 54 | patch: numericCast(layout.patch) 55 | ) 56 | } 57 | } 58 | 59 | extension GnuABITag { 60 | public enum OS: UInt32, CaseIterable { 61 | /// GNU_ABI_TAG_LINUX 62 | case linux = 0 63 | /// GNU_ABI_TAG_HURD 64 | case hurd = 1 65 | /// GNU_ABI_TAG_SOLARIS 66 | case solaris = 2 67 | /// GNU_ABI_TAG_FREEBSD 68 | case freebsd = 3 69 | /// GNU_ABI_TAG_NETBSD 70 | case netbsd = 4 71 | /// GNU_ABI_TAG_SYLLABLE 72 | case syllable = 5 73 | /// GNU_ABI_TAG_NACL 74 | case nacl = 6 75 | } 76 | } 77 | 78 | extension GnuABITag.OS: CustomStringConvertible { 79 | public var description: String { 80 | switch self { 81 | case .linux: "GNU_ABI_TAG_LINUX" 82 | case .hurd: "GNU_ABI_TAG_HURD" 83 | case .solaris: "GNU_ABI_TAG_SOLARIS" 84 | case .freebsd: "GNU_ABI_TAG_FREEBSD" 85 | case .netbsd: "GNU_ABI_TAG_NETBSD" 86 | case .syllable: "GNU_ABI_TAG_SYLLABLE" 87 | case .nacl: "GNU_ABI_TAG_NACL" 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Note/GNU/GnuHardwareCapabilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GnuHardwareCapabilities.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/05 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public struct GnuHardwareCapabilities { 12 | public let numberOfEntries: Int 13 | public let mask: UInt32 14 | public let entries: [String] 15 | } 16 | 17 | extension GnuHardwareCapabilities { 18 | init?(data: Data) { 19 | guard data.count >= 8 else { return nil } 20 | let num_entries = data.withUnsafeBytes { 21 | $0.load(as: UInt32.self) 22 | } 23 | let mask = data.withUnsafeBytes { 24 | $0.load(fromByteOffset: 4, as: UInt32.self) 25 | } 26 | guard let entries = String( 27 | data: data.advanced(by: 8), 28 | encoding: .utf8 29 | ) else { 30 | return nil 31 | } 32 | self.numberOfEntries = numericCast(num_entries) 33 | self.mask = mask 34 | self.entries = entries.components(separatedBy: .newlines) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Note/GNU/GnuNoteContent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GnuNoteContent.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/05 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public enum GnuNoteContent { 12 | /// NT_GNU_ABI_TAG 13 | case abi_tag(GnuABITag) 14 | /// NT_GNU_HWCAP 15 | case hwcap(GnuHardwareCapabilities) 16 | /// NT_GNU_BUILD_ID 17 | case build_id(String) 18 | /// NT_GNU_GOLD_VERSION 19 | case gold_version(String) 20 | /// NT_GNU_PROPERTY_TYPE_0 21 | case property_type_0(Data) 22 | } 23 | 24 | extension GnuNoteContent { 25 | public var type: GnuNoteType { 26 | switch self { 27 | case .abi_tag: .abi_tag 28 | case .hwcap: .hwcap 29 | case .build_id: .build_id 30 | case .gold_version: .gold_version 31 | case .property_type_0: .property_type_0 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Note/GNU/GnuNoteType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GnuNoteType.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/05 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public enum GnuNoteType: UInt32, CaseIterable { 12 | /// NT_GNU_ABI_TAG 13 | case abi_tag = 1 14 | /// NT_GNU_HWCAP 15 | case hwcap = 2 16 | /// NT_GNU_BUILD_ID 17 | case build_id = 3 18 | /// NT_GNU_GOLD_VERSION 19 | case gold_version = 4 20 | /// NT_GNU_PROPERTY_TYPE_0 21 | case property_type_0 = 5 22 | } 23 | 24 | extension GnuNoteType: CustomStringConvertible { 25 | public var description: String { 26 | switch self { 27 | case .abi_tag: "NT_GNU_ABI_TAG" 28 | case .hwcap: "NT_GNU_HWCAP" 29 | case .build_id: "NT_GNU_BUILD_ID" 30 | case .gold_version: "NT_GNU_GOLD_VERSION" 31 | case .property_type_0: "NT_GNU_PROPERTY_TYPE_0" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Relocation/ELF32Relocation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF32Relocation.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public enum ELF32Relocation { 13 | case general(ELF32RelocationInfo) 14 | case addend(ELF32RelocationAddendInfo) 15 | } 16 | 17 | extension ELF32Relocation: ELFRelocationProtocol { 18 | public var offset: Int { 19 | switch self { 20 | case let .general(v): numericCast(v.r_offset) 21 | case let .addend(v): numericCast(v.r_offset) 22 | } 23 | } 24 | 25 | public var symbolIndex: Int { 26 | switch self { 27 | case let .general(v): v.symbolIndex 28 | case let .addend(v): v.symbolIndex 29 | } 30 | } 31 | 32 | public var _type: Int { 33 | switch self { 34 | case let .general(v): numericCast(v._type) 35 | case let .addend(v): numericCast(v._type) 36 | } 37 | } 38 | 39 | public var addend: Int { 40 | switch self { 41 | case let .addend(v): numericCast(v.r_addend) 42 | default: 0 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Relocation/ELF32RelocationInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF32RelocationInfo.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32RelocationInfo: LayoutWrapper { 13 | public typealias Layout = Elf32_Rel 14 | 15 | public var layout: Layout 16 | } 17 | 18 | public struct ELF32RelocationAddendInfo: LayoutWrapper { 19 | public typealias Layout = Elf32_Rela 20 | 21 | public var layout: Layout 22 | } 23 | 24 | extension ELF32RelocationInfo { 25 | public var symbolIndex: Int { 26 | numericCast(layout.r_info >> 8) // ELF32_R_SYM 27 | } 28 | 29 | public var _type: UInt32 { 30 | layout.r_info & 0xff// ELF32_R_TYPE 31 | } 32 | } 33 | 34 | extension ELF32RelocationAddendInfo { 35 | public var symbolIndex: Int { 36 | numericCast(layout.r_info >> 8) // ELF32_R_SYM 37 | } 38 | 39 | public var _type: UInt32 { 40 | layout.r_info & 0xff// ELF32_R_TYPE 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Relocation/ELF64Relocation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF64Relocation.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public enum ELF64Relocation { 13 | case general(ELF64RelocationInfo) 14 | case addend(ELF64RelocationAddendInfo) 15 | } 16 | 17 | extension ELF64Relocation: ELFRelocationProtocol { 18 | public var offset: Int { 19 | switch self { 20 | case let .general(v): numericCast(v.r_offset) 21 | case let .addend(v): numericCast(v.r_offset) 22 | } 23 | } 24 | 25 | public var symbolIndex: Int { 26 | switch self { 27 | case let .general(v): v.symbolIndex 28 | case let .addend(v): v.symbolIndex 29 | } 30 | } 31 | 32 | public var _type: Int { 33 | switch self { 34 | case let .general(v): numericCast(v._type) 35 | case let .addend(v): numericCast(v._type) 36 | } 37 | } 38 | 39 | public var addend: Int { 40 | switch self { 41 | case let .addend(v): numericCast(v.r_addend) 42 | default: 0 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Relocation/ELF64RelocationInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELF64RelocationInfo.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF64RelocationInfo: LayoutWrapper { 13 | public typealias Layout = Elf64_Rel 14 | 15 | public var layout: Layout 16 | } 17 | 18 | public struct ELF64RelocationAddendInfo: LayoutWrapper { 19 | public typealias Layout = Elf64_Rela 20 | 21 | public var layout: Layout 22 | } 23 | 24 | extension ELF64RelocationInfo { 25 | public var symbolIndex: Int { 26 | numericCast(layout.r_info >> 32) // ELF64_R_SYM 27 | } 28 | 29 | public var _type: UInt64 { 30 | layout.r_info & 0xffffffff// ELF64_R_TYPE 31 | } 32 | } 33 | 34 | extension ELF64RelocationAddendInfo { 35 | public var symbolIndex: Int { 36 | numericCast(layout.r_info >> 32) // ELF64_R_SYM 37 | } 38 | 39 | public var _type: UInt64 { 40 | layout.r_info & 0xffffffff// ELF64_R_TYPE 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/StringTableEntry.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringTableEntry.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public struct StringTableEntry: Codable, Equatable { 12 | public let string: String 13 | /// Offset from the beginning of the string table 14 | public let offset: Int 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Symbol/ELFSymbol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFSymbol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32Symbol: LayoutWrapper { 13 | public typealias Layout = Elf32_Sym 14 | 15 | public var layout: Layout 16 | } 17 | 18 | public struct ELF64Symbol: LayoutWrapper { 19 | public typealias Layout = Elf64_Sym 20 | 21 | public var layout: Layout 22 | } 23 | 24 | extension ELF32Symbol: ELFSymbolProtocol { 25 | public var nameOffset: Int { 26 | numericCast(layout.st_name) 27 | } 28 | 29 | public var _commonBinding: SymbolBinding? { 30 | // ELF32_ST_BIND 31 | .init( 32 | rawValue: numericCast(layout.st_info >> 4), 33 | osabi: .none 34 | ) 35 | } 36 | 37 | public func binding(inELF header: ELFHeader) -> SymbolBinding? { 38 | // ELF32_ST_BIND 39 | .init( 40 | rawValue: numericCast(layout.st_info >> 4), 41 | osabi: header.osABI ?? .none 42 | ) 43 | } 44 | 45 | public var _commonType: SymbolType? { 46 | // ELF32_ST_TYPE 47 | .init( 48 | rawValue: numericCast(layout.st_info & 0xf), 49 | osabi: .none, 50 | machine: .none 51 | ) 52 | } 53 | 54 | public func type(inELF header: ELFHeader) -> SymbolType? { 55 | .init( 56 | rawValue: numericCast(layout.st_info & 0xf), 57 | osabi: header.osABI ?? .none, 58 | machine: header.machine ?? .none 59 | ) 60 | } 61 | 62 | public var visibility: SymbolVisibility! { 63 | // ELF32_ST_VISIBILITY 64 | .init(rawValue: layout.st_other & 0x3) 65 | } 66 | 67 | public var sectionIndex: Int? { 68 | let SHN_LORESERVE = 0xff00 69 | guard numericCast(layout.st_shndx) < SHN_LORESERVE else { return nil } 70 | return numericCast(layout.st_shndx) 71 | } 72 | 73 | public var _commonSpecialSection: SpecialSectionIndex? { 74 | .init( 75 | rawValue: numericCast(layout.st_shndx), 76 | osabi: .none, 77 | machine: .none 78 | ) 79 | } 80 | 81 | public func specialSection(inELF header: ELFHeader) -> SpecialSectionIndex? { 82 | .init( 83 | rawValue: numericCast(layout.st_shndx), 84 | osabi: header.osABI ?? .none, 85 | machine: header.machine ?? .none 86 | ) 87 | } 88 | } 89 | 90 | extension ELF64Symbol: ELFSymbolProtocol { 91 | public var nameOffset: Int { 92 | numericCast(layout.st_name) 93 | } 94 | 95 | public var _commonBinding: SymbolBinding? { 96 | // ELF64_ST_BIND 97 | .init( 98 | rawValue: numericCast(layout.st_info >> 4), 99 | osabi: .none 100 | ) 101 | } 102 | 103 | public func binding(inELF header: ELFHeader) -> SymbolBinding? { 104 | // ELF64_ST_BIND 105 | .init( 106 | rawValue: numericCast(layout.st_info >> 4), 107 | osabi: header.osABI ?? .none 108 | ) 109 | } 110 | 111 | public var _commonType: SymbolType? { 112 | // ELF64_ST_TYPE 113 | .init( 114 | rawValue: numericCast(layout.st_info & 0xf), 115 | osabi: .none, 116 | machine: .none 117 | ) 118 | } 119 | 120 | public func type(inELF header: ELFHeader) -> SymbolType? { 121 | .init( 122 | rawValue: numericCast(layout.st_info & 0xf), 123 | osabi: header.osABI ?? .none, 124 | machine: header.machine ?? .none 125 | ) 126 | } 127 | 128 | public var visibility: SymbolVisibility! { 129 | // ELF64_ST_VISIBILITY 130 | .init(rawValue: layout.st_other & 0x3) 131 | } 132 | 133 | public var sectionIndex: Int? { 134 | let SHN_LORESERVE = 0xff00 135 | guard numericCast(layout.st_shndx) < SHN_LORESERVE else { return nil } 136 | return numericCast(layout.st_shndx) 137 | } 138 | 139 | public var _commonSpecialSection: SpecialSectionIndex? { 140 | .init( 141 | rawValue: numericCast(layout.st_shndx), 142 | osabi: .none, 143 | machine: .none 144 | ) 145 | } 146 | 147 | public func specialSection(inELF header: ELFHeader) -> SpecialSectionIndex? { 148 | .init( 149 | rawValue: numericCast(layout.st_shndx), 150 | osabi: header.osABI ?? .none, 151 | machine: header.machine ?? .none 152 | ) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Symbol/SymbolBinding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SymbolBinding.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public enum SymbolBinding: CaseIterable { 13 | /// STB_LOCAL 14 | case local 15 | /// STB_GLOBAL 16 | case global 17 | /// STB_WEAK 18 | case weak 19 | /// STB_GNU_UNIQUE 20 | case gnu_unique 21 | /// STB_HP_ALIAS 22 | case hp_alias 23 | /// STB_VMS_WEAK 24 | case vms_weak 25 | /// STB_VMS_SYSTEM 26 | case vms_system 27 | } 28 | 29 | extension SymbolBinding/*: RawRepresentable*/ { 30 | public typealias RawValue = UInt8 31 | 32 | public init?( 33 | rawValue: RawValue, 34 | osabi: ELFOSABI 35 | ) { 36 | switch rawValue { 37 | case 0: self = .local 38 | case 1: self = .global 39 | case 2: self = .weak 40 | case 10 where osabi == .linux: self = .gnu_unique 41 | case 10 where osabi == .hpux: self = .hp_alias 42 | case 11 where osabi == .openvms: self = .vms_weak 43 | case 12 where osabi == .openvms: self = .vms_system 44 | default: return nil 45 | } 46 | } 47 | 48 | public var rawValue: RawValue { 49 | switch self { 50 | case .local: 0 51 | case .global: 1 52 | case .weak: 2 53 | case .gnu_unique: 10 54 | case .hp_alias: 10 55 | case .vms_weak: 11 56 | case .vms_system: 12 57 | } 58 | } 59 | } 60 | 61 | extension SymbolBinding: CustomStringConvertible { 62 | public var description: String { 63 | switch self { 64 | case .local: "STB_LOCAL" 65 | case .global: "STB_GLOBAL" 66 | case .weak: "STB_WEAK" 67 | case .gnu_unique: "STB_GNU_UNIQUE" 68 | case .hp_alias: "STB_HP_ALIAS" 69 | case .vms_weak: "STB_VMS_WEAK" 70 | case .vms_system: "STB_VMS_SYSTEM" 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Symbol/SymbolType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SymbolType.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public enum SymbolType: CaseIterable { 13 | /// STT_NOTYPE 14 | case notype 15 | /// STT_OBJECT 16 | case object 17 | /// STT_FUNC 18 | case `func` 19 | /// STT_SECTION 20 | case section 21 | /// STT_FILE 22 | case file 23 | /// STT_COMMON 24 | case common 25 | /// STT_TLS 26 | case tls 27 | /// STT_RELC 28 | case relc 29 | /// STT_SRELC 30 | case srelc 31 | /// STT_GNU_IFUNC 32 | case gnu_ifunc 33 | /// STT_ARM_TFUNC 34 | case arm_tfunc 35 | /// STT_ARM_16BIT 36 | case arm_16bit 37 | /// STT_PARISC_MILLI 38 | case parisc_milli 39 | /// STT_HP_OPAQUE 40 | case hp_opaque 41 | /// STT_HP_STUB 42 | case hp_stub 43 | /// STT_REGISTER 44 | case register 45 | /// STT_RENESAS_ENTRY 46 | case renesas_entry 47 | } 48 | 49 | extension SymbolType/*: RawRepresentable*/ { 50 | public typealias RawValue = UInt8 51 | 52 | public init?( 53 | rawValue: RawValue, 54 | osabi: ELFOSABI, 55 | machine: ELFMachine 56 | ) { 57 | switch rawValue { 58 | case 0: self = .notype 59 | case 1: self = .object 60 | case 2: self = .func 61 | case 3: self = .section 62 | case 4: self = .file 63 | case 5: self = .common 64 | case 6: self = .tls 65 | case 8: self = .relc 66 | case 9: self = .srelc 67 | 68 | case 10 where [.linux, .freebsd].contains(osabi): 69 | self = .gnu_ifunc 70 | 71 | case _ where machine == .arm: 72 | switch rawValue { 73 | case 13: self = .arm_tfunc 74 | return 75 | case 15: self = .arm_16bit 76 | return 77 | default: 78 | return nil 79 | } 80 | 81 | case _ where machine == .parisc: 82 | switch rawValue { 83 | case 13: self = .parisc_milli 84 | case 11: self = .hp_opaque 85 | case 12: self = .hp_stub 86 | return 87 | default: 88 | return nil 89 | } 90 | 91 | case _ where machine == .sparcv9: 92 | switch rawValue { 93 | case 13: self = .register 94 | return 95 | default: 96 | return nil 97 | } 98 | 99 | case _ where [.v800, .v850, .cygnus_v850].contains(machine): 100 | switch rawValue { 101 | case 14: self = .renesas_entry 102 | return 103 | default: 104 | return nil 105 | } 106 | 107 | default: return nil 108 | } 109 | } 110 | public var rawValue: RawValue { 111 | switch self { 112 | case .notype: 0 113 | case .object: 1 114 | case .func: 2 115 | case .section: 3 116 | case .file: 4 117 | case .common: 5 118 | case .tls: 6 119 | case .relc: 8 120 | case .srelc: 9 121 | case .gnu_ifunc: 10 122 | case .arm_tfunc: 13 123 | case .arm_16bit: 15 124 | case .parisc_milli: 13 125 | case .hp_opaque: 11 126 | case .hp_stub: 12 127 | case .register: 13 128 | case .renesas_entry: 14 129 | } 130 | } 131 | } 132 | extension SymbolType: CustomStringConvertible { 133 | public var description: String { 134 | switch self { 135 | case .notype: "STT_NOTYPE" 136 | case .object: "STT_OBJECT" 137 | case .func: "STT_FUNC" 138 | case .section: "STT_SECTION" 139 | case .file: "STT_FILE" 140 | case .common: "STT_COMMON" 141 | case .tls: "STT_TLS" 142 | case .relc: "STT_RELC" 143 | case .srelc: "STT_SRELC" 144 | case .gnu_ifunc: "STT_GNU_IFUNC" 145 | case .arm_tfunc: "STT_ARM_TFUNC" 146 | case .arm_16bit: "STT_ARM_16BIT" 147 | case .parisc_milli: "STT_PARISC_MILLI" 148 | case .hp_opaque: "STT_HP_OPAQUE" 149 | case .hp_stub: "STT_HP_STUB" 150 | case .register: "STT_REGISTER" 151 | case .renesas_entry: "STT_RENESAS_ENTRY" 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Symbol/SymbolVisibility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SymbolVisibility.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public enum SymbolVisibility: UInt8, CaseIterable { 13 | /// STV_DEFAULT 14 | case `default` = 0 15 | /// STV_INTERNAL 16 | case `internal` = 1 17 | /// STV_HIDDEN 18 | case hidden = 2 19 | /// STV_PROTECTED 20 | case protected = 3 21 | /// STV_EXPORTED 22 | case exported = 4 23 | /// STV_SINGLETON 24 | case singleton = 5 25 | /// STV_ELIMINATE 26 | case eliminate = 6 27 | } 28 | 29 | extension SymbolVisibility: CustomStringConvertible { 30 | public var description: String { 31 | switch self { 32 | case .default: "STV_DEFAULT" 33 | case .internal: "STV_INTERNAL" 34 | case .hidden: "STV_HIDDEN" 35 | case .protected: "STV_PROTECTED" 36 | case .exported: "STV_EXPORTED" 37 | case .singleton: "STV_SINGLETON" 38 | case .eliminate: "STV_ELIMINATE" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/SymbolInfo/ELFSymbolInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFSymbolInfo.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32SymbolInfo: LayoutWrapper { 13 | public typealias Layout = Elf32_Syminfo 14 | 15 | public var layout: Layout 16 | } 17 | 18 | public struct ELF64SymbolInfo: LayoutWrapper { 19 | public typealias Layout = Elf64_Syminfo 20 | 21 | public var layout: Layout 22 | } 23 | 24 | extension ELF32SymbolInfo: ELFSymbolInfoProtocol { 25 | public var dynamicEntryIndex: Int? { 26 | specialBound == nil ? numericCast(layout.si_boundto) : nil 27 | } 28 | 29 | public var specialBound: SymbolInfoSpecialBound? { 30 | .init(rawValue: layout.si_boundto) 31 | } 32 | 33 | public var flags: SymbolInfoFlags { 34 | .init(rawValue: layout.si_flags) 35 | } 36 | } 37 | 38 | extension ELF64SymbolInfo: ELFSymbolInfoProtocol { 39 | public var dynamicEntryIndex: Int? { 40 | specialBound == nil ? numericCast(layout.si_boundto) : nil 41 | } 42 | 43 | public var specialBound: SymbolInfoSpecialBound? { 44 | .init(rawValue: layout.si_boundto) 45 | } 46 | 47 | public var flags: SymbolInfoFlags { 48 | .init(rawValue: layout.si_flags) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/SymbolInfo/SymbolInfoFlags.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SymbolInfoFlags.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct SymbolInfoFlags: BitFlags { 13 | public typealias RawValue = UInt16 14 | 15 | public var rawValue: RawValue 16 | 17 | public init(rawValue: RawValue) { 18 | self.rawValue = rawValue 19 | } 20 | } 21 | 22 | extension SymbolInfoFlags { 23 | /// SYMINFO_FLG_DIRECT 24 | public static let direct = SymbolInfoFlags( 25 | rawValue: Bit.direct.rawValue 26 | ) 27 | /// SYMINFO_FLG_FILTER 28 | public static let filter = SymbolInfoFlags( 29 | rawValue: Bit.filter.rawValue 30 | ) 31 | /// SYMINFO_FLG_COPY 32 | public static let copy = SymbolInfoFlags( 33 | rawValue: Bit.copy.rawValue 34 | ) 35 | /// SYMINFO_FLG_LAZYLOAD 36 | public static let lazyload = SymbolInfoFlags( 37 | rawValue: Bit.lazyload.rawValue 38 | ) 39 | /// SYMINFO_FLG_DIRECTBIND 40 | public static let directbind = SymbolInfoFlags( 41 | rawValue: Bit.directbind.rawValue 42 | ) 43 | /// SYMINFO_FLG_NOEXTDIRECT 44 | public static let noextdirect = SymbolInfoFlags( 45 | rawValue: Bit.noextdirect.rawValue 46 | ) 47 | /// SYMINFO_FLG_AUXILIARY 48 | public static let auxiliary = SymbolInfoFlags( 49 | rawValue: Bit.auxiliary.rawValue 50 | ) 51 | /// SYMINFO_FLG_INTERPOSE 52 | public static let interpose = SymbolInfoFlags( 53 | rawValue: Bit.interpose.rawValue 54 | ) 55 | /// SYMINFO_FLG_CAP 56 | public static let cap = SymbolInfoFlags( 57 | rawValue: Bit.cap.rawValue 58 | ) 59 | /// SYMINFO_FLG_DEFERRED 60 | public static let deferred = SymbolInfoFlags( 61 | rawValue: Bit.deferred.rawValue 62 | ) 63 | } 64 | 65 | extension SymbolInfoFlags { 66 | public enum Bit: UInt16, CaseIterable { 67 | /// SYMINFO_FLG_DIRECT 68 | case direct = 1 69 | /// SYMINFO_FLG_FILTER 70 | case filter = 2 71 | /// SYMINFO_FLG_COPY 72 | case copy = 4 73 | /// SYMINFO_FLG_LAZYLOAD 74 | case lazyload = 8 75 | /// SYMINFO_FLG_DIRECTBIND 76 | case directbind = 0x10 77 | /// SYMINFO_FLG_NOEXTDIRECT 78 | case noextdirect = 0x20 79 | /// SYMINFO_FLG_AUXILIARY 80 | case auxiliary = 0x40 81 | /// SYMINFO_FLG_INTERPOSE 82 | case interpose = 0x80 83 | /// SYMINFO_FLG_CAP 84 | case cap = 0x100 85 | /// SYMINFO_FLG_DEFERRED 86 | case deferred = 0x200 87 | } 88 | } 89 | 90 | extension SymbolInfoFlags.Bit: CustomStringConvertible { 91 | public var description: String { 92 | switch self { 93 | case .direct: "SYMINFO_FLG_DIRECT" 94 | case .filter: "SYMINFO_FLG_FILTER" 95 | case .copy: "SYMINFO_FLG_COPY" 96 | case .lazyload: "SYMINFO_FLG_LAZYLOAD" 97 | case .directbind: "SYMINFO_FLG_DIRECTBIND" 98 | case .noextdirect: "SYMINFO_FLG_NOEXTDIRECT" 99 | case .auxiliary: "SYMINFO_FLG_AUXILIARY" 100 | case .interpose: "SYMINFO_FLG_INTERPOSE" 101 | case .cap: "SYMINFO_FLG_CAP" 102 | case .deferred: "SYMINFO_FLG_DEFERRED" 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/SymbolInfo/SymbolInfoSpecialBound.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SymbolInfoSpecialBound.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public enum SymbolInfoSpecialBound: UInt16, CaseIterable { 13 | /// SYMINFO_BT_SELF 14 | case `self` = 0xffff 15 | /// SYMINFO_BT_PARENT 16 | case parent = 0xfffe 17 | /// SYMINFO_BT_NONE 18 | case none = 0xfffd 19 | /// SYMINFO_BT_EXTERN 20 | case extern = 0xfffc 21 | } 22 | 23 | extension SymbolInfoSpecialBound: CustomStringConvertible { 24 | public var description: String { 25 | switch self { 26 | case .`self`: "SYMINFO_BT_SELF" 27 | case .parent: "SYMINFO_BT_PARENT" 28 | case .none: "SYMINFO_BT_NONE" 29 | case .extern: "SYMINFO_BT_EXTERN" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Version.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Version.swift 3 | // 4 | // 5 | // Created by p-x9 on 2023/11/29. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Version { 12 | public let major: Int 13 | public let minor: Int 14 | public let patch: Int 15 | } 16 | 17 | extension Version: CustomStringConvertible { 18 | public var description: String { 19 | "\(major).\(minor).\(patch)" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Version/VersionDef/ELFVersionDef.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionDef.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32VersionDef: LayoutWrapper { 13 | public typealias Layout = Elf32_Verdef 14 | 15 | public var layout: Layout 16 | public let _index: Int 17 | public let _offset: Int 18 | } 19 | 20 | public struct ELF64VersionDef: LayoutWrapper { 21 | public typealias Layout = Elf64_Verdef 22 | 23 | public var layout: Layout 24 | public let _index: Int 25 | public let _offset: Int 26 | 27 | } 28 | 29 | extension ELF32VersionDef: ELFVersionDefProtocol { 30 | public typealias Aux = ELF32VersionDefAux 31 | 32 | public var flags: VersionFlags { 33 | .init(rawValue: layout.vd_flags) 34 | } 35 | 36 | public var versionIndex: Int { 37 | numericCast(layout.vd_ndx) 38 | } 39 | 40 | public var numberOfAux: Int { 41 | numericCast(layout.vd_cnt) 42 | } 43 | 44 | public var hash: Int { 45 | numericCast(layout.vd_hash) 46 | } 47 | 48 | public var auxOffset: Int { 49 | numericCast(layout.vd_aux) 50 | } 51 | 52 | public var nextOffset: Int { 53 | numericCast(layout.vd_next) 54 | } 55 | } 56 | 57 | extension ELF32VersionDef { 58 | public func _next(in elf: ELFFile) -> Self? { 59 | guard nextOffset != 0 else { 60 | return nil 61 | } 62 | if let dynamics = elf.dynamics32, 63 | let max = dynamics.numberOfVersionDefs, 64 | _index + 1 >= max { 65 | return nil 66 | } 67 | let offset = self._offset + nextOffset 68 | let layout: Layout = elf.fileHandle.read( 69 | offset: numericCast(offset) 70 | ) 71 | return .init( 72 | layout: layout, 73 | _index: _index + 1, 74 | _offset: offset 75 | ) 76 | } 77 | 78 | public func _aux(in elf: ELFFile) -> Aux? { 79 | guard numberOfAux > 0 else { return nil } 80 | 81 | let offset = _offset + numericCast(layout.vd_aux) 82 | let layout: Aux.Layout = elf.fileHandle.read( 83 | offset: numericCast(offset) 84 | ) 85 | return .init( 86 | layout: layout, 87 | _index: 0, 88 | _offset: offset 89 | ) 90 | } 91 | } 92 | 93 | extension ELF32VersionDef { 94 | public func _next(in elf: ELFImage) -> Self? { 95 | guard nextOffset != 0 else { 96 | return nil 97 | } 98 | if let dynamics = elf.dynamics32, 99 | let max = dynamics.numberOfVersionDefs, 100 | _index + 1 >= max { 101 | return nil 102 | } 103 | let offset = self._offset + nextOffset 104 | let layout: Layout = elf.ptr 105 | .advanced(by: offset) 106 | .autoBoundPointee() 107 | return .init( 108 | layout: layout, 109 | _index: _index + 1, 110 | _offset: offset 111 | ) 112 | } 113 | 114 | public func _aux(in elf: ELFImage) -> Aux? { 115 | guard numberOfAux > 0 else { return nil } 116 | 117 | let offset = _offset + numericCast(layout.vd_aux) 118 | let layout: Aux.Layout = elf.ptr 119 | .advanced(by: offset) 120 | .autoBoundPointee() 121 | return .init( 122 | layout: layout, 123 | _index: 0, 124 | _offset: offset 125 | ) 126 | } 127 | } 128 | 129 | extension ELF64VersionDef: ELFVersionDefProtocol { 130 | public typealias Aux = ELF64VersionDefAux 131 | 132 | public var flags: VersionFlags { 133 | .init(rawValue: layout.vd_flags) 134 | } 135 | 136 | public var versionIndex: Int { 137 | numericCast(layout.vd_ndx) 138 | } 139 | 140 | public var numberOfAux: Int { 141 | numericCast(layout.vd_cnt) 142 | } 143 | 144 | public var hash: Int { 145 | numericCast(layout.vd_hash) 146 | } 147 | 148 | public var auxOffset: Int { 149 | numericCast(layout.vd_aux) 150 | } 151 | 152 | public var nextOffset: Int { 153 | numericCast(layout.vd_next) 154 | } 155 | } 156 | 157 | extension ELF64VersionDef { 158 | public func _next(in elf: ELFFile) -> Self? { 159 | guard let dynamics = elf.dynamics64, 160 | let max = dynamics.numberOfVersionDefs, 161 | _index + 1 < max, 162 | nextOffset != 0 else { 163 | return nil 164 | } 165 | let offset = self._offset + nextOffset 166 | let layout: Layout = elf.fileHandle.read( 167 | offset: numericCast(offset) 168 | ) 169 | return .init( 170 | layout: layout, 171 | _index: _index + 1, 172 | _offset: offset 173 | ) 174 | } 175 | 176 | public func _aux(in elf: ELFFile) -> Aux? { 177 | guard numberOfAux > 0 else { return nil } 178 | 179 | let offset = _offset + numericCast(layout.vd_aux) 180 | let layout: Aux.Layout = elf.fileHandle.read( 181 | offset: numericCast(offset) 182 | ) 183 | return .init( 184 | layout: layout, 185 | _index: 0, 186 | _offset: offset 187 | ) 188 | } 189 | } 190 | 191 | extension ELF64VersionDef { 192 | public func _next(in elf: ELFImage) -> Self? { 193 | guard let dynamics = elf.dynamics64, 194 | let max = dynamics.numberOfVersionDefs, 195 | _index + 1 < max, 196 | nextOffset != 0 else { 197 | return nil 198 | } 199 | let offset = self._offset + nextOffset 200 | let layout: Layout = elf.ptr 201 | .advanced(by: offset) 202 | .autoBoundPointee() 203 | return .init( 204 | layout: layout, 205 | _index: _index + 1, 206 | _offset: offset 207 | ) 208 | } 209 | 210 | public func _aux(in elf: ELFImage) -> Aux? { 211 | guard numberOfAux > 0 else { return nil } 212 | 213 | let offset = _offset + numericCast(layout.vd_aux) 214 | let layout: Aux.Layout = elf.ptr 215 | .advanced(by: offset) 216 | .autoBoundPointee() 217 | return .init( 218 | layout: layout, 219 | _index: 0, 220 | _offset: offset 221 | ) 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Version/VersionDef/ELFVersionDefAux.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionDefAux.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32VersionDefAux: LayoutWrapper { 13 | public typealias Layout = Elf32_Verdaux 14 | 15 | public var layout: Layout 16 | public let _index: Int 17 | public let _offset: Int 18 | } 19 | 20 | public struct ELF64VersionDefAux: LayoutWrapper { 21 | public typealias Layout = Elf64_Verdaux 22 | 23 | public var layout: Layout 24 | public let _index: Int 25 | public let _offset: Int 26 | } 27 | 28 | extension ELF32VersionDefAux: ELFVersionDefAuxProtocol { 29 | public var nameOffset: Int { 30 | numericCast(layout.vda_name) 31 | } 32 | 33 | public var nextOffset: Int { 34 | numericCast(layout.vda_next) 35 | } 36 | } 37 | 38 | extension ELF32VersionDefAux { 39 | public func _next(in elf: ELFFile) -> Self? { 40 | guard nextOffset != 0 else { 41 | return nil 42 | } 43 | let offset = self._offset + nextOffset 44 | let layout: Layout = elf.fileHandle.read( 45 | offset: numericCast(offset) 46 | ) 47 | return .init( 48 | layout: layout, 49 | _index: _index + 1, 50 | _offset: offset 51 | ) 52 | } 53 | 54 | public func name(in elf: ELFFile) -> String? { 55 | guard let dynamics = elf.dynamics32, 56 | let strings = dynamics.strings(in: elf) else { 57 | return nil 58 | } 59 | return strings.string(at: nameOffset)?.string 60 | } 61 | } 62 | 63 | extension ELF32VersionDefAux { 64 | public func _next(in elf: ELFImage) -> Self? { 65 | guard nextOffset != 0 else { 66 | return nil 67 | } 68 | let offset = self._offset + nextOffset 69 | let layout: Layout = elf.ptr 70 | .advanced(by: offset) 71 | .autoBoundPointee() 72 | return .init( 73 | layout: layout, 74 | _index: _index + 1, 75 | _offset: offset 76 | ) 77 | } 78 | 79 | public func name(in elf: ELFImage) -> String? { 80 | guard let dynamics = elf.dynamics32, 81 | let strings = dynamics.strings(in: elf) else { 82 | return nil 83 | } 84 | return strings.string(at: nameOffset)?.string 85 | } 86 | } 87 | 88 | extension ELF64VersionDefAux: ELFVersionDefAuxProtocol { 89 | public var nameOffset: Int { 90 | numericCast(layout.vda_name) 91 | } 92 | 93 | public var nextOffset: Int { 94 | numericCast(layout.vda_next) 95 | } 96 | } 97 | 98 | extension ELF64VersionDefAux { 99 | public func _next(in elf: ELFFile) -> Self? { 100 | guard nextOffset != 0 else { 101 | return nil 102 | } 103 | let offset = self._offset + nextOffset 104 | let layout: Layout = elf.fileHandle.read( 105 | offset: numericCast(offset) 106 | ) 107 | return .init( 108 | layout: layout, 109 | _index: _index + 1, 110 | _offset: offset 111 | ) 112 | } 113 | 114 | public func name(in elf: ELFFile) -> String? { 115 | guard let dynamics = elf.dynamics64, 116 | let strings = dynamics.strings(in: elf) else { 117 | return nil 118 | } 119 | return strings.string(at: nameOffset)?.string 120 | } 121 | } 122 | 123 | extension ELF64VersionDefAux { 124 | public func _next(in elf: ELFImage) -> Self? { 125 | guard nextOffset != 0 else { 126 | return nil 127 | } 128 | let offset = self._offset + nextOffset 129 | let layout: Layout = elf.ptr 130 | .advanced(by: offset) 131 | .autoBoundPointee() 132 | return .init( 133 | layout: layout, 134 | _index: _index + 1, 135 | _offset: offset 136 | ) 137 | } 138 | 139 | public func name(in elf: ELFImage) -> String? { 140 | guard let dynamics = elf.dynamics64, 141 | let strings = dynamics.strings(in: elf) else { 142 | return nil 143 | } 144 | return strings.string(at: nameOffset)?.string 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Version/VersionFlags.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VersionFlags.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct VersionFlags: BitFlags { 13 | public typealias RawValue = UInt16 14 | 15 | public var rawValue: RawValue 16 | 17 | public init(rawValue: RawValue) { 18 | self.rawValue = rawValue 19 | } 20 | } 21 | 22 | extension VersionFlags { 23 | /// VER_FLG_BASE 24 | public static let base = VersionFlags( 25 | rawValue: Bit.base.rawValue 26 | ) 27 | /// VER_FLG_WEAK 28 | public static let weak = VersionFlags( 29 | rawValue: Bit.weak.rawValue 30 | ) 31 | /// VER_FLG_INFO 32 | public static let info = VersionFlags( 33 | rawValue: Bit.info.rawValue 34 | ) 35 | } 36 | 37 | extension VersionFlags { 38 | public enum Bit: UInt16, CaseIterable { 39 | /// VER_FLG_BASE 40 | case base = 1 41 | /// VER_FLG_WEAK 42 | case weak = 2 43 | /// VER_FLG_INFO 44 | case info = 4 45 | } 46 | } 47 | 48 | extension VersionFlags.Bit: CustomStringConvertible { 49 | public var description: String { 50 | switch self { 51 | case .base: "VER_FLG_BASE" 52 | case .weak: "VER_FLG_WEAK" 53 | case .info: "VER_FLG_INFO" 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Version/VersionNeed/ELFVersionNeed.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionNeed.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32VersionNeed: LayoutWrapper { 13 | public typealias Layout = Elf32_Verneed 14 | 15 | public var layout: Layout 16 | public let _index: Int 17 | public let _offset: Int 18 | } 19 | 20 | public struct ELF64VersionNeed: LayoutWrapper { 21 | public typealias Layout = Elf64_Verneed 22 | 23 | public var layout: Layout 24 | public let _index: Int 25 | public let _offset: Int 26 | } 27 | 28 | extension ELF32VersionNeed: ELFVersionNeedProtocol { 29 | public typealias Aux = ELF32VersionNeedAux 30 | 31 | public var fileNameOffset: Int { 32 | numericCast(layout.vn_file) 33 | } 34 | 35 | public var numberOfAux: Int { 36 | numericCast(layout.vn_cnt) 37 | } 38 | 39 | public var auxOffset: Int { 40 | numericCast(layout.vn_aux) 41 | } 42 | 43 | public var nextOffset: Int { 44 | numericCast(layout.vn_next) 45 | } 46 | } 47 | 48 | extension ELF32VersionNeed { 49 | public func fileName(in elf: ELFFile) -> String? { 50 | guard let dynamics = elf.dynamics32, 51 | let strings = dynamics.strings(in: elf) else { 52 | return nil 53 | } 54 | return strings.string(at: fileNameOffset)?.string 55 | } 56 | 57 | public func _next(in elf: ELFFile) -> Self? { 58 | guard let dynamics = elf.dynamics32, 59 | let max = dynamics.numberOfVersionNeeds, 60 | _index + 1 < max, 61 | nextOffset != 0 else { 62 | return nil 63 | } 64 | let offset = self._offset + nextOffset 65 | let layout: Layout = elf.fileHandle.read( 66 | offset: numericCast(offset) 67 | ) 68 | return .init( 69 | layout: layout, 70 | _index: _index + 1, 71 | _offset: offset 72 | ) 73 | } 74 | 75 | public func _aux(in elf: ELFFile) -> Aux? { 76 | guard numberOfAux > 0 else { return nil } 77 | 78 | let offset = _offset + numericCast(layout.vn_aux) 79 | let layout: ELF32VersionNeedAux.Layout = elf.fileHandle.read( 80 | offset: numericCast(offset) 81 | ) 82 | return .init( 83 | layout: layout, 84 | _index: 0, 85 | _offset: offset 86 | ) 87 | } 88 | } 89 | 90 | extension ELF32VersionNeed { 91 | public func fileName(in elf: ELFImage) -> String? { 92 | guard let dynamics = elf.dynamics32, 93 | let strings = dynamics.strings(in: elf) else { 94 | return nil 95 | } 96 | return strings.string(at: fileNameOffset)?.string 97 | } 98 | 99 | public func _next(in elf: ELFImage) -> Self? { 100 | guard let dynamics = elf.dynamics32, 101 | let max = dynamics.numberOfVersionNeeds, 102 | _index + 1 < max, 103 | nextOffset != 0 else { 104 | return nil 105 | } 106 | let offset = self._offset + nextOffset 107 | let layout: Layout = elf.ptr 108 | .advanced(by: offset) 109 | .autoBoundPointee() 110 | return .init( 111 | layout: layout, 112 | _index: _index + 1, 113 | _offset: offset 114 | ) 115 | } 116 | 117 | public func _aux(in elf: ELFImage) -> Aux? { 118 | guard numberOfAux > 0 else { return nil } 119 | 120 | let offset = _offset + numericCast(layout.vn_aux) 121 | let layout: ELF32VersionNeedAux.Layout = elf.ptr 122 | .advanced(by: offset) 123 | .autoBoundPointee() 124 | return .init( 125 | layout: layout, 126 | _index: 0, 127 | _offset: offset 128 | ) 129 | } 130 | } 131 | 132 | extension ELF64VersionNeed: ELFVersionNeedProtocol { 133 | public typealias Aux = ELF64VersionNeedAux 134 | 135 | public var fileNameOffset: Int { 136 | numericCast(layout.vn_file) 137 | } 138 | 139 | public var numberOfAux: Int { 140 | numericCast(layout.vn_cnt) 141 | } 142 | 143 | public var auxOffset: Int { 144 | numericCast(layout.vn_aux) 145 | } 146 | 147 | public var nextOffset: Int { 148 | numericCast(layout.vn_next) 149 | } 150 | } 151 | 152 | extension ELF64VersionNeed { 153 | public func fileName(in elf: ELFFile) -> String? { 154 | guard let dynamics = elf.dynamics64, 155 | let strings = dynamics.strings(in: elf) else { 156 | return nil 157 | } 158 | return strings.string(at: fileNameOffset)?.string 159 | } 160 | 161 | public func _next(in elf: ELFFile) -> Self? { 162 | guard nextOffset != 0 else { 163 | return nil 164 | } 165 | if let dynamics = elf.dynamics64, 166 | let max = dynamics.numberOfVersionNeeds, 167 | _index + 1 >= max { 168 | return nil 169 | } 170 | let offset = self._offset + nextOffset 171 | let layout: Layout = elf.fileHandle.read( 172 | offset: numericCast(offset) 173 | ) 174 | return .init( 175 | layout: layout, 176 | _index: _index + 1, 177 | _offset: offset 178 | ) 179 | } 180 | 181 | public func _aux(in elf: ELFFile) -> Aux? { 182 | guard numberOfAux > 0 else { return nil } 183 | 184 | let offset = _offset + numericCast(layout.vn_aux) 185 | let layout: ELF64VersionNeedAux.Layout = elf.fileHandle.read( 186 | offset: numericCast(offset) 187 | ) 188 | return .init( 189 | layout: layout, 190 | _index: 0, 191 | _offset: offset 192 | ) 193 | } 194 | } 195 | 196 | extension ELF64VersionNeed { 197 | public func fileName(in elf: ELFImage) -> String? { 198 | guard let dynamics = elf.dynamics64, 199 | let strings = dynamics.strings(in: elf) else { 200 | return nil 201 | } 202 | return strings.string(at: fileNameOffset)?.string 203 | } 204 | 205 | public func _next(in elf: ELFImage) -> Self? { 206 | guard nextOffset != 0 else { 207 | return nil 208 | } 209 | if let dynamics = elf.dynamics64, 210 | let max = dynamics.numberOfVersionNeeds, 211 | _index + 1 >= max { 212 | return nil 213 | } 214 | let offset = self._offset + nextOffset 215 | let layout: Layout = elf.ptr 216 | .advanced(by: offset) 217 | .autoBoundPointee() 218 | return .init( 219 | layout: layout, 220 | _index: _index + 1, 221 | _offset: offset 222 | ) 223 | } 224 | 225 | public func _aux(in elf: ELFImage) -> Aux? { 226 | guard numberOfAux > 0 else { return nil } 227 | 228 | let offset = _offset + numericCast(layout.vn_aux) 229 | let layout: ELF64VersionNeedAux.Layout = elf.ptr 230 | .advanced(by: offset) 231 | .autoBoundPointee() 232 | return .init( 233 | layout: layout, 234 | _index: 0, 235 | _offset: offset 236 | ) 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Version/VersionNeed/ELFVersionNeedAux.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionNeedAux.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32VersionNeedAux: LayoutWrapper { 13 | public typealias Layout = Elf32_Vernaux 14 | 15 | public var layout: Layout 16 | public let _index: Int 17 | public let _offset: Int 18 | } 19 | 20 | public struct ELF64VersionNeedAux: LayoutWrapper { 21 | public typealias Layout = Elf64_Vernaux 22 | 23 | public var layout: Layout 24 | public let _index: Int 25 | public let _offset: Int 26 | } 27 | 28 | extension ELF32VersionNeedAux: ELFVersionNeedAuxProtocol { 29 | public var hash: Int { 30 | numericCast(layout.vna_hash) 31 | } 32 | 33 | public var flags: VersionFlags { 34 | .init(rawValue: layout.vna_flags) 35 | } 36 | 37 | public var version: Int { 38 | numericCast(layout.vna_other) 39 | } 40 | 41 | public var nextOffset: Int { 42 | numericCast(layout.vna_next) 43 | } 44 | } 45 | 46 | extension ELF32VersionNeedAux { 47 | public func name(in elf: ELFFile) -> String? { 48 | guard let dynamics = elf.dynamics32, 49 | let strings = dynamics.strings(in: elf) else { 50 | return nil 51 | } 52 | return strings.string(at: numericCast(layout.vna_name))?.string 53 | } 54 | 55 | public func _next(in elf: ELFFile) -> Self? { 56 | guard nextOffset != 0 else { 57 | return nil 58 | } 59 | let offset = self._offset + nextOffset 60 | let layout: Layout = elf.fileHandle.read( 61 | offset: numericCast(offset) 62 | ) 63 | return .init( 64 | layout: layout, 65 | _index: _index + 1, 66 | _offset: offset 67 | ) 68 | } 69 | } 70 | 71 | extension ELF32VersionNeedAux { 72 | public func name(in elf: ELFImage) -> String? { 73 | guard let dynamics = elf.dynamics32, 74 | let strings = dynamics.strings(in: elf) else { 75 | return nil 76 | } 77 | return strings.string(at: numericCast(layout.vna_name))?.string 78 | } 79 | 80 | public func _next(in elf: ELFImage) -> Self? { 81 | guard nextOffset != 0 else { 82 | return nil 83 | } 84 | let offset = self._offset + nextOffset 85 | let layout: Layout = elf.ptr 86 | .advanced(by: offset) 87 | .autoBoundPointee() 88 | return .init( 89 | layout: layout, 90 | _index: _index + 1, 91 | _offset: offset 92 | ) 93 | } 94 | } 95 | 96 | extension ELF64VersionNeedAux: ELFVersionNeedAuxProtocol { 97 | public var hash: Int { 98 | numericCast(layout.vna_hash) 99 | } 100 | 101 | public var flags: VersionFlags { 102 | .init(rawValue: layout.vna_flags) 103 | } 104 | 105 | public var version: Int { 106 | numericCast(layout.vna_other) 107 | } 108 | 109 | public var nextOffset: Int { 110 | numericCast(layout.vna_next) 111 | } 112 | } 113 | 114 | extension ELF64VersionNeedAux { 115 | public func name(in elf: ELFFile) -> String? { 116 | guard let dynamics = elf.dynamics64, 117 | let strings = dynamics.strings(in: elf) else { 118 | return nil 119 | } 120 | return strings.string(at: numericCast(layout.vna_name))?.string 121 | } 122 | 123 | public func _next(in elf: ELFFile) -> Self? { 124 | guard nextOffset != 0 else { 125 | return nil 126 | } 127 | let offset = self._offset + nextOffset 128 | let layout: Layout = elf.fileHandle.read( 129 | offset: numericCast(offset) 130 | ) 131 | return .init( 132 | layout: layout, 133 | _index: _index + 1, 134 | _offset: offset 135 | ) 136 | } 137 | } 138 | 139 | extension ELF64VersionNeedAux { 140 | public func name(in elf: ELFImage) -> String? { 141 | guard let dynamics = elf.dynamics64, 142 | let strings = dynamics.strings(in: elf) else { 143 | return nil 144 | } 145 | return strings.string(at: numericCast(layout.vna_name))?.string 146 | } 147 | 148 | public func _next(in elf: ELFImage) -> Self? { 149 | guard nextOffset != 0 else { 150 | return nil 151 | } 152 | let offset = self._offset + nextOffset 153 | let layout: Layout = elf.ptr 154 | .advanced(by: offset) 155 | .autoBoundPointee() 156 | return .init( 157 | layout: layout, 158 | _index: _index + 1, 159 | _offset: offset 160 | ) 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /Sources/ELFKit/Model/Version/VersionSym/ELFVersionSym.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionSym.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public struct ELF32VersionSym: LayoutWrapper { 13 | public typealias Layout = Elf32_Versym 14 | 15 | public var layout: Layout 16 | } 17 | 18 | public struct ELF64VersionSym: LayoutWrapper { 19 | public typealias Layout = Elf64_Versym 20 | 21 | public var layout: Layout 22 | } 23 | 24 | extension ELF32VersionSym: ELFVersionSymProtocol { 25 | public var isHidden: Bool { 26 | let VERSYM_HIDDEN = 0x8000 27 | return (numericCast(layout) & VERSYM_HIDDEN) != 0 28 | } 29 | 30 | public var version: Int { 31 | let VERSYM_VERSION = 0x7fff 32 | if isHidden { 33 | return numericCast((numericCast(layout) & VERSYM_VERSION)) 34 | } else { 35 | return numericCast(layout) 36 | } 37 | } 38 | } 39 | 40 | extension ELF64VersionSym: ELFVersionSymProtocol { 41 | public var isHidden: Bool { 42 | let VERSYM_HIDDEN = 0x8000 43 | return (numericCast(layout) & VERSYM_HIDDEN) != 0 44 | } 45 | 46 | public var version: Int { 47 | let VERSYM_VERSION = 0x7fff 48 | if isHidden { 49 | return numericCast((numericCast(layout) & VERSYM_VERSION)) 50 | } else { 51 | return numericCast(layout) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFDynamicProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFDynamicProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/28 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFDynamicProtocol { 12 | associatedtype HashTable: ELFHashTableProtocol 13 | associatedtype GnuHashTable: ELFGnuHashTableProtocol 14 | associatedtype Symbol: ELFSymbolProtocol 15 | associatedtype Relocation: ELFRelocationProtocol 16 | associatedtype SymbolInfo: ELFSymbolInfoProtocol 17 | associatedtype VersionDef: ELFVersionDefProtocol 18 | associatedtype VersionNeed: ELFVersionNeedProtocol 19 | associatedtype VersionSym: ELFVersionSymProtocol 20 | 21 | typealias HashTableHeader = HashTable.Header 22 | 23 | var _commonTag: DynamicTag? { get } 24 | func tag(inELF header: ELFHeader) -> DynamicTag? 25 | 26 | var value: Int { get } 27 | var pointer: Int { get } 28 | } 29 | 30 | extension ELFDynamicProtocol { 31 | public func pointer(for elf: ELFImage) -> UnsafeRawPointer? { 32 | if Int(bitPattern: elf.ptr) > pointer { 33 | return elf.ptr.advanced(by: pointer) 34 | } 35 | return UnsafeRawPointer(bitPattern: pointer) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFDynamicsSequence.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFDynamicsSequence.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/09 6 | // 7 | // 8 | 9 | public protocol ELFDynamicsSequence: RandomAccessCollection 10 | where Element == Dynamic, 11 | Index == Int { 12 | associatedtype ELF: ELFRepresentable 13 | associatedtype Dynamic: ELFDynamicProtocol, LayoutWrapper 14 | 15 | associatedtype Symbols: RandomAccessCollection 16 | associatedtype SymbolInfos: RandomAccessCollection 17 | associatedtype VersionSyms: RandomAccessCollection 18 | 19 | /// Dynamic string table 20 | /// 21 | /// Retrieved from dynamic with `DT_STRTAB` tag 22 | /// 23 | /// The contents are the same as in the `.dynstr` section. 24 | /// 25 | /// - Parameter elf: ELF to which this dynamic belongs 26 | /// - Returns: string table 27 | func strings(in elf: ELF) -> ELF.Strings? 28 | /// List of depended shared objects. 29 | /// 30 | /// Retrieved from dynamic with `DT_NEEDED` tag 31 | /// 32 | /// - Parameter elf: ELF to which this dynamic belongs 33 | /// - Returns: shared object names 34 | func neededs(in elf: ELF) -> [String] 35 | /// List of runpaths 36 | /// 37 | /// Retrieved from dynamic with `DT_RPATH` tag 38 | /// 39 | /// - Warning: `DT_RUNPATH` is often used instead of `DT_RPATH` in modern linkers 40 | /// Also consider using the ``runpaths(in:)`` method 41 | /// - Parameter elf: ELF to which this dynamic belongs 42 | /// - Returns: runpaths 43 | func rpaths(in elf: ELF) -> [String] 44 | /// List of runpaths 45 | /// 46 | /// Retrieved from dynamic with `DT_RUNPATH` tag 47 | /// 48 | /// - Parameter elf: ELF to which this dynamic belongs 49 | /// - Returns: runpaths 50 | func runpaths(in elf: ELF) -> [String] 51 | /// Shared object name of this ELF 52 | /// 53 | /// Retrieved from dynamic with `DT_SONAME` tag 54 | /// 55 | /// - Parameter elf: ELF to which this dynamic belongs 56 | /// - Returns: shared object name 57 | func sharedObjectName(in elf: ELF) -> String? 58 | 59 | /// Hash table header for dynamic symbol 60 | /// 61 | /// Retrieved from dynamic with `DT_HASH` tag 62 | /// 63 | /// - Parameter elf: ELF to which this dynamic belongs 64 | /// - Returns: hash table header 65 | func hashTableHeader(in elf: ELF) -> Dynamic.HashTableHeader? 66 | /// Hash table for dynamic symbol 67 | /// 68 | /// Retrieved from dynamic with `DT_HASH` tag 69 | /// 70 | /// - Parameter elf: ELF to which this dynamic belongs 71 | /// - Returns: hash table 72 | func hashTable(in elf: ELF) -> Dynamic.HashTable? 73 | 74 | /// GNU Hash table header for dynamic symbol 75 | /// 76 | /// Retrieved from dynamic with `DT_GNU_HASH` tag 77 | /// 78 | /// - Parameter elf: ELF to which this dynamic belongs 79 | /// - Returns: gnu hash table header 80 | func gnuHashTableHeader(in elf: ELF) -> ELFGnuHashTableHeader? 81 | /// GNU Hash table for dynamic symbol 82 | /// 83 | /// Retrieved from dynamic with `DT_GNU_HASH` tag 84 | /// 85 | /// - Parameter elf: ELF to which this dynamic belongs 86 | /// - Returns: gnu hash table 87 | func gnuHashTable(in elf: ELF) -> Dynamic.GnuHashTable? 88 | 89 | /// Number of dynamic symbols in this elf 90 | /// - Parameter elf: ELF to which this dynamic belongs 91 | /// - Returns: number of dynamic symbols 92 | func numberOfSymbols(in elf: ELF) -> Int? 93 | 94 | /// List of dynamic symbols 95 | /// 96 | /// Retrieved from dynamic with `DT_SYMTAB` tag 97 | /// 98 | /// - Parameter elf: ELF to which this dynamic belongs 99 | /// - Returns: dynamic symbols 100 | func symbols(in elf: ELF) -> Symbols? 101 | 102 | func symbolInfos(in elf: ELF) -> SymbolInfos? 103 | 104 | func relocations(in elf: ELF) -> AnyRandomAccessCollection? 105 | 106 | var flags: DynamicFlags { get } 107 | var flags1: DynamicFlags1 { get } 108 | 109 | var numberOfVersionDefs: Int? { get } 110 | func _versionDef(in elf: ELF) -> Dynamic.VersionDef? 111 | func versionDefs(in elf: ELF) -> [Dynamic.VersionDef] 112 | 113 | var numberOfVersionNeeds: Int? { get } 114 | func _versionNeed(in elf: ELF) -> Dynamic.VersionNeed? 115 | func versionNeeds(in elf: ELF) -> [Dynamic.VersionNeed] 116 | 117 | func versionSyms(in elf: ELF) -> VersionSyms? 118 | } 119 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFHashTableProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFHashTableProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/29 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFHashTableHeaderProtocol { 12 | var numberOfBuckets: Int { get } 13 | var numberOfChains: Int { get } 14 | } 15 | 16 | public protocol ELFHashTableProtocol { 17 | associatedtype Header: ELFHashTableHeaderProtocol 18 | associatedtype Hashelt: FixedWidthInteger 19 | associatedtype Symbol: ELFSymbolProtocol 20 | 21 | var header: Header { get } 22 | var buckets: [Hashelt] { get } 23 | var chains: [Hashelt] { get } 24 | 25 | init(header: Header, buckets: [Hashelt], chains: [Hashelt]) 26 | 27 | func findSymbol(named symbol: String, in elf: ELFFile) -> Symbol? 28 | func findSymbol(named symbol: String, in elf: ELFImage) -> Symbol? 29 | 30 | static func hash(for name: String) -> Int 31 | } 32 | 33 | extension ELFHashTableProtocol { 34 | public static func hash(for name: String) -> Int { 35 | let cString = name.cString(using: .utf8) 36 | var h: UInt = 0 37 | 38 | if let cString { 39 | for ch in cString where ch != 0 { 40 | h = (h &<< 4) + UInt(ch) 41 | let g = h & 0xf0000000 42 | if g > 0 { 43 | h ^= g &>> 24 44 | } 45 | h &= ~g 46 | } 47 | } 48 | 49 | return numericCast(h) 50 | } 51 | } 52 | 53 | extension ELFHashTableProtocol { 54 | @_disfavoredOverload 55 | public func findSymbol( 56 | named symbol: String, 57 | in elf: ELFFile 58 | ) -> (any ELFSymbolProtocol)? { 59 | findSymbol(named: symbol, in: elf) 60 | } 61 | 62 | @_disfavoredOverload 63 | public func findSymbol( 64 | named symbol: String, 65 | in elf: ELFImage 66 | ) -> (any ELFSymbolProtocol)? { 67 | findSymbol(named: symbol, in: elf) 68 | } 69 | } 70 | 71 | public protocol ELFGnuHashTableProtocol { 72 | associatedtype Hashelt: FixedWidthInteger 73 | associatedtype Bloom: FixedWidthInteger 74 | associatedtype Symbol: ELFSymbolProtocol 75 | 76 | var header: ELFGnuHashTableHeader { get } 77 | 78 | var bloom: [Bloom] { get } 79 | var buckets: [Hashelt] { get } 80 | 81 | var chainsOffset: Int { get } 82 | 83 | init(header: ELFGnuHashTableHeader, bloom: [Bloom], buckets: [Hashelt], chainsOffset: Int) 84 | 85 | func numberOfSymbols(in elf: ELFFile) -> Int? 86 | func numberOfSymbols(in elf: ELFImage) -> Int? 87 | 88 | func findSymbol(named symbol: String, in elf: ELFFile) -> Symbol? 89 | func findSymbol(named symbol: String, in elf: ELFImage) -> Symbol? 90 | 91 | static func hash(for name: String) -> Int 92 | } 93 | 94 | extension ELFGnuHashTableProtocol { 95 | public func numberOfSymbols(in elf: ELFFile) -> Int? { 96 | // https://flapenguin.me/elf-dt-gnu-hash 97 | guard let maxBucket = buckets.max(), 98 | 0 < maxBucket else { 99 | return nil 100 | } 101 | var ix: UInt32 = numericCast(maxBucket) 102 | var chain: Hashelt = elf.fileHandle.read( 103 | offset: numericCast(chainsOffset) 104 | + numericCast(ix - header.gh_symndx) * numericCast(MemoryLayout.size) 105 | ) 106 | while (chain & 1) == 0 { 107 | ix += 1 108 | chain = elf.fileHandle.read( 109 | offset: numericCast(chainsOffset) 110 | + numericCast(ix - header.gh_symndx) * numericCast(MemoryLayout.size) 111 | ) 112 | } 113 | return numericCast(ix) + 1 // First `STN_UNDEF` symbol 114 | } 115 | 116 | public func numberOfSymbols(in elf: ELFImage) -> Int? { 117 | // https://flapenguin.me/elf-dt-gnu-hash 118 | guard let maxBucket = buckets.max(), 119 | 0 < maxBucket else { 120 | return nil 121 | } 122 | var ix: UInt32 = numericCast(maxBucket) 123 | var chain: Hashelt = elf.ptr 124 | .advanced( 125 | by: numericCast(chainsOffset) 126 | + numericCast(ix - header.gh_symndx) * numericCast(MemoryLayout.size) 127 | ) 128 | .autoBoundPointee() 129 | while (chain & 1) == 0 { 130 | ix += 1 131 | chain = elf.ptr 132 | .advanced( 133 | by: numericCast(chainsOffset) 134 | + numericCast(ix - header.gh_symndx) * numericCast(MemoryLayout.size) 135 | ) 136 | .autoBoundPointee() 137 | } 138 | return numericCast(ix) + 1 // First `STN_UNDEF` symbol 139 | } 140 | } 141 | 142 | extension ELFGnuHashTableProtocol { 143 | public static func hash(for name: String) -> Int { 144 | let cString = name.cString(using: .utf8) 145 | var h: UInt = 5381 146 | 147 | if let cString { 148 | for ch in cString where ch != 0 { 149 | h = h &* 33 + UInt(ch) 150 | } 151 | } 152 | 153 | return numericCast(h & 0xffffffff) 154 | } 155 | } 156 | 157 | extension ELFGnuHashTableProtocol { 158 | @_disfavoredOverload 159 | public func findSymbol( 160 | named symbol: String, 161 | in elf: ELFFile 162 | ) -> (any ELFSymbolProtocol)? { 163 | findSymbol(named: symbol, in: elf) 164 | } 165 | 166 | @_disfavoredOverload 167 | public func findSymbol( 168 | named symbol: String, 169 | in elf: ELFImage 170 | ) -> (any ELFSymbolProtocol)? { 171 | findSymbol(named: symbol, in: elf) 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFNoteHeaderProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFNoteHeaderProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public protocol ELFNoteHeaderProtocol { 13 | var nameSize: Int { get } 14 | var descriptionSize: Int { get } 15 | var type: Int { get } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFNoteProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFNoteProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/28 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFNoteProtocol { 12 | associatedtype Header: ELFNoteHeaderProtocol, LayoutWrapper 13 | 14 | var header: Header { get } 15 | var name: String? { get } 16 | var descriptionData: Data? { get } 17 | 18 | init?(data: Data) 19 | 20 | var gnuNoteContent: GnuNoteContent? { get } 21 | } 22 | 23 | extension ELFNoteProtocol { 24 | var layoutSize: Int { 25 | header.layoutSize + header.nameSize + header.descriptionSize 26 | } 27 | 28 | var align: Int { 4 } 29 | 30 | var padding: Int { 31 | let reminder = layoutSize % align 32 | if reminder == 0 { return 0 } 33 | return align - reminder 34 | } 35 | } 36 | 37 | extension ELFNoteProtocol { 38 | public var gnuNoteContent: GnuNoteContent? { 39 | guard let name, name == "GNU", 40 | let descriptionData else { 41 | return nil 42 | } 43 | guard let type = GnuNoteType(rawValue: numericCast(header.type)) else { 44 | return nil 45 | } 46 | switch type { 47 | case .abi_tag: 48 | guard let abiTag = GnuABITag(data: descriptionData) else { 49 | return nil 50 | } 51 | return .abi_tag(abiTag) 52 | case .hwcap: 53 | guard let cap = GnuHardwareCapabilities(data: descriptionData) else { 54 | return nil 55 | } 56 | return .hwcap(cap) 57 | case .build_id: 58 | let id = descriptionData 59 | .map { $0 & 0xFF } 60 | .map { String(format: "%02x", $0) } 61 | .joined() 62 | return .build_id(id) 63 | case .gold_version: 64 | guard let version = String(cString: descriptionData) else { 65 | return nil 66 | } 67 | return .gold_version(version) 68 | case .property_type_0: 69 | return .property_type_0(descriptionData) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFProgramHeaderProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFProgramHeaderProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFProgramHeaderProtocol { 12 | associatedtype Relocation: ELFRelocationProtocol 13 | associatedtype Note: ELFNoteProtocol 14 | associatedtype Dynamic: ELFDynamicProtocol 15 | 16 | var _commonType: ProgramType? { get } 17 | func type(inELF header: ELFHeader) -> ProgramType? 18 | 19 | var _commonFlags: ProgramFlags { get } 20 | func flags(inELF header: ELFHeader) -> ProgramFlags 21 | 22 | var offset: Int { get } 23 | var virtualAddress: Int { get } 24 | var physicalAddress: Int { get } 25 | var fileSize: Int { get } 26 | var memorySize: Int { get } 27 | var align: Int { get } 28 | 29 | func _notes(in elf: ELFFile) -> _ELFNotes? 30 | func _dynamics(in elf: ELFFile) -> DataSequence? 31 | 32 | func _notes(in elf: ELFImage) -> _ELFNotes? 33 | func _dynamics(in elf: ELFImage) -> MemorySequence? 34 | } 35 | 36 | extension ELFProgramHeaderProtocol { 37 | public func _notes(in elf: ELFFile) -> _ELFNotes? { 38 | guard type(inELF: elf.header) == .note else { return nil } 39 | let data = elf.fileHandle.readData( 40 | offset: numericCast(offset), 41 | size: fileSize 42 | ) 43 | return .init(data: data) 44 | } 45 | 46 | @_disfavoredOverload 47 | public func _notes(in elf: ELFFile) -> AnySequence? { 48 | guard let sequence: _ELFNotes = _notes(in: elf) else { 49 | return nil 50 | } 51 | return AnySequence(sequence.map { 52 | $0 as (any ELFNoteProtocol) 53 | }) 54 | } 55 | } 56 | 57 | extension ELFProgramHeaderProtocol { 58 | public func _notes(in elf: ELFImage) -> _ELFNotes? { 59 | guard type(inELF: elf.header) == .note else { return nil } 60 | let data: Data = .init( 61 | bytes: elf.ptr.advanced(by: virtualAddress), 62 | count: memorySize 63 | ) 64 | return .init(data: data) 65 | } 66 | 67 | @_disfavoredOverload 68 | public func _notes(in elf: ELFImage) -> AnySequence? { 69 | guard let sequence: _ELFNotes = _notes(in: elf) else { 70 | return nil 71 | } 72 | return AnySequence(sequence.map { 73 | $0 as (any ELFNoteProtocol) 74 | }) 75 | } 76 | } 77 | 78 | extension ELFProgramHeaderProtocol where Dynamic: LayoutWrapper { 79 | public func _dynamics(in elf: ELFFile) -> DataSequence? { 80 | guard type(inELF: elf.header) == .dynamic else { return nil } 81 | let count = fileSize / Dynamic.layoutSize 82 | return elf.fileHandle.readDataSequence( 83 | offset: UInt64(offset), 84 | numberOfElements: count 85 | ) 86 | } 87 | 88 | public func _dynamics(in elf: ELFImage) -> MemorySequence? { 89 | guard type(inELF: elf.header) == .dynamic else { return nil } 90 | let count = fileSize / Dynamic.layoutSize 91 | return .init( 92 | .init( 93 | basePointer: elf.ptr 94 | .advanced(by: virtualAddress) 95 | .assumingMemoryBound(to: Dynamic.self), 96 | numberOfElements: count 97 | ) 98 | ) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFRelocationProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFRelocationProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/29 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFRelocationProtocol { 12 | var offset: Int { get } 13 | var symbolIndex: Int { get } 14 | var _type: Int { get } 15 | var addend: Int { get } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFRepresentable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFRepresentable.swift 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/08 6 | // 7 | // 8 | 9 | 10 | import Foundation 11 | 12 | public protocol ELFRepresentable { 13 | associatedtype Programs64: RandomAccessCollection 14 | associatedtype Programs32: RandomAccessCollection 15 | 16 | associatedtype Dynamics64: ELFDynamicsSequence where Dynamics64.ELF == Self 17 | associatedtype Dynamics32: ELFDynamicsSequence where Dynamics32.ELF == Self 18 | 19 | associatedtype Symbols64: RandomAccessCollection 20 | associatedtype Symbols32: RandomAccessCollection 21 | 22 | associatedtype Strings: StringTable 23 | 24 | /// A boolean value that indicates whether ELF is a 64-bit architecture. 25 | var is64Bit: Bool { get } 26 | 27 | /// Size of ELF header. [byte] 28 | var headerSize: Int { get } 29 | 30 | /// ELF header 31 | var header: ELFHeader { get } 32 | 33 | /// List of runpaths 34 | var rpaths: [String] { get } 35 | /// List of depended dynamic libraries 36 | var dependencies: [String] { get } 37 | 38 | /// List of segments 39 | var programs: [any ELFProgramHeaderProtocol] { get } 40 | /// Sequence of 64-bit architecture segments 41 | var programs64: Programs64? { get } 42 | /// Sequence of 32-bit architecture segments 43 | var programs32: Programs32? { get } 44 | 45 | /// List of dynamics 46 | var dynamics: [any ELFDynamicProtocol]? { get } 47 | /// Sequence of 64-bit architecture dynamics 48 | var dynamics64: Dynamics64? { get } 49 | /// Sequence of 32-bit architecture dynamics 50 | var dynamics32: Dynamics32? { get } 51 | 52 | /// List of dynamic symbols 53 | var dynamicSymbols: [any ELFSymbolProtocol] { get } 54 | /// Sequence of 64-bit architecture dynamic symbols 55 | var dynamicSymbols64: Symbols64? { get } 56 | /// Sequence of 32-bit architecture dynamic symbols 57 | var dynamicSymbols32: Symbols32? { get } 58 | 59 | /// Sequence of dynamic symbol strings. 60 | var dynamicStringTable: Strings? { get } 61 | } 62 | 63 | extension ELFRepresentable { 64 | public var programs: [any ELFProgramHeaderProtocol] { 65 | if let programs64 { 66 | return Array(programs64) 67 | } else if let programs32 { 68 | return Array(programs32) 69 | } 70 | return [] 71 | } 72 | 73 | public var dynamics: [any ELFDynamicProtocol]? { 74 | if is64Bit { 75 | dynamics64?.map { $0 } 76 | } else { 77 | dynamics32?.map { $0 } 78 | } 79 | } 80 | 81 | public var dynamicSymbols: [any ELFSymbolProtocol] { 82 | if is64Bit, let dynamicSymbols64 { 83 | return Array(dynamicSymbols64) 84 | } else if let dynamicSymbols32 { 85 | return Array(dynamicSymbols32) 86 | } else { 87 | return [] 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFSectionHeaderProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFSectionHeaderProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFSectionHeaderProtocol { 12 | associatedtype Relocation: ELFRelocationProtocol 13 | associatedtype Note: ELFNoteProtocol 14 | associatedtype Dynamic: ELFDynamicProtocol 15 | 16 | var nameOffset: Int { get } 17 | 18 | var _commonFlags: SectionFlags { get } 19 | func flags(inELF header: ELFHeader) -> SectionFlags 20 | 21 | var address: Int { get } 22 | var offset: Int { get } 23 | var size: Int { get } 24 | var link: Int { get } 25 | var addressAlignment: Int { get } 26 | var entrySize: Int { get } 27 | 28 | var _commonType: SectionType? { get } 29 | func type(inELF header: ELFHeader) -> SectionType? 30 | 31 | func name(in elf: ELFFile) -> String? 32 | 33 | func _strings(in elf: ELFFile) -> ELFFile.Strings? 34 | func _relocations(in elf: ELFFile) -> AnyRandomAccessCollection? 35 | func _notes(in elf: ELFFile) -> _ELFNotes? 36 | func _dynamics(in elf: ELFFile) -> DataSequence? 37 | 38 | func _hashTableHeader(in elf: ELFFile) -> Dynamic.HashTableHeader? 39 | func _hashTable(in elf: ELFFile) -> Dynamic.HashTable? 40 | 41 | func _gnuHashTableHeader(in elf: ELFFile) -> ELFGnuHashTableHeader? 42 | func _gnuHashTable(in elf: ELFFile) -> Dynamic.GnuHashTable? 43 | 44 | func _versionDef(in elf: ELFFile) -> Dynamic.VersionDef? 45 | func _versionDefs(in elf: ELFFile) -> [Dynamic.VersionDef]? 46 | 47 | func _versionNeed(in elf: ELFFile) -> Dynamic.VersionNeed? 48 | func _versionNeeds(in elf: ELFFile) -> [Dynamic.VersionNeed]? 49 | 50 | func _versionSyms(in elf: ELFFile) -> DataSequence? 51 | 52 | func _strings(in elf: ELFImage) -> ELFImage.Strings? 53 | } 54 | 55 | extension ELFSectionHeaderProtocol { 56 | public func name(in elf: ELFFile) -> String? { 57 | guard let data = elf.sectionHeaderStrings?.data else { 58 | return nil 59 | } 60 | return String( 61 | cString: data.advanced(by: nameOffset) 62 | ) 63 | } 64 | } 65 | 66 | // MARK: - String Table 67 | extension ELFSectionHeaderProtocol { 68 | public func _strings(in elf: ELFFile) -> ELFFile.Strings? { 69 | guard type(inELF: elf.header) == .strtab else { return nil } 70 | return .init( 71 | elf: elf, 72 | offset: offset, 73 | size: size 74 | ) 75 | } 76 | 77 | public func _strings(in elf: ELFImage) -> ELFImage.Strings? { 78 | guard type(inELF: elf.header) == .strtab else { return nil } 79 | return .init( 80 | basePointer: elf.ptr 81 | .advanced(by: offset) 82 | .assumingMemoryBound(to: UInt8.self), 83 | tableSize: size 84 | ) 85 | } 86 | } 87 | 88 | // MARK: - Note 89 | extension ELFSectionHeaderProtocol { 90 | public func _notes(in elf: ELFFile) -> _ELFNotes? { 91 | guard type(inELF: elf.header) == .note else { return nil } 92 | let data = elf.fileHandle.readData( 93 | offset: numericCast(offset), 94 | size: size 95 | ) 96 | return .init(data: data) 97 | } 98 | 99 | @_disfavoredOverload 100 | public func _notes(in elf: ELFFile) -> AnySequence? { 101 | guard let sequence: _ELFNotes = _notes(in: elf) else { 102 | return nil 103 | } 104 | return AnySequence(sequence.map { 105 | $0 as (any ELFNoteProtocol) 106 | }) 107 | } 108 | } 109 | 110 | // MARK: - Dynamics 111 | extension ELFSectionHeaderProtocol where Dynamic: LayoutWrapper { 112 | public func _dynamics(in elf: ELFFile) -> DataSequence? { 113 | guard type(inELF: elf.header) == .dynamic else { return nil } 114 | let count = size / Dynamic.layoutSize 115 | return .init( 116 | elf.fileHandle.readDataSequence( 117 | offset: UInt64(offset), 118 | numberOfElements: count 119 | ) 120 | ) 121 | } 122 | } 123 | 124 | // MARK: - Hash Table 125 | extension ELFSectionHeaderProtocol where Dynamic.HashTableHeader: LayoutWrapper { 126 | public func _hashTableHeader(in elf: ELFFile) -> Dynamic.HashTableHeader? { 127 | guard type(inELF: elf.header) == .hash else { return nil } 128 | return elf.fileHandle.read( 129 | offset: numericCast(offset) 130 | ) 131 | } 132 | 133 | public func _hashTable(in elf: ELFFile) -> Dynamic.HashTable? { 134 | guard let header = _hashTableHeader(in: elf) else { 135 | return nil 136 | } 137 | return header._readContent( 138 | in: elf, 139 | at: offset 140 | ) 141 | } 142 | } 143 | 144 | // MARK: - GNU Hash Table 145 | extension ELFSectionHeaderProtocol { 146 | public func _gnuHashTableHeader(in elf: ELFFile) -> ELFGnuHashTableHeader? { 147 | guard let name = name(in: elf), 148 | name.starts(with: ".gnu"), 149 | type(inELF: elf.header) == .gnu_hash else { 150 | return nil 151 | } 152 | return elf.fileHandle.read( 153 | offset: numericCast(offset) 154 | ) 155 | } 156 | 157 | public func _gnuHashTable(in elf: ELFFile) -> Dynamic.GnuHashTable? { 158 | guard let header = _gnuHashTableHeader(in: elf) else { 159 | return nil 160 | } 161 | return header._readContent( 162 | in: elf, 163 | at: offset 164 | ) 165 | } 166 | } 167 | 168 | // MARK: - Verson Defs 169 | extension ELFSectionHeaderProtocol { 170 | public func _versionDefs(in elf: ELFFile) -> [Dynamic.VersionDef]? { 171 | var def = _versionDef(in: elf) 172 | if def == nil { return nil } 173 | var defs: [Dynamic.VersionDef] = [] 174 | while def != nil { 175 | guard let _def = def else { break } 176 | defs.append(_def) 177 | def = _def._next(in: elf) 178 | } 179 | return defs 180 | } 181 | } 182 | 183 | // MARK: - Verson Needs 184 | extension ELFSectionHeaderProtocol { 185 | public func _versionNeeds(in elf: ELFFile) -> [Dynamic.VersionNeed]? { 186 | var def = _versionNeed(in: elf) 187 | if def == nil { return nil } 188 | var defs: [Dynamic.VersionNeed] = [] 189 | while def != nil { 190 | guard let _def = def else { break } 191 | defs.append(_def) 192 | def = _def._next(in: elf) 193 | } 194 | return defs 195 | } 196 | } 197 | 198 | // MARK: - Version Syms 199 | extension ELFSectionHeaderProtocol where Dynamic.VersionSym: LayoutWrapper { 200 | public func _versionSyms(in elf: ELFFile) -> DataSequence? { 201 | guard [.gnu_versym, .sunw_versym].contains(type(inELF: elf.header)) else { 202 | return nil 203 | } 204 | let numberOfSymbols = size / Dynamic.VersionSym.layoutSize 205 | return elf.fileHandle.readDataSequence( 206 | offset: numericCast(offset), 207 | numberOfElements: numberOfSymbols 208 | ) 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFSymbolInfoProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFSymbolInfoProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFSymbolInfoProtocol { 12 | var dynamicEntryIndex: Int? { get } 13 | var specialBound: SymbolInfoSpecialBound? { get } 14 | var flags: SymbolInfoFlags { get } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFSymbolProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFSymbolProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | import ELFKitC 11 | 12 | public protocol ELFSymbolProtocol { 13 | var nameOffset: Int { get } 14 | 15 | var _commonBinding: SymbolBinding? { get } 16 | func binding(inELF header: ELFHeader) -> SymbolBinding? 17 | 18 | var _commonType: SymbolType? { get } 19 | func type(inELF header: ELFHeader) -> SymbolType? 20 | 21 | var visibility: SymbolVisibility! { get } 22 | var sectionIndex: Int? { get } 23 | 24 | var _commonSpecialSection: SpecialSectionIndex? { get } 25 | func specialSection(inELF header: ELFHeader) -> SpecialSectionIndex? 26 | 27 | func name(in elf: ELFFile, isDynamic: Bool) -> String? 28 | func demangledName(in elf: ELFFile, isDynamic: Bool) -> String? 29 | 30 | func name(in elf: ELFImage, isDynamic: Bool) -> String? 31 | func demangledName(in elf: ELFImage, isDynamic: Bool) -> String? 32 | } 33 | 34 | extension ELFSymbolProtocol { 35 | public func name(in elf: ELFFile, isDynamic: Bool) -> String? { 36 | var strings: ELFFile.Strings? 37 | if isDynamic { 38 | strings = elf.dynamicStringTable 39 | } else { 40 | strings = elf.stringTable 41 | } 42 | guard let strings else { return nil } 43 | return strings.string(at: nameOffset)?.string 44 | } 45 | 46 | public func name(in elf: ELFImage, isDynamic: Bool) -> String? { 47 | var strings: ELFImage.Strings? 48 | if isDynamic { 49 | strings = elf.dynamicStringTable 50 | } else { 51 | // FIXME: section is not available 52 | // strings = elf.stringTable 53 | } 54 | guard let strings else { return nil } 55 | return strings.string(at: nameOffset)?.string 56 | } 57 | } 58 | 59 | extension ELFSymbolProtocol { 60 | public func demangledName(in elf: ELFFile, isDynamic: Bool) -> String? { 61 | guard let name = name(in: elf, isDynamic: isDynamic) else { 62 | return nil 63 | } 64 | return stdlib_demangleName(name) 65 | } 66 | 67 | public func demangledName(in elf: ELFImage, isDynamic: Bool) -> String? { 68 | guard let name = name(in: elf, isDynamic: isDynamic) else { 69 | return nil 70 | } 71 | return stdlib_demangleName(name) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFVersionDefAuxProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionDefAuxProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFVersionDefAuxProtocol { 12 | var _offset: Int { get } 13 | var _index: Int { get } 14 | var nameOffset: Int { get } 15 | var nextOffset: Int { get } 16 | 17 | func name(in elf: ELFFile) -> String? 18 | func _next(in elf: ELFFile) -> Self? 19 | 20 | func name(in elf: ELFImage) -> String? 21 | func _next(in elf: ELFImage) -> Self? 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFVersionDefProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionDefProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFVersionDefProtocol { 12 | associatedtype Aux: ELFVersionDefAuxProtocol 13 | 14 | var _offset: Int { get } 15 | var _index: Int { get } 16 | 17 | var flags: VersionFlags { get } 18 | var versionIndex: Int { get } 19 | var numberOfAux: Int { get } 20 | var hash: Int { get } 21 | var auxOffset: Int { get } 22 | var nextOffset: Int { get } 23 | 24 | func auxes(in elf: ELFFile) -> [Aux] 25 | func _next(in elf: ELFFile) -> Self? 26 | func _aux(in elf: ELFFile) -> Aux? 27 | 28 | func auxes(in elf: ELFImage) -> [Aux] 29 | func _next(in elf: ELFImage) -> Self? 30 | func _aux(in elf: ELFImage) -> Aux? 31 | } 32 | 33 | extension ELFVersionDefProtocol { 34 | public func auxes(in elf: ELFFile) -> [Aux] { 35 | var aux = _aux(in: elf) 36 | var auxes: [Aux] = [] 37 | while aux != nil { 38 | guard let _aux = aux else { break } 39 | auxes.append(_aux) 40 | aux = _aux._next(in: elf) 41 | } 42 | return auxes 43 | } 44 | 45 | public func auxes(in elf: ELFImage) -> [Aux] { 46 | var aux = _aux(in: elf) 47 | var auxes: [Aux] = [] 48 | while aux != nil { 49 | guard let _aux = aux else { break } 50 | auxes.append(_aux) 51 | aux = _aux._next(in: elf) 52 | } 53 | return auxes 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFVersionNeedAuxProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionDefNeedProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFVersionNeedAuxProtocol { 12 | var _offset: Int { get } 13 | var _index: Int { get } 14 | var hash: Int { get } 15 | var flags: VersionFlags { get } 16 | var version: Int { get } 17 | var nextOffset: Int { get } 18 | 19 | func name(in elf: ELFFile) -> String? 20 | func _next(in elf: ELFFile) -> Self? 21 | 22 | func name(in elf: ELFImage) -> String? 23 | func _next(in elf: ELFImage) -> Self? 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFVersionNeedProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionNeedProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ELFVersionNeedProtocol { 12 | associatedtype Aux: ELFVersionNeedAuxProtocol 13 | 14 | var _offset: Int { get } 15 | var _index: Int { get } 16 | 17 | var fileNameOffset: Int { get } 18 | var numberOfAux: Int { get } 19 | var auxOffset: Int { get } 20 | var nextOffset: Int { get } 21 | 22 | func fileName(in elf: ELFFile) -> String? 23 | func auxes(in elf: ELFFile) -> [Aux] 24 | func _next(in elf: ELFFile) -> Self? 25 | func _aux(in elf: ELFFile) -> Aux? 26 | 27 | func fileName(in elf: ELFImage) -> String? 28 | func auxes(in elf: ELFImage) -> [Aux] 29 | func _next(in elf: ELFImage) -> Self? 30 | func _aux(in elf: ELFImage) -> Aux? 31 | } 32 | 33 | extension ELFVersionNeedProtocol { 34 | public func auxes(in elf: ELFFile) -> [Aux] { 35 | var aux = _aux(in: elf) 36 | var auxes: [Aux] = [] 37 | while aux != nil { 38 | guard let _aux = aux else { break } 39 | auxes.append(_aux) 40 | aux = _aux._next(in: elf) 41 | } 42 | return auxes 43 | } 44 | 45 | public func auxes(in elf: ELFImage) -> [Aux] { 46 | var aux = _aux(in: elf) 47 | var auxes: [Aux] = [] 48 | while aux != nil { 49 | guard let _aux = aux else { break } 50 | auxes.append(_aux) 51 | aux = _aux._next(in: elf) 52 | } 53 | return auxes 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/ELFVersionSymProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ELFVersionSymProtocol.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/30 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | // ref: https://github.com/freebsd/freebsd-src/blob/f76effed14b25bfa0c47b10f6d8a076104c48d94/contrib/elftoolchain/readelf/readelf.c#L4113 12 | public protocol ELFVersionSymProtocol { 13 | var isHidden: Bool { get } 14 | var version: Int { get } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ELFKit/Protocol/LayoutWrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutWrapper.swift 3 | // 4 | // 5 | // Created by p-x9 on 2023/11/29. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | @dynamicMemberLookup 12 | public protocol LayoutWrapper { 13 | associatedtype Layout 14 | 15 | var layout: Layout { get set } 16 | } 17 | 18 | extension LayoutWrapper { 19 | public subscript(dynamicMember keyPath: KeyPath) -> Value { 20 | layout[keyPath: keyPath] 21 | } 22 | } 23 | 24 | extension LayoutWrapper { 25 | static var layoutSize: Int { 26 | MemoryLayout.size 27 | } 28 | 29 | var layoutSize: Int { 30 | MemoryLayout.size 31 | } 32 | } 33 | 34 | extension LayoutWrapper { 35 | static func layoutOffset(of key: PartialKeyPath) -> Int { 36 | MemoryLayout.offset(of: key)! 37 | } 38 | 39 | func layoutOffset(of key: PartialKeyPath) -> Int { 40 | MemoryLayout.offset(of: key)! 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/ELFKit/Sections.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sections.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/27 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | extension Sequence where Element: ELFSectionHeaderProtocol { 12 | var _dynamic: Element? { 13 | first(where: { $0._commonType == .dynamic }) 14 | } 15 | 16 | var _dynsym: Element? { 17 | first(where: { $0._commonType == .dynsym }) 18 | } 19 | 20 | var _symtab: Element? { 21 | first(where: { $0._commonType == .symtab }) 22 | } 23 | 24 | func _dynstr(in elf: ELFFile) -> Element? { 25 | first(where: { 26 | $0._commonType == .strtab && $0.name(in: elf) == ".dynstr" 27 | }) 28 | } 29 | 30 | func _strtab(in elf: ELFFile) -> Element? { 31 | first(where: { 32 | $0._commonType == .strtab && $0.name(in: elf) == ".strtab" 33 | }) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/ELFKit/Segments.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Segments.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/29 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | extension Sequence where Element: ELFProgramHeaderProtocol { 12 | var _dynamic: Element? { 13 | first(where: { $0._commonType == .dynamic }) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ELFKit/Util/BitFlags.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BitFlags.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/01/20. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol BitFlags: OptionSet { 12 | associatedtype Bit: CaseIterable, RawRepresentable, CustomStringConvertible where Bit.RawValue == RawValue 13 | 14 | associatedtype Element = Self 15 | 16 | var rawValue: RawValue { get } 17 | } 18 | 19 | extension BitFlags where Element == Self { 20 | public var bits: [Bit] { 21 | Bit.allCases 22 | .lazy 23 | .filter { 24 | contains(.init(rawValue: $0.rawValue)) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ELFKit/Util/ConditionalBitFlags.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConditionalBitFlags.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/11 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ConditionalBitFlags: SetAlgebra { 12 | associatedtype RawValue: FixedWidthInteger 13 | associatedtype Element = Bit 14 | associatedtype Bit: Hashable, CaseIterable, RawRepresentable, CustomStringConvertible where Bit.RawValue == RawValue 15 | associatedtype ArrayLiteralElement = Element 16 | var rawValue: RawValue { get set } 17 | var _bits: Set { get set } 18 | 19 | init(rawValue: RawValue, _bits: Set) 20 | } 21 | 22 | extension ConditionalBitFlags where Element == Bit { 23 | public func contains(_ member: Element) -> Bool { 24 | _bits.contains(member) 25 | } 26 | 27 | public func union(_ other: Self) -> Self { 28 | .init( 29 | rawValue: rawValue | other.rawValue, 30 | _bits: _bits.union(other._bits) 31 | ) 32 | } 33 | 34 | public func intersection(_ other: Self) -> Self { 35 | .init( 36 | rawValue: rawValue & other.rawValue, 37 | _bits: _bits.intersection(other._bits) 38 | ) 39 | } 40 | 41 | public func symmetricDifference(_ other: Self) -> Self { 42 | .init( 43 | rawValue: rawValue ^ other.rawValue, 44 | _bits: _bits.symmetricDifference(other._bits) 45 | ) 46 | } 47 | 48 | public mutating func formUnion(_ other: Self) { 49 | rawValue = rawValue | other.rawValue 50 | _bits.formUnion(other._bits) 51 | } 52 | 53 | public mutating func formIntersection(_ other: Self) { 54 | rawValue = rawValue & other.rawValue 55 | _bits.formIntersection(other._bits) 56 | } 57 | 58 | public mutating func formSymmetricDifference(_ other: Self) { 59 | rawValue = rawValue ^ other.rawValue 60 | _bits.formSymmetricDifference(other._bits) 61 | } 62 | 63 | public init() { 64 | self.init(rawValue: 0, _bits: []) 65 | } 66 | 67 | public mutating func insert(_ newMember: __owned Bit) -> (inserted: Bool, memberAfterInsert: Bit) { 68 | rawValue = rawValue | newMember.rawValue 69 | return _bits.insert(newMember) 70 | } 71 | 72 | public mutating func remove(_ member: Bit) -> Bit? { 73 | rawValue = rawValue & ~member.rawValue 74 | return _bits.remove(member) 75 | } 76 | 77 | public mutating func update(with newMember: __owned Bit) -> Bit? { 78 | rawValue = rawValue | newMember.rawValue 79 | return _bits.update(with: newMember) 80 | } 81 | } 82 | 83 | extension ConditionalBitFlags { 84 | public var bits: [Bit] { 85 | Array(_bits) 86 | } 87 | 88 | public var unknownBits: RawValue { 89 | var rawValue = rawValue 90 | bits.forEach { rawValue &= ~$0.rawValue } 91 | return rawValue 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Sources/ELFKit/Util/Sequence/DataSequence.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataSequence.swift 3 | // 4 | // 5 | // Created by p-x9 on 2023/12/06. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public struct DataSequence: Sequence { 12 | public typealias Element = T 13 | 14 | private let data: Data 15 | private let entrySize: Int 16 | private let numberOfElements: Int 17 | 18 | @_spi(Support) 19 | public init( 20 | data: Data, 21 | numberOfElements: Int 22 | ) { 23 | self.data = data 24 | self.entrySize = MemoryLayout.size 25 | self.numberOfElements = numberOfElements 26 | } 27 | 28 | @_spi(Support) 29 | public init( 30 | data: Data, 31 | entrySize: Int 32 | ) { 33 | self.data = data 34 | self.entrySize = entrySize 35 | self.numberOfElements = data.count / entrySize 36 | } 37 | 38 | public func makeIterator() -> Iterator { 39 | Iterator( 40 | data: data, 41 | entrySize: entrySize, 42 | numberOfElements: numberOfElements 43 | ) 44 | } 45 | } 46 | 47 | extension DataSequence { 48 | public var size: Int { 49 | data.count 50 | } 51 | } 52 | 53 | extension DataSequence { 54 | public struct Iterator: IteratorProtocol { 55 | public typealias Element = T 56 | 57 | private let data: Data 58 | private let entrySize: Int 59 | private let numberOfElements: Int 60 | 61 | private var nextIndex: Int = 0 62 | private var nextOffset: Int = 0 63 | 64 | init( 65 | data: Data, 66 | entrySize: Int, 67 | numberOfElements: Int 68 | ) { 69 | self.data = data 70 | self.entrySize = entrySize 71 | self.numberOfElements = numberOfElements 72 | } 73 | 74 | public mutating func next() -> Element? { 75 | guard nextIndex < numberOfElements else { return nil } 76 | guard nextOffset + entrySize <= data.count else { return nil } 77 | 78 | defer { 79 | nextIndex += 1 80 | nextOffset += entrySize 81 | } 82 | 83 | return data.withUnsafeBytes { 84 | guard let baseAddress = $0.baseAddress else { return nil } 85 | return baseAddress.advanced(by: nextOffset).load(as: Element.self) 86 | } 87 | } 88 | } 89 | } 90 | 91 | extension DataSequence: Collection { 92 | public typealias Index = Int 93 | 94 | public var startIndex: Index { 0 } 95 | public var endIndex: Index { numberOfElements } 96 | 97 | public func index(after i: Int) -> Int { 98 | i + 1 99 | } 100 | 101 | public subscript(position: Int) -> Element { 102 | precondition(position >= 0) 103 | precondition(position < endIndex) 104 | precondition(data.count >= (position + 1) * entrySize) 105 | return data.withUnsafeBytes { 106 | guard let baseAddress = $0.baseAddress else { 107 | fatalError("data is empty") 108 | } 109 | return baseAddress 110 | .advanced(by: position * entrySize) 111 | .load(as: Element.self) 112 | } 113 | } 114 | } 115 | 116 | extension DataSequence: RandomAccessCollection {} 117 | -------------------------------------------------------------------------------- /Sources/ELFKit/Util/Sequence/MemorySequence.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MemorySequence.swift 3 | // 4 | // 5 | // Created by p-x9 on 2023/11/29. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public struct MemorySequence: Sequence { 12 | public typealias Element = T 13 | 14 | private let basePointer: UnsafeRawPointer 15 | private let entrySize: Int 16 | private let numberOfElements: Int 17 | 18 | @_spi(Support) 19 | public init( 20 | basePointer: UnsafePointer, 21 | numberOfElements: Int 22 | ) { 23 | self.basePointer = .init(basePointer) 24 | self.entrySize = MemoryLayout.size 25 | self.numberOfElements = numberOfElements 26 | } 27 | 28 | @_spi(Support) 29 | public init( 30 | basePointer: UnsafePointer, 31 | entrySize: Int, 32 | numberOfElements: Int 33 | ) { 34 | self.basePointer = .init(basePointer) 35 | self.entrySize = entrySize 36 | self.numberOfElements = numberOfElements 37 | } 38 | 39 | public func makeIterator() -> Iterator { 40 | Iterator( 41 | basePointer: basePointer, 42 | entrySize: entrySize, 43 | numberOfElements: numberOfElements 44 | ) 45 | } 46 | } 47 | 48 | extension MemorySequence { 49 | public var size: Int { 50 | entrySize * numberOfElements 51 | } 52 | } 53 | 54 | extension MemorySequence { 55 | public struct Iterator: IteratorProtocol { 56 | public typealias Element = T 57 | 58 | private let basePointer: UnsafeRawPointer 59 | private let entrySize: Int 60 | private let numberOfElements: Int 61 | 62 | private var nextIndex: Int = 0 63 | 64 | init( 65 | basePointer: UnsafeRawPointer, 66 | entrySize: Int, 67 | numberOfElements: Int 68 | ) { 69 | self.basePointer = basePointer 70 | self.entrySize = entrySize 71 | self.numberOfElements = numberOfElements 72 | } 73 | 74 | public mutating func next() -> Element? { 75 | guard nextIndex < numberOfElements else { return nil } 76 | defer { nextIndex += 1 } 77 | return basePointer 78 | .advanced(by: nextIndex * entrySize) 79 | .load(as: Element.self) 80 | } 81 | } 82 | } 83 | 84 | extension MemorySequence: Collection { 85 | public typealias Index = Int 86 | 87 | public var startIndex: Index { 0 } 88 | public var endIndex: Index { numberOfElements } 89 | 90 | public func index(after i: Int) -> Int { 91 | i + 1 92 | } 93 | 94 | public subscript(position: Int) -> Element { 95 | precondition(position >= 0) 96 | precondition(position < endIndex) 97 | return basePointer 98 | .advanced(by: position * entrySize) 99 | .load(as: Element.self) 100 | } 101 | } 102 | 103 | extension MemorySequence: RandomAccessCollection {} 104 | -------------------------------------------------------------------------------- /Sources/ELFKit/Util/SwiftDemangle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftDemangle.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/01/05. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | @_silgen_name("swift_demangle") 12 | internal func _stdlib_demangleImpl( 13 | mangledName: UnsafePointer?, 14 | mangledNameLength: UInt, 15 | outputBuffer: UnsafeMutablePointer?, 16 | outputBufferSize: UnsafeMutablePointer?, 17 | flags: UInt32 18 | ) -> UnsafeMutablePointer? 19 | 20 | internal func stdlib_demangleName( 21 | _ mangledName: String 22 | ) -> String { 23 | guard !mangledName.isEmpty else { return mangledName } 24 | return mangledName.utf8CString.withUnsafeBufferPointer { mangledNameUTF8 in 25 | let demangledNamePtr = _stdlib_demangleImpl( 26 | mangledName: mangledNameUTF8.baseAddress, 27 | mangledNameLength: numericCast(mangledNameUTF8.count - 1), 28 | outputBuffer: nil, 29 | outputBufferSize: nil, 30 | flags: 0 31 | ) 32 | 33 | if let demangledNamePtr { 34 | let demangledName = String(cString: demangledNamePtr) 35 | free(demangledNamePtr) 36 | return demangledName 37 | } 38 | return mangledName 39 | } 40 | } 41 | 42 | internal func stdlib_demangleName( 43 | _ mangledName: UnsafePointer 44 | ) -> UnsafePointer { 45 | 46 | let demangledNamePtr = _stdlib_demangleImpl( 47 | mangledName: mangledName, 48 | mangledNameLength: numericCast(strlen(mangledName)), 49 | outputBuffer: nil, 50 | outputBufferSize: nil, 51 | flags: 0 52 | ) 53 | if let demangledNamePtr { 54 | return .init(demangledNamePtr) 55 | } 56 | return mangledName 57 | } 58 | -------------------------------------------------------------------------------- /Sources/ELFKit/Util/exported.swift: -------------------------------------------------------------------------------- 1 | // 2 | // exported.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | @_exported import ELFKitC 10 | -------------------------------------------------------------------------------- /Sources/ELFKitC/dummy.c: -------------------------------------------------------------------------------- 1 | // 2 | // dummy.c 3 | // 4 | // 5 | // Created by p-x9 on 2024/04/26 6 | // 7 | // 8 | 9 | #include 10 | -------------------------------------------------------------------------------- /Sources/ELFKitC/include/additional.h: -------------------------------------------------------------------------------- 1 | // 2 | // additional.h 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/05 6 | // 7 | // 8 | 9 | #ifndef additional_h 10 | #define additional_h 11 | 12 | #endif /* additional_h */ 13 | -------------------------------------------------------------------------------- /Sources/ELFKitC/include/elf_common.h: -------------------------------------------------------------------------------- 1 | // 2 | // elf_common.h 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/12 6 | // 7 | // 8 | 9 | #ifndef elf_common_h 10 | #define elf_common_h 11 | 12 | #include 13 | 14 | #if __has_include() 15 | #include 16 | #endif 17 | 18 | // ref: https://github.com/freebsd/freebsd-src/blob/2f923a0cedb8db9b8bd042c5b457dee6333604fe/sys/sys/elf_common.h#L48 19 | typedef struct { 20 | uint32_t n_namesz; /* Length of name. */ 21 | uint32_t n_descsz; /* Length of descriptor. */ 22 | uint32_t n_type; /* Type of this note. */ 23 | } Elf_Note; 24 | typedef Elf_Note Elf_Nhdr; 25 | 26 | // ref: https://github.com/freebsd/freebsd-src/blob/2f923a0cedb8db9b8bd042c5b457dee6333604fe/sys/sys/elf_common.h#L116 27 | typedef struct { 28 | uint32_t gh_nbuckets; /* Number of hash buckets. */ 29 | uint32_t gh_symndx; /* First visible symbol in .dynsym. */ 30 | uint32_t gh_maskwords; /* #maskwords used in bloom filter. */ 31 | uint32_t gh_shift2; /* Bloom filter shift count. */ 32 | } Elf_GNU_Hash_Header; 33 | 34 | #undef EI_NIDENT 35 | #define EI_NIDENT 16 36 | 37 | #endif /* elf_common_h */ 38 | -------------------------------------------------------------------------------- /Sources/ELFKitC/include/elf_linux.h: -------------------------------------------------------------------------------- 1 | // 2 | // elf_linux.h 3 | // ELFKit 4 | // 5 | // Created by p-x9 on 2025/02/07 6 | // 7 | // 8 | 9 | #ifndef elf_linux_h 10 | #define elf_linux_h 11 | 12 | #ifdef __linux__ 13 | 14 | #include 15 | 16 | // need to check for __musl__ or else: 17 | // ELFKit/Sources/ELFKitC/include/elf_linux.h:17:8: error: redefinition of 'dl_phdr_info' 18 | #ifndef __musl__ 19 | struct dl_phdr_info { 20 | ElfW(Addr) dlpi_addr; 21 | const char *dlpi_name; 22 | const ElfW(Phdr) *dlpi_phdr; 23 | ElfW(Half) dlpi_phnum; 24 | }; 25 | #endif 26 | 27 | extern int dl_iterate_phdr(int (*callback) (struct dl_phdr_info *info, size_t size, void *data), void *data); 28 | 29 | #endif /* __linux__ */ 30 | 31 | #endif /* elf_linux_h */ 32 | -------------------------------------------------------------------------------- /Tests/ELFKitTests/ELFKitTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import ELFKit 3 | 4 | final class ELFKitTests: XCTestCase {} 5 | -------------------------------------------------------------------------------- /Tests/ELFKitTests/Util/Linux.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Linux.swift 3 | // 4 | // 5 | // Created by p-x9 on 2024/05/12 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(Linux) 12 | func autoreleasepool(block: () -> T) -> T { block() } 13 | #endif 14 | -------------------------------------------------------------------------------- /scripts/docc-preview.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TARGET='ELFKit' 4 | 5 | preview_docc() { 6 | mkdir -p docs 7 | 8 | $(xcrun --find docc) preview \ 9 | "./Sources/${TARGET}/Documentation.docc" \ 10 | --additional-symbol-graph-dir symbol-graphs \ 11 | --output-path "docs" 12 | } 13 | 14 | sh ./scripts/generate-symbols.sh 15 | 16 | preview_docc 17 | -------------------------------------------------------------------------------- /scripts/docc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TARGET='ELFKit' 4 | REPO_NAME='ELFKit' 5 | 6 | generate_docc() { 7 | mkdir -p docs 8 | 9 | $(xcrun --find docc) convert \ 10 | "./Sources/${TARGET}/Documentation.docc" \ 11 | --output-path "docs" \ 12 | --hosting-base-path "${REPO_NAME}" \ 13 | --additional-symbol-graph-dir ./symbol-graphs 14 | } 15 | 16 | sh ./scripts/generate-symbols.sh 17 | 18 | generate_docc 19 | -------------------------------------------------------------------------------- /scripts/generate-symbols.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SYMBOL_DIR='./symbol-graphs' 4 | 5 | clean_build() { 6 | rm -rf ./.build 7 | } 8 | 9 | clean_xcbuild() { 10 | destination=$1 11 | scheme=$2 12 | 13 | xcodebuild -scheme "$scheme" \ 14 | -destination "generic/platform=${destination}" \ 15 | clean 16 | } 17 | 18 | clean_symbol() { 19 | rm -rf SYMBOL_DIR 20 | } 21 | 22 | generate_symbol_graphs() { 23 | destination=$1 24 | scheme=$2 25 | 26 | mkdir -p .build/symbol-graphs 27 | mkdir -p "$SYMBOL_DIR" 28 | 29 | xcodebuild clean build -scheme "${scheme}"\ 30 | -destination "generic/platform=${destination}" \ 31 | OTHER_SWIFT_FLAGS="-emit-extension-block-symbols -emit-symbol-graph -emit-symbol-graph-dir $(pwd)/.build/symbol-graphs" 32 | 33 | mv "./.build/symbol-graphs/${scheme}.symbols.json" "${SYMBOL_DIR}/${scheme}_${destination}.symbols.json" 34 | 35 | if [ -d "./Sources/$scheme/include" ]; then 36 | local HEADERS=$(ls "./Sources/$scheme/include") 37 | while IFS= read -r header; do 38 | xcrun clang \ 39 | -extract-api \ 40 | --product-name=$scheme \ 41 | -o "$SYMBOL_DIR/$scheme-$header.json" \ 42 | "$(pwd)/Sources/$scheme/include/$header" 43 | done <<<"$HEADERS" 44 | fi 45 | } 46 | 47 | 48 | clean_build 49 | clean_xcbuild ios ELFKitC 50 | clean_xcbuild ios ELFKit 51 | 52 | clean_symbol 53 | 54 | generate_symbol_graphs ios ELFKitC 55 | generate_symbol_graphs ios ELFKit 56 | --------------------------------------------------------------------------------