markgc.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include <string.h>
  26. #include <stdio.h>
  27. #include <stdbool.h>
  28. #include <fcntl.h>
  29. #include <limits.h>
  30. #include <sys/mman.h>
  31. #include <sys/stat.h>
  32. #include <sys/errno.h>
  33. #include <os/overflow.h>
  34. #include <mach-o/fat.h>
  35. #include <mach-o/arch.h>
  36. #include <mach-o/loader.h>
  37. // Some OS X SDKs don't define these.
  38. #ifndef CPU_TYPE_ARM
  39. #define CPU_TYPE_ARM ((cpu_type_t) 12)
  40. #endif
  41. #ifndef CPU_ARCH_ABI64
  42. #define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */
  43. #endif
  44. #ifndef CPU_TYPE_ARM64
  45. #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
  46. #endif
  47. // File abstraction taken from ld64/FileAbstraction.hpp
  48. // and ld64/MachOFileAbstraction.hpp.
  49. #ifdef __OPTIMIZE__
  50. #define INLINE __attribute__((always_inline))
  51. #else
  52. #define INLINE
  53. #endif
  54. //
  55. // This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants
  56. //
  57. // For example: to make a utility that handles 32-bit little enidan files use: Pointer32<LittleEndian>
  58. //
  59. //
  60. // get16() read a 16-bit number from an E endian struct
  61. // set16() write a 16-bit number to an E endian struct
  62. // get32() read a 32-bit number from an E endian struct
  63. // set32() write a 32-bit number to an E endian struct
  64. // get64() read a 64-bit number from an E endian struct
  65. // set64() write a 64-bit number to an E endian struct
  66. //
  67. // getBits() read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
  68. // setBits() write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
  69. //
  70. // getBitsRaw() read a bit field from a struct with native endianness
  71. // setBitsRaw() write a bit field from a struct with native endianness
  72. //
  73. class BigEndian
  74. {
  75. public:
  76. static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt16(&from, 0); }
  77. static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteBigInt16(&into, 0, value); }
  78. static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); }
  79. static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteBigInt32(&into, 0, value); }
  80. static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); }
  81. static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteBigInt64(&into, 0, value); }
  82. static uint32_t getBits(const uint32_t& from,
  83. uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
  84. static void setBits(uint32_t& into, uint32_t value,
  85. uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
  86. static uint32_t getBitsRaw(const uint32_t& from,
  87. uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }
  88. static void setBitsRaw(uint32_t& into, uint32_t value,
  89. uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
  90. const uint32_t mask = ((1<<bitCount)-1);
  91. temp &= ~(mask << (32-firstBit-bitCount));
  92. temp |= ((value & mask) << (32-firstBit-bitCount));
  93. into = temp; }
  94. enum { little_endian = 0 };
  95. };
  96. class LittleEndian
  97. {
  98. public:
  99. static uint16_t get16(const uint16_t& from) INLINE { return OSReadLittleInt16(&from, 0); }
  100. static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteLittleInt16(&into, 0, value); }
  101. static uint32_t get32(const uint32_t& from) INLINE { return OSReadLittleInt32(&from, 0); }
  102. static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteLittleInt32(&into, 0, value); }
  103. static uint64_t get64(const uint64_t& from) INLINE { return OSReadLittleInt64(&from, 0); }
  104. static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteLittleInt64(&into, 0, value); }
  105. static uint32_t getBits(const uint32_t& from,
  106. uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
  107. static void setBits(uint32_t& into, uint32_t value,
  108. uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
  109. static uint32_t getBitsRaw(const uint32_t& from,
  110. uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }
  111. static void setBitsRaw(uint32_t& into, uint32_t value,
  112. uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
  113. const uint32_t mask = ((1<<bitCount)-1);
  114. temp &= ~(mask << firstBit);
  115. temp |= ((value & mask) << firstBit);
  116. into = temp; }
  117. enum { little_endian = 1 };
  118. };
  119. #if __BIG_ENDIAN__
  120. typedef BigEndian CurrentEndian;
  121. typedef LittleEndian OtherEndian;
  122. #elif __LITTLE_ENDIAN__
  123. typedef LittleEndian CurrentEndian;
  124. typedef BigEndian OtherEndian;
  125. #else
  126. #error unknown endianness
  127. #endif
  128. template <typename _E>
  129. class Pointer32
  130. {
  131. public:
  132. typedef uint32_t uint_t;
  133. typedef int32_t sint_t;
  134. typedef _E E;
  135. static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); }
  136. static void setP(uint_t& into, uint64_t value) INLINE { _E::set32(into, value); }
  137. };
  138. template <typename _E>
  139. class Pointer64
  140. {
  141. public:
  142. typedef uint64_t uint_t;
  143. typedef int64_t sint_t;
  144. typedef _E E;
  145. static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); }
  146. static void setP(uint_t& into, uint64_t value) INLINE { _E::set64(into, value); }
  147. };
  148. //
  149. // mach-o file header
  150. //
  151. template <typename P> struct macho_header_content {};
  152. template <> struct macho_header_content<Pointer32<BigEndian> > { mach_header fields; };
  153. template <> struct macho_header_content<Pointer64<BigEndian> > { mach_header_64 fields; };
  154. template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header fields; };
  155. template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64 fields; };
  156. template <typename P>
  157. class macho_header {
  158. public:
  159. uint32_t magic() const INLINE { return E::get32(header.fields.magic); }
  160. void set_magic(uint32_t value) INLINE { E::set32(header.fields.magic, value); }
  161. uint32_t cputype() const INLINE { return E::get32(header.fields.cputype); }
  162. void set_cputype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cputype, value); }
  163. uint32_t cpusubtype() const INLINE { return E::get32(header.fields.cpusubtype); }
  164. void set_cpusubtype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }
  165. uint32_t filetype() const INLINE { return E::get32(header.fields.filetype); }
  166. void set_filetype(uint32_t value) INLINE { E::set32(header.fields.filetype, value); }
  167. uint32_t ncmds() const INLINE { return E::get32(header.fields.ncmds); }
  168. void set_ncmds(uint32_t value) INLINE { E::set32(header.fields.ncmds, value); }
  169. uint32_t sizeofcmds() const INLINE { return E::get32(header.fields.sizeofcmds); }
  170. void set_sizeofcmds(uint32_t value) INLINE { E::set32(header.fields.sizeofcmds, value); }
  171. uint32_t flags() const INLINE { return E::get32(header.fields.flags); }
  172. void set_flags(uint32_t value) INLINE { E::set32(header.fields.flags, value); }
  173. uint32_t reserved() const INLINE { return E::get32(header.fields.reserved); }
  174. void set_reserved(uint32_t value) INLINE { E::set32(header.fields.reserved, value); }
  175. typedef typename P::E E;
  176. private:
  177. macho_header_content<P> header;
  178. };
  179. //
  180. // mach-o load command
  181. //
  182. template <typename P>
  183. class macho_load_command {
  184. public:
  185. uint32_t cmd() const INLINE { return E::get32(command.cmd); }
  186. void set_cmd(uint32_t value) INLINE { E::set32(command.cmd, value); }
  187. uint32_t cmdsize() const INLINE { return E::get32(command.cmdsize); }
  188. void set_cmdsize(uint32_t value) INLINE { E::set32(command.cmdsize, value); }
  189. typedef typename P::E E;
  190. private:
  191. load_command command;
  192. };
  193. //
  194. // mach-o segment load command
  195. //
  196. template <typename P> struct macho_segment_content {};
  197. template <> struct macho_segment_content<Pointer32<BigEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
  198. template <> struct macho_segment_content<Pointer64<BigEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
  199. template <> struct macho_segment_content<Pointer32<LittleEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
  200. template <> struct macho_segment_content<Pointer64<LittleEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
  201. template <typename P>
  202. class macho_segment_command {
  203. public:
  204. uint32_t cmd() const INLINE { return E::get32(segment.fields.cmd); }
  205. void set_cmd(uint32_t value) INLINE { E::set32(segment.fields.cmd, value); }
  206. uint32_t cmdsize() const INLINE { return E::get32(segment.fields.cmdsize); }
  207. void set_cmdsize(uint32_t value) INLINE { E::set32(segment.fields.cmdsize, value); }
  208. const char* segname() const INLINE { return segment.fields.segname; }
  209. void set_segname(const char* value) INLINE { strncpy(segment.fields.segname, value, 16); }
  210. uint64_t vmaddr() const INLINE { return P::getP(segment.fields.vmaddr); }
  211. void set_vmaddr(uint64_t value) INLINE { P::setP(segment.fields.vmaddr, value); }
  212. uint64_t vmsize() const INLINE { return P::getP(segment.fields.vmsize); }
  213. void set_vmsize(uint64_t value) INLINE { P::setP(segment.fields.vmsize, value); }
  214. uint64_t fileoff() const INLINE { return P::getP(segment.fields.fileoff); }
  215. void set_fileoff(uint64_t value) INLINE { P::setP(segment.fields.fileoff, value); }
  216. uint64_t filesize() const INLINE { return P::getP(segment.fields.filesize); }
  217. void set_filesize(uint64_t value) INLINE { P::setP(segment.fields.filesize, value); }
  218. uint32_t maxprot() const INLINE { return E::get32(segment.fields.maxprot); }
  219. void set_maxprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.maxprot, value); }
  220. uint32_t initprot() const INLINE { return E::get32(segment.fields.initprot); }
  221. void set_initprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.initprot, value); }
  222. uint32_t nsects() const INLINE { return E::get32(segment.fields.nsects); }
  223. void set_nsects(uint32_t value) INLINE { E::set32(segment.fields.nsects, value); }
  224. uint32_t flags() const INLINE { return E::get32(segment.fields.flags); }
  225. void set_flags(uint32_t value) INLINE { E::set32(segment.fields.flags, value); }
  226. enum {
  227. CMD = macho_segment_content<P>::CMD
  228. };
  229. typedef typename P::E E;
  230. private:
  231. macho_segment_content<P> segment;
  232. };
  233. //
  234. // mach-o section
  235. //
  236. template <typename P> struct macho_section_content {};
  237. template <> struct macho_section_content<Pointer32<BigEndian> > { section fields; };
  238. template <> struct macho_section_content<Pointer64<BigEndian> > { section_64 fields; };
  239. template <> struct macho_section_content<Pointer32<LittleEndian> > { section fields; };
  240. template <> struct macho_section_content<Pointer64<LittleEndian> > { section_64 fields; };
  241. template <typename P>
  242. class macho_section {
  243. public:
  244. const char* sectname() const INLINE { return section.fields.sectname; }
  245. void set_sectname(const char* value) INLINE { strncpy(section.fields.sectname, value, 16); }
  246. const char* segname() const INLINE { return section.fields.segname; }
  247. void set_segname(const char* value) INLINE { strncpy(section.fields.segname, value, 16); }
  248. uint64_t addr() const INLINE { return P::getP(section.fields.addr); }
  249. void set_addr(uint64_t value) INLINE { P::setP(section.fields.addr, value); }
  250. uint64_t size() const INLINE { return P::getP(section.fields.size); }
  251. void set_size(uint64_t value) INLINE { P::setP(section.fields.size, value); }
  252. uint32_t offset() const INLINE { return E::get32(section.fields.offset); }
  253. void set_offset(uint32_t value) INLINE { E::set32(section.fields.offset, value); }
  254. uint32_t align() const INLINE { return E::get32(section.fields.align); }
  255. void set_align(uint32_t value) INLINE { E::set32(section.fields.align, value); }
  256. uint32_t reloff() const INLINE { return E::get32(section.fields.reloff); }
  257. void set_reloff(uint32_t value) INLINE { E::set32(section.fields.reloff, value); }
  258. uint32_t nreloc() const INLINE { return E::get32(section.fields.nreloc); }
  259. void set_nreloc(uint32_t value) INLINE { E::set32(section.fields.nreloc, value); }
  260. uint32_t flags() const INLINE { return E::get32(section.fields.flags); }
  261. void set_flags(uint32_t value) INLINE { E::set32(section.fields.flags, value); }
  262. uint32_t reserved1() const INLINE { return E::get32(section.fields.reserved1); }
  263. void set_reserved1(uint32_t value) INLINE { E::set32(section.fields.reserved1, value); }
  264. uint32_t reserved2() const INLINE { return E::get32(section.fields.reserved2); }
  265. void set_reserved2(uint32_t value) INLINE { E::set32(section.fields.reserved2, value); }
  266. typedef typename P::E E;
  267. private:
  268. macho_section_content<P> section;
  269. };
  270. static bool debug = true;
  271. bool processFile(const char *filename);
  272. int main(int argc, const char *argv[]) {
  273. for (int i = 1; i < argc; ++i) {
  274. if (!processFile(argv[i])) return 1;
  275. }
  276. return 0;
  277. }
  278. struct imageinfo {
  279. uint32_t version;
  280. uint32_t flags;
  281. };
  282. // Segment and section names are 16 bytes and may be un-terminated.
  283. bool segnameEquals(const char *lhs, const char *rhs)
  284. {
  285. return 0 == strncmp(lhs, rhs, 16);
  286. }
  287. bool segnameStartsWith(const char *segname, const char *prefix)
  288. {
  289. return 0 == strncmp(segname, prefix, strlen(prefix));
  290. }
  291. bool sectnameEquals(const char *lhs, const char *rhs)
  292. {
  293. return segnameEquals(lhs, rhs);
  294. }
  295. template <typename P>
  296. void dosect(uint8_t *start, macho_section<P> *sect)
  297. {
  298. if (debug) printf("section %.16s from segment %.16s\n",
  299. sect->sectname(), sect->segname());
  300. // Strip S_MOD_INIT/TERM_FUNC_POINTERS. We don't want dyld to call
  301. // our init funcs because it is too late, and we don't want anyone to
  302. // call our term funcs ever.
  303. if (segnameStartsWith(sect->segname(), "__DATA") &&
  304. sectnameEquals(sect->sectname(), "__mod_init_func"))
  305. {
  306. // section type 0 is S_REGULAR
  307. sect->set_flags(sect->flags() & ~SECTION_TYPE);
  308. sect->set_sectname("__objc_init_func");
  309. if (debug) printf("disabled __mod_init_func section\n");
  310. }
  311. if (segnameStartsWith(sect->segname(), "__DATA") &&
  312. sectnameEquals(sect->sectname(), "__mod_term_func"))
  313. {
  314. // section type 0 is S_REGULAR
  315. sect->set_flags(sect->flags() & ~SECTION_TYPE);
  316. sect->set_sectname("__objc_term_func");
  317. if (debug) printf("disabled __mod_term_func section\n");
  318. }
  319. }
  320. template <typename P>
  321. void doseg(uint8_t *start, macho_segment_command<P> *seg)
  322. {
  323. if (debug) printf("segment name: %.16s, nsects %u\n",
  324. seg->segname(), seg->nsects());
  325. macho_section<P> *sect = (macho_section<P> *)(seg + 1);
  326. for (uint32_t i = 0; i < seg->nsects(); ++i) {
  327. dosect(start, &sect[i]);
  328. }
  329. }
  330. template<typename P>
  331. bool parse_macho(uint8_t *buffer)
  332. {
  333. macho_header<P>* mh = (macho_header<P>*)buffer;
  334. uint8_t *cmds = (uint8_t *)(mh + 1);
  335. for (uint32_t c = 0; c < mh->ncmds(); c++) {
  336. macho_load_command<P>* cmd = (macho_load_command<P>*)cmds;
  337. cmds += cmd->cmdsize();
  338. if (cmd->cmd() == LC_SEGMENT || cmd->cmd() == LC_SEGMENT_64) {
  339. doseg(buffer, (macho_segment_command<P>*)cmd);
  340. }
  341. }
  342. return true;
  343. }
  344. bool parse_macho(uint8_t *buffer)
  345. {
  346. uint32_t magic = *(uint32_t *)buffer;
  347. switch (magic) {
  348. case MH_MAGIC_64:
  349. return parse_macho<Pointer64<CurrentEndian>>(buffer);
  350. case MH_MAGIC:
  351. return parse_macho<Pointer32<CurrentEndian>>(buffer);
  352. case MH_CIGAM_64:
  353. return parse_macho<Pointer64<OtherEndian>>(buffer);
  354. case MH_CIGAM:
  355. return parse_macho<Pointer32<OtherEndian>>(buffer);
  356. default:
  357. printf("file is not mach-o (magic %x)\n", magic);
  358. return false;
  359. }
  360. }
  361. bool parse_fat(uint8_t *buffer, size_t size)
  362. {
  363. uint32_t magic;
  364. if (size < sizeof(magic)) {
  365. printf("file is too small\n");
  366. return false;
  367. }
  368. magic = *(uint32_t *)buffer;
  369. if (magic != FAT_MAGIC && magic != FAT_CIGAM) {
  370. /* Not a fat file */
  371. return parse_macho(buffer);
  372. } else {
  373. struct fat_header *fh;
  374. uint32_t fat_magic, fat_nfat_arch;
  375. struct fat_arch *archs;
  376. if (size < sizeof(struct fat_header)) {
  377. printf("file is too small\n");
  378. return false;
  379. }
  380. fh = (struct fat_header *)buffer;
  381. fat_magic = OSSwapBigToHostInt32(fh->magic);
  382. fat_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);
  383. size_t fat_arch_size;
  384. // fat_nfat_arch * sizeof(struct fat_arch) + sizeof(struct fat_header)
  385. if (os_mul_and_add_overflow(fat_nfat_arch, sizeof(struct fat_arch),
  386. sizeof(struct fat_header), &fat_arch_size))
  387. {
  388. printf("too many fat archs\n");
  389. return false;
  390. }
  391. if (size < fat_arch_size) {
  392. printf("file is too small\n");
  393. return false;
  394. }
  395. archs = (struct fat_arch *)(buffer + sizeof(struct fat_header));
  396. /* Special case hidden CPU_TYPE_ARM64 */
  397. size_t fat_arch_plus_one_size;
  398. if (os_add_overflow(fat_arch_size, sizeof(struct fat_arch),
  399. &fat_arch_plus_one_size))
  400. {
  401. printf("too many fat archs\n");
  402. return false;
  403. }
  404. if (size >= fat_arch_plus_one_size) {
  405. if (fat_nfat_arch > 0
  406. && OSSwapBigToHostInt32(archs[fat_nfat_arch].cputype) == CPU_TYPE_ARM64) {
  407. fat_nfat_arch++;
  408. }
  409. }
  410. /* End special case hidden CPU_TYPE_ARM64 */
  411. if (debug) printf("%d fat architectures\n",
  412. fat_nfat_arch);
  413. for (uint32_t i = 0; i < fat_nfat_arch; i++) {
  414. uint32_t arch_cputype = OSSwapBigToHostInt32(archs[i].cputype);
  415. uint32_t arch_cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);
  416. uint32_t arch_offset = OSSwapBigToHostInt32(archs[i].offset);
  417. uint32_t arch_size = OSSwapBigToHostInt32(archs[i].size);
  418. if (debug) printf("cputype %d cpusubtype %d\n",
  419. arch_cputype, arch_cpusubtype);
  420. /* Check that slice data is after all fat headers and archs */
  421. if (arch_offset < fat_arch_size) {
  422. printf("file is badly formed\n");
  423. return false;
  424. }
  425. /* Check that the slice ends before the file does */
  426. if (arch_offset > size) {
  427. printf("file is badly formed\n");
  428. return false;
  429. }
  430. if (arch_size > size) {
  431. printf("file is badly formed\n");
  432. return false;
  433. }
  434. if (arch_offset > (size - arch_size)) {
  435. printf("file is badly formed\n");
  436. return false;
  437. }
  438. bool ok = parse_macho(buffer + arch_offset);
  439. if (!ok) return false;
  440. }
  441. return true;
  442. }
  443. }
  444. bool processFile(const char *filename)
  445. {
  446. if (debug) printf("file %s\n", filename);
  447. int fd = open(filename, O_RDWR);
  448. if (fd < 0) {
  449. printf("open %s: %s\n", filename, strerror(errno));
  450. return false;
  451. }
  452. struct stat st;
  453. if (fstat(fd, &st) < 0) {
  454. printf("fstat %s: %s\n", filename, strerror(errno));
  455. return false;
  456. }
  457. void *buffer = mmap(NULL, (size_t)st.st_size, PROT_READ|PROT_WRITE,
  458. MAP_FILE|MAP_SHARED, fd, 0);
  459. if (buffer == MAP_FAILED) {
  460. printf("mmap %s: %s\n", filename, strerror(errno));
  461. return false;
  462. }
  463. bool result = parse_fat((uint8_t *)buffer, (size_t)st.st_size);
  464. munmap(buffer, (size_t)st.st_size);
  465. close(fd);
  466. return result;
  467. }