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