@@ -99,110 +99,112 @@ public enum ExecutableArchitecture: String {
99
99
#endif
100
100
}
101
101
102
+ #if os(Windows)
102
103
extension Process {
103
- #if os(Windows)
104
- /// Resolves the filename from the `Path` environment variable and read its COFF header to determine the architecture
105
- /// of the binary.
106
- ///
107
- /// - Parameters:
108
- /// - cwd: The current working directory.
109
- /// - env: A dictionary of the environment variables and their values. Usually of the parent shell.
110
- /// - filename: The name of the file we are resolving the architecture of.
111
- /// - Returns: The architecture of the file which was found in the `Path`.
112
- static func readWindowsExecutableArchitecture(
113
- cwd: AbsolutePath ? , envBlock: ProcessEnvironmentBlock , filename: String
114
- ) -> ExecutableArchitecture {
115
- let searchPaths = getEnvSearchPaths (
116
- pathString: envBlock [ " Path " ] , currentWorkingDirectory: cwd)
117
- guard
118
- let filePath = lookupExecutablePath (
119
- filename: filename, currentWorkingDirectory: cwd, searchPaths: searchPaths)
120
- else {
121
- return . unknown
122
- }
123
- guard let fileHandle = FileHandle ( forReadingAtPath: filePath. pathString) else {
124
- return . unknown
125
- }
126
-
127
- defer { fileHandle. closeFile ( ) }
128
-
129
- // Infering the architecture of a Windows executable from its COFF header involves the following:
130
- // 1. Get the COFF header offset from the pointer located at the 0x3C offset (4 bytes long).
131
- // 2. Jump to that offset and read the next 6 bytes.
132
- // 3. The first 4 are the signature which should be equal to 0x50450000.
133
- // 4. The last 2 are the machine architecture which can be infered from the value we get.
134
- //
135
- // The link below provides a visualization of the COFF header and the process to get to it.
136
- // https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg
137
- guard ( try ? fileHandle. seek ( toOffset: 0x3C ) ) != nil else {
138
- return . unknown
139
- }
140
- guard let offsetPointer = try ? fileHandle. read ( upToCount: 4 ) ,
141
- offsetPointer. count == 4
142
- else {
143
- return . unknown
144
- }
104
+ /// Resolves the filename from the `Path` environment variable and read its COFF header to determine the architecture
105
+ /// of the binary.
106
+ ///
107
+ /// - Parameters:
108
+ /// - cwd: The current working directory.
109
+ /// - env: A dictionary of the environment variables and their values. Usually of the parent shell.
110
+ /// - filename: The name of the file we are resolving the architecture of.
111
+ /// - Returns: The architecture of the file which was found in the `Path`.
112
+ static func readWindowsExecutableArchitecture(
113
+ cwd: AbsolutePath ? , envBlock: ProcessEnvironmentBlock , filename: String
114
+ ) -> ExecutableArchitecture {
115
+ let searchPaths = getEnvSearchPaths (
116
+ pathString: envBlock [ " Path " ] , currentWorkingDirectory: cwd)
117
+ guard
118
+ let filePath = lookupExecutablePath (
119
+ filename: filename, currentWorkingDirectory: cwd, searchPaths: searchPaths)
120
+ else {
121
+ return . unknown
122
+ }
123
+ guard let fileHandle = FileHandle ( forReadingAtPath: filePath. pathString) else {
124
+ return . unknown
125
+ }
145
126
146
- let peHeaderOffset = offsetPointer. withUnsafeBytes { $0. load ( as: UInt32 . self) }
127
+ defer { fileHandle. closeFile ( ) }
128
+
129
+ // Infering the architecture of a Windows executable from its COFF header involves the following:
130
+ // 1. Get the COFF header offset from the pointer located at the 0x3C offset (4 bytes long).
131
+ // 2. Jump to that offset and read the next 6 bytes.
132
+ // 3. The first 4 are the signature which should be equal to 0x50450000.
133
+ // 4. The last 2 are the machine architecture which can be infered from the value we get.
134
+ //
135
+ // The link below provides a visualization of the COFF header and the process to get to it.
136
+ // https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg
137
+ guard ( try ? fileHandle. seek ( toOffset: 0x3C ) ) != nil else {
138
+ return . unknown
139
+ }
140
+ guard let offsetPointer = try ? fileHandle. read ( upToCount: 4 ) ,
141
+ offsetPointer. count == 4
142
+ else {
143
+ return . unknown
144
+ }
147
145
148
- guard ( try ? fileHandle. seek ( toOffset: UInt64 ( peHeaderOffset) ) ) != nil else {
149
- return . unknown
150
- }
151
- guard let coffHeader = try ? fileHandle. read ( upToCount: 6 ) , coffHeader. count == 6 else {
152
- return . unknown
153
- }
146
+ let peHeaderOffset = offsetPointer. withUnsafeBytes { $0. load ( as: UInt32 . self) }
154
147
155
- let signature = coffHeader. prefix ( 4 )
156
- let machineBytes = coffHeader. suffix ( 2 )
148
+ guard ( try ? fileHandle. seek ( toOffset: UInt64 ( peHeaderOffset) ) ) != nil else {
149
+ return . unknown
150
+ }
151
+ guard let coffHeader = try ? fileHandle. read ( upToCount: 6 ) , coffHeader. count == 6 else {
152
+ return . unknown
153
+ }
157
154
158
- guard signature == Data ( [ 0x50 , 0x45 , 0x00 , 0x00 ] ) else {
159
- return . unknown
160
- }
155
+ let signature = coffHeader. prefix ( 4 )
156
+ let machineBytes = coffHeader. suffix ( 2 )
161
157
162
- let machine = machineBytes . withUnsafeBytes { $0 . load ( as : UInt16 . self ) }
163
- return . fromPEMachineByte ( machine : Int32 ( machine ) )
158
+ guard signature == Data ( [ 0x50 , 0x45 , 0x00 , 0x00 ] ) else {
159
+ return . unknown
164
160
}
165
- #endif
166
161
167
- #if os(macOS)
168
- static func readDarwinExecutableArchitecture(
169
- cwd: AbsolutePath ? , envBlock: ProcessEnvironmentBlock , filename: String
170
- ) -> ExecutableArchitecture {
171
- let magicNumber : UInt32 = 0xcafe_babe
172
-
173
- let searchPaths = getEnvSearchPaths (
174
- pathString: envBlock [ " PATH " ] , currentWorkingDirectory: cwd)
175
- guard
176
- let filePath = lookupExecutablePath (
177
- filename: filename, currentWorkingDirectory: cwd, searchPaths: searchPaths)
178
- else {
179
- return . unknown
180
- }
181
- guard let fileHandle = FileHandle ( forReadingAtPath: filePath. pathString) else {
182
- return . unknown
183
- }
162
+ let machine = machineBytes. withUnsafeBytes { $0. load ( as: UInt16 . self) }
163
+ return . fromPEMachineByte( machine: Int32 ( machine) )
164
+ }
165
+ }
166
+ #endif
184
167
185
- defer {
186
- try ? fileHandle. close ( )
187
- }
168
+ #if os(macOS)
169
+ extension Process {
170
+ static func readDarwinExecutableArchitecture(
171
+ cwd: AbsolutePath ? , envBlock: ProcessEnvironmentBlock , filename: String
172
+ ) -> ExecutableArchitecture {
173
+ let magicNumber : UInt32 = 0xcafe_babe
174
+
175
+ let searchPaths = getEnvSearchPaths (
176
+ pathString: envBlock [ " PATH " ] , currentWorkingDirectory: cwd)
177
+ guard
178
+ let filePath = lookupExecutablePath (
179
+ filename: filename, currentWorkingDirectory: cwd, searchPaths: searchPaths)
180
+ else {
181
+ return . unknown
182
+ }
183
+ guard let fileHandle = FileHandle ( forReadingAtPath: filePath. pathString) else {
184
+ return . unknown
185
+ }
188
186
189
- // The first 4 bytes of a Mach-O header contain the magic number. We use it to determine if the binary is
190
- // universal.
191
- // https://github.com/apple/darwin-xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h
192
- let magicData = fileHandle. readData ( ofLength: 4 )
193
- let magic = magicData. withUnsafeBytes { $0. load ( as: UInt32 . self) . bigEndian }
187
+ defer {
188
+ try ? fileHandle. close ( )
189
+ }
194
190
195
- if magic == magicNumber {
196
- return . universal
197
- }
191
+ // The first 4 bytes of a Mach-O header contain the magic number. We use it to determine if the binary is
192
+ // universal.
193
+ // https://github.com/apple/darwin-xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h
194
+ let magicData = fileHandle. readData ( ofLength: 4 )
195
+ let magic = magicData. withUnsafeBytes { $0. load ( as: UInt32 . self) . bigEndian }
198
196
199
- // If the binary is not universal, the next 4 bytes contain the CPU type.
200
- guard ( try ? fileHandle. seek ( toOffset: 4 ) ) != nil else {
201
- return . unknown
202
- }
203
- let cpuTypeData = fileHandle. readData ( ofLength: 4 )
204
- let cpuType = cpuTypeData. withUnsafeBytes { $0. load ( as: Int32 . self) }
205
- return . fromMachoCPUType( cpuType: cpuType)
197
+ if magic == magicNumber {
198
+ return . universal
206
199
}
207
- #endif
200
+
201
+ // If the binary is not universal, the next 4 bytes contain the CPU type.
202
+ guard ( try ? fileHandle. seek ( toOffset: 4 ) ) != nil else {
203
+ return . unknown
204
+ }
205
+ let cpuTypeData = fileHandle. readData ( ofLength: 4 )
206
+ let cpuType = cpuTypeData. withUnsafeBytes { $0. load ( as: Int32 . self) }
207
+ return . fromMachoCPUType( cpuType: cpuType)
208
+ }
208
209
}
210
+ #endif
0 commit comments