├── .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 | [](https://github.com/p-x9/ELFKit/issues)
8 | [](https://github.com/p-x9/ELFKit/network/members)
9 | [](https://github.com/p-x9/ELFKit/stargazers)
10 | [](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 |
--------------------------------------------------------------------------------