/* Load a Mach-O executable or dylinker. The file may be fat or thin. */ static int load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, const char *filename, vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry) { vki_uint32_t magic; SysRes res; if (size < sizeof(magic)) { print("bad executable (no Mach-O magic)\n"); return -1; } res = VG_(pread)(fd, &magic, sizeof(magic), offset); if (sr_isError(res) || sr_Res(res) != sizeof(magic)) { print("bad executable (no Mach-O magic)\n"); return -1; } if (magic == MAGIC) { // thin return load_thin_file(fd, offset, size, filetype, filename, out_stack_start, out_stack_end, out_text, out_entry, out_linker_entry); } else if (magic == VG_(htonl)(FAT_MAGIC)) { // fat return load_fat_file(fd, offset, size, filetype, filename, out_stack_start, out_stack_end, out_text, out_entry, out_linker_entry); } else { // huh? print("bad executable (bad Mach-O magic)\n"); return -1; } }
/* Load a fat Mach-O executable. */ static int load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, const HChar *filename, vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry) { struct fat_header fh; vki_off_t arch_offset; int i; cpu_type_t good_arch; #if defined(VGA_arm) cpu_subtype_t highest_subtype; #endif SysRes res; #if defined(VGA_ppc32) good_arch = CPU_TYPE_POWERPC; #elif defined(VGA_ppc64be) good_arch = CPU_TYPE_POWERPC64BE; #elif defined(VGA_ppc64le) good_arch = CPU_TYPE_POWERPC64LE; #elif defined(VGA_x86) good_arch = CPU_TYPE_I386; #elif defined(VGA_amd64) good_arch = CPU_TYPE_X86_64; #elif defined(VGA_arm) good_arch = CPU_TYPE_ARM; highest_subtype = CPU_SUBTYPE_ARM_V7; #else # error unknown architecture #endif // Read fat header // All fat contents are BIG-ENDIAN if (size < sizeof(fh)) { print("bad executable (bad fat header)\n"); return -1; } res = VG_(pread)(fd, &fh, sizeof(fh), offset); if (sr_isError(res) || sr_Res(res) != sizeof(fh)) { print("bad executable (bad fat header)\n"); return -1; } // Scan arch headers looking for a good one arch_offset = offset + sizeof(fh); fh.nfat_arch = VG_(ntohl)(fh.nfat_arch); for (i = 0; i < fh.nfat_arch; i++) { struct fat_arch arch; if (arch_offset + sizeof(arch) > size) { print("bad executable (corrupt fat archs)\n"); return -1; } res = VG_(pread)(fd, &arch, sizeof(arch), arch_offset); arch_offset += sizeof(arch); if (sr_isError(res) || sr_Res(res) != sizeof(arch)) { VG_(printf)("bad executable (corrupt fat arch) %x %llu\n", arch.cputype, (ULong)arch_offset); return -1; } arch.cputype = VG_(ntohl)(arch.cputype); arch.cpusubtype = VG_(ntohl)(arch.cpusubtype); arch.offset = VG_(ntohl)(arch.offset); arch.size = VG_(ntohl)(arch.size); arch.align = VG_(ntohl)(arch.align); #if defined(VGA_arm) if ((arch.cputype == good_arch) && (arch.cpusubtype <= highest_subtype)) { #else if (arch.cputype == good_arch) { #endif // use this arch if (arch.offset > size || arch.offset + arch.size > size) { print("bad executable (corrupt fat arch 2)\n"); return -1; } return load_mach_file(fd, offset+arch.offset, arch.size, filetype, filename, out_stack_start, out_stack_end, out_text, out_entry, out_linker_entry); } } print("bad executable (can't run on this machine)\n"); return -1; } /* Load a Mach-O executable or dylinker. The file may be fat or thin. */ static int load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, const HChar *filename, vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry) { vki_uint32_t magic; SysRes res; if (size < sizeof(magic)) { print("bad executable (no Mach-O magic)\n"); return -1; } res = VG_(pread)(fd, &magic, sizeof(magic), offset); if (sr_isError(res) || sr_Res(res) != sizeof(magic)) { print("bad executable (no Mach-O magic)\n"); return -1; } if (magic == MAGIC) { // thin return load_thin_file(fd, offset, size, filetype, filename, out_stack_start, out_stack_end, out_text, out_entry, out_linker_entry); } else if (magic == VG_(htonl)(FAT_MAGIC)) { // fat return load_fat_file(fd, offset, size, filetype, filename, out_stack_start, out_stack_end, out_text, out_entry, out_linker_entry); } else { // huh? print("bad executable (bad Mach-O magic)\n"); return -1; } }