forked from Carthage/Carthage
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MachHeader.swift
144 lines (125 loc) · 3.86 KB
/
MachHeader.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import Foundation
import MachO.loader
import ReactiveTask
import ReactiveSwift
import Result
/// Represents a Mach header
///
/// Provides a unified structure for
/// `MachO.loader.mach_header` and `MachO.loader.mach_header_64`
struct MachHeader {
enum Endianness {
case little
case big
}
let magic: UInt32
let cpuType: cpu_type_t
let cpuSubtype: cpu_type_t
let fileType: UInt32
let ncmds: UInt32
let sizeofcmds: UInt32
let flags: UInt32
let reserved: UInt32?
var is64BitHeader: Bool {
return magic == MH_MAGIC_64 || magic == MH_CIGAM_64
}
var is32BitHeader: Bool {
return !is64BitHeader
}
var endianess: Endianness {
return magic == MH_CIGAM_64 || magic == MH_CIGAM ? .big : .little
}
}
extension MachHeader {
static let carthageSupportedFileTypes: Set<UInt32> = {
return Set([
MH_OBJECT, // Carthage accepts static libraries
MH_BUNDLE, // Bundles https://github.com/ResearchKit/ResearchKit/blob/1.3.0/ResearchKit/Info.plist#L15-L16
MH_DYLIB, // or dynamic shared libraries
].map { UInt32($0) }
)
}()
}
extension MachHeader {
/// Reads the Mach headers from a Mach-O file.
/// - Parameter url: The url of the Mach-O file
/// - Remark: Uses `objdump` to read the header and parse the output.
/// The output is composed of one or more sets of lines like the following:
///
/// Mach header
/// magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
/// 0xfeedfacf 16777223 3 0x00 1 8 1720 0x00002000
///
/// - See Also: [LLVM MachODump.cpp](https://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/MachODump.cpp?view=markup&pathrev=225383###see%C2%B7line%C2%B72745)
static func headers(forMachOFileAtUrl url: URL) -> SignalProducer<MachHeader, CarthageError> {
// This is the command `otool -h` actually invokes
let task = Task("/usr/bin/xcrun", arguments: [
"objdump",
"-macho",
"-private-header",
"-non-verbose",
url.resolvingSymlinksInPath().path,
]
)
return task.launch(standardInput: nil)
.ignoreTaskData()
.map { String(data: $0, encoding: .utf8) ?? "" }
.filter { !$0.isEmpty }
.flatMap(.merge) { (output: String) -> SignalProducer<(String, String), NoError> in
output.linesProducer.combinePrevious()
}.filterMap { previousLine, currentLine -> MachHeader? in
let previousLineComponents = previousLine
.components(separatedBy: CharacterSet.whitespaces)
.filter { !$0.isEmpty }
let currentLineComponents = currentLine
.components(separatedBy: CharacterSet.whitespaces)
.filter { !$0.isEmpty }
let strippedComponents = currentLineComponents
.map { $0.stripping(prefix: "0x") }
let magicIdentifiers = [
MH_MAGIC_64,
MH_CIGAM_64,
MH_MAGIC,
MH_CIGAM,
].lazy
// swiftlint:disable comma
guard previousLineComponents == [
"magic",
"cputype",
"cpusubtype",
"caps",
"filetype",
"ncmds",
"sizeofcmds",
"flags",
]
, !strippedComponents.isEmpty
, let magic = UInt32(strippedComponents.first!, radix: 16)
, magicIdentifiers.first(where: { $0 == magic }) != nil else {
return nil
}
// swiftlint:enable comma
guard
let cpuType = cpu_type_t(strippedComponents[1], radix: 10),
let cpuSubtype = cpu_subtype_t(strippedComponents[2], radix: 10),
let fileType = UInt32(strippedComponents[4], radix: 10),
let ncmds = UInt32(strippedComponents[5], radix: 10),
let sizeofcmds = UInt32(strippedComponents[6], radix: 10),
let flags = UInt32(strippedComponents[7], radix: 16)
else {
return nil
}
return MachHeader(
magic: magic,
cpuType: cpuType,
cpuSubtype: cpuSubtype,
fileType: fileType,
ncmds: ncmds,
sizeofcmds: sizeofcmds,
flags: flags,
reserved: nil
)
}
.mapError(CarthageError.taskError)
}
}