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