@@ -16,7 +16,10 @@ Module: Read Mach-O
16
16
#include < util/invariant.h>
17
17
18
18
#ifdef __APPLE__
19
+ #include < architecture/byte_order.h>
19
20
#include < mach-o/fat.h>
21
+ #include < mach-o/loader.h>
22
+ #include < mach-o/swap.h>
20
23
#endif
21
24
22
25
#include < util/run.h>
@@ -92,3 +95,213 @@ bool osx_fat_readert::extract_gb(
92
95
" lipo" , {" lipo" , " -thin" , " hppa7100LC" , " -output" , dest, source}) !=
93
96
0 ;
94
97
}
98
+
99
+ // guided by https://lowlevelbits.org/parsing-mach-o-files/
100
+ bool is_osx_mach_object (char hdr[4 ])
101
+ {
102
+ #ifdef __APPLE__
103
+ uint32_t *magic = reinterpret_cast <uint32_t *>(hdr);
104
+
105
+ switch (*magic)
106
+ {
107
+ case MH_MAGIC:
108
+ case MH_CIGAM:
109
+ case MH_MAGIC_64:
110
+ case MH_CIGAM_64:
111
+ return true ;
112
+ }
113
+ #else
114
+ (void )hdr; // unused parameter
115
+ #endif
116
+
117
+ return false ;
118
+ }
119
+
120
+ void osx_mach_o_readert::process_sections_32 (uint32_t nsects, bool need_swap)
121
+ {
122
+ #ifdef __APPLE__
123
+ for (uint32_t i = 0 ; i < nsects; ++i)
124
+ {
125
+ // NOLINTNEXTLINE(readability/identifiers)
126
+ struct section s;
127
+ in.read (reinterpret_cast <char *>(&s), sizeof (s));
128
+
129
+ if (!in)
130
+ throw deserialization_exceptiont (" failed to read Mach-O section" );
131
+
132
+ if (need_swap)
133
+ swap_section (&s, 1 , NXHostByteOrder ());
134
+
135
+ sections.emplace (s.sectname , sectiont (s.sectname , s.offset , s.size ));
136
+ }
137
+ #else
138
+ // unused parameters
139
+ (void )nsects;
140
+ (void )need_swap;
141
+ #endif
142
+ }
143
+
144
+ void osx_mach_o_readert::process_sections_64 (uint32_t nsects, bool need_swap)
145
+ {
146
+ #ifdef __APPLE__
147
+ for (uint32_t i = 0 ; i < nsects; ++i)
148
+ {
149
+ // NOLINTNEXTLINE(readability/identifiers)
150
+ struct section_64 s;
151
+ in.read (reinterpret_cast <char *>(&s), sizeof (s));
152
+
153
+ if (!in)
154
+ throw deserialization_exceptiont (" failed to read 64-bit Mach-O section" );
155
+
156
+ if (need_swap)
157
+ swap_section_64 (&s, 1 , NXHostByteOrder ());
158
+
159
+ sections.emplace (s.sectname , sectiont (s.sectname , s.offset , s.size ));
160
+ }
161
+ #else
162
+ // unused parameters
163
+ (void )nsects;
164
+ (void )need_swap;
165
+ #endif
166
+ }
167
+
168
+ void osx_mach_o_readert::process_commands (
169
+ uint32_t ncmds,
170
+ std::size_t offset,
171
+ bool need_swap)
172
+ {
173
+ #ifdef __APPLE__
174
+ for (uint32_t i = 0 ; i < ncmds; ++i)
175
+ {
176
+ in.seekg (offset);
177
+
178
+ // NOLINTNEXTLINE(readability/identifiers)
179
+ struct load_command lc;
180
+ in.read (reinterpret_cast <char *>(&lc), sizeof (lc));
181
+
182
+ if (!in)
183
+ throw deserialization_exceptiont (" failed to read Mach-O command" );
184
+
185
+ if (need_swap)
186
+ swap_load_command (&lc, NXHostByteOrder ());
187
+
188
+ // we may need to re-read the command once we have figured out its type; in
189
+ // particular, segment commands contain additional information that we have
190
+ // now just read a prefix of
191
+ in.seekg (offset);
192
+
193
+ switch (lc.cmd )
194
+ {
195
+ case LC_SEGMENT:
196
+ {
197
+ // NOLINTNEXTLINE(readability/identifiers)
198
+ struct segment_command seg;
199
+ in.read (reinterpret_cast <char *>(&seg), sizeof (seg));
200
+
201
+ if (!in)
202
+ throw deserialization_exceptiont (" failed to read Mach-O segment" );
203
+
204
+ if (need_swap)
205
+ swap_segment_command (&seg, NXHostByteOrder ());
206
+
207
+ process_sections_32 (seg.nsects , need_swap);
208
+ break ;
209
+ }
210
+ case LC_SEGMENT_64:
211
+ {
212
+ // NOLINTNEXTLINE(readability/identifiers)
213
+ struct segment_command_64 seg;
214
+ in.read (reinterpret_cast <char *>(&seg), sizeof (seg));
215
+
216
+ if (!in)
217
+ throw deserialization_exceptiont (" failed to read Mach-O segment" );
218
+
219
+ if (need_swap)
220
+ swap_segment_command_64 (&seg, NXHostByteOrder ());
221
+
222
+ process_sections_64 (seg.nsects , need_swap);
223
+ break ;
224
+ }
225
+ default :
226
+ break ;
227
+ }
228
+
229
+ offset += lc.cmdsize ;
230
+ }
231
+ #else
232
+ // unused parameters
233
+ (void )ncmds;
234
+ (void )offset;
235
+ (void )need_swap;
236
+ #endif
237
+ }
238
+
239
+ osx_mach_o_readert::osx_mach_o_readert (std::istream &_in) : in(_in)
240
+ {
241
+ // read magic
242
+ uint32_t magic;
243
+ in.read (reinterpret_cast <char *>(&magic), sizeof (magic));
244
+
245
+ if (!in)
246
+ throw deserialization_exceptiont (" failed to read Mach-O magic" );
247
+
248
+ #ifdef __APPLE__
249
+ bool is_64 = false , need_swap = false ;
250
+ switch (magic)
251
+ {
252
+ case MH_CIGAM:
253
+ need_swap = true ;
254
+ break ;
255
+ case MH_MAGIC:
256
+ break ;
257
+ case MH_CIGAM_64:
258
+ need_swap = true ;
259
+ is_64 = true ;
260
+ break ;
261
+ case MH_MAGIC_64:
262
+ is_64 = true ;
263
+ break ;
264
+ default :
265
+ throw deserialization_exceptiont (" no Mach-O magic" );
266
+ }
267
+
268
+ uint32_t ncmds = 0 ;
269
+ std::size_t offset = 0 ;
270
+
271
+ // re-read from the beginning, now reading the full header
272
+ in.seekg (0 );
273
+
274
+ if (!is_64)
275
+ {
276
+ // NOLINTNEXTLINE(readability/identifiers)
277
+ struct mach_header mh;
278
+ in.read (reinterpret_cast <char *>(&mh), sizeof (mh));
279
+
280
+ if (!in)
281
+ throw deserialization_exceptiont (" failed to read 32-bit Mach-O header" );
282
+
283
+ if (need_swap)
284
+ swap_mach_header (&mh, NXHostByteOrder ());
285
+
286
+ ncmds = mh.ncmds ;
287
+ offset = sizeof (mh);
288
+ }
289
+ else
290
+ {
291
+ // NOLINTNEXTLINE(readability/identifiers)
292
+ struct mach_header_64 mh;
293
+ in.read (reinterpret_cast <char *>(&mh), sizeof (mh));
294
+
295
+ if (!in)
296
+ throw deserialization_exceptiont (" failed to read 64-bit Mach-O header" );
297
+
298
+ if (need_swap)
299
+ swap_mach_header_64 (&mh, NXHostByteOrder ());
300
+
301
+ ncmds = mh.ncmds ;
302
+ offset = sizeof (mh);
303
+ }
304
+
305
+ process_commands (ncmds, offset, need_swap);
306
+ #endif
307
+ }
0 commit comments