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