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-2011 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
70
71static void print(const char *str)
72{
73   VG_(printf)("%s", str);
74}
75
76static void check_mmap(SysRes res, Addr base, SizeT len, HChar* who)
77{
78   if (sr_isError(res)) {
79      VG_(printf)("valgrind: mmap(0x%llx, %lld) failed in UME (%s).\n",
80                  (ULong)base, (Long)len, who);
81      VG_(exit)(1);
82   }
83}
84
85
86static int
87load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
88               const char *filename,
89               vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
90               vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry);
91
92static int
93load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
94              const char *filename,
95              vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
96              vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry);
97
98static int
99load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
100               const char *filename,
101               vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
102               vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry);
103
104
105/* Open and map a dylinker file.
106   Returns 0 on success, -1 on any failure.
107   filename must be an absolute path.
108   The dylinker's entry point is returned in *out_linker_entry.
109 */
110static int
111open_dylinker(const char *filename, vki_uint8_t **out_linker_entry)
112{
113   struct vg_stat sb;
114   vki_size_t filesize;
115   SysRes res;
116   int fd;
117   int err;
118
119   if (filename[0] != '/') {
120      print("bad executable (dylinker name is not an absolute path)\n");
121      return -1;
122   }
123
124   res = VG_(open)(filename, VKI_O_RDONLY, 0);
125   fd = sr_Res(res);
126   if (sr_isError(res)) {
127      print("couldn't open dylinker: ");
128      print(filename);
129      print("\n");
130      return -1;
131   }
132   err = VG_(fstat)(fd, &sb);
133   if (err) {
134      print("couldn't stat dylinker: ");
135      print(filename);
136      print("\n");
137      VG_(close)(fd);
138      return -1;
139   }
140   filesize = sb.size;
141
142   err = load_mach_file(fd, 0, filesize, MH_DYLINKER, filename,
143                        NULL, NULL, NULL, out_linker_entry, NULL);
144   if (err) {
145      print("...while loading dylinker: ");
146      print(filename);
147      print("\n");
148   }
149   VG_(close)(fd);
150   return err;
151}
152
153
154/*
155   Process an LC_SEGMENT command, mapping it into memory if appropriate.
156   fd[offset..size) is a Mach-O thin file.
157   Returns 0 on success, -1 on any failure.
158   If this segment contains the executable's Mach headers, their
159     loaded address is returned in *text.
160   If this segment is a __UNIXSTACK, its start address is returned in
161     *stack_start.
162*/
163static int
164load_segment(int fd, vki_off_t offset, vki_off_t size,
165             vki_uint8_t **text, vki_uint8_t **stack_start,
166             struct SEGMENT_COMMAND *segcmd, const HChar *filename)
167{
168   SysRes res;
169   Addr addr;
170   vki_size_t filesize; // page-aligned
171   vki_size_t vmsize;   // page-aligned
172   unsigned int prot;
173
174   // GrP fixme mark __UNIXSTACK as SF_STACK
175
176   // Don't honour the client's request to map PAGEZERO.  Why not?
177   // Because when the kernel loaded the valgrind tool executable,
178   // it will have mapped pagezero itself.  So further attempts
179   // to map it when loading the client are guaranteed to fail.
180#if VG_WORDSIZE == 4
181   if (segcmd->vmaddr == 0 && 0 == VG_(strcmp)(segcmd->segname, SEG_PAGEZERO)) {
182      if (segcmd->vmsize != 0x1000) {
183         print("bad executable (__PAGEZERO is not 4 KB)\n");
184         return -1;
185      }
186      return 0;
187   }
188#endif
189#if VG_WORDSIZE == 8
190   if (segcmd->vmaddr == 0 && 0 == VG_(strcmp)(segcmd->segname, SEG_PAGEZERO)) {
191      if (segcmd->vmsize != 0x100000000) {
192         print("bad executable (__PAGEZERO is not 4 GB)\n");
193         return -1;
194      }
195      return 0;
196   }
197#endif
198
199   // Record the segment containing the Mach headers themselves
200   if (segcmd->fileoff == 0  &&  segcmd->filesize != 0) {
201      if (text) *text = (vki_uint8_t *)segcmd->vmaddr;
202   }
203
204   // Record the __UNIXSTACK start
205   if (0 == VG_(strcmp)(segcmd->segname, SEG_UNIXSTACK)) {
206      if (stack_start) *stack_start = (vki_uint8_t *)segcmd->vmaddr;
207   }
208
209   // Sanity-check the segment
210   if (segcmd->fileoff + segcmd->filesize > size) {
211      print("bad executable (invalid segment command)\n");
212      return -1;
213   }
214   if (segcmd->vmsize == 0) {
215      return 0;  // nothing to map - ok
216   }
217
218   // Get desired memory protection
219   // GrP fixme need maxprot too
220   prot = (((segcmd->initprot & VM_PROT_READ) ? VKI_PROT_READ : 0) |
221           ((segcmd->initprot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) |
222           ((segcmd->initprot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0));
223
224   // Map the segment
225   filesize = VG_PGROUNDUP(segcmd->filesize);
226   vmsize = VG_PGROUNDUP(segcmd->vmsize);
227   if (filesize > 0) {
228      addr = (Addr)segcmd->vmaddr;
229      VG_(debugLog)(2, "ume", "mmap fixed (file) (%#lx, %lu)\n", addr, filesize);
230      res = VG_(am_mmap_named_file_fixed_client)(addr, filesize, prot, fd,
231                                                 offset + segcmd->fileoff,
232                                                 filename);
233      check_mmap(res, addr, filesize, "load_segment1");
234   }
235
236   // Zero-fill the remainder of the segment, if any
237   if (segcmd->filesize != filesize) {
238      // non-page-aligned part
239      // GrP fixme kernel doesn't do this?
240      //bzero(segcmd->filesize+(vki_uint8_t *)addr, filesize-segcmd->filesize);
241   }
242   if (filesize != vmsize) {
243      // page-aligned part
244      SizeT length = vmsize - filesize;
245      addr = (Addr)(filesize + segcmd->vmaddr);
246      VG_(debugLog)(2, "ume", "mmap fixed (anon) (%#lx, %lu)\n", addr, length);
247      res = VG_(am_mmap_anon_fixed_client)(addr, length, prot);
248      check_mmap(res, addr, length, "load_segment2");
249   }
250
251   return 0;
252}
253
254
255/*
256   Parse a LC_THREAD or LC_UNIXTHREAD command.
257   Return 0 on success, -1 on any failure.
258   The stack address is returned in *stack. If the executable requested
259   a non-default stack address, *customstack is set to TRUE. The thread's
260   entry point is returned in *entry.
261   The stack itself (if any) is not mapped.
262   Other custom register settings are silently ignored (GrP fixme).
263*/
264static int
265load_genericthread(vki_uint8_t **stack_end,
266                   int *customstack, vki_uint8_t **entry,
267                   struct thread_command *threadcmd)
268{
269   unsigned int flavor;
270   unsigned int count;
271   unsigned int *p;
272   unsigned int left;
273
274   p = (unsigned int *)(threadcmd + 1);
275   left = (threadcmd->cmdsize - sizeof(struct thread_command)) / sizeof(*p);
276
277   while (left > 0) {
278      if (left < 2) {
279         print("bad executable (invalid thread command)\n");
280         return -1;
281      }
282      flavor = *p++; left--;
283      count = *p++; left--;
284
285      if (left < count) {
286         print("bad executable (invalid thread command 2)\n");
287         return -1;
288      }
289
290#if defined(VGA_x86)
291      if (flavor == i386_THREAD_STATE && count == i386_THREAD_STATE_COUNT) {
292         i386_thread_state_t *state = (i386_thread_state_t *)p;
293         if (entry) *entry = (vki_uint8_t *)state->__eip;
294         if (stack_end) *stack_end = (vki_uint8_t *)(state->__esp ? state->__esp : VKI_USRSTACK);
295         if (customstack) *customstack = state->__esp;
296         return 0;
297      }
298
299#elif defined(VGA_amd64)
300      if (flavor == x86_THREAD_STATE64 && count == x86_THREAD_STATE64_COUNT){
301         x86_thread_state64_t *state = (x86_thread_state64_t *)p;
302         if (entry) *entry = (vki_uint8_t *)state->__rip;
303         if (stack_end) *stack_end = (vki_uint8_t *)(state->__rsp ? state->__rsp : VKI_USRSTACK64);
304         if (customstack) *customstack = state->__rsp;
305         return 0;
306      }
307
308#else
309# error unknown platform
310#endif
311      p += count;
312      left -= count;
313   }
314
315   print("bad executable (no arch-compatible thread state)\n");
316   return -1;
317}
318
319
320/* Returns the main stack size on this platform,
321   using getrlimit or a fixed size.
322   GrP fixme 64-bit? */
323static vki_size_t default_stack_size(void)
324{
325   struct vki_rlimit lim;
326   int err = VG_(getrlimit)(VKI_RLIMIT_STACK, &lim);
327   if (err) return 8*1024*1024; // 8 MB
328   else return lim.rlim_cur;
329}
330
331
332/*
333   Processes a LC_UNIXTHREAD command.
334   Returns 0 on success, -1 on any failure.
335   The stack is mapped in and returned in *out_stack.
336   The thread's entry point is returned in *out_entry.
337*/
338static int
339load_unixthread(vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
340                vki_uint8_t **out_entry, struct thread_command *threadcmd)
341{
342   int err;
343   vki_uint8_t *stack_end;
344   int customstack;
345
346   err = load_genericthread(&stack_end, &customstack, out_entry, threadcmd);
347   if (err) return -1;
348
349   if (!stack_end) {
350      print("bad executable (no thread stack)\n");
351      return -1;
352   }
353
354   if (!customstack) {
355      // Map the stack
356      vki_size_t stacksize = VG_PGROUNDUP(default_stack_size());
357      vm_address_t stackbase = VG_PGROUNDDN(stack_end-stacksize);
358      SysRes res;
359
360      res = VG_(am_mmap_anon_fixed_client)(stackbase, stacksize, VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC);
361      check_mmap(res, stackbase, stacksize, "load_unixthread1");
362      if (out_stack_start) *out_stack_start = (vki_uint8_t *)stackbase;
363   } else {
364      // custom stack - mapped via __UNIXTHREAD segment
365   }
366
367   if (out_stack_end) *out_stack_end = stack_end;
368
369   return 0;
370}
371
372
373/*
374   Processes an LC_LOAD_DYLINKER command.
375   Returns 0 on success, -1 on any error.
376   The linker itself is mapped into memory.
377   The linker's entry point is returned in *linker_entry.
378*/
379static int
380load_dylinker(vki_uint8_t **linker_entry, struct dylinker_command *dycmd)
381{
382   const char *name;
383
384   if (dycmd->name.offset >= dycmd->cmdsize) {
385      print("bad executable (invalid dylinker command)\n");
386      return -1;
387   }
388
389   name = dycmd->name.offset + (char *)dycmd;
390
391   // GrP fixme assumes name is terminated somewhere
392   return open_dylinker(name, linker_entry);
393}
394
395
396/*
397    Process an LC_THREAD command.
398    Returns 0 on success, -1 on any failure.
399    The thread's entry point is returned in *out_entry.
400*/
401static int
402load_thread(vki_uint8_t **out_entry, struct thread_command *threadcmd)
403{
404   int customstack;
405   int err;
406
407   err = load_genericthread(NULL, &customstack, out_entry, threadcmd);
408   if (err) return -1;
409   if (customstack) {
410      print("bad executable (stackless thread has stack)\n");
411      return -1;
412   }
413   return 0;
414}
415
416
417/*
418  Loads a Mach-O executable into memory, along with any threads,
419  stacks, and dylinker.
420  Returns 0 on success, -1 on any failure.
421  fd[offset..offset+size) is a Mach-O thin file.
422  filetype is MH_EXECUTE or MH_DYLINKER.
423  The mapped but empty stack is returned in *out_stack.
424  The executable's Mach headers are returned in *out_text.
425  The executable's entry point is returned in *out_entry.
426  The dylinker's entry point (if any) is returned in *out_linker_entry.
427  GrP fixme need to return whether dylinker was found - stack layout is different
428*/
429static int
430load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
431               const char *filename,
432               vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
433               vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry)
434{
435   struct MACH_HEADER mh;
436   vki_uint8_t *headers;
437   vki_uint8_t *headers_end;
438   struct load_command *lc;
439   struct load_command *lcend;
440   struct SEGMENT_COMMAND *segcmd;
441   struct thread_command *threadcmd;
442   struct dylinker_command *dycmd;
443   int err;
444   SysRes res;
445   vki_size_t len;
446
447   vki_uint8_t *stack_start = NULL;   // allocated thread stack (hot end)
448   vki_uint8_t *stack_end = NULL;   // allocated thread stack (cold end)
449   vki_uint8_t *entry = NULL;   // static entry point
450   vki_uint8_t *text = NULL;    // start of text segment (i.e. the mach headers)
451   vki_uint8_t *linker_entry = NULL; // dylinker entry point
452
453   // Read Mach-O header
454   if (sizeof(mh) > size) {
455      print("bad executable (no Mach-O header)\n");
456   }
457   res = VG_(pread)(fd, &mh, sizeof(mh), offset);
458   if (sr_isError(res)  ||  sr_Res(res) != sizeof(mh)) {
459      print("bad executable (no Mach-O header)\n");
460      return -1;
461   }
462
463
464   // Sanity-check the header itself
465   if (mh.magic != MAGIC) {
466      print("bad executable (no Mach-O magic)\n");
467      return -1;
468   }
469
470   if (mh.filetype != filetype) {
471      // expecting MH_EXECUTE or MH_DYLINKER
472      print("bad executable (wrong file type)\n");
473      return -1;
474   }
475
476
477   // Map all headers into memory
478   len = sizeof(mh) + mh.sizeofcmds;
479   if (len > size) {
480      print("bad executable (missing load commands)\n");
481      return -1;
482   }
483
484   headers = VG_(malloc)("ume.macho.headers", len);
485   res = VG_(pread)(fd, headers, len, offset);
486   if (sr_isError(res)) {
487      print("couldn't read load commands from executable\n");
488      return -1;
489   }
490   headers_end = headers + size;
491
492
493   // Map some segments into client memory:
494   // LC_SEGMENT    (text, data, etc)
495   // UNIXSTACK     (stack)
496   // LOAD_DYLINKER (dyld)
497   lcend = (struct load_command *)(headers + mh.sizeofcmds + sizeof(mh));
498   for (lc = (struct load_command *)(headers + sizeof(mh));
499        lc < lcend;
500        lc = (struct load_command *)(lc->cmdsize + (vki_uint8_t *)lc))
501   {
502      if ((vki_uint8_t *)lc < headers  ||
503          lc->cmdsize+(vki_uint8_t *)lc > headers_end) {
504          print("bad executable (invalid load commands)\n");
505          return -1;
506      }
507
508      switch (lc->cmd) {
509      case LC_SEGMENT_CMD:
510         if (lc->cmdsize < sizeof(struct SEGMENT_COMMAND)) {
511            print("bad executable (invalid load commands)\n");
512            return -1;
513         }
514         segcmd = (struct SEGMENT_COMMAND *)lc;
515         err = load_segment(fd, offset, size, &text, &stack_start,
516                            segcmd, filename);
517         if (err) return -1;
518
519         break;
520
521      case LC_UNIXTHREAD:
522         if (stack_end  ||  entry) {
523            print("bad executable (multiple thread commands)\n");
524            return -1;
525         }
526         if (lc->cmdsize < sizeof(struct thread_command)) {
527            print("bad executable (invalid load commands)\n");
528            return -1;
529         }
530         threadcmd = (struct thread_command *)lc;
531         err = load_unixthread(&stack_start, &stack_end, &entry, threadcmd);
532         if (err) return -1;
533         break;
534
535      case LC_LOAD_DYLINKER:
536         if (filetype == MH_DYLINKER) {
537            print("bad executable (dylinker needs a dylinker)\n");
538            return -1;
539         }
540         if (linker_entry) {
541            print("bad executable (multiple dylinker commands)\n");
542         }
543         if (lc->cmdsize < sizeof(struct dylinker_command)) {
544            print("bad executable (invalid load commands)\n");
545            return -1;
546         }
547         dycmd = (struct dylinker_command *)lc;
548         err = load_dylinker(&linker_entry, dycmd);
549         if (err) return -1;
550         break;
551
552      case LC_THREAD:
553         if (filetype == MH_EXECUTE) {
554            print("bad executable (stackless thread)\n");
555            return -1;
556         }
557         if (stack_end  ||  entry) {
558            print("bad executable (multiple thread commands)\n");
559            return -1;
560         }
561         if (lc->cmdsize < sizeof(struct thread_command)) {
562            print("bad executable (invalid load commands)\n");
563            return -1;
564         }
565         threadcmd = (struct thread_command *)lc;
566         err = load_thread(&entry, threadcmd);
567         if (err) return -1;
568         break;
569
570      default:
571         break;
572      }
573   }
574
575
576   // Done with the headers
577   VG_(free)(headers);
578
579   if (filetype == MH_EXECUTE) {
580      // Verify the necessary pieces for an executable:
581      // a stack
582      // a text segment
583      // an entry point (static or linker)
584      if (!stack_end || !stack_start) {
585         print("bad executable (no stack)\n");
586         return -1;
587      }
588      if (!text) {
589         print("bad executable (no text segment)\n");
590         return -1;
591      }
592      if (!entry  &&  !linker_entry) {
593         print("bad executable (no entry point)\n");
594         return -1;
595      }
596   }
597   else if (filetype == MH_DYLINKER) {
598      // Verify the necessary pieces for a dylinker:
599      // an entry point
600      if (!entry) {
601         print("bad executable (no entry point)\n");
602         return -1;
603      }
604   }
605
606   if (out_stack_start) *out_stack_start = stack_start;
607   if (out_stack_end) *out_stack_end = stack_end;
608   if (out_text)  *out_text = text;
609   if (out_entry) *out_entry = entry;
610   if (out_linker_entry) *out_linker_entry = linker_entry;
611
612   return 0;
613}
614
615
616/*
617 Load a fat Mach-O executable.
618*/
619static int
620load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
621             const char *filename,
622             vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
623             vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry)
624{
625   struct fat_header fh;
626   vki_off_t arch_offset;
627   int i;
628   cpu_type_t good_arch;
629   SysRes res;
630
631#if defined(VGA_ppc32)
632   good_arch = CPU_TYPE_POWERPC;
633#elif defined(VGA_ppc64)
634   good_arch = CPU_TYPE_POWERPC64;
635#elif defined(VGA_x86)
636   good_arch = CPU_TYPE_I386;
637#elif defined(VGA_amd64)
638   good_arch = CPU_TYPE_X86_64;
639#else
640# error unknown architecture
641#endif
642
643   // Read fat header
644   // All fat contents are BIG-ENDIAN
645   if (size < sizeof(fh)) {
646      print("bad executable (bad fat header)\n");
647      return -1;
648   }
649   res = VG_(pread)(fd, &fh, sizeof(fh), offset);
650   if (sr_isError(res)  ||  sr_Res(res) != sizeof(fh)) {
651      print("bad executable (bad fat header)\n");
652      return -1;
653   }
654
655   // Scan arch headers looking for a good one
656   arch_offset = offset + sizeof(fh);
657   fh.nfat_arch = VG_(ntohl)(fh.nfat_arch);
658   for (i = 0; i < fh.nfat_arch; i++) {
659      struct fat_arch arch;
660      if (arch_offset + sizeof(arch) > size) {
661          print("bad executable (corrupt fat archs)\n");
662          return -1;
663      }
664
665      res = VG_(pread)(fd, &arch, sizeof(arch), arch_offset);
666      arch_offset += sizeof(arch);
667      if (sr_isError(res)  ||  sr_Res(res) != sizeof(arch)) {
668         VG_(printf)("bad executable (corrupt fat arch) %x %llu\n",
669                     arch.cputype, (ULong)arch_offset);
670         return -1;
671      }
672
673      arch.cputype = VG_(ntohl)(arch.cputype);
674      arch.cpusubtype = VG_(ntohl)(arch.cpusubtype);
675      arch.offset = VG_(ntohl)(arch.offset);
676      arch.size = VG_(ntohl)(arch.size);
677      arch.align = VG_(ntohl)(arch.align);
678      if (arch.cputype == good_arch) {
679         // use this arch
680         if (arch.offset > size  ||  arch.offset + arch.size > size) {
681            print("bad executable (corrupt fat arch 2)\n");
682            return -1;
683         }
684         return load_mach_file(fd, offset+arch.offset, arch.size, filetype,
685                               filename, out_stack_start, out_stack_end,
686                               out_text, out_entry, out_linker_entry);
687      }
688   }
689
690   print("bad executable (can't run on this machine)\n");
691   return -1;
692}
693
694/*
695 Load a Mach-O executable or dylinker.
696 The file may be fat or thin.
697*/
698static int
699load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
700              const char *filename,
701              vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
702              vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry)
703{
704   vki_uint32_t magic;
705   SysRes res;
706
707   if (size < sizeof(magic)) {
708      print("bad executable (no Mach-O magic)\n");
709      return -1;
710   }
711   res = VG_(pread)(fd, &magic, sizeof(magic), offset);
712   if (sr_isError(res)  ||  sr_Res(res) != sizeof(magic)) {
713      print("bad executable (no Mach-O magic)\n");
714      return -1;
715   }
716
717   if (magic == MAGIC) {
718      // thin
719      return load_thin_file(fd, offset, size, filetype, filename,
720                            out_stack_start, out_stack_end,
721                            out_text, out_entry, out_linker_entry);
722   } else if (magic == VG_(htonl)(FAT_MAGIC)) {
723      // fat
724      return load_fat_file(fd, offset, size, filetype, filename,
725                           out_stack_start, out_stack_end,
726                           out_text, out_entry, out_linker_entry);
727   } else {
728      // huh?
729      print("bad executable (bad Mach-O magic)\n");
730      return -1;
731   }
732}
733
734
735Bool VG_(match_macho)(Char *hdr, Int len)
736{
737   vki_uint32_t *magic = (vki_uint32_t *)hdr;
738
739   // GrP fixme check more carefully for matching fat arch?
740
741   return (len >= VKI_PAGE_SIZE  &&
742           (*magic == MAGIC  ||  *magic == VG_(ntohl)(FAT_MAGIC)))
743      ? True : False;
744}
745
746
747Int VG_(load_macho)(Int fd, const HChar *name, ExeInfo *info)
748{
749   int err;
750   struct vg_stat sb;
751   vki_uint8_t *stack_start;
752   vki_uint8_t *stack_end;
753   vki_uint8_t *text;
754   vki_uint8_t *entry;
755   vki_uint8_t *linker_entry;
756
757   err = VG_(fstat)(fd, &sb);
758   if (err) {
759      print("couldn't stat executable\n");
760      return VKI_ENOEXEC;
761   }
762
763   err = load_mach_file(fd, 0, sb.size, MH_EXECUTE, name,
764                        &stack_start, &stack_end,
765                        &text, &entry, &linker_entry);
766   if (err) return VKI_ENOEXEC;
767
768   // GrP fixme exe_base
769   // GrP fixme exe_end
770   info->entry = (Addr)entry;
771   info->init_ip = (Addr)(linker_entry ? linker_entry : entry);
772   info->brkbase = 0xffffffff; // GrP fixme hack
773   info->init_toc = 0; // GrP fixme unused
774
775   info->stack_start = (Addr)stack_start;
776   info->stack_end = (Addr)stack_end;
777   info->text = (Addr)text;
778   info->dynamic = linker_entry ? True : False;
779
780   info->executable_path = VG_(strdup)("ume.macho.executable_path", name);
781
782   return 0;
783}
784
785#endif // defined(VGO_darwin)
786
787/*--------------------------------------------------------------------*/
788/*--- end                                                          ---*/
789/*--------------------------------------------------------------------*/
790
791