1
2/*--------------------------------------------------------------------*/
3/*--- User-mode execve() for Mach-O executables      m_ume_macho.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
9
10   Copyright (C) 2005-2017 Apple Inc.
11      Greg Parker  gparker@apple.com
12
13   This program is free software; you can redistribute it and/or
14   modify it under the terms of the GNU General Public License as
15   published by the Free Software Foundation; either version 2 of the
16   License, or (at your option) any later version.
17
18   This program is distributed in the hope that it will be useful, but
19   WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21   General Public License for more details.
22
23   You should have received a copy of the GNU General Public License
24   along with this program; if not, write to the Free Software
25   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26   02111-1307, USA.
27
28   The GNU General Public License is contained in the file COPYING.
29*/
30
31#if defined(VGO_darwin)
32
33#include "pub_core_basics.h"
34#include "pub_core_vki.h"
35
36#include "pub_core_aspacemgr.h"     // various mapping fns
37#include "pub_core_debuglog.h"
38#include "pub_core_libcassert.h"    // VG_(exit), vg_assert
39#include "pub_core_libcbase.h"      // VG_(memcmp), etc
40#include "pub_core_libcfile.h"      // VG_(open) et al
41#include "pub_core_libcprint.h"
42#include "pub_core_libcproc.h"
43#include "pub_core_machine.h"       // VG_ELF_CLASS (XXX: which should be moved)
44#include "pub_core_mallocfree.h"    // VG_(malloc), VG_(free)
45#include "pub_core_syscall.h"       // VG_(strerror)
46#include "pub_core_ume.h"           // self
47
48#include "priv_ume.h"
49
50#include <mach/mach.h>
51
52#include <mach-o/dyld.h>
53#include <mach-o/fat.h>
54#include <mach-o/loader.h>
55
56#if VG_WORDSIZE == 4
57#define MAGIC MH_MAGIC
58#define MACH_HEADER mach_header
59#define LC_SEGMENT_CMD LC_SEGMENT
60#define SEGMENT_COMMAND segment_command
61#define SECTION section
62#else
63#define MAGIC MH_MAGIC_64
64#define MACH_HEADER mach_header_64
65#define LC_SEGMENT_CMD LC_SEGMENT_64
66#define SEGMENT_COMMAND segment_command_64
67#define SECTION section_64
68#endif
69
70typedef struct load_info_t {
71  vki_uint8_t *stack_start; // allocated thread stack (hot end)
72  vki_uint8_t *stack_end; // allocated thread stack (cold end)
73  vki_uint8_t *text; // start of text segment (i.e. the mach headers)
74  vki_uint8_t *entry; // static entry point
75  vki_uint8_t *linker_entry; // dylinker entry point
76  Addr linker_offset; // dylinker text offset
77  vki_size_t max_addr; // biggest address reached while loading segments
78} load_info_t;
79
80static void print(const HChar *str)
81{
82   VG_(printf)("%s", str);
83}
84
85static void check_mmap(SysRes res, Addr base, SizeT len, const HChar* who)
86{
87   if (sr_isError(res)) {
88      VG_(printf)("valgrind: mmap-FIXED(0x%llx, %lld) failed in UME (%s) "
89                  "with error %lu (%s).\n",
90                  (ULong)base, (Long)len, who,
91                  sr_Err(res), VG_(strerror)(sr_Err(res)) );
92      VG_(exit)(1);
93   }
94}
95
96#if DARWIN_VERS >= DARWIN_10_8
97static void check_mmap_float(SysRes res, SizeT len, const HChar* who)
98{
99   if (sr_isError(res)) {
100      VG_(printf)("valgrind: mmap-FLOAT(size=%lld) failed in UME (%s) "
101                  "with error %lu (%s).\n",
102                  (Long)len, who,
103                  sr_Err(res), VG_(strerror)(sr_Err(res)) );
104      VG_(exit)(1);
105   }
106}
107#endif
108
109static int
110load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
111               const HChar *filename, load_info_t *out_info);
112
113static int
114load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
115              const HChar *filename, load_info_t *out_info);
116
117static int
118load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
119               const HChar *filename, load_info_t *out_info);
120
121
122/* Open and map a dylinker file.
123   Returns 0 on success, -1 on any failure.
124   filename must be an absolute path.
125   The dylinker's entry point is returned in out_info->linker_entry.
126 */
127static int
128open_dylinker(const HChar *filename, load_info_t *out_info)
129{
130   struct vg_stat sb;
131   vki_size_t filesize;
132   SysRes res;
133   int fd;
134   int err;
135
136   if (filename[0] != '/') {
137      print("bad executable (dylinker name is not an absolute path)\n");
138      return -1;
139   }
140
141   res = VG_(open)(filename, VKI_O_RDONLY, 0);
142   fd = sr_Res(res);
143   if (sr_isError(res)) {
144      VG_(printf)("couldn't open dylinker: %s\n", filename);
145      return -1;
146   }
147   err = VG_(fstat)(fd, &sb);
148   if (err) {
149      VG_(printf)("couldn't stat dylinker: %s\n", filename);
150      VG_(close)(fd);
151      return -1;
152   }
153   filesize = sb.size;
154
155   err = load_mach_file(fd, 0, filesize, MH_DYLINKER, filename, out_info);
156   if (err) {
157      VG_(printf)("...while loading dylinker: %s\n", filename);
158   }
159   VG_(close)(fd);
160   return err;
161}
162
163
164/*
165   Process an LC_SEGMENT command, mapping it into memory if appropriate.
166   fd[offset..size) is a Mach-O thin file.
167   Returns 0 on success, -1 on any failure.
168   If this segment contains the executable's Mach headers, their
169     loaded address is returned in out_info->text.
170   If this segment is a __UNIXSTACK, its start address is returned in
171     out_info->stack_start.
172*/
173static int
174load_segment(int fd, vki_off_t offset, vki_off_t size,
175             struct SEGMENT_COMMAND *segcmd, const HChar *filename,
176             load_info_t *out_info)
177{
178   SysRes res;
179   Addr addr;
180   vki_size_t filesize; // page-aligned
181   vki_size_t vmsize;   // page-aligned
182   vki_size_t vmend;    // page-aligned
183   unsigned int prot;
184   Addr slided_addr = segcmd->vmaddr + out_info->linker_offset;
185
186   // GrP fixme mark __UNIXSTACK as SF_STACK
187
188   // Don't honour the client's request to map PAGEZERO.  Why not?
189   // Because when the kernel loaded the valgrind tool executable,
190   // it will have mapped pagezero itself.  So further attempts
191   // to map it when loading the client are guaranteed to fail.
192#if VG_WORDSIZE == 4
193   if (segcmd->vmaddr == 0 && 0 == VG_(strcmp)(segcmd->segname, SEG_PAGEZERO)) {
194      if (segcmd->vmsize != 0x1000) {
195         print("bad executable (__PAGEZERO is not 4 KB)\n");
196         return -1;
197      }
198      return 0;
199   }
200#endif
201#if VG_WORDSIZE == 8
202   if (segcmd->vmaddr == 0 && 0 == VG_(strcmp)(segcmd->segname, SEG_PAGEZERO)) {
203      if (segcmd->vmsize != 0x100000000) {
204         print("bad executable (__PAGEZERO is not 4 GB)\n");
205         return -1;
206      }
207      return 0;
208   }
209#endif
210
211   // Record the segment containing the Mach headers themselves
212   if (segcmd->fileoff == 0  &&  segcmd->filesize != 0) {
213      out_info->text = (vki_uint8_t *)slided_addr;
214   }
215
216   // Record the __UNIXSTACK start
217   if (0 == VG_(strcmp)(segcmd->segname, SEG_UNIXSTACK)) {
218      out_info->stack_start = (vki_uint8_t *)slided_addr;
219   }
220
221   // Sanity-check the segment
222   if (segcmd->fileoff + segcmd->filesize > size) {
223      print("bad executable (invalid segment command)\n");
224      return -1;
225   }
226
227   vmend = VG_PGROUNDUP(slided_addr + segcmd->vmsize);
228   if (vmend > out_info->max_addr) {
229      out_info->max_addr = vmend;
230   }
231
232   if (segcmd->vmsize == 0) {
233      return 0;  // nothing to map - ok
234   }
235
236   // Get desired memory protection
237   // GrP fixme need maxprot too
238   prot = (((segcmd->initprot & VM_PROT_READ) ? VKI_PROT_READ : 0) |
239           ((segcmd->initprot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) |
240           ((segcmd->initprot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0));
241
242   // Map the segment
243   filesize = VG_PGROUNDUP(segcmd->filesize);
244   vmsize = VG_PGROUNDUP(segcmd->vmsize);
245   if (filesize > 0) {
246      addr = slided_addr;
247      VG_(debugLog)(2, "ume", "mmap fixed (file) (%#lx, %lu)\n", addr, filesize);
248      res = VG_(am_mmap_named_file_fixed_client)(addr, filesize, prot, fd,
249                                                 offset + segcmd->fileoff,
250                                                 filename);
251      check_mmap(res, addr, filesize, "load_segment1");
252   }
253
254   // Zero-fill the remainder of the segment, if any
255   if (segcmd->filesize != filesize) {
256      // non-page-aligned part
257      // GrP fixme kernel doesn't do this?
258      //bzero(segcmd->filesize+(vki_uint8_t *)addr, filesize-segcmd->filesize);
259   }
260   if (filesize != vmsize) {
261      // page-aligned part
262      SizeT length = vmsize - filesize;
263      addr = (Addr)(filesize + slided_addr);
264      VG_(debugLog)(2, "ume", "mmap fixed (anon) (%#lx, %lu)\n", addr, length);
265      res = VG_(am_mmap_anon_fixed_client)(addr, length, prot);
266      check_mmap(res, addr, length, "load_segment2");
267   }
268
269   return 0;
270}
271
272
273/*
274   Parse a LC_THREAD or LC_UNIXTHREAD command.
275   Return 0 on success, -1 on any failure.
276   If the thread is a LC_UNIXTHREAD, the stack address is returned in out_info->stack_end.
277   If the executable requested a non-default stack address,
278   *customstack is set to TRUE. The thread's entry point is returned in out_info->entry.
279   The stack itself (if any) is not mapped.
280   Other custom register settings are silently ignored (GrP fixme).
281*/
282static int
283load_genericthread(struct thread_command *threadcmd, int type,
284                    int *customstack, load_info_t *out_info)
285{
286   unsigned int flavor;
287   unsigned int count;
288   unsigned int *p;
289   unsigned int left;
290
291   p = (unsigned int *)(threadcmd + 1);
292   left = (threadcmd->cmdsize - sizeof(struct thread_command)) / sizeof(*p);
293
294   while (left > 0) {
295      if (left < 2) {
296         print("bad executable (invalid thread command)\n");
297         return -1;
298      }
299      flavor = *p++; left--;
300      count = *p++; left--;
301
302      if (left < count) {
303         print("bad executable (invalid thread command 2)\n");
304         return -1;
305      }
306
307#if defined(VGA_x86)
308      if (flavor == i386_THREAD_STATE && count == i386_THREAD_STATE_COUNT) {
309         i386_thread_state_t *state = (i386_thread_state_t *)p;
310         out_info->entry = (vki_uint8_t *)state->__eip;
311         if (type == LC_UNIXTHREAD) {
312            out_info->stack_end =
313              (vki_uint8_t *)(state->__esp ? state->__esp : VKI_USRSTACK);
314            vg_assert(VG_IS_PAGE_ALIGNED(out_info->stack_end));
315            out_info->stack_end--;
316         }
317         if (customstack) *customstack = state->__esp;
318         return 0;
319      }
320
321#elif defined(VGA_amd64)
322      if (flavor == x86_THREAD_STATE64 && count == x86_THREAD_STATE64_COUNT){
323         x86_thread_state64_t *state = (x86_thread_state64_t *)p;
324         out_info->entry = (vki_uint8_t *)state->__rip;
325         if (type == LC_UNIXTHREAD) {
326            out_info->stack_end =
327              (vki_uint8_t *)(state->__rsp ? state->__rsp : VKI_USRSTACK64);
328            vg_assert(VG_IS_PAGE_ALIGNED(out_info->stack_end));
329            out_info->stack_end--;
330         }
331         if (customstack) *customstack = state->__rsp;
332         return 0;
333      }
334
335#else
336# error unknown platform
337#endif
338      p += count;
339      left -= count;
340   }
341
342   print("bad executable (no arch-compatible thread state)\n");
343   return -1;
344}
345
346
347/* Returns the main stack size on this platform,
348   using getrlimit or a fixed size.
349   GrP fixme 64-bit? */
350static vki_size_t default_stack_size(void)
351{
352   struct vki_rlimit lim;
353   int err = VG_(getrlimit)(VKI_RLIMIT_STACK, &lim);
354   if (err) return 8*1024*1024; // 8 MB
355   else return lim.rlim_cur;
356}
357
358
359/*
360   Processes a LC_UNIXTHREAD command.
361   Returns 0 on success, -1 on any failure.
362   The stack is mapped in and returned in out_info->stack_start and out_info->stack_end.
363   The thread's entry point is returned in out_info->entry.
364*/
365static int
366load_unixthread(struct thread_command *threadcmd, load_info_t *out_info)
367{
368   int err;
369   int customstack;
370
371   err = load_genericthread(threadcmd, LC_UNIXTHREAD, &customstack, out_info);
372   if (err) return -1;
373
374   if (!out_info->stack_end) {
375      print("bad executable (no thread stack)\n");
376      return -1;
377   }
378
379   if (!customstack) {
380      // Map the stack
381      vki_size_t stacksize = VG_PGROUNDUP(default_stack_size());
382      vm_address_t stackbase = VG_PGROUNDDN(out_info->stack_end+1-stacksize);
383      SysRes res;
384
385      res = VG_(am_mmap_anon_fixed_client)(stackbase, stacksize, VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC);
386      check_mmap(res, stackbase, stacksize, "load_unixthread1");
387      out_info->stack_start = (vki_uint8_t *)stackbase;
388   } else {
389      // custom stack - mapped via __UNIXTHREAD segment
390   }
391
392   return 0;
393}
394
395
396/* Allocates a stack mapping at a V-chosen address.  Pertains to
397   LC_MAIN commands, which seem to have appeared in OSX 10.8.
398
399   This is a really nasty hack -- allocates 64M+stack size, then
400   deallocates the 64M, to guarantee that the stack is at least 64M
401   above zero. */
402#if DARWIN_VERS >= DARWIN_10_8
403static int
404handle_lcmain ( vki_size_t requested_size,
405                load_info_t *out_info )
406{
407   if (requested_size == 0) {
408      requested_size = default_stack_size();
409   }
410   requested_size = VG_PGROUNDUP(requested_size);
411
412   const vki_size_t HACK = 64 * 1024 * 1024;
413   requested_size += HACK;
414
415   SysRes res = VG_(am_mmap_anon_float_client)(requested_size,
416                   VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC);
417   check_mmap_float(res, requested_size, "handle_lcmain");
418   vg_assert(!sr_isError(res));
419   out_info->stack_start = (vki_uint8_t*)sr_Res(res);
420   out_info->stack_end   = out_info->stack_start + requested_size - 1;
421
422   Bool need_discard = False;
423   res = VG_(am_munmap_client)(&need_discard, (Addr)out_info->stack_start, HACK);
424   if (sr_isError(res)) return -1;
425   vg_assert(!need_discard); // True == wtf?
426
427   out_info->stack_start += HACK;
428
429   return 0;
430}
431#endif /* DARWIN_VERS >= DARWIN_10_8 */
432
433
434
435/*
436   Processes an LC_LOAD_DYLINKER command.
437   Returns 0 on success, -1 on any error.
438   The linker itself is mapped into memory.
439   The linker's entry point is returned in out_info->linker_entry.
440*/
441static int
442load_dylinker(struct dylinker_command *dycmd, load_info_t *out_info)
443{
444   const HChar *name;
445   int ret;
446   load_info_t linker_info;
447   linker_info.stack_start = NULL;
448   linker_info.stack_end = NULL;
449   linker_info.text = NULL;
450   linker_info.entry = NULL;
451   linker_info.linker_entry = NULL;
452   linker_info.linker_offset = 0;
453   linker_info.max_addr = out_info->max_addr;
454
455   if (dycmd->name.offset >= dycmd->cmdsize) {
456      print("bad executable (invalid dylinker command)\n");
457      return -1;
458   }
459
460   name = dycmd->name.offset + (HChar *)dycmd;
461
462   // GrP fixme assumes name is terminated somewhere
463   ret = open_dylinker(name, &linker_info);
464   if (linker_info.entry) {
465      out_info->linker_entry = linker_info.entry + linker_info.linker_offset;
466   }
467   out_info->max_addr = linker_info.max_addr;
468   return ret;
469}
470
471
472/*
473    Process an LC_THREAD command.
474    Returns 0 on success, -1 on any failure.
475    The thread's entry point is returned in out_info->entry.
476*/
477static int
478load_thread(struct thread_command *threadcmd, load_info_t *out_info)
479{
480   int customstack;
481   int err;
482
483   err = load_genericthread(threadcmd, LC_THREAD, &customstack, out_info);
484   if (err) return -1;
485   if (customstack) {
486      print("bad executable (stackless thread has stack)\n");
487      return -1;
488   }
489   return 0;
490}
491
492
493/*
494  Loads a Mach-O executable into memory, along with any threads,
495  stacks, and dylinker.
496  Returns 0 on success, -1 on any failure.
497  fd[offset..offset+size) is a Mach-O thin file.
498  filetype is MH_EXECUTE or MH_DYLINKER.
499  The mapped but empty stack is returned in out_info->stack_start.
500  The executable's Mach headers are returned in out_info->text.
501  The executable's entry point is returned in out_info->entry.
502  The dylinker's entry point (if any) is returned in out_info->linker_entry.
503  The dylinker's offset (macOS 10.12) is returned in out_info->linker_offset.
504  GrP fixme need to return whether dylinker was found - stack layout is different
505*/
506static int
507load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
508               const HChar *filename, load_info_t *out_info)
509{
510   VG_(debugLog)(1, "ume", "load_thin_file: begin:   %s\n", filename);
511   struct MACH_HEADER mh;
512   vki_uint8_t *headers;
513   vki_uint8_t *headers_end;
514   struct load_command *lc;
515   struct load_command *lcend;
516   struct SEGMENT_COMMAND *segcmd;
517   struct thread_command *threadcmd;
518   struct dylinker_command *dycmd;
519   int err;
520   SysRes res;
521   vki_size_t len;
522
523   // Read Mach-O header
524   if (sizeof(mh) > size) {
525      print("bad executable (no Mach-O header)\n");
526   }
527   res = VG_(pread)(fd, &mh, sizeof(mh), offset);
528   if (sr_isError(res)  ||  sr_Res(res) != sizeof(mh)) {
529      print("bad executable (no Mach-O header)\n");
530      return -1;
531   }
532
533
534   // Sanity-check the header itself
535   if (mh.magic != MAGIC) {
536      print("bad executable (no Mach-O magic)\n");
537      return -1;
538   }
539
540   if (mh.filetype != filetype) {
541      // expecting MH_EXECUTE or MH_DYLINKER
542      print("bad executable (wrong file type)\n");
543      return -1;
544   }
545
546
547   // Map all headers into memory
548   len = sizeof(mh) + mh.sizeofcmds;
549   if (len > size) {
550      print("bad executable (missing load commands)\n");
551      return -1;
552   }
553
554   headers = VG_(malloc)("ume.macho.headers", len);
555   res = VG_(pread)(fd, headers, len, offset);
556   if (sr_isError(res)) {
557      print("couldn't read load commands from executable\n");
558      return -1;
559   }
560   headers_end = headers + len;
561
562
563   // Map some segments into client memory:
564   // LC_SEGMENT    (text, data, etc)
565   // UNIXSTACK     (stack)
566   // LOAD_DYLINKER (dyld)
567   lcend = (struct load_command *)(headers + mh.sizeofcmds + sizeof(mh));
568   for (lc = (struct load_command *)(headers + sizeof(mh));
569        lc < lcend;
570        lc = (struct load_command *)(lc->cmdsize + (vki_uint8_t *)lc))
571   {
572      if ((vki_uint8_t *)lc < headers  ||
573          lc->cmdsize+(vki_uint8_t *)lc > headers_end) {
574          print("bad executable (invalid load commands)\n");
575          return -1;
576      }
577
578      switch (lc->cmd) {
579
580#if   DARWIN_VERS >= DARWIN_10_8
581      case LC_MAIN: { /* New in 10.8 */
582         struct entry_point_command* epcmd
583            = (struct entry_point_command*)lc;
584         if (out_info->stack_start || out_info->stack_end) {
585            print("bad executable (multiple indications of stack)");
586            return -1;
587         }
588         err = handle_lcmain(epcmd->stacksize, out_info);
589         if (err) return -1;
590         VG_(debugLog)(2, "ume", "lc_main: created stack %p-%p\n",
591	               out_info->stack_start, out_info->stack_end);
592         break;
593      }
594#     endif
595
596      case LC_SEGMENT_CMD:
597         if (lc->cmdsize < sizeof(struct SEGMENT_COMMAND)) {
598            print("bad executable (invalid load commands)\n");
599            return -1;
600         }
601         segcmd = (struct SEGMENT_COMMAND *)lc;
602#if   DARWIN_VERS >= DARWIN_10_12
603         /* dyld text address is relative instead of absolute in 10.12 */
604         if (filetype == MH_DYLINKER && segcmd->vmaddr == 0 && segcmd->fileoff == 0) {
605            out_info->linker_offset = out_info->max_addr;
606         }
607#     endif
608         err = load_segment(fd, offset, size, segcmd, filename, out_info);
609         if (err) return -1;
610
611         break;
612
613      case LC_UNIXTHREAD:
614         if (out_info->stack_end || out_info->entry) {
615            print("bad executable (multiple thread commands)\n");
616            return -1;
617         }
618         if (lc->cmdsize < sizeof(struct thread_command)) {
619            print("bad executable (invalid load commands)\n");
620            return -1;
621         }
622         threadcmd = (struct thread_command *)lc;
623         err = load_unixthread(threadcmd, out_info);
624         if (err) return -1;
625         break;
626
627      case LC_LOAD_DYLINKER:
628         if (filetype == MH_DYLINKER) {
629            print("bad executable (dylinker needs a dylinker)\n");
630            return -1;
631         }
632         if (out_info->linker_entry) {
633            print("bad executable (multiple dylinker commands)\n");
634         }
635         if (lc->cmdsize < sizeof(struct dylinker_command)) {
636            print("bad executable (invalid load commands)\n");
637            return -1;
638         }
639         dycmd = (struct dylinker_command *)lc;
640         err = load_dylinker(dycmd, out_info);
641         if (err) return -1;
642         break;
643
644      case LC_THREAD:
645         if (filetype == MH_EXECUTE) {
646            print("bad executable (stackless thread)\n");
647            return -1;
648         }
649         if (out_info->stack_end || out_info->entry) {
650            print("bad executable (multiple thread commands)\n");
651            return -1;
652         }
653         if (lc->cmdsize < sizeof(struct thread_command)) {
654            print("bad executable (invalid load commands)\n");
655            return -1;
656         }
657         threadcmd = (struct thread_command *)lc;
658         err = load_thread(threadcmd, out_info);
659         if (err) return -1;
660         break;
661
662      default:
663         break;
664      }
665   }
666
667
668   // Done with the headers
669   VG_(free)(headers);
670
671   if (filetype == MH_EXECUTE) {
672      // Verify the necessary pieces for an executable:
673      // a stack
674      // a text segment
675      // an entry point (static or linker)
676      if (!out_info->stack_end || !out_info->stack_start) {
677         VG_(printf)("bad executable %s (no stack)\n", filename);
678         return -1;
679      }
680      if (!out_info->text) {
681         print("bad executable (no text segment)\n");
682         return -1;
683      }
684      if (!out_info->entry && !out_info->linker_entry) {
685         print("bad executable (no entry point)\n");
686         return -1;
687      }
688   }
689   else if (filetype == MH_DYLINKER) {
690      // Verify the necessary pieces for a dylinker:
691      // an entry point
692      if (!out_info->entry) {
693         print("bad executable (no entry point)\n");
694         return -1;
695      }
696   }
697
698   VG_(debugLog)(1, "ume", "load_thin_file: success: %s\n", filename);
699   return 0;
700}
701
702
703/*
704 Load a fat Mach-O executable.
705*/
706static int
707load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
708             const HChar *filename, load_info_t *out_info)
709{
710   struct fat_header fh;
711   vki_off_t arch_offset;
712   int i;
713   cpu_type_t good_arch;
714   SysRes res;
715
716#if defined(VGA_ppc32)
717   good_arch = CPU_TYPE_POWERPC;
718#elif defined(VGA_ppc64be)
719   good_arch = CPU_TYPE_POWERPC64BE;
720#elif defined(VGA_ppc64le)
721   good_arch = CPU_TYPE_POWERPC64LE;
722#elif defined(VGA_x86)
723   good_arch = CPU_TYPE_I386;
724#elif defined(VGA_amd64)
725   good_arch = CPU_TYPE_X86_64;
726#else
727# error unknown architecture
728#endif
729
730   // Read fat header
731   // All fat contents are BIG-ENDIAN
732   if (size < sizeof(fh)) {
733      print("bad executable (bad fat header)\n");
734      return -1;
735   }
736   res = VG_(pread)(fd, &fh, sizeof(fh), offset);
737   if (sr_isError(res)  ||  sr_Res(res) != sizeof(fh)) {
738      print("bad executable (bad fat header)\n");
739      return -1;
740   }
741
742   // Scan arch headers looking for a good one
743   arch_offset = offset + sizeof(fh);
744   fh.nfat_arch = VG_(ntohl)(fh.nfat_arch);
745   for (i = 0; i < fh.nfat_arch; i++) {
746      struct fat_arch arch;
747      if (arch_offset + sizeof(arch) > size) {
748          print("bad executable (corrupt fat archs)\n");
749          return -1;
750      }
751
752      res = VG_(pread)(fd, &arch, sizeof(arch), arch_offset);
753      arch_offset += sizeof(arch);
754      if (sr_isError(res)  ||  sr_Res(res) != sizeof(arch)) {
755         VG_(printf)("bad executable (corrupt fat arch) %x %llu\n",
756                     arch.cputype, (ULong)arch_offset);
757         return -1;
758      }
759
760      arch.cputype = VG_(ntohl)(arch.cputype);
761      arch.cpusubtype = VG_(ntohl)(arch.cpusubtype);
762      arch.offset = VG_(ntohl)(arch.offset);
763      arch.size = VG_(ntohl)(arch.size);
764      arch.align = VG_(ntohl)(arch.align);
765      if (arch.cputype == good_arch) {
766         // use this arch
767         if (arch.offset > size  ||  arch.offset + arch.size > size) {
768            print("bad executable (corrupt fat arch 2)\n");
769            return -1;
770         }
771         return load_mach_file(fd, offset+arch.offset, arch.size, filetype, filename, out_info);
772      }
773   }
774
775   print("bad executable (can't run on this machine)\n");
776   return -1;
777}
778
779/*
780 Load a Mach-O executable or dylinker.
781 The file may be fat or thin.
782*/
783static int
784load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
785              const HChar *filename, load_info_t *out_info)
786{
787   vki_uint32_t magic;
788   SysRes res;
789
790   if (size < sizeof(magic)) {
791      print("bad executable (no Mach-O magic)\n");
792      return -1;
793   }
794   res = VG_(pread)(fd, &magic, sizeof(magic), offset);
795   if (sr_isError(res)  ||  sr_Res(res) != sizeof(magic)) {
796      print("bad executable (no Mach-O magic)\n");
797      return -1;
798   }
799
800   if (magic == MAGIC) {
801      // thin
802      return load_thin_file(fd, offset, size, filetype, filename, out_info);
803   } else if (magic == VG_(htonl)(FAT_MAGIC)) {
804      // fat
805      return load_fat_file(fd, offset, size, filetype, filename, out_info);
806   } else {
807      // huh?
808      print("bad executable (bad Mach-O magic)\n");
809      return -1;
810   }
811}
812
813
814Bool VG_(match_macho)(const void *hdr, SizeT len)
815{
816   const vki_uint32_t *magic = hdr;
817
818   // GrP fixme check more carefully for matching fat arch?
819
820   return (len >= VKI_PAGE_SIZE  &&
821           (*magic == MAGIC  ||  *magic == VG_(ntohl)(FAT_MAGIC)))
822      ? True : False;
823}
824
825
826Int VG_(load_macho)(Int fd, const HChar *name, ExeInfo *info)
827{
828   int err;
829   struct vg_stat sb;
830   load_info_t load_info;
831   load_info.stack_start = NULL;
832   load_info.stack_end = NULL;
833   load_info.text = NULL;
834   load_info.entry = NULL;
835   load_info.linker_entry = NULL;
836   load_info.linker_offset = 0;
837   load_info.max_addr = 0;
838
839   err = VG_(fstat)(fd, &sb);
840   if (err) {
841      print("couldn't stat executable\n");
842      return VKI_ENOEXEC;
843   }
844
845   err = load_mach_file(fd, 0, sb.size, MH_EXECUTE, name, &load_info);
846   if (err) return VKI_ENOEXEC;
847
848   // GrP fixme exe_base
849   // GrP fixme exe_end
850   info->entry = (Addr) load_info.entry;
851   info->init_ip = (Addr)(load_info.linker_entry ? load_info.linker_entry : load_info.entry);
852   info->brkbase = 0xffffffff; // GrP fixme hack
853   info->init_toc = 0; // GrP fixme unused
854
855   info->stack_start = (Addr) load_info.stack_start;
856   info->stack_end = (Addr) load_info.stack_end;
857   info->text = (Addr) load_info.text;
858   info->dynamic = load_info.linker_entry ? True : False;
859
860   info->executable_path = VG_(strdup)("ume.macho.executable_path", name);
861
862   return 0;
863}
864
865#endif // defined(VGO_darwin)
866
867/*--------------------------------------------------------------------*/
868/*--- end                                                          ---*/
869/*--------------------------------------------------------------------*/
870
871