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