108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/* Derived from Valgrind sources, coregrind/m_debuginfo/readmacho.c. 308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj GPL 2+ therefore. 408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Can be compiled as either a 32- or 64-bit program (doesn't matter). 608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj*/ 708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/* What does this program do? In short it postprocesses tool 9e95d03fff3786ef9462a45cdd6717b0793630377sewardj executables on MacOSX, after linking using /usr/bin/ld. 10e95d03fff3786ef9462a45cdd6717b0793630377sewardj 11e95d03fff3786ef9462a45cdd6717b0793630377sewardj This is to deal with two separate and entirely unrelated problems. 12e95d03fff3786ef9462a45cdd6717b0793630377sewardj Problem (1) is a bug in the linker in Xcode 4.0.0. Problem (2) is 13e95d03fff3786ef9462a45cdd6717b0793630377sewardj much newer and concerns linking 64-bit tool executables for 14e95d03fff3786ef9462a45cdd6717b0793630377sewardj Yosemite (10.10). 15e95d03fff3786ef9462a45cdd6717b0793630377sewardj 16e95d03fff3786ef9462a45cdd6717b0793630377sewardj --- Problem (1) ------------------------------------------------ 17e95d03fff3786ef9462a45cdd6717b0793630377sewardj 18e95d03fff3786ef9462a45cdd6717b0793630377sewardj This is a bug in the linker on Xcode 4.0.0 and Xcode 4.0.1. Xcode 19e95d03fff3786ef9462a45cdd6717b0793630377sewardj versions prior to 4.0.0 are unaffected. 2008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 2108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj The tracking bug is https://bugs.kde.org/show_bug.cgi?id=267997 2208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 2308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj The bug causes 64-bit tool executables to segfault at startup, 2408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj because: 2508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 2608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Comparing the MachO load commands vs a (working) tool executable 2708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj that was created by Xcode 3.2.x, it appears that the new linker has 2808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj partially ignored the build system's request to place the tool 2908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj executable's stack at a non standard location. The build system 3008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj tells the linker "-stack_addr 0x134000000 -stack_size 0x800000". 3108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 3208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj With the Xcode 3.2 linker those flags produce two results: 3308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 3408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj (1) A load command to allocate the stack at the said location: 3508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Load command 3 3608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cmd LC_SEGMENT_64 3708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cmdsize 72 3808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj segname __UNIXSTACK 3908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj vmaddr 0x0000000133800000 4008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj vmsize 0x0000000000800000 4108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fileoff 2285568 4208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj filesize 0 4308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj maxprot 0x00000007 4408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj initprot 0x00000003 4508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj nsects 0 4608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj flags 0x0 4708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 4808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj (2) A request (in LC_UNIXTHREAD) to set %rsp to the correct value 4908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj at process startup, 0x134000000. 5008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 5108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj With Xcode 4.0.1, (1) is missing but (2) is still present. The 5208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj tool executable therefore starts up with %rsp pointing to unmapped 5308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj memory and faults almost instantly. 5408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 5508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj The workaround implemented by this program is documented in comment 5608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 8 of bug 267997, viz: 5708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 5808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj One really sick workaround is to observe that the executables 5908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj contain a redundant MachO load command: 6008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 6108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Load command 2 6208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cmd LC_SEGMENT_64 6308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cmdsize 72 6408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj segname __LINKEDIT 6508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj vmaddr 0x0000000138dea000 6608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj vmsize 0x00000000000ad000 6708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fileoff 2658304 6808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj filesize 705632 6908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj maxprot 0x00000007 7008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj initprot 0x00000001 7108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj nsects 0 7208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj flags 0x0 7308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 7408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj The described section presumably contains information intended for 7508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj the dynamic linker, but is irrelevant because this is a statically 7608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj linked executable. Hence it might be possible to postprocess the 7708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj executables after linking, to overwrite this entry with the 7808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj information that would have been in the missing __UNIXSTACK entry. 7908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj I tried this by hand (with a binary editor) earlier and got 8008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj something that worked. 81e95d03fff3786ef9462a45cdd6717b0793630377sewardj 82e95d03fff3786ef9462a45cdd6717b0793630377sewardj --- Problem (2) ------------------------------------------------ 83e95d03fff3786ef9462a45cdd6717b0793630377sewardj 84e95d03fff3786ef9462a45cdd6717b0793630377sewardj On MacOSX 10.10 (Yosemite), the kernel requires all valid 85e95d03fff3786ef9462a45cdd6717b0793630377sewardj executables to have a __PAGEZERO section with SVMA of zero and size 86e95d03fff3786ef9462a45cdd6717b0793630377sewardj of at least one page. However, our tool executables have a 87e95d03fff3786ef9462a45cdd6717b0793630377sewardj __PAGEZERO section with SVMA set to the requested Valgrind load 88e95d03fff3786ef9462a45cdd6717b0793630377sewardj address (typically 0x1'3800'0000). And the kernel won't start 89e95d03fff3786ef9462a45cdd6717b0793630377sewardj those. So we take the opportunity to "fix" this by setting the 90e95d03fff3786ef9462a45cdd6717b0793630377sewardj SVMA to zero. Seems to work and have no obvious bad side effects. 9108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj*/ 9208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 9308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#define DEBUGPRINTING 0 9408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 9508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <assert.h> 9608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <stdlib.h> 9708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <stdio.h> 9808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <string.h> 9908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <sys/mman.h> 10008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <sys/stat.h> 10108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <unistd.h> 10208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <fcntl.h> 10308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 10408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#undef PLAT_x86_darwin 10508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#undef PLAT_amd64_darwin 10608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 10708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#if defined(__APPLE__) && defined(__i386__) 10808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj# define PLAT_x86_darwin 1 10908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#elif defined(__APPLE__) && defined(__x86_64__) 11008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj# define PLAT_amd64_darwin 1 11108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#else 11208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj# error "Can't be compiled on this platform" 11308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#endif 11408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 11508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <mach-o/loader.h> 11608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <mach-o/nlist.h> 11708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <mach-o/fat.h> 11808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#include <mach/i386/thread_status.h> 11908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 120e95d03fff3786ef9462a45cdd6717b0793630377sewardj/* Get hold of DARWIN_VERS, and check it has a sane value. */ 121e95d03fff3786ef9462a45cdd6717b0793630377sewardj#include "config.h" 122e95d03fff3786ef9462a45cdd6717b0793630377sewardj#if DARWIN_VERS != DARWIN_10_5 && DARWIN_VERS != DARWIN_10_6 \ 123e95d03fff3786ef9462a45cdd6717b0793630377sewardj && DARWIN_VERS != DARWIN_10_7 && DARWIN_VERS != DARWIN_10_8 \ 124e95d03fff3786ef9462a45cdd6717b0793630377sewardj && DARWIN_VERS != DARWIN_10_9 && DARWIN_VERS != DARWIN_10_10 125e95d03fff3786ef9462a45cdd6717b0793630377sewardj# error "Unknown DARWIN_VERS value. This file only compiles on Darwin." 126e95d03fff3786ef9462a45cdd6717b0793630377sewardj#endif 127e95d03fff3786ef9462a45cdd6717b0793630377sewardj 12808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 12908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef unsigned char UChar; 13008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef signed char Char; 13108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef char HChar; /* signfulness depends on host */ 13208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 13308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef unsigned int UInt; 13408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef signed int Int; 13508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 13608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef unsigned char Bool; 13708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#define True ((Bool)1) 13808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj#define False ((Bool)0) 13908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 14008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef unsigned long UWord; 14108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 14208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef UWord SizeT; 14308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef UWord Addr; 14408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 14508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef unsigned long long int ULong; 14608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef signed long long int Long; 14708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 14808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 14908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 15008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj__attribute__((noreturn)) 15108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjvoid fail ( HChar* msg ) 15208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj{ 15308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fprintf(stderr, "fixup_macho_loadcmds: fail: %s\n", msg); 15408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj exit(1); 15508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj} 15608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 15708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 15808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*------------------------------------------------------------*/ 15908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*--- ---*/ 16008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*--- Mach-O file mapping/unmapping helpers ---*/ 16108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*--- ---*/ 16208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*------------------------------------------------------------*/ 16308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 16408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjtypedef 16508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct { 16608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* These two describe the entire mapped-in ("primary") image, 16708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fat headers, kitchen sink, whatnot: the entire file. The 16808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj image is mapped into img[0 .. img_szB-1]. */ 16908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj UChar* img; 17008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj SizeT img_szB; 17108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* These two describe the Mach-O object of interest, which is 17208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj presumably somewhere inside the primary image. 17308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj map_image_aboard() below, which generates this info, will 17408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj carefully check that the macho_ fields denote a section of 17508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj memory that falls entirely inside img[0 .. img_szB-1]. */ 17608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj UChar* macho_img; 17708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj SizeT macho_img_szB; 17808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 17908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ImageInfo; 18008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 18108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 18208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjBool is_macho_object_file( const void* buf, SizeT szB ) 18308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj{ 18408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* (JRS: the Mach-O headers might not be in this mapped data, 18508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj because we only mapped a page for this initial check, 18608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj or at least not very much, and what's at the start of the file 18708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj is in general a so-called fat header. The Mach-O object we're 18808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj interested in could be arbitrarily far along the image, and so 18908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj we can't assume its header will fall within this page.) */ 19008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 19108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* But we can say that either it's a fat object, in which case it 19208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj begins with a fat header, or it's unadorned Mach-O, in which 19308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj case it starts with a normal header. At least do what checks we 19408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj can to establish whether or not we're looking at something 19508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj sane. */ 19608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 19708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj const struct fat_header* fh_be = buf; 19808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj const struct mach_header_64* mh = buf; 19908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 20008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(buf); 20108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (szB < sizeof(struct fat_header)) 20208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return False; 20308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (ntohl(fh_be->magic) == FAT_MAGIC) 20408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return True; 20508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 20608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (szB < sizeof(struct mach_header_64)) 20708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return False; 20808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (mh->magic == MH_MAGIC_64) 20908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return True; 21008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 21108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return False; 21208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj} 21308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 21408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 21508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/* Unmap an image mapped in by map_image_aboard. */ 21608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjstatic void unmap_image ( /*MOD*/ImageInfo* ii ) 21708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj{ 21808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Int r; 21908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->img); 22008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->img_szB > 0); 22108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj r = munmap( ii->img, ii->img_szB ); 22208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* Do we care if this fails? I suppose so; it would indicate 22308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj some fairly serious snafu with the mapping of the file. */ 22408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert( !r ); 22508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj memset(ii, 0, sizeof(*ii)); 22608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj} 22708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 22808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 22908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/* Map a given fat or thin object aboard, find the thin part if 23008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj necessary, do some checks, and write details of both the fat and 23108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj thin parts into *ii. Returns 32 (and leaves the file unmapped) if 23208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj the thin part is a 32 bit file. Returns 64 if it's a 64 bit file. 23308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Does not return on failure. Guarantees to return pointers to a 23408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj valid(ish) Mach-O image if it succeeds. */ 23508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjstatic Int map_image_aboard ( /*OUT*/ImageInfo* ii, HChar* filename ) 23608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj{ 23708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj memset(ii, 0, sizeof(*ii)); 23808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 23908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* First off, try to map the thing in. */ 24008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj { SizeT size; 24108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Int r, fd; 24208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct stat stat_buf; 24308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 24408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj r = stat(filename, &stat_buf); 24508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (r) 24608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Can't stat image (to determine its size)?!"); 24708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj size = stat_buf.st_size; 24808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 24908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fd = open(filename, O_RDWR, 0); 25008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (fd == -1) 25108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Can't open image for possible modification!"); 25208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 25308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("size %lu fd %d\n", size, fd); 25408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj void* v = mmap ( NULL, size, PROT_READ|PROT_WRITE, 25508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj MAP_FILE|MAP_SHARED, fd, 0 ); 25608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (v == MAP_FAILED) { 25708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj perror("mmap failed"); 25808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Can't mmap image for possible modification!"); 25908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 26008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 26108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj close(fd); 26208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 26308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ii->img = (UChar*)v; 26408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ii->img_szB = size; 26508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 26608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 26708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* Now it's mapped in and we have .img and .img_szB set. Look for 26808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj the embedded Mach-O object. If not findable, unmap and fail. */ 26908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj { struct fat_header* fh_be; 27008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct fat_header fh; 27108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct mach_header_64* mh; 27208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 27308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj // Assume initially that we have a thin image, and update 27408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj // these if it turns out to be fat. 27508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ii->macho_img = ii->img; 27608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ii->macho_img_szB = ii->img_szB; 27708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 27808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj // Check for fat header. 27908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (ii->img_szB < sizeof(struct fat_header)) 28008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Invalid Mach-O file (0 too small)."); 28108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 28208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj // Fat header is always BIG-ENDIAN 28308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fh_be = (struct fat_header *)ii->img; 28408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fh.magic = ntohl(fh_be->magic); 28508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fh.nfat_arch = ntohl(fh_be->nfat_arch); 28608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (fh.magic == FAT_MAGIC) { 28708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj // Look for a good architecture. 28808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct fat_arch *arch_be; 28908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct fat_arch arch; 29008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Int f; 29108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (ii->img_szB < sizeof(struct fat_header) 29208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj + fh.nfat_arch * sizeof(struct fat_arch)) 29308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Invalid Mach-O file (1 too small)."); 29408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 29508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj for (f = 0, arch_be = (struct fat_arch *)(fh_be+1); 29608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj f < fh.nfat_arch; 29708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj f++, arch_be++) { 29808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Int cputype; 29908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj# if defined(PLAT_x86_darwin) 30008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cputype = CPU_TYPE_X86; 30108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj# elif defined(PLAT_amd64_darwin) 30208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cputype = CPU_TYPE_X86_64; 30308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj# else 30408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj# error "unknown architecture" 30508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj# endif 30608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj arch.cputype = ntohl(arch_be->cputype); 30708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj arch.cpusubtype = ntohl(arch_be->cpusubtype); 30808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj arch.offset = ntohl(arch_be->offset); 30908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj arch.size = ntohl(arch_be->size); 31008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (arch.cputype == cputype) { 31108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (ii->img_szB < arch.offset + arch.size) 31208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Invalid Mach-O file (2 too small)."); 31308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ii->macho_img = ii->img + arch.offset; 31408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ii->macho_img_szB = arch.size; 31508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj break; 31608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 31708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 31808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (f == fh.nfat_arch) 31908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("No acceptable architecture found in fat file."); 32008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 32108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 32208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* Sanity check what we found. */ 32308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 32408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* assured by logic above */ 32508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->img_szB >= sizeof(struct fat_header)); 32608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 32708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (ii->macho_img_szB < sizeof(struct mach_header_64)) 32808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Invalid Mach-O file (3 too small)."); 32908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 33008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (ii->macho_img_szB > ii->img_szB) 33108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Invalid Mach-O file (thin bigger than fat)."); 33208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 33308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (ii->macho_img >= ii->img 33408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj && ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB) { 33508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* thin entirely within fat, as expected */ 33608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } else { 33708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Invalid Mach-O file (thin not inside fat)."); 33808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 33908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 34008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj mh = (struct mach_header_64 *)ii->macho_img; 34108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (mh->magic == MH_MAGIC) { 34208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->img); 34308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->macho_img); 34408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->img_szB > 0); 34508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->macho_img_szB > 0); 34608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->macho_img >= ii->img); 34708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB); 34808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return 32; 34908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 35008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (mh->magic != MH_MAGIC_64) 35108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Invalid Mach-O file (bad magic)."); 35208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 35308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (ii->macho_img_szB < sizeof(struct mach_header_64) + mh->sizeofcmds) 35408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Invalid Mach-O file (4 too small)."); 35508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 35608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 35708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->img); 35808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->macho_img); 35908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->img_szB > 0); 36008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->macho_img_szB > 0); 36108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->macho_img >= ii->img); 36208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB); 36308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return 64; 36408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj} 36508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 36608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 36708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*------------------------------------------------------------*/ 36808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*--- ---*/ 36908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*--- Mach-O top-level processing ---*/ 37008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*--- ---*/ 37108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/*------------------------------------------------------------*/ 37208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 37308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjvoid modify_macho_loadcmds ( HChar* filename, 37408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ULong expected_stack_start, 37508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ULong expected_stack_size ) 37608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj{ 37708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ImageInfo ii; 37808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj memset(&ii, 0, sizeof(ii)); 37908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 38008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Int size = map_image_aboard( &ii, filename ); 38108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (size == 32) { 38208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fprintf(stderr, "fixup_macho_loadcmds: Is 32-bit MachO file;" 38308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj " no modifications needed.\n"); 38408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj goto out; 38508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 38608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 38708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(size == 64); 38808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 38908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj assert(ii.macho_img != NULL && ii.macho_img_szB > 0); 39008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 39108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* Poke around in the Mach-O header, to find some important 39208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj stuff. 39308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj * the location of the __UNIXSTACK load command, if any 39408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj * the location of the __LINKEDIT load command, if any 39508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj * the initial RSP value as stated in the LC_UNIXTHREAD 39608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj */ 39708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 39808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* The collected data */ 39908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ULong init_rsp = 0; 40008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Bool have_rsp = False; 40108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct segment_command_64* seg__unixstack = NULL; 40208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct segment_command_64* seg__linkedit = NULL; 403e95d03fff3786ef9462a45cdd6717b0793630377sewardj struct segment_command_64* seg__pagezero = NULL; 40408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 40508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* Loop over the load commands and fill in the above 4 variables. */ 40608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 40708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj { struct mach_header_64 *mh = (struct mach_header_64 *)ii.macho_img; 40808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct load_command *cmd; 40908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Int c; 41008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 41108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj for (c = 0, cmd = (struct load_command *)(mh+1); 41208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj c < mh->ncmds; 41308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj c++, cmd = (struct load_command *)(cmd->cmdsize 41408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj + (unsigned long)cmd)) { 41508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 41608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("load cmd: offset %4lu size %3d kind %2d = ", 41708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj (unsigned long)((UChar*)cmd - (UChar*)ii.macho_img), 41808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cmd->cmdsize, cmd->cmd); 41908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 42008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj switch (cmd->cmd) { 42108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj case LC_SEGMENT_64: 42208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 42308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("LC_SEGMENT_64"); 42408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj break; 42508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj case LC_SYMTAB: 42608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 42708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("LC_SYMTAB"); 42808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj break; 429627c649161bb457d7681625a8ea98929acee4abasewardj case LC_DYSYMTAB: 430627c649161bb457d7681625a8ea98929acee4abasewardj if (DEBUGPRINTING) 431627c649161bb457d7681625a8ea98929acee4abasewardj printf("LC_DYSYMTAB"); 432627c649161bb457d7681625a8ea98929acee4abasewardj break; 43308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj case LC_UUID: 43408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 43508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("LC_UUID"); 43608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj break; 43708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj case LC_UNIXTHREAD: 43808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 43908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("LC_UNIXTHREAD"); 44008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj break; 44108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj default: 442e95d03fff3786ef9462a45cdd6717b0793630377sewardj if (DEBUGPRINTING) 44308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("???"); 44408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("unexpected load command in Mach header"); 44508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj break; 44608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 44708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 44808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("\n"); 44908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 45008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* Note what the stated initial RSP value is, so we can 45108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj check it is as expected. */ 45208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (cmd->cmd == LC_UNIXTHREAD) { 45308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct thread_command* tcmd = (struct thread_command*)cmd; 45408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj UInt* w32s = (UInt*)( (UChar*)tcmd + sizeof(*tcmd) ); 45508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 45608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("UnixThread: flavor %u = ", w32s[0]); 45708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (w32s[0] == x86_THREAD_STATE64 && !have_rsp) { 45808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 45908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("x86_THREAD_STATE64\n"); 46008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj x86_thread_state64_t* state64 46108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj = (x86_thread_state64_t*)(&w32s[2]); 46208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj have_rsp = True; 46308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj init_rsp = state64->__rsp; 46408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 46508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("rsp = 0x%llx\n", init_rsp); 46608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } else { 46708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 46808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("???"); 46908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 47008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (DEBUGPRINTING) 47108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj printf("\n"); 47208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 47308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 47408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (cmd->cmd == LC_SEGMENT_64) { 47508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct segment_command_64 *seg = (struct segment_command_64 *)cmd; 47608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (0 == strcmp(seg->segname, "__LINKEDIT")) 47708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj seg__linkedit = seg; 47808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (0 == strcmp(seg->segname, "__UNIXSTACK")) 47908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj seg__unixstack = seg; 480e95d03fff3786ef9462a45cdd6717b0793630377sewardj if (0 == strcmp(seg->segname, "__PAGEZERO")) 481e95d03fff3786ef9462a45cdd6717b0793630377sewardj seg__pagezero = seg; 48208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 48308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 48408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 48508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 48608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 48708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* 48808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Actions are then as follows: 48908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 49008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj * (always) check the RSP value is as expected, and abort if not 49108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 49208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj * if there's a UNIXSTACK load command, check it is as expected. 49308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj If not abort, if yes, do nothing more. 49408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 49508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj * (so there's no UNIXSTACK load command). if there's a LINKEDIT 49608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj load command, check if it is minimally usable (has 0 for 49708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj nsects and flags). If yes, convert it to a UNIXSTACK load 49808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj command. If there is none, or is unusable, then we're out of 49908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj options and have to abort. 50008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj */ 50108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (!have_rsp) 50208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Can't find / check initial RSP setting"); 50308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (init_rsp != expected_stack_start + expected_stack_size) 50408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("Initial RSP value not as expected"); 50508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 50608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fprintf(stderr, "fixup_macho_loadcmds: " 50708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj "initial RSP is as expected (0x%llx)\n", 50808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj expected_stack_start + expected_stack_size ); 50908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 51008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg__unixstack) { 51108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct segment_command_64 *seg = seg__unixstack; 51208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg->vmaddr != expected_stack_start) 51308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("has __UNIXSTACK, but wrong ::vmaddr"); 51408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg->vmsize != expected_stack_size) 51508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("has __UNIXSTACK, but wrong ::vmsize"); 51608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg->maxprot != 7) 51708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("has __UNIXSTACK, but wrong ::maxprot (should be 7)"); 51808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg->initprot != 3) 51908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("has __UNIXSTACK, but wrong ::initprot (should be 3)"); 52008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg->nsects != 0) 52108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("has __UNIXSTACK, but wrong ::nsects (should be 0)"); 52208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg->flags != 0) 52308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("has __UNIXSTACK, but wrong ::flags (should be 0)"); 52408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* looks ok */ 52508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fprintf(stderr, "fixup_macho_loadcmds: " 52608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj "acceptable __UNIXSTACK present; no modifications.\n" ); 527e95d03fff3786ef9462a45cdd6717b0793630377sewardj goto maybe_mash_pagezero; 52808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 52908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 53008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg__linkedit) { 53108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj struct segment_command_64 *seg = seg__linkedit; 53208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg->nsects != 0) 53308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("has __LINKEDIT, but wrong ::nsects (should be 0)"); 53408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (seg->flags != 0) 53508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("has __LINKEDIT, but wrong ::flags (should be 0)"); 53608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fprintf(stderr, "fixup_macho_loadcmds: " 53708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj "no __UNIXSTACK present.\n" ); 53808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fprintf(stderr, "fixup_macho_loadcmds: " 53908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj "converting __LINKEDIT to __UNIXSTACK.\n" ); 54008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj strcpy(seg->segname, "__UNIXSTACK"); 54108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj seg->vmaddr = expected_stack_start; 54208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj seg->vmsize = expected_stack_size; 54308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj seg->fileoff = 0; 54408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj seg->filesize = 0; 54508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj seg->maxprot = 7; 54608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj seg->initprot = 3; 54708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* success */ 548e95d03fff3786ef9462a45cdd6717b0793630377sewardj goto maybe_mash_pagezero; 54908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj } 55008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 55108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* out of options */ 55208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("no __UNIXSTACK found and no usable __LINKEDIT found; " 55308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj "out of options."); 55408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj /* NOTREACHED */ 55508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 556e95d03fff3786ef9462a45cdd6717b0793630377sewardj maybe_mash_pagezero: 557e95d03fff3786ef9462a45cdd6717b0793630377sewardj /* Deal with Problem (2) as documented above. */ 558e95d03fff3786ef9462a45cdd6717b0793630377sewardj# if DARWIN_VERS == DARWIN_10_10 559e95d03fff3786ef9462a45cdd6717b0793630377sewardj assert(size == 64); 560e95d03fff3786ef9462a45cdd6717b0793630377sewardj if (!seg__pagezero) { 561e95d03fff3786ef9462a45cdd6717b0793630377sewardj fail("Can't find __PAGEZERO to modify; can't continue."); 562e95d03fff3786ef9462a45cdd6717b0793630377sewardj } 563e95d03fff3786ef9462a45cdd6717b0793630377sewardj fprintf(stderr, "fixup_macho_loadcmds: " 564e95d03fff3786ef9462a45cdd6717b0793630377sewardj "changing __PAGEZERO.vmaddr from %p to 0x0.\n", 565e95d03fff3786ef9462a45cdd6717b0793630377sewardj (void*)seg__pagezero->vmaddr); 566e95d03fff3786ef9462a45cdd6717b0793630377sewardj seg__pagezero->vmaddr = 0; 567e95d03fff3786ef9462a45cdd6717b0793630377sewardj# endif 568e95d03fff3786ef9462a45cdd6717b0793630377sewardj 569e95d03fff3786ef9462a45cdd6717b0793630377sewardj out: 57008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (ii.img) 57108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj unmap_image(&ii); 57208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj} 57308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 57408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 57508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjstatic Bool is_plausible_tool_exe_name ( HChar* nm ) 57608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj{ 57708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj HChar* p; 57808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (!nm) 57908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return False; 58008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 58108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj // Does it end with this string? 58208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj p = strstr(nm, "-x86-darwin"); 58308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (p && 0 == strcmp(p, "-x86-darwin")) 58408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return True; 58508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 58608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj p = strstr(nm, "-amd64-darwin"); 58708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (p && 0 == strcmp(p, "-amd64-darwin")) 58808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return True; 58908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 59008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return False; 59108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj} 59208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 59308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 59408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardjint main ( int argc, char** argv ) 59508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj{ 59608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj Int r; 59708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ULong req_stack_addr = 0; 59808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj ULong req_stack_size = 0; 59908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 60008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (argc != 4) 60108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("args: -stack_addr-arg -stack_size-arg " 60208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj "name-of-tool-executable-to-modify"); 60308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 60408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj r= sscanf(argv[1], "0x%llx", &req_stack_addr); 60508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (r != 1) fail("invalid stack_addr arg"); 60608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 60708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj r= sscanf(argv[2], "0x%llx", &req_stack_size); 60808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (r != 1) fail("invalid stack_size arg"); 60908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 61008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fprintf(stderr, "fixup_macho_loadcmds: " 61108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj "requested stack_addr (top) 0x%llx, " 61208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj "stack_size 0x%llx\n", req_stack_addr, req_stack_size ); 61308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 61408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj if (!is_plausible_tool_exe_name(argv[3])) 61508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fail("implausible tool exe name -- not of the form *-{x86,amd64}-darwin"); 61608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 61708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fprintf(stderr, "fixup_macho_loadcmds: examining tool exe: %s\n", 61808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj argv[3] ); 61908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj modify_macho_loadcmds( argv[3], req_stack_addr - req_stack_size, 62008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj req_stack_size ); 62108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 62208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj return 0; 62308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj} 62408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 62508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/* 62608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cmd LC_SEGMENT_64 62708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cmdsize 72 62808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj segname __LINKEDIT 62908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj vmaddr 0x0000000138dea000 63008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj vmsize 0x00000000000ad000 63108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fileoff 2658304 63208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj filesize 705632 63308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj maxprot 0x00000007 63408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj initprot 0x00000001 63508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj nsects 0 63608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj flags 0x0 63708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj*/ 63808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj 63908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj/* 64008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cmd LC_SEGMENT_64 64108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj cmdsize 72 64208f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj segname __UNIXSTACK 64308f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj vmaddr 0x0000000133800000 64408f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj vmsize 0x0000000000800000 64508f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj fileoff 2498560 64608f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj filesize 0 64708f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj maxprot 0x00000007 64808f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj initprot 0x00000003 64908f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj nsects 0 65008f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj flags 0x0 65108f5a27676dedc7197a8b81f80ebc83d1e311af9sewardj*/ 652