/* Open and map a dylinker file. Returns 0 on success, -1 on any failure. filename must be an absolute path. The dylinker's entry point is returned in *out_linker_entry. */ static int open_dylinker(const char *filename, vki_uint8_t **out_linker_entry) { struct vg_stat sb; vki_size_t filesize; SysRes res; int fd; int err; if (filename[0] != '/') { print("bad executable (dylinker name is not an absolute path)\n"); return -1; } res = VG_(open)(filename, VKI_O_RDONLY, 0); fd = sr_Res(res); if (sr_isError(res)) { print("couldn't open dylinker: "); print(filename); print("\n"); return -1; } err = VG_(fstat)(fd, &sb); if (err) { print("couldn't stat dylinker: "); print(filename); print("\n"); VG_(close)(fd); return -1; } filesize = sb.size; err = load_mach_file(fd, 0, filesize, MH_DYLINKER, filename, NULL, NULL, NULL, out_linker_entry, NULL); if (err) { print("...while loading dylinker: "); print(filename); print("\n"); } VG_(close)(fd); return err; }
Int VG_(load_macho)(Int fd, const HChar *name, ExeInfo *info) { int err; struct vg_stat sb; vki_uint8_t *stack_start; vki_uint8_t *stack_end; vki_uint8_t *text; vki_uint8_t *entry; vki_uint8_t *linker_entry; err = VG_(fstat)(fd, &sb); if (err) { print("couldn't stat executable\n"); return VKI_ENOEXEC; } err = load_mach_file(fd, 0, sb.size, MH_EXECUTE, name, &stack_start, &stack_end, &text, &entry, &linker_entry); if (err) return VKI_ENOEXEC; // GrP fixme exe_base // GrP fixme exe_end info->entry = (Addr)entry; info->init_ip = (Addr)(linker_entry ? linker_entry : entry); info->brkbase = 0xffffffff; // GrP fixme hack info->init_toc = 0; // GrP fixme unused info->stack_start = (Addr)stack_start; info->stack_end = (Addr)stack_end; info->text = (Addr)text; info->dynamic = linker_entry ? True : False; info->executable_path = VG_(strdup)("ume.macho.executable_path", name); return 0; }
/* 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 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) { struct fat_header fh; vki_off_t arch_offset; int i; cpu_type_t good_arch; SysRes res; #if defined(VGA_ppc32) good_arch = CPU_TYPE_POWERPC; #elif defined(VGA_ppc64) good_arch = CPU_TYPE_POWERPC64; #elif defined(VGA_x86) good_arch = CPU_TYPE_I386; #elif defined(VGA_amd64) good_arch = CPU_TYPE_X86_64; #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 (arch.cputype == good_arch) { // 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 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; } }