syswrap openat2 for all linux arches
[valgrind.git] / coregrind / m_ume / macho.c
blob046d17493389ac1d665bff363239daa78ccf0990
2 /*--------------------------------------------------------------------*/
3 /*--- User-mode execve() for Mach-O executables m_ume_macho.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2005-2017 Apple Inc.
11 Greg Parker gparker@apple.com
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.
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.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
29 #if defined(VGO_darwin)
31 #include "pub_core_basics.h"
32 #include "pub_core_vki.h"
34 #include "pub_core_aspacemgr.h" // various mapping fns
35 #include "pub_core_debuglog.h"
36 #include "pub_core_libcassert.h" // VG_(exit), vg_assert
37 #include "pub_core_libcbase.h" // VG_(memcmp), etc
38 #include "pub_core_libcfile.h" // VG_(open) et al
39 #include "pub_core_libcprint.h"
40 #include "pub_core_libcproc.h"
41 #include "pub_core_machine.h" // VG_ELF_CLASS (XXX: which should be moved)
42 #include "pub_core_mallocfree.h" // VG_(malloc), VG_(free)
43 #include "pub_core_syscall.h" // VG_(strerror)
44 #include "pub_core_ume.h" // self
46 #include "priv_ume.h"
48 #include <mach/mach.h>
50 #include <mach-o/dyld.h>
51 #include <mach-o/fat.h>
52 #include <mach-o/loader.h>
54 #if VG_WORDSIZE == 4
55 #define MAGIC MH_MAGIC
56 #define MACH_HEADER mach_header
57 #define LC_SEGMENT_CMD LC_SEGMENT
58 #define SEGMENT_COMMAND segment_command
59 #define SECTION section
60 #else
61 #define MAGIC MH_MAGIC_64
62 #define MACH_HEADER mach_header_64
63 #define LC_SEGMENT_CMD LC_SEGMENT_64
64 #define SEGMENT_COMMAND segment_command_64
65 #define SECTION section_64
66 #endif
68 typedef struct load_info_t {
69 vki_uint8_t *stack_start; // allocated thread stack (hot end)
70 vki_uint8_t *stack_end; // allocated thread stack (cold end)
71 vki_uint8_t *text; // start of text segment (i.e. the mach headers)
72 vki_uint8_t *entry; // static entry point
73 vki_uint8_t *linker_entry; // dylinker entry point
74 Addr linker_offset; // dylinker text offset
75 vki_size_t max_addr; // biggest address reached while loading segments
76 } load_info_t;
78 static void print(const HChar *str)
80 VG_(printf)("%s", str);
83 static void check_mmap(SysRes res, Addr base, SizeT len, const HChar* who)
85 if (sr_isError(res)) {
86 VG_(printf)("valgrind: mmap-FIXED(0x%llx, %lld) failed in UME (%s) "
87 "with error %lu (%s).\n",
88 (ULong)base, (Long)len, who,
89 sr_Err(res), VG_(strerror)(sr_Err(res)) );
90 VG_(exit)(1);
94 #if DARWIN_VERS >= DARWIN_10_8
95 static void check_mmap_float(SysRes res, SizeT len, const HChar* who)
97 if (sr_isError(res)) {
98 VG_(printf)("valgrind: mmap-FLOAT(size=%lld) failed in UME (%s) "
99 "with error %lu (%s).\n",
100 (Long)len, who,
101 sr_Err(res), VG_(strerror)(sr_Err(res)) );
102 VG_(exit)(1);
105 #endif
107 static int
108 load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
109 const HChar *filename, load_info_t *out_info);
111 static int
112 load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
113 const HChar *filename, load_info_t *out_info);
115 static int
116 load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
117 const HChar *filename, load_info_t *out_info);
120 /* Open and map a dylinker file.
121 Returns 0 on success, -1 on any failure.
122 filename must be an absolute path.
123 The dylinker's entry point is returned in out_info->linker_entry.
125 static int
126 open_dylinker(const HChar *filename, load_info_t *out_info)
128 struct vg_stat sb;
129 vki_size_t filesize;
130 SysRes res;
131 int fd;
132 int err;
134 if (filename[0] != '/') {
135 print("bad executable (dylinker name is not an absolute path)\n");
136 return -1;
139 res = VG_(open)(filename, VKI_O_RDONLY, 0);
140 fd = sr_Res(res);
141 if (sr_isError(res)) {
142 VG_(printf)("couldn't open dylinker: %s\n", filename);
143 return -1;
145 err = VG_(fstat)(fd, &sb);
146 if (err) {
147 VG_(printf)("couldn't stat dylinker: %s\n", filename);
148 VG_(close)(fd);
149 return -1;
151 filesize = sb.size;
153 err = load_mach_file(fd, 0, filesize, MH_DYLINKER, filename, out_info);
154 if (err) {
155 VG_(printf)("...while loading dylinker: %s\n", filename);
157 VG_(close)(fd);
158 return err;
163 Process an LC_SEGMENT command, mapping it into memory if appropriate.
164 fd[offset..size) is a Mach-O thin file.
165 Returns 0 on success, -1 on any failure.
166 If this segment contains the executable's Mach headers, their
167 loaded address is returned in out_info->text.
168 If this segment is a __UNIXSTACK, its start address is returned in
169 out_info->stack_start.
171 static int
172 load_segment(int fd, vki_off_t offset, vki_off_t size,
173 struct SEGMENT_COMMAND *segcmd, const HChar *filename,
174 load_info_t *out_info)
176 SysRes res;
177 Addr addr;
178 vki_size_t filesize; // page-aligned
179 vki_size_t vmsize; // page-aligned
180 vki_size_t vmend; // page-aligned
181 unsigned int prot;
182 Addr slided_addr = segcmd->vmaddr + out_info->linker_offset;
184 // GrP fixme mark __UNIXSTACK as SF_STACK
186 // Don't honour the client's request to map PAGEZERO. Why not?
187 // Because when the kernel loaded the valgrind tool executable,
188 // it will have mapped pagezero itself. So further attempts
189 // to map it when loading the client are guaranteed to fail.
190 #if VG_WORDSIZE == 4
191 if (segcmd->vmaddr == 0 && 0 == VG_(strcmp)(segcmd->segname, SEG_PAGEZERO)) {
192 if (segcmd->vmsize != 0x1000) {
193 print("bad executable (__PAGEZERO is not 4 KB)\n");
194 return -1;
196 return 0;
198 #endif
199 #if VG_WORDSIZE == 8
200 if (segcmd->vmaddr == 0 && 0 == VG_(strcmp)(segcmd->segname, SEG_PAGEZERO)) {
201 if (segcmd->vmsize != 0x100000000) {
202 print("bad executable (__PAGEZERO is not 4 GB)\n");
203 return -1;
205 return 0;
207 #endif
209 // Record the segment containing the Mach headers themselves
210 if (segcmd->fileoff == 0 && segcmd->filesize != 0) {
211 out_info->text = (vki_uint8_t *)slided_addr;
214 // Record the __UNIXSTACK start
215 if (0 == VG_(strcmp)(segcmd->segname, SEG_UNIXSTACK)) {
216 out_info->stack_start = (vki_uint8_t *)slided_addr;
219 // Sanity-check the segment
220 if (segcmd->fileoff + segcmd->filesize > size) {
221 print("bad executable (invalid segment command)\n");
222 return -1;
225 vmend = VG_PGROUNDUP(slided_addr + segcmd->vmsize);
226 if (vmend > out_info->max_addr) {
227 out_info->max_addr = vmend;
230 if (segcmd->vmsize == 0) {
231 return 0; // nothing to map - ok
234 // Get desired memory protection
235 // GrP fixme need maxprot too
236 prot = (((segcmd->initprot & VM_PROT_READ) ? VKI_PROT_READ : 0) |
237 ((segcmd->initprot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) |
238 ((segcmd->initprot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0));
240 // Map the segment
241 filesize = VG_PGROUNDUP(segcmd->filesize);
242 vmsize = VG_PGROUNDUP(segcmd->vmsize);
243 if (filesize > 0) {
244 addr = slided_addr;
245 VG_(debugLog)(2, "ume", "mmap fixed (file) (%#lx, %lu)\n", addr, filesize);
246 res = VG_(am_mmap_named_file_fixed_client)(addr, filesize, prot, fd,
247 offset + segcmd->fileoff,
248 filename);
249 check_mmap(res, addr, filesize, "load_segment1");
252 // Zero-fill the remainder of the segment, if any
253 if (segcmd->filesize != filesize) {
254 // non-page-aligned part
255 // GrP fixme kernel doesn't do this?
256 //bzero(segcmd->filesize+(vki_uint8_t *)addr, filesize-segcmd->filesize);
258 if (filesize != vmsize) {
259 // page-aligned part
260 SizeT length = vmsize - filesize;
261 addr = (Addr)(filesize + slided_addr);
262 VG_(debugLog)(2, "ume", "mmap fixed (anon) (%#lx, %lu)\n", addr, length);
263 res = VG_(am_mmap_anon_fixed_client)(addr, length, prot);
264 check_mmap(res, addr, length, "load_segment2");
267 return 0;
272 Parse a LC_THREAD or LC_UNIXTHREAD command.
273 Return 0 on success, -1 on any failure.
274 If the thread is a LC_UNIXTHREAD, the stack address is returned in out_info->stack_end.
275 If the executable requested a non-default stack address,
276 *customstack is set to TRUE. The thread's entry point is returned in out_info->entry.
277 The stack itself (if any) is not mapped.
278 Other custom register settings are silently ignored (GrP fixme).
280 static int
281 load_genericthread(struct thread_command *threadcmd, int type,
282 int *customstack, load_info_t *out_info)
284 unsigned int flavor;
285 unsigned int count;
286 unsigned int *p;
287 unsigned int left;
289 p = (unsigned int *)(threadcmd + 1);
290 left = (threadcmd->cmdsize - sizeof(struct thread_command)) / sizeof(*p);
292 while (left > 0) {
293 if (left < 2) {
294 print("bad executable (invalid thread command)\n");
295 return -1;
297 flavor = *p++; left--;
298 count = *p++; left--;
300 if (left < count) {
301 print("bad executable (invalid thread command 2)\n");
302 return -1;
305 #if defined(VGA_x86)
306 if (flavor == i386_THREAD_STATE && count == i386_THREAD_STATE_COUNT) {
307 i386_thread_state_t *state = (i386_thread_state_t *)p;
308 out_info->entry = (vki_uint8_t *)state->__eip;
309 if (type == LC_UNIXTHREAD) {
310 out_info->stack_end =
311 (vki_uint8_t *)(state->__esp ? state->__esp : VKI_USRSTACK);
312 vg_assert(VG_IS_PAGE_ALIGNED(out_info->stack_end));
313 out_info->stack_end--;
315 if (customstack) *customstack = state->__esp;
316 return 0;
319 #elif defined(VGA_amd64)
320 if (flavor == x86_THREAD_STATE64 && count == x86_THREAD_STATE64_COUNT){
321 x86_thread_state64_t *state = (x86_thread_state64_t *)p;
322 out_info->entry = (vki_uint8_t *)state->__rip;
323 if (type == LC_UNIXTHREAD) {
324 out_info->stack_end =
325 (vki_uint8_t *)(state->__rsp ? state->__rsp : VKI_USRSTACK64);
326 vg_assert(VG_IS_PAGE_ALIGNED(out_info->stack_end));
327 out_info->stack_end--;
329 if (customstack) *customstack = state->__rsp;
330 return 0;
333 #else
334 # error unknown platform
335 #endif
336 p += count;
337 left -= count;
340 print("bad executable (no arch-compatible thread state)\n");
341 return -1;
345 /* Returns the main stack size on this platform,
346 using getrlimit or a fixed size.
347 GrP fixme 64-bit? */
348 static vki_size_t default_stack_size(void)
350 struct vki_rlimit lim;
351 int err = VG_(getrlimit)(VKI_RLIMIT_STACK, &lim);
352 if (err) return 8*1024*1024; // 8 MB
353 else return lim.rlim_cur;
358 Processes a LC_UNIXTHREAD command.
359 Returns 0 on success, -1 on any failure.
360 The stack is mapped in and returned in out_info->stack_start and out_info->stack_end.
361 The thread's entry point is returned in out_info->entry.
363 static int
364 load_unixthread(struct thread_command *threadcmd, load_info_t *out_info)
366 int err;
367 int customstack;
369 err = load_genericthread(threadcmd, LC_UNIXTHREAD, &customstack, out_info);
370 if (err) return -1;
372 if (!out_info->stack_end) {
373 print("bad executable (no thread stack)\n");
374 return -1;
377 if (!customstack) {
378 // Map the stack
379 vki_size_t stacksize = VG_PGROUNDUP(default_stack_size());
380 vm_address_t stackbase = VG_PGROUNDDN(out_info->stack_end+1-stacksize);
381 SysRes res;
383 res = VG_(am_mmap_anon_fixed_client)(stackbase, stacksize, VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC);
384 check_mmap(res, stackbase, stacksize, "load_unixthread1");
385 out_info->stack_start = (vki_uint8_t *)stackbase;
386 } else {
387 // custom stack - mapped via __UNIXTHREAD segment
390 return 0;
394 /* Allocates a stack mapping at a V-chosen address. Pertains to
395 LC_MAIN commands, which seem to have appeared in OSX 10.8.
397 This is a really nasty hack -- allocates 64M+stack size, then
398 deallocates the 64M, to guarantee that the stack is at least 64M
399 above zero. */
400 #if DARWIN_VERS >= DARWIN_10_8
401 static int
402 handle_lcmain ( vki_size_t requested_size,
403 load_info_t *out_info )
405 if (requested_size == 0) {
406 requested_size = default_stack_size();
408 requested_size = VG_PGROUNDUP(requested_size);
410 const vki_size_t HACK = 64 * 1024 * 1024;
411 requested_size += HACK;
413 SysRes res = VG_(am_mmap_anon_float_client)(requested_size,
414 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC);
415 check_mmap_float(res, requested_size, "handle_lcmain");
416 vg_assert(!sr_isError(res));
417 out_info->stack_start = (vki_uint8_t*)sr_Res(res);
418 out_info->stack_end = out_info->stack_start + requested_size - 1;
420 Bool need_discard = False;
421 res = VG_(am_munmap_client)(&need_discard, (Addr)out_info->stack_start, HACK);
422 if (sr_isError(res)) return -1;
423 vg_assert(!need_discard); // True == wtf?
425 out_info->stack_start += HACK;
427 return 0;
429 #endif /* DARWIN_VERS >= DARWIN_10_8 */
434 Processes an LC_LOAD_DYLINKER command.
435 Returns 0 on success, -1 on any error.
436 The linker itself is mapped into memory.
437 The linker's entry point is returned in out_info->linker_entry.
439 static int
440 load_dylinker(struct dylinker_command *dycmd, load_info_t *out_info)
442 const HChar *name;
443 int ret;
444 load_info_t linker_info;
445 linker_info.stack_start = NULL;
446 linker_info.stack_end = NULL;
447 linker_info.text = NULL;
448 linker_info.entry = NULL;
449 linker_info.linker_entry = NULL;
450 linker_info.linker_offset = 0;
451 linker_info.max_addr = out_info->max_addr;
453 if (dycmd->name.offset >= dycmd->cmdsize) {
454 print("bad executable (invalid dylinker command)\n");
455 return -1;
458 name = dycmd->name.offset + (HChar *)dycmd;
460 // GrP fixme assumes name is terminated somewhere
461 ret = open_dylinker(name, &linker_info);
462 if (linker_info.entry) {
463 out_info->linker_entry = linker_info.entry + linker_info.linker_offset;
465 out_info->max_addr = linker_info.max_addr;
466 return ret;
471 Process an LC_THREAD command.
472 Returns 0 on success, -1 on any failure.
473 The thread's entry point is returned in out_info->entry.
475 static int
476 load_thread(struct thread_command *threadcmd, load_info_t *out_info)
478 int customstack;
479 int err;
481 err = load_genericthread(threadcmd, LC_THREAD, &customstack, out_info);
482 if (err) return -1;
483 if (customstack) {
484 print("bad executable (stackless thread has stack)\n");
485 return -1;
487 return 0;
492 Loads a Mach-O executable into memory, along with any threads,
493 stacks, and dylinker.
494 Returns 0 on success, -1 on any failure.
495 fd[offset..offset+size) is a Mach-O thin file.
496 filetype is MH_EXECUTE or MH_DYLINKER.
497 The mapped but empty stack is returned in out_info->stack_start.
498 The executable's Mach headers are returned in out_info->text.
499 The executable's entry point is returned in out_info->entry.
500 The dylinker's entry point (if any) is returned in out_info->linker_entry.
501 The dylinker's offset (macOS 10.12) is returned in out_info->linker_offset.
502 GrP fixme need to return whether dylinker was found - stack layout is different
504 static int
505 load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
506 const HChar *filename, load_info_t *out_info)
508 VG_(debugLog)(1, "ume", "load_thin_file: begin: %s\n", filename);
509 struct MACH_HEADER mh;
510 vki_uint8_t *headers;
511 vki_uint8_t *headers_end;
512 struct load_command *lc;
513 struct load_command *lcend;
514 struct SEGMENT_COMMAND *segcmd;
515 struct thread_command *threadcmd;
516 struct dylinker_command *dycmd;
517 int err;
518 SysRes res;
519 vki_size_t len;
521 // Read Mach-O header
522 if (sizeof(mh) > size) {
523 print("bad executable (no Mach-O header)\n");
525 res = VG_(pread)(fd, &mh, sizeof(mh), offset);
526 if (sr_isError(res) || sr_Res(res) != sizeof(mh)) {
527 print("bad executable (no Mach-O header)\n");
528 return -1;
532 // Sanity-check the header itself
533 if (mh.magic != MAGIC) {
534 print("bad executable (no Mach-O magic)\n");
535 return -1;
538 if (mh.filetype != filetype) {
539 // expecting MH_EXECUTE or MH_DYLINKER
540 print("bad executable (wrong file type)\n");
541 return -1;
545 // Map all headers into memory
546 len = sizeof(mh) + mh.sizeofcmds;
547 if (len > size) {
548 print("bad executable (missing load commands)\n");
549 return -1;
552 headers = VG_(malloc)("ume.macho.headers", len);
553 res = VG_(pread)(fd, headers, len, offset);
554 if (sr_isError(res)) {
555 print("couldn't read load commands from executable\n");
556 return -1;
558 headers_end = headers + len;
561 // Map some segments into client memory:
562 // LC_SEGMENT (text, data, etc)
563 // UNIXSTACK (stack)
564 // LOAD_DYLINKER (dyld)
565 lcend = (struct load_command *)(headers + mh.sizeofcmds + sizeof(mh));
566 for (lc = (struct load_command *)(headers + sizeof(mh));
567 lc < lcend;
568 lc = (struct load_command *)(lc->cmdsize + (vki_uint8_t *)lc))
570 if ((vki_uint8_t *)lc < headers ||
571 lc->cmdsize+(vki_uint8_t *)lc > headers_end) {
572 print("bad executable (invalid load commands)\n");
573 return -1;
576 switch (lc->cmd) {
578 #if DARWIN_VERS >= DARWIN_10_8
579 case LC_MAIN: { /* New in 10.8 */
580 struct entry_point_command* epcmd
581 = (struct entry_point_command*)lc;
582 if (out_info->stack_start || out_info->stack_end) {
583 print("bad executable (multiple indications of stack)");
584 return -1;
586 err = handle_lcmain(epcmd->stacksize, out_info);
587 if (err) return -1;
588 VG_(debugLog)(2, "ume", "lc_main: created stack %p-%p\n",
589 out_info->stack_start, out_info->stack_end);
590 break;
592 # endif
594 case LC_SEGMENT_CMD:
595 if (lc->cmdsize < sizeof(struct SEGMENT_COMMAND)) {
596 print("bad executable (invalid load commands)\n");
597 return -1;
599 segcmd = (struct SEGMENT_COMMAND *)lc;
600 #if DARWIN_VERS >= DARWIN_10_12
601 /* dyld text address is relative instead of absolute in 10.12 */
602 if (filetype == MH_DYLINKER && segcmd->vmaddr == 0 && segcmd->fileoff == 0) {
603 out_info->linker_offset = out_info->max_addr;
605 # endif
606 err = load_segment(fd, offset, size, segcmd, filename, out_info);
607 if (err) return -1;
609 break;
611 case LC_UNIXTHREAD:
612 if (out_info->stack_end || out_info->entry) {
613 print("bad executable (multiple thread commands)\n");
614 return -1;
616 if (lc->cmdsize < sizeof(struct thread_command)) {
617 print("bad executable (invalid load commands)\n");
618 return -1;
620 threadcmd = (struct thread_command *)lc;
621 err = load_unixthread(threadcmd, out_info);
622 if (err) return -1;
623 break;
625 case LC_LOAD_DYLINKER:
626 if (filetype == MH_DYLINKER) {
627 print("bad executable (dylinker needs a dylinker)\n");
628 return -1;
630 if (out_info->linker_entry) {
631 print("bad executable (multiple dylinker commands)\n");
633 if (lc->cmdsize < sizeof(struct dylinker_command)) {
634 print("bad executable (invalid load commands)\n");
635 return -1;
637 dycmd = (struct dylinker_command *)lc;
638 err = load_dylinker(dycmd, out_info);
639 if (err) return -1;
640 break;
642 case LC_THREAD:
643 if (filetype == MH_EXECUTE) {
644 print("bad executable (stackless thread)\n");
645 return -1;
647 if (out_info->stack_end || out_info->entry) {
648 print("bad executable (multiple thread commands)\n");
649 return -1;
651 if (lc->cmdsize < sizeof(struct thread_command)) {
652 print("bad executable (invalid load commands)\n");
653 return -1;
655 threadcmd = (struct thread_command *)lc;
656 err = load_thread(threadcmd, out_info);
657 if (err) return -1;
658 break;
660 default:
661 break;
666 // Done with the headers
667 VG_(free)(headers);
669 if (filetype == MH_EXECUTE) {
670 // Verify the necessary pieces for an executable:
671 // a stack
672 // a text segment
673 // an entry point (static or linker)
674 if (!out_info->stack_end || !out_info->stack_start) {
675 VG_(printf)("bad executable %s (no stack)\n", filename);
676 return -1;
678 if (!out_info->text) {
679 print("bad executable (no text segment)\n");
680 return -1;
682 if (!out_info->entry && !out_info->linker_entry) {
683 print("bad executable (no entry point)\n");
684 return -1;
687 else if (filetype == MH_DYLINKER) {
688 // Verify the necessary pieces for a dylinker:
689 // an entry point
690 if (!out_info->entry) {
691 print("bad executable (no entry point)\n");
692 return -1;
696 VG_(debugLog)(1, "ume", "load_thin_file: success: %s\n", filename);
697 return 0;
702 Load a fat Mach-O executable.
704 static int
705 load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
706 const HChar *filename, load_info_t *out_info)
708 struct fat_header fh;
709 vki_off_t arch_offset;
710 int i;
711 cpu_type_t good_arch;
712 SysRes res;
714 #if defined(VGA_ppc32)
715 good_arch = CPU_TYPE_POWERPC;
716 #elif defined(VGA_ppc64be)
717 good_arch = CPU_TYPE_POWERPC64BE;
718 #elif defined(VGA_ppc64le)
719 good_arch = CPU_TYPE_POWERPC64LE;
720 #elif defined(VGA_x86)
721 good_arch = CPU_TYPE_I386;
722 #elif defined(VGA_amd64)
723 good_arch = CPU_TYPE_X86_64;
724 #else
725 # error unknown architecture
726 #endif
728 // Read fat header
729 // All fat contents are BIG-ENDIAN
730 if (size < sizeof(fh)) {
731 print("bad executable (bad fat header)\n");
732 return -1;
734 res = VG_(pread)(fd, &fh, sizeof(fh), offset);
735 if (sr_isError(res) || sr_Res(res) != sizeof(fh)) {
736 print("bad executable (bad fat header)\n");
737 return -1;
740 // Scan arch headers looking for a good one
741 arch_offset = offset + sizeof(fh);
742 fh.nfat_arch = VG_(ntohl)(fh.nfat_arch);
743 for (i = 0; i < fh.nfat_arch; i++) {
744 struct fat_arch arch;
745 if (arch_offset + sizeof(arch) > size) {
746 print("bad executable (corrupt fat archs)\n");
747 return -1;
750 res = VG_(pread)(fd, &arch, sizeof(arch), arch_offset);
751 arch_offset += sizeof(arch);
752 if (sr_isError(res) || sr_Res(res) != sizeof(arch)) {
753 VG_(printf)("bad executable (corrupt fat arch) %x %llu\n",
754 arch.cputype, (ULong)arch_offset);
755 return -1;
758 arch.cputype = VG_(ntohl)(arch.cputype);
759 arch.cpusubtype = VG_(ntohl)(arch.cpusubtype);
760 arch.offset = VG_(ntohl)(arch.offset);
761 arch.size = VG_(ntohl)(arch.size);
762 arch.align = VG_(ntohl)(arch.align);
763 if (arch.cputype == good_arch) {
764 // use this arch
765 if (arch.offset > size || arch.offset + arch.size > size) {
766 print("bad executable (corrupt fat arch 2)\n");
767 return -1;
769 return load_mach_file(fd, offset+arch.offset, arch.size, filetype, filename, out_info);
773 print("bad executable (can't run on this machine)\n");
774 return -1;
778 Load a Mach-O executable or dylinker.
779 The file may be fat or thin.
781 static int
782 load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
783 const HChar *filename, load_info_t *out_info)
785 vki_uint32_t magic;
786 SysRes res;
788 if (size < sizeof(magic)) {
789 print("bad executable (no Mach-O magic)\n");
790 return -1;
792 res = VG_(pread)(fd, &magic, sizeof(magic), offset);
793 if (sr_isError(res) || sr_Res(res) != sizeof(magic)) {
794 print("bad executable (no Mach-O magic)\n");
795 return -1;
798 if (magic == MAGIC) {
799 // thin
800 return load_thin_file(fd, offset, size, filetype, filename, out_info);
801 } else if (magic == VG_(htonl)(FAT_MAGIC)) {
802 // fat
803 return load_fat_file(fd, offset, size, filetype, filename, out_info);
804 } else {
805 // huh?
806 print("bad executable (bad Mach-O magic)\n");
807 return -1;
812 Bool VG_(match_macho)(const void *hdr, SizeT len)
814 const vki_uint32_t *magic = hdr;
816 // GrP fixme check more carefully for matching fat arch?
818 return (len >= VKI_PAGE_SIZE &&
819 (*magic == MAGIC || *magic == VG_(ntohl)(FAT_MAGIC)))
820 ? True : False;
824 Int VG_(load_macho)(Int fd, const HChar *name, ExeInfo *info)
826 int err;
827 struct vg_stat sb;
828 load_info_t load_info;
829 load_info.stack_start = NULL;
830 load_info.stack_end = NULL;
831 load_info.text = NULL;
832 load_info.entry = NULL;
833 load_info.linker_entry = NULL;
834 load_info.linker_offset = 0;
835 load_info.max_addr = 0;
837 err = VG_(fstat)(fd, &sb);
838 if (err) {
839 print("couldn't stat executable\n");
840 return VKI_ENOEXEC;
843 err = load_mach_file(fd, 0, sb.size, MH_EXECUTE, name, &load_info);
844 if (err) return VKI_ENOEXEC;
846 // GrP fixme exe_base
847 // GrP fixme exe_end
848 info->entry = (Addr) load_info.entry;
849 info->init_ip = (Addr)(load_info.linker_entry ? load_info.linker_entry : load_info.entry);
850 info->brkbase = 0xffffffff; // GrP fixme hack
851 info->init_toc = 0; // GrP fixme unused
853 info->stack_start = (Addr) load_info.stack_start;
854 info->stack_end = (Addr) load_info.stack_end;
855 info->text = (Addr) load_info.text;
856 info->dynamic = load_info.linker_entry ? True : False;
858 info->executable_path = VG_(strdup)("ume.macho.executable_path", name);
860 return 0;
863 #endif // defined(VGO_darwin)
865 /*--------------------------------------------------------------------*/
866 /*--- end ---*/
867 /*--------------------------------------------------------------------*/