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