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