@@ -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,217 @@ 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 (
121
+ uint32_t nsects,
122
+ bool need_swap)
123
+ {
124
+ #ifdef __APPLE__
125
+ for (uint32_t i = 0 ; i < nsects; ++i)
126
+ {
127
+ // NOLINTNEXTLINE(readability/identifiers)
128
+ struct section s;
129
+ in.read (reinterpret_cast <char *>(&s), sizeof (s));
130
+
131
+ if (!in)
132
+ throw deserialization_exceptiont (" failed to read Mach-O section" );
133
+
134
+ if (need_swap)
135
+ swap_section (&s, 1 , NXHostByteOrder ());
136
+
137
+ sections.emplace (s.sectname , sectiont (s.sectname , s.offset , s.size ));
138
+ }
139
+ #else
140
+ // unused parameters
141
+ (void )nsects;
142
+ (void )need_swap;
143
+ #endif
144
+ }
145
+
146
+ void osx_mach_o_readert::process_sections_64 (
147
+ uint32_t nsects,
148
+ bool need_swap)
149
+ {
150
+ #ifdef __APPLE__
151
+ for (uint32_t i = 0 ; i < nsects; ++i)
152
+ {
153
+ // NOLINTNEXTLINE(readability/identifiers)
154
+ struct section_64 s;
155
+ in.read (reinterpret_cast <char *>(&s), sizeof (s));
156
+
157
+ if (!in)
158
+ throw deserialization_exceptiont (" failed to read 64-bit Mach-O section" );
159
+
160
+ if (need_swap)
161
+ swap_section_64 (&s, 1 , NXHostByteOrder ());
162
+
163
+ sections.emplace (s.sectname , sectiont (s.sectname , s.offset , s.size ));
164
+ }
165
+ #else
166
+ // unused parameters
167
+ (void )nsects;
168
+ (void )need_swap;
169
+ #endif
170
+ }
171
+
172
+ void osx_mach_o_readert::process_commands (
173
+ uint32_t ncmds,
174
+ std::size_t offset,
175
+ bool need_swap)
176
+ {
177
+ #ifdef __APPLE__
178
+ for (uint32_t i = 0 ; i < ncmds; ++i)
179
+ {
180
+ in.seekg (offset);
181
+
182
+ // NOLINTNEXTLINE(readability/identifiers)
183
+ struct load_command lc;
184
+ in.read (reinterpret_cast <char *>(&lc), sizeof (lc));
185
+
186
+ if (!in)
187
+ throw deserialization_exceptiont (" failed to read Mach-O command" );
188
+
189
+ if (need_swap)
190
+ swap_load_command (&lc, NXHostByteOrder ());
191
+
192
+ // we may need to re-read the command once we have figured out its type; in
193
+ // particular, segment commands contain additional information that we have
194
+ // now just read a prefix of
195
+ in.seekg (offset);
196
+
197
+ switch (lc.cmd )
198
+ {
199
+ case LC_SEGMENT:
200
+ {
201
+ // NOLINTNEXTLINE(readability/identifiers)
202
+ struct segment_command seg;
203
+ in.read (reinterpret_cast <char *>(&seg), sizeof (seg));
204
+
205
+ if (!in)
206
+ throw deserialization_exceptiont (" failed to read Mach-O segment" );
207
+
208
+ if (need_swap)
209
+ swap_segment_command (&seg, NXHostByteOrder ());
210
+
211
+ process_sections_32 (seg.nsects , need_swap);
212
+ break ;
213
+ }
214
+ case LC_SEGMENT_64:
215
+ {
216
+ // NOLINTNEXTLINE(readability/identifiers)
217
+ struct segment_command_64 seg;
218
+ in.read (reinterpret_cast <char *>(&seg), sizeof (seg));
219
+
220
+ if (!in)
221
+ throw deserialization_exceptiont (" failed to read Mach-O segment" );
222
+
223
+ if (need_swap)
224
+ swap_segment_command_64 (&seg, NXHostByteOrder ());
225
+
226
+ process_sections_64 (seg.nsects , need_swap);
227
+ break ;
228
+ }
229
+ default :
230
+ break ;
231
+ }
232
+
233
+ offset += lc.cmdsize ;
234
+ }
235
+ #else
236
+ // unused parameters
237
+ (void )ncmds;
238
+ (void )offset;
239
+ (void )need_swap;
240
+ #endif
241
+ }
242
+
243
+ osx_mach_o_readert::osx_mach_o_readert (std::istream &_in) : in(_in)
244
+ {
245
+ // read magic
246
+ uint32_t magic;
247
+ in.read (reinterpret_cast <char *>(&magic), sizeof (magic));
248
+
249
+ if (!in)
250
+ throw deserialization_exceptiont (" failed to read Mach-O magic" );
251
+
252
+ #ifdef __APPLE__
253
+ bool is_64 = false , need_swap = false ;
254
+ switch (magic)
255
+ {
256
+ case MH_CIGAM:
257
+ need_swap = true ;
258
+ break ;
259
+ case MH_MAGIC:
260
+ break ;
261
+ case MH_CIGAM_64:
262
+ need_swap = true ;
263
+ is_64 = true ;
264
+ break ;
265
+ case MH_MAGIC_64:
266
+ is_64 = true ;
267
+ break ;
268
+ default :
269
+ throw deserialization_exceptiont (" no Mach-O magic" );
270
+ }
271
+
272
+ uint32_t ncmds = 0 ;
273
+ std::size_t offset = 0 ;
274
+
275
+ // re-read from the beginning, now reading the full header
276
+ in.seekg (0 );
277
+
278
+ if (!is_64)
279
+ {
280
+ // NOLINTNEXTLINE(readability/identifiers)
281
+ struct mach_header mh;
282
+ in.read (reinterpret_cast <char *>(&mh), sizeof (mh));
283
+
284
+ if (!in)
285
+ throw deserialization_exceptiont (" failed to read 32-bit Mach-O header" );
286
+
287
+ if (need_swap)
288
+ swap_mach_header (&mh, NXHostByteOrder ());
289
+
290
+ ncmds = mh.ncmds ;
291
+ offset = sizeof (mh);
292
+ }
293
+ else
294
+ {
295
+ // NOLINTNEXTLINE(readability/identifiers)
296
+ struct mach_header_64 mh;
297
+ in.read (reinterpret_cast <char *>(&mh), sizeof (mh));
298
+
299
+ if (!in)
300
+ throw deserialization_exceptiont (" failed to read 64-bit Mach-O header" );
301
+
302
+ if (need_swap)
303
+ swap_mach_header_64 (&mh, NXHostByteOrder ());
304
+
305
+ ncmds = mh.ncmds ;
306
+ offset = sizeof (mh);
307
+ }
308
+
309
+ process_commands (ncmds, offset, need_swap);
310
+ #endif
311
+ }
0 commit comments