]> git.saurik.com Git - apple/objc4.git/blob - markgc.cpp
objc4-680.tar.gz
[apple/objc4.git] / markgc.cpp
1 /*
2 * Copyright (c) 2007-2009 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdbool.h>
29 #include <fcntl.h>
30 #include <limits.h>
31 #include <sys/mman.h>
32 #include <sys/stat.h>
33 #include <sys/errno.h>
34 #include <mach-o/fat.h>
35 #include <mach-o/arch.h>
36 #include <mach-o/loader.h>
37
38 // from "objc-private.h"
39 // masks for objc_image_info.flags
40 #define OBJC_IMAGE_SUPPORTS_GC (1<<1)
41
42 // Some OS X SDKs don't define these.
43 #ifndef CPU_TYPE_ARM
44 #define CPU_TYPE_ARM ((cpu_type_t) 12)
45 #endif
46 #ifndef CPU_ARCH_ABI64
47 #define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */
48 #endif
49 #ifndef CPU_TYPE_ARM64
50 #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
51 #endif
52
53 // File abstraction taken from ld64/FileAbstraction.hpp
54 // and ld64/MachOFileAbstraction.hpp.
55
56 #ifdef __OPTIMIZE__
57 #define INLINE __attribute__((always_inline))
58 #else
59 #define INLINE
60 #endif
61
62 //
63 // This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants
64 //
65 // For example: to make a utility that handles 32-bit little enidan files use: Pointer32<LittleEndian>
66 //
67 //
68 // get16() read a 16-bit number from an E endian struct
69 // set16() write a 16-bit number to an E endian struct
70 // get32() read a 32-bit number from an E endian struct
71 // set32() write a 32-bit number to an E endian struct
72 // get64() read a 64-bit number from an E endian struct
73 // set64() write a 64-bit number to an E endian struct
74 //
75 // getBits() read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
76 // setBits() write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
77 //
78 // getBitsRaw() read a bit field from a struct with native endianness
79 // setBitsRaw() write a bit field from a struct with native endianness
80 //
81
82 class BigEndian
83 {
84 public:
85 static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt16(&from, 0); }
86 static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteBigInt16(&into, 0, value); }
87
88 static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); }
89 static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteBigInt32(&into, 0, value); }
90
91 static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); }
92 static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteBigInt64(&into, 0, value); }
93
94 static uint32_t getBits(const uint32_t& from,
95 uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
96 static void setBits(uint32_t& into, uint32_t value,
97 uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
98
99 static uint32_t getBitsRaw(const uint32_t& from,
100 uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }
101 static void setBitsRaw(uint32_t& into, uint32_t value,
102 uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
103 const uint32_t mask = ((1<<bitCount)-1);
104 temp &= ~(mask << (32-firstBit-bitCount));
105 temp |= ((value & mask) << (32-firstBit-bitCount));
106 into = temp; }
107 enum { little_endian = 0 };
108 };
109
110
111 class LittleEndian
112 {
113 public:
114 static uint16_t get16(const uint16_t& from) INLINE { return OSReadLittleInt16(&from, 0); }
115 static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteLittleInt16(&into, 0, value); }
116
117 static uint32_t get32(const uint32_t& from) INLINE { return OSReadLittleInt32(&from, 0); }
118 static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteLittleInt32(&into, 0, value); }
119
120 static uint64_t get64(const uint64_t& from) INLINE { return OSReadLittleInt64(&from, 0); }
121 static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteLittleInt64(&into, 0, value); }
122
123 static uint32_t getBits(const uint32_t& from,
124 uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
125 static void setBits(uint32_t& into, uint32_t value,
126 uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
127
128 static uint32_t getBitsRaw(const uint32_t& from,
129 uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }
130 static void setBitsRaw(uint32_t& into, uint32_t value,
131 uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
132 const uint32_t mask = ((1<<bitCount)-1);
133 temp &= ~(mask << firstBit);
134 temp |= ((value & mask) << firstBit);
135 into = temp; }
136 enum { little_endian = 1 };
137 };
138
139 #if __BIG_ENDIAN__
140 typedef BigEndian CurrentEndian;
141 typedef LittleEndian OtherEndian;
142 #elif __LITTLE_ENDIAN__
143 typedef LittleEndian CurrentEndian;
144 typedef BigEndian OtherEndian;
145 #else
146 #error unknown endianness
147 #endif
148
149
150 template <typename _E>
151 class Pointer32
152 {
153 public:
154 typedef uint32_t uint_t;
155 typedef int32_t sint_t;
156 typedef _E E;
157
158 static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); }
159 static void setP(uint_t& into, uint64_t value) INLINE { _E::set32(into, value); }
160 };
161
162
163 template <typename _E>
164 class Pointer64
165 {
166 public:
167 typedef uint64_t uint_t;
168 typedef int64_t sint_t;
169 typedef _E E;
170
171 static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); }
172 static void setP(uint_t& into, uint64_t value) INLINE { _E::set64(into, value); }
173 };
174
175
176 //
177 // mach-o file header
178 //
179 template <typename P> struct macho_header_content {};
180 template <> struct macho_header_content<Pointer32<BigEndian> > { mach_header fields; };
181 template <> struct macho_header_content<Pointer64<BigEndian> > { mach_header_64 fields; };
182 template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header fields; };
183 template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64 fields; };
184
185 template <typename P>
186 class macho_header {
187 public:
188 uint32_t magic() const INLINE { return E::get32(header.fields.magic); }
189 void set_magic(uint32_t value) INLINE { E::set32(header.fields.magic, value); }
190
191 uint32_t cputype() const INLINE { return E::get32(header.fields.cputype); }
192 void set_cputype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cputype, value); }
193
194 uint32_t cpusubtype() const INLINE { return E::get32(header.fields.cpusubtype); }
195 void set_cpusubtype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }
196
197 uint32_t filetype() const INLINE { return E::get32(header.fields.filetype); }
198 void set_filetype(uint32_t value) INLINE { E::set32(header.fields.filetype, value); }
199
200 uint32_t ncmds() const INLINE { return E::get32(header.fields.ncmds); }
201 void set_ncmds(uint32_t value) INLINE { E::set32(header.fields.ncmds, value); }
202
203 uint32_t sizeofcmds() const INLINE { return E::get32(header.fields.sizeofcmds); }
204 void set_sizeofcmds(uint32_t value) INLINE { E::set32(header.fields.sizeofcmds, value); }
205
206 uint32_t flags() const INLINE { return E::get32(header.fields.flags); }
207 void set_flags(uint32_t value) INLINE { E::set32(header.fields.flags, value); }
208
209 uint32_t reserved() const INLINE { return E::get32(header.fields.reserved); }
210 void set_reserved(uint32_t value) INLINE { E::set32(header.fields.reserved, value); }
211
212 typedef typename P::E E;
213 private:
214 macho_header_content<P> header;
215 };
216
217
218 //
219 // mach-o load command
220 //
221 template <typename P>
222 class macho_load_command {
223 public:
224 uint32_t cmd() const INLINE { return E::get32(command.cmd); }
225 void set_cmd(uint32_t value) INLINE { E::set32(command.cmd, value); }
226
227 uint32_t cmdsize() const INLINE { return E::get32(command.cmdsize); }
228 void set_cmdsize(uint32_t value) INLINE { E::set32(command.cmdsize, value); }
229
230 typedef typename P::E E;
231 private:
232 load_command command;
233 };
234
235
236
237
238 //
239 // mach-o segment load command
240 //
241 template <typename P> struct macho_segment_content {};
242 template <> struct macho_segment_content<Pointer32<BigEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
243 template <> struct macho_segment_content<Pointer64<BigEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
244 template <> struct macho_segment_content<Pointer32<LittleEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
245 template <> struct macho_segment_content<Pointer64<LittleEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
246
247 template <typename P>
248 class macho_segment_command {
249 public:
250 uint32_t cmd() const INLINE { return E::get32(segment.fields.cmd); }
251 void set_cmd(uint32_t value) INLINE { E::set32(segment.fields.cmd, value); }
252
253 uint32_t cmdsize() const INLINE { return E::get32(segment.fields.cmdsize); }
254 void set_cmdsize(uint32_t value) INLINE { E::set32(segment.fields.cmdsize, value); }
255
256 const char* segname() const INLINE { return segment.fields.segname; }
257 void set_segname(const char* value) INLINE { strncpy(segment.fields.segname, value, 16); }
258
259 uint64_t vmaddr() const INLINE { return P::getP(segment.fields.vmaddr); }
260 void set_vmaddr(uint64_t value) INLINE { P::setP(segment.fields.vmaddr, value); }
261
262 uint64_t vmsize() const INLINE { return P::getP(segment.fields.vmsize); }
263 void set_vmsize(uint64_t value) INLINE { P::setP(segment.fields.vmsize, value); }
264
265 uint64_t fileoff() const INLINE { return P::getP(segment.fields.fileoff); }
266 void set_fileoff(uint64_t value) INLINE { P::setP(segment.fields.fileoff, value); }
267
268 uint64_t filesize() const INLINE { return P::getP(segment.fields.filesize); }
269 void set_filesize(uint64_t value) INLINE { P::setP(segment.fields.filesize, value); }
270
271 uint32_t maxprot() const INLINE { return E::get32(segment.fields.maxprot); }
272 void set_maxprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.maxprot, value); }
273
274 uint32_t initprot() const INLINE { return E::get32(segment.fields.initprot); }
275 void set_initprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.initprot, value); }
276
277 uint32_t nsects() const INLINE { return E::get32(segment.fields.nsects); }
278 void set_nsects(uint32_t value) INLINE { E::set32(segment.fields.nsects, value); }
279
280 uint32_t flags() const INLINE { return E::get32(segment.fields.flags); }
281 void set_flags(uint32_t value) INLINE { E::set32(segment.fields.flags, value); }
282
283 enum {
284 CMD = macho_segment_content<P>::CMD
285 };
286
287 typedef typename P::E E;
288 private:
289 macho_segment_content<P> segment;
290 };
291
292
293 //
294 // mach-o section
295 //
296 template <typename P> struct macho_section_content {};
297 template <> struct macho_section_content<Pointer32<BigEndian> > { section fields; };
298 template <> struct macho_section_content<Pointer64<BigEndian> > { section_64 fields; };
299 template <> struct macho_section_content<Pointer32<LittleEndian> > { section fields; };
300 template <> struct macho_section_content<Pointer64<LittleEndian> > { section_64 fields; };
301
302 template <typename P>
303 class macho_section {
304 public:
305 const char* sectname() const INLINE { return section.fields.sectname; }
306 void set_sectname(const char* value) INLINE { strncpy(section.fields.sectname, value, 16); }
307
308 const char* segname() const INLINE { return section.fields.segname; }
309 void set_segname(const char* value) INLINE { strncpy(section.fields.segname, value, 16); }
310
311 uint64_t addr() const INLINE { return P::getP(section.fields.addr); }
312 void set_addr(uint64_t value) INLINE { P::setP(section.fields.addr, value); }
313
314 uint64_t size() const INLINE { return P::getP(section.fields.size); }
315 void set_size(uint64_t value) INLINE { P::setP(section.fields.size, value); }
316
317 uint32_t offset() const INLINE { return E::get32(section.fields.offset); }
318 void set_offset(uint32_t value) INLINE { E::set32(section.fields.offset, value); }
319
320 uint32_t align() const INLINE { return E::get32(section.fields.align); }
321 void set_align(uint32_t value) INLINE { E::set32(section.fields.align, value); }
322
323 uint32_t reloff() const INLINE { return E::get32(section.fields.reloff); }
324 void set_reloff(uint32_t value) INLINE { E::set32(section.fields.reloff, value); }
325
326 uint32_t nreloc() const INLINE { return E::get32(section.fields.nreloc); }
327 void set_nreloc(uint32_t value) INLINE { E::set32(section.fields.nreloc, value); }
328
329 uint32_t flags() const INLINE { return E::get32(section.fields.flags); }
330 void set_flags(uint32_t value) INLINE { E::set32(section.fields.flags, value); }
331
332 uint32_t reserved1() const INLINE { return E::get32(section.fields.reserved1); }
333 void set_reserved1(uint32_t value) INLINE { E::set32(section.fields.reserved1, value); }
334
335 uint32_t reserved2() const INLINE { return E::get32(section.fields.reserved2); }
336 void set_reserved2(uint32_t value) INLINE { E::set32(section.fields.reserved2, value); }
337
338 typedef typename P::E E;
339 private:
340 macho_section_content<P> section;
341 };
342
343
344
345
346 static bool debug = true;
347
348 bool processFile(const char *filename);
349
350 int main(int argc, const char *argv[]) {
351 for (int i = 1; i < argc; ++i) {
352 if (!processFile(argv[i])) return 1;
353 }
354 return 0;
355 }
356
357 struct imageinfo {
358 uint32_t version;
359 uint32_t flags;
360 };
361
362
363 // Segment and section names are 16 bytes and may be un-terminated.
364 bool segnameEquals(const char *lhs, const char *rhs)
365 {
366 return 0 == strncmp(lhs, rhs, 16);
367 }
368
369 bool segnameStartsWith(const char *segname, const char *prefix)
370 {
371 return 0 == strncmp(segname, prefix, strlen(prefix));
372 }
373
374 bool sectnameEquals(const char *lhs, const char *rhs)
375 {
376 return segnameEquals(lhs, rhs);
377 }
378
379
380 template <typename P>
381 void dosect(uint8_t *start, macho_section<P> *sect, bool isOldABI, bool isOSX)
382 {
383 if (debug) printf("section %.16s from segment %.16s\n",
384 sect->sectname(), sect->segname());
385
386 if (isOSX) {
387 // Add "supports GC" flag to objc image info
388 if ((segnameStartsWith(sect->segname(), "__DATA") &&
389 sectnameEquals(sect->sectname(), "__objc_imageinfo")) ||
390 (segnameEquals(sect->segname(), "__OBJC") &&
391 sectnameEquals(sect->sectname(), "__image_info")))
392 {
393 imageinfo *ii = (imageinfo*)(start + sect->offset());
394 P::E::set32(ii->flags, P::E::get32(ii->flags) | OBJC_IMAGE_SUPPORTS_GC);
395 if (debug) printf("added GC support flag\n");
396 }
397 }
398
399 if (isOldABI) {
400 // Keep init funcs because libSystem doesn't call _objc_init().
401 } else {
402 // Strip S_MOD_INIT/TERM_FUNC_POINTERS. We don't want dyld to call
403 // our init funcs because it is too late, and we don't want anyone to
404 // call our term funcs ever.
405 if (segnameStartsWith(sect->segname(), "__DATA") &&
406 sectnameEquals(sect->sectname(), "__mod_init_func"))
407 {
408 // section type 0 is S_REGULAR
409 sect->set_flags(sect->flags() & ~SECTION_TYPE);
410 sect->set_sectname("__objc_init_func");
411 if (debug) printf("disabled __mod_init_func section\n");
412 }
413 if (segnameStartsWith(sect->segname(), "__DATA") &&
414 sectnameEquals(sect->sectname(), "__mod_term_func"))
415 {
416 // section type 0 is S_REGULAR
417 sect->set_flags(sect->flags() & ~SECTION_TYPE);
418 sect->set_sectname("__objc_term_func");
419 if (debug) printf("disabled __mod_term_func section\n");
420 }
421 }
422 }
423
424 template <typename P>
425 void doseg(uint8_t *start, macho_segment_command<P> *seg,
426 bool isOldABI, bool isOSX)
427 {
428 if (debug) printf("segment name: %.16s, nsects %u\n",
429 seg->segname(), seg->nsects());
430 macho_section<P> *sect = (macho_section<P> *)(seg + 1);
431 for (uint32_t i = 0; i < seg->nsects(); ++i) {
432 dosect(start, &sect[i], isOldABI, isOSX);
433 }
434 }
435
436
437 template<typename P>
438 bool parse_macho(uint8_t *buffer)
439 {
440 macho_header<P>* mh = (macho_header<P>*)buffer;
441 uint8_t *cmds;
442
443 bool isOldABI = false;
444 bool isOSX = false;
445 cmds = (uint8_t *)(mh + 1);
446 for (uint32_t c = 0; c < mh->ncmds(); c++) {
447 macho_load_command<P>* cmd = (macho_load_command<P>*)cmds;
448 cmds += cmd->cmdsize();
449 if (cmd->cmd() == LC_SEGMENT || cmd->cmd() == LC_SEGMENT_64) {
450 macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
451 if (segnameEquals(seg->segname(), "__OBJC")) isOldABI = true;
452 }
453 else if (cmd->cmd() == LC_VERSION_MIN_MACOSX) {
454 isOSX = true;
455 }
456 }
457
458 if (debug) printf("ABI=%s, OS=%s\n",
459 isOldABI ? "old" : "new", isOSX ? "osx" : "ios");
460
461 cmds = (uint8_t *)(mh + 1);
462 for (uint32_t c = 0; c < mh->ncmds(); c++) {
463 macho_load_command<P>* cmd = (macho_load_command<P>*)cmds;
464 cmds += cmd->cmdsize();
465 if (cmd->cmd() == LC_SEGMENT || cmd->cmd() == LC_SEGMENT_64) {
466 doseg(buffer, (macho_segment_command<P>*)cmd, isOldABI, isOSX);
467 }
468 }
469
470 return true;
471 }
472
473
474 bool parse_macho(uint8_t *buffer)
475 {
476 uint32_t magic = *(uint32_t *)buffer;
477
478 switch (magic) {
479 case MH_MAGIC_64:
480 return parse_macho<Pointer64<CurrentEndian>>(buffer);
481 case MH_MAGIC:
482 return parse_macho<Pointer32<CurrentEndian>>(buffer);
483 case MH_CIGAM_64:
484 return parse_macho<Pointer64<OtherEndian>>(buffer);
485 case MH_CIGAM:
486 return parse_macho<Pointer32<OtherEndian>>(buffer);
487 default:
488 printf("file is not mach-o (magic %x)\n", magic);
489 return false;
490 }
491 }
492
493
494 bool parse_fat(uint8_t *buffer, size_t size)
495 {
496 uint32_t magic;
497
498 if (size < sizeof(magic)) {
499 printf("file is too small\n");
500 return false;
501 }
502
503 magic = *(uint32_t *)buffer;
504 if (magic != FAT_MAGIC && magic != FAT_CIGAM) {
505 /* Not a fat file */
506 return parse_macho(buffer);
507 } else {
508 struct fat_header *fh;
509 uint32_t fat_magic, fat_nfat_arch;
510 struct fat_arch *archs;
511
512 if (size < sizeof(struct fat_header)) {
513 printf("file is too small\n");
514 return false;
515 }
516
517 fh = (struct fat_header *)buffer;
518 fat_magic = OSSwapBigToHostInt32(fh->magic);
519 fat_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);
520
521 if (size < (sizeof(struct fat_header) + fat_nfat_arch * sizeof(struct fat_arch))) {
522 printf("file is too small\n");
523 return false;
524 }
525
526 archs = (struct fat_arch *)(buffer + sizeof(struct fat_header));
527
528 /* Special case hidden CPU_TYPE_ARM64 */
529 if (size >= (sizeof(struct fat_header) + (fat_nfat_arch + 1) * sizeof(struct fat_arch))) {
530 if (fat_nfat_arch > 0
531 && OSSwapBigToHostInt32(archs[fat_nfat_arch].cputype) == CPU_TYPE_ARM64) {
532 fat_nfat_arch++;
533 }
534 }
535 /* End special case hidden CPU_TYPE_ARM64 */
536
537 if (debug) printf("%d fat architectures\n",
538 fat_nfat_arch);
539
540 for (uint32_t i = 0; i < fat_nfat_arch; i++) {
541 uint32_t arch_cputype = OSSwapBigToHostInt32(archs[i].cputype);
542 uint32_t arch_cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);
543 uint32_t arch_offset = OSSwapBigToHostInt32(archs[i].offset);
544 uint32_t arch_size = OSSwapBigToHostInt32(archs[i].size);
545
546 if (debug) printf("cputype %d cpusubtype %d\n",
547 arch_cputype, arch_cpusubtype);
548
549 /* Check that slice data is after all fat headers and archs */
550 if (arch_offset < (sizeof(struct fat_header) + fat_nfat_arch * sizeof(struct fat_arch))) {
551 printf("file is badly formed\n");
552 return false;
553 }
554
555 /* Check that the slice ends before the file does */
556 if (arch_offset > size) {
557 printf("file is badly formed\n");
558 return false;
559 }
560
561 if (arch_size > size) {
562 printf("file is badly formed\n");
563 return false;
564 }
565
566 if (arch_offset > (size - arch_size)) {
567 printf("file is badly formed\n");
568 return false;
569 }
570
571 bool ok = parse_macho(buffer + arch_offset);
572 if (!ok) return false;
573 }
574 return true;
575 }
576 }
577
578 bool processFile(const char *filename)
579 {
580 if (debug) printf("file %s\n", filename);
581 int fd = open(filename, O_RDWR);
582 if (fd < 0) {
583 printf("open %s: %s\n", filename, strerror(errno));
584 return false;
585 }
586
587 struct stat st;
588 if (fstat(fd, &st) < 0) {
589 printf("fstat %s: %s\n", filename, strerror(errno));
590 return false;
591 }
592
593 void *buffer = mmap(NULL, (size_t)st.st_size, PROT_READ|PROT_WRITE,
594 MAP_FILE|MAP_SHARED, fd, 0);
595 if (buffer == MAP_FAILED) {
596 printf("mmap %s: %s\n", filename, strerror(errno));
597 return false;
598 }
599
600 bool result = parse_fat((uint8_t *)buffer, (size_t)st.st_size);
601 munmap(buffer, (size_t)st.st_size);
602 close(fd);
603 return result;
604 }