1b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 2b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Derived from Valgrind sources, coregrind/m_debuginfo/readmacho.c. 3b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov GPL 2+ therefore. 4b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 5b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Can be compiled as either a 32- or 64-bit program (doesn't matter). 6b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/ 7b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 8b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* What does this program do? In short it postprocesses tool 9b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov executables on MacOSX, after linking using /usr/bin/ld. This is so 10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov as to work around a bug in the linker on Xcode 4.0.0 and Xcode 11b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 4.0.1. Xcode versions prior to 4.0.0 are unaffected. 12b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 13b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov The tracking bug is https://bugs.kde.org/show_bug.cgi?id=267997 14b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 15b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov The bug causes 64-bit tool executables to segfault at startup, 16b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov because: 17b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 18b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Comparing the MachO load commands vs a (working) tool executable 19b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov that was created by Xcode 3.2.x, it appears that the new linker has 20b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov partially ignored the build system's request to place the tool 21b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov executable's stack at a non standard location. The build system 22b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov tells the linker "-stack_addr 0x134000000 -stack_size 0x800000". 23b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 24b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov With the Xcode 3.2 linker those flags produce two results: 25b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 26b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov (1) A load command to allocate the stack at the said location: 27b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Load command 3 28b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmd LC_SEGMENT_64 29b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmdsize 72 30b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov segname __UNIXSTACK 31b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vmaddr 0x0000000133800000 32b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vmsize 0x0000000000800000 33b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fileoff 2285568 34b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov filesize 0 35b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov maxprot 0x00000007 36b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov initprot 0x00000003 37b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov nsects 0 38b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov flags 0x0 39b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 40b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov (2) A request (in LC_UNIXTHREAD) to set %rsp to the correct value 41b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov at process startup, 0x134000000. 42b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 43b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov With Xcode 4.0.1, (1) is missing but (2) is still present. The 44b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov tool executable therefore starts up with %rsp pointing to unmapped 45b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov memory and faults almost instantly. 46b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 47b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov The workaround implemented by this program is documented in comment 48b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 8 of bug 267997, viz: 49b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 50b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov One really sick workaround is to observe that the executables 51b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov contain a redundant MachO load command: 52b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 53b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Load command 2 54b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmd LC_SEGMENT_64 55b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmdsize 72 56b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov segname __LINKEDIT 57b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vmaddr 0x0000000138dea000 58b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vmsize 0x00000000000ad000 59b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fileoff 2658304 60b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov filesize 705632 61b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov maxprot 0x00000007 62b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov initprot 0x00000001 63b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov nsects 0 64b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov flags 0x0 65b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 66b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov The described section presumably contains information intended for 67b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov the dynamic linker, but is irrelevant because this is a statically 68b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov linked executable. Hence it might be possible to postprocess the 69b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov executables after linking, to overwrite this entry with the 70b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov information that would have been in the missing __UNIXSTACK entry. 71b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov I tried this by hand (with a binary editor) earlier and got 72b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov something that worked. 73b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/ 74b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 75b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define DEBUGPRINTING 0 76b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 77b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <assert.h> 78b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <stdlib.h> 79b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <stdio.h> 80b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <string.h> 81b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <sys/mman.h> 82b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <sys/stat.h> 83b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <unistd.h> 84b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <fcntl.h> 85b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 86b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 87b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#undef PLAT_x86_darwin 88b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#undef PLAT_amd64_darwin 89b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 90b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if defined(__APPLE__) && defined(__i386__) 91b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# define PLAT_x86_darwin 1 92b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(__APPLE__) && defined(__x86_64__) 93b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# define PLAT_amd64_darwin 1 94b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#else 95b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# error "Can't be compiled on this platform" 96b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#endif 97b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 98b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <mach-o/loader.h> 99b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <mach-o/nlist.h> 100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <mach-o/fat.h> 101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <mach/i386/thread_status.h> 102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef unsigned char UChar; 105b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef signed char Char; 106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef char HChar; /* signfulness depends on host */ 107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef unsigned int UInt; 109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef signed int Int; 110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef unsigned char Bool; 112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define True ((Bool)1) 113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define False ((Bool)0) 114b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef unsigned long UWord; 116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef UWord SizeT; 118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef UWord Addr; 119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef unsigned long long int ULong; 121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef signed long long int Long; 122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 124b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov__attribute__((noreturn)) 126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid fail ( HChar* msg ) 127b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{ 128b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fprintf(stderr, "fixup_macho_loadcmds: fail: %s\n", msg); 129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov exit(1); 130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} 131b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 133b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*------------------------------------------------------------*/ 134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*--- ---*/ 135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*--- Mach-O file mapping/unmapping helpers ---*/ 136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*--- ---*/ 137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*------------------------------------------------------------*/ 138b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovtypedef 140b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct { 141b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* These two describe the entire mapped-in ("primary") image, 142b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fat headers, kitchen sink, whatnot: the entire file. The 143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov image is mapped into img[0 .. img_szB-1]. */ 144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov UChar* img; 145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT img_szB; 146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* These two describe the Mach-O object of interest, which is 147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov presumably somewhere inside the primary image. 148b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov map_image_aboard() below, which generates this info, will 149b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov carefully check that the macho_ fields denote a section of 150b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov memory that falls entirely inside img[0 .. img_szB-1]. */ 151b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov UChar* macho_img; 152b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT macho_img_szB; 153b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 154b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ImageInfo; 155b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 156b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 157b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovBool is_macho_object_file( const void* buf, SizeT szB ) 158b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{ 159b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* (JRS: the Mach-O headers might not be in this mapped data, 160b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov because we only mapped a page for this initial check, 161b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov or at least not very much, and what's at the start of the file 162b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov is in general a so-called fat header. The Mach-O object we're 163b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov interested in could be arbitrarily far along the image, and so 164b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov we can't assume its header will fall within this page.) */ 165b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 166b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* But we can say that either it's a fat object, in which case it 167b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov begins with a fat header, or it's unadorned Mach-O, in which 168b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov case it starts with a normal header. At least do what checks we 169b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov can to establish whether or not we're looking at something 170b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov sane. */ 171b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 172b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov const struct fat_header* fh_be = buf; 173b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov const struct mach_header_64* mh = buf; 174b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 175b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(buf); 176b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (szB < sizeof(struct fat_header)) 177b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return False; 178b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ntohl(fh_be->magic) == FAT_MAGIC) 179b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 180b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 181b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (szB < sizeof(struct mach_header_64)) 182b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return False; 183b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (mh->magic == MH_MAGIC_64) 184b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 185b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 186b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return False; 187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} 188b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 189b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 190b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Unmap an image mapped in by map_image_aboard. */ 191b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void unmap_image ( /*MOD*/ImageInfo* ii ) 192b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{ 193b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Int r; 194b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->img); 195b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->img_szB > 0); 196b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov r = munmap( ii->img, ii->img_szB ); 197b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* Do we care if this fails? I suppose so; it would indicate 198b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov some fairly serious snafu with the mapping of the file. */ 199b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert( !r ); 200b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov memset(ii, 0, sizeof(*ii)); 201b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} 202b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 203b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 204b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Map a given fat or thin object aboard, find the thin part if 205b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov necessary, do some checks, and write details of both the fat and 206b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov thin parts into *ii. Returns 32 (and leaves the file unmapped) if 207b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov the thin part is a 32 bit file. Returns 64 if it's a 64 bit file. 208b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Does not return on failure. Guarantees to return pointers to a 209b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov valid(ish) Mach-O image if it succeeds. */ 210b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic Int map_image_aboard ( /*OUT*/ImageInfo* ii, HChar* filename ) 211b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{ 212b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov memset(ii, 0, sizeof(*ii)); 213b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* First off, try to map the thing in. */ 215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov { SizeT size; 216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Int r, fd; 217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct stat stat_buf; 218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov r = stat(filename, &stat_buf); 220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (r) 221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Can't stat image (to determine its size)?!"); 222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov size = stat_buf.st_size; 223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fd = open(filename, O_RDWR, 0); 225b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (fd == -1) 226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Can't open image for possible modification!"); 227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("size %lu fd %d\n", size, fd); 229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov void* v = mmap ( NULL, size, PROT_READ|PROT_WRITE, 230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MAP_FILE|MAP_SHARED, fd, 0 ); 231b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (v == MAP_FAILED) { 232b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov perror("mmap failed"); 233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Can't mmap image for possible modification!"); 234b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 236b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov close(fd); 237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 238b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ii->img = (UChar*)v; 239b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ii->img_szB = size; 240b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 241b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 242b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* Now it's mapped in and we have .img and .img_szB set. Look for 243b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov the embedded Mach-O object. If not findable, unmap and fail. */ 244b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov { struct fat_header* fh_be; 245b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct fat_header fh; 246b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct mach_header_64* mh; 247b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 248b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Assume initially that we have a thin image, and update 249b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // these if it turns out to be fat. 250b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ii->macho_img = ii->img; 251b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ii->macho_img_szB = ii->img_szB; 252b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 253b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Check for fat header. 254b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ii->img_szB < sizeof(struct fat_header)) 255b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Invalid Mach-O file (0 too small)."); 256b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 257b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Fat header is always BIG-ENDIAN 258b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fh_be = (struct fat_header *)ii->img; 259b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fh.magic = ntohl(fh_be->magic); 260b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fh.nfat_arch = ntohl(fh_be->nfat_arch); 261b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (fh.magic == FAT_MAGIC) { 262b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Look for a good architecture. 263b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct fat_arch *arch_be; 264b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct fat_arch arch; 265b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Int f; 266b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ii->img_szB < sizeof(struct fat_header) 267b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov + fh.nfat_arch * sizeof(struct fat_arch)) 268b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Invalid Mach-O file (1 too small)."); 269b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 270b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov for (f = 0, arch_be = (struct fat_arch *)(fh_be+1); 271b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov f < fh.nfat_arch; 272b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov f++, arch_be++) { 273b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Int cputype; 274b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# if defined(PLAT_x86_darwin) 275b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cputype = CPU_TYPE_X86; 276b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# elif defined(PLAT_amd64_darwin) 277b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cputype = CPU_TYPE_X86_64; 278b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# else 279b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# error "unknown architecture" 280b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# endif 281b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov arch.cputype = ntohl(arch_be->cputype); 282b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov arch.cpusubtype = ntohl(arch_be->cpusubtype); 283b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov arch.offset = ntohl(arch_be->offset); 284b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov arch.size = ntohl(arch_be->size); 285b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (arch.cputype == cputype) { 286b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ii->img_szB < arch.offset + arch.size) 287b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Invalid Mach-O file (2 too small)."); 288b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ii->macho_img = ii->img + arch.offset; 289b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ii->macho_img_szB = arch.size; 290b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 291b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 292b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 293b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (f == fh.nfat_arch) 294b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("No acceptable architecture found in fat file."); 295b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 296b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 297b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* Sanity check what we found. */ 298b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 299b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* assured by logic above */ 300b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->img_szB >= sizeof(struct fat_header)); 301b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 302b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ii->macho_img_szB < sizeof(struct mach_header_64)) 303b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Invalid Mach-O file (3 too small)."); 304b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 305b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ii->macho_img_szB > ii->img_szB) 306b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Invalid Mach-O file (thin bigger than fat)."); 307b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 308b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ii->macho_img >= ii->img 309b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov && ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB) { 310b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* thin entirely within fat, as expected */ 311b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } else { 312b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Invalid Mach-O file (thin not inside fat)."); 313b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 314b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 315b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov mh = (struct mach_header_64 *)ii->macho_img; 316b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (mh->magic == MH_MAGIC) { 317b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->img); 318b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->macho_img); 319b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->img_szB > 0); 320b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->macho_img_szB > 0); 321b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->macho_img >= ii->img); 322b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB); 323b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return 32; 324b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 325b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (mh->magic != MH_MAGIC_64) 326b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Invalid Mach-O file (bad magic)."); 327b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 328b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ii->macho_img_szB < sizeof(struct mach_header_64) + mh->sizeofcmds) 329b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Invalid Mach-O file (4 too small)."); 330b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 331b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 332b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->img); 333b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->macho_img); 334b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->img_szB > 0); 335b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->macho_img_szB > 0); 336b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->macho_img >= ii->img); 337b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB); 338b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return 64; 339b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} 340b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 341b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 342b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*------------------------------------------------------------*/ 343b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*--- ---*/ 344b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*--- Mach-O top-level processing ---*/ 345b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*--- ---*/ 346b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*------------------------------------------------------------*/ 347b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 348b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid modify_macho_loadcmds ( HChar* filename, 349b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ULong expected_stack_start, 350b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ULong expected_stack_size ) 351b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{ 352b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ImageInfo ii; 353b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov memset(&ii, 0, sizeof(ii)); 354b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 355b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Int size = map_image_aboard( &ii, filename ); 356b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (size == 32) { 357b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fprintf(stderr, "fixup_macho_loadcmds: Is 32-bit MachO file;" 358b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov " no modifications needed.\n"); 359b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov goto out; 360b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 361b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 362b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(size == 64); 363b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 364b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assert(ii.macho_img != NULL && ii.macho_img_szB > 0); 365b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 366b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* Poke around in the Mach-O header, to find some important 367b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov stuff. 368b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * the location of the __UNIXSTACK load command, if any 369b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * the location of the __LINKEDIT load command, if any 370b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * the initial RSP value as stated in the LC_UNIXTHREAD 371b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov */ 372b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 373b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* The collected data */ 374b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ULong init_rsp = 0; 375b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Bool have_rsp = False; 376b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct segment_command_64* seg__unixstack = NULL; 377b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct segment_command_64* seg__linkedit = NULL; 378b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 379b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* Loop over the load commands and fill in the above 4 variables. */ 380b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 381b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov { struct mach_header_64 *mh = (struct mach_header_64 *)ii.macho_img; 382b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct load_command *cmd; 383b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Int c; 384b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 385b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov for (c = 0, cmd = (struct load_command *)(mh+1); 386b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov c < mh->ncmds; 387b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov c++, cmd = (struct load_command *)(cmd->cmdsize 388b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov + (unsigned long)cmd)) { 389b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 390b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("load cmd: offset %4lu size %3d kind %2d = ", 391b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov (unsigned long)((UChar*)cmd - (UChar*)ii.macho_img), 392b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmd->cmdsize, cmd->cmd); 393b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 394b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov switch (cmd->cmd) { 395b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov case LC_SEGMENT_64: 396b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 397b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("LC_SEGMENT_64"); 398b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 399b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov case LC_SYMTAB: 400b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 401b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("LC_SYMTAB"); 402b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 403b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov case LC_DYSYMTAB: 404b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 405b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("LC_DYSYMTAB"); 406b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 407b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov case LC_UUID: 408b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 409b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("LC_UUID"); 410b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 411b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov case LC_UNIXTHREAD: 412b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 413b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("LC_UNIXTHREAD"); 414b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 415b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov default: 416b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("???"); 417b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("unexpected load command in Mach header"); 418b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 419b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 420b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 421b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("\n"); 422b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 423b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* Note what the stated initial RSP value is, so we can 424b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov check it is as expected. */ 425b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (cmd->cmd == LC_UNIXTHREAD) { 426b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct thread_command* tcmd = (struct thread_command*)cmd; 427b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov UInt* w32s = (UInt*)( (UChar*)tcmd + sizeof(*tcmd) ); 428b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 429b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("UnixThread: flavor %u = ", w32s[0]); 430b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (w32s[0] == x86_THREAD_STATE64 && !have_rsp) { 431b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 432b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("x86_THREAD_STATE64\n"); 433b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov x86_thread_state64_t* state64 434b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov = (x86_thread_state64_t*)(&w32s[2]); 435b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov have_rsp = True; 436b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov init_rsp = state64->__rsp; 437b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 438b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("rsp = 0x%llx\n", init_rsp); 439b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } else { 440b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 441b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("???"); 442b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 443b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DEBUGPRINTING) 444b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov printf("\n"); 445b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 446b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 447b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (cmd->cmd == LC_SEGMENT_64) { 448b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct segment_command_64 *seg = (struct segment_command_64 *)cmd; 449b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (0 == strcmp(seg->segname, "__LINKEDIT")) 450b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov seg__linkedit = seg; 451b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (0 == strcmp(seg->segname, "__UNIXSTACK")) 452b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov seg__unixstack = seg; 453b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 454b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 455b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 456b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 457b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 458b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* 459b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Actions are then as follows: 460b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 461b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * (always) check the RSP value is as expected, and abort if not 462b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 463b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * if there's a UNIXSTACK load command, check it is as expected. 464b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov If not abort, if yes, do nothing more. 465b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 466b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * (so there's no UNIXSTACK load command). if there's a LINKEDIT 467b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov load command, check if it is minimally usable (has 0 for 468b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov nsects and flags). If yes, convert it to a UNIXSTACK load 469b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov command. If there is none, or is unusable, then we're out of 470b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov options and have to abort. 471b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov */ 472b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (!have_rsp) 473b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Can't find / check initial RSP setting"); 474b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (init_rsp != expected_stack_start + expected_stack_size) 475b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("Initial RSP value not as expected"); 476b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 477b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fprintf(stderr, "fixup_macho_loadcmds: " 478b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "initial RSP is as expected (0x%llx)\n", 479b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov expected_stack_start + expected_stack_size ); 480b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 481b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg__unixstack) { 482b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct segment_command_64 *seg = seg__unixstack; 483b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg->vmaddr != expected_stack_start) 484b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("has __UNIXSTACK, but wrong ::vmaddr"); 485b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg->vmsize != expected_stack_size) 486b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("has __UNIXSTACK, but wrong ::vmsize"); 487b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg->maxprot != 7) 488b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("has __UNIXSTACK, but wrong ::maxprot (should be 7)"); 489b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg->initprot != 3) 490b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("has __UNIXSTACK, but wrong ::initprot (should be 3)"); 491b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg->nsects != 0) 492b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("has __UNIXSTACK, but wrong ::nsects (should be 0)"); 493b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg->flags != 0) 494b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("has __UNIXSTACK, but wrong ::flags (should be 0)"); 495b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* looks ok */ 496b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fprintf(stderr, "fixup_macho_loadcmds: " 497b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "acceptable __UNIXSTACK present; no modifications.\n" ); 498b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov goto out; 499b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 500b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 501b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg__linkedit) { 502b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov struct segment_command_64 *seg = seg__linkedit; 503b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg->nsects != 0) 504b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("has __LINKEDIT, but wrong ::nsects (should be 0)"); 505b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (seg->flags != 0) 506b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("has __LINKEDIT, but wrong ::flags (should be 0)"); 507b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fprintf(stderr, "fixup_macho_loadcmds: " 508b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "no __UNIXSTACK present.\n" ); 509b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fprintf(stderr, "fixup_macho_loadcmds: " 510b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "converting __LINKEDIT to __UNIXSTACK.\n" ); 511b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov strcpy(seg->segname, "__UNIXSTACK"); 512b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov seg->vmaddr = expected_stack_start; 513b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov seg->vmsize = expected_stack_size; 514b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov seg->fileoff = 0; 515b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov seg->filesize = 0; 516b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov seg->maxprot = 7; 517b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov seg->initprot = 3; 518b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* success */ 519b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov goto out; 520b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 521b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 522b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* out of options */ 523b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("no __UNIXSTACK found and no usable __LINKEDIT found; " 524b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "out of options."); 525b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* NOTREACHED */ 526b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 527b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov out: 528b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ii.img) 529b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov unmap_image(&ii); 530b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} 531b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 532b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 533b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic Bool is_plausible_tool_exe_name ( HChar* nm ) 534b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{ 535b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov HChar* p; 536b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (!nm) 537b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return False; 538b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 539b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Does it end with this string? 540b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov p = strstr(nm, "-x86-darwin"); 541b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (p && 0 == strcmp(p, "-x86-darwin")) 542b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 543b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 544b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov p = strstr(nm, "-amd64-darwin"); 545b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (p && 0 == strcmp(p, "-amd64-darwin")) 546b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 547b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 548b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return False; 549b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} 550b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 551b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 552b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovint main ( int argc, char** argv ) 553b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{ 554b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Int r; 555b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ULong req_stack_addr = 0; 556b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ULong req_stack_size = 0; 557b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 558b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (argc != 4) 559b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("args: -stack_addr-arg -stack_size-arg " 560b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "name-of-tool-executable-to-modify"); 561b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 562b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov r= sscanf(argv[1], "0x%llx", &req_stack_addr); 563b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (r != 1) fail("invalid stack_addr arg"); 564b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 565b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov r= sscanf(argv[2], "0x%llx", &req_stack_size); 566b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (r != 1) fail("invalid stack_size arg"); 567b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 568b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fprintf(stderr, "fixup_macho_loadcmds: " 569b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "requested stack_addr (top) 0x%llx, " 570b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "stack_size 0x%llx\n", req_stack_addr, req_stack_size ); 571b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 572b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (!is_plausible_tool_exe_name(argv[3])) 573b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fail("implausible tool exe name -- not of the form *-{x86,amd64}-darwin"); 574b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 575b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fprintf(stderr, "fixup_macho_loadcmds: examining tool exe: %s\n", 576b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov argv[3] ); 577b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov modify_macho_loadcmds( argv[3], req_stack_addr - req_stack_size, 578b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov req_stack_size ); 579b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 580b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return 0; 581b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} 582b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 583b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* 584b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmd LC_SEGMENT_64 585b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmdsize 72 586b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov segname __LINKEDIT 587b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vmaddr 0x0000000138dea000 588b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vmsize 0x00000000000ad000 589b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fileoff 2658304 590b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov filesize 705632 591b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov maxprot 0x00000007 592b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov initprot 0x00000001 593b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov nsects 0 594b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov flags 0x0 595b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/ 596b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 597b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* 598b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmd LC_SEGMENT_64 599b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmdsize 72 600b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov segname __UNIXSTACK 601b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vmaddr 0x0000000133800000 602b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vmsize 0x0000000000800000 603b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov fileoff 2498560 604b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov filesize 0 605b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov maxprot 0x00000007 606b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov initprot 0x00000003 607b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov nsects 0 608b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov flags 0x0 609b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/ 610