1f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
2f76d27a697a7b0bf3b84490baf60623fc96a23afnjn/*--------------------------------------------------------------------*/
3f76d27a697a7b0bf3b84490baf60623fc96a23afnjn/*--- Launching valgrind                         launcher-darwin.c ---*/
4f76d27a697a7b0bf3b84490baf60623fc96a23afnjn/*--------------------------------------------------------------------*/
5f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
6f76d27a697a7b0bf3b84490baf60623fc96a23afnjn/*
7f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   This file is part of Valgrind, a dynamic binary instrumentation
8f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   framework.
9f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
10ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   Copyright (C) 2000-2017 Julian Seward
11f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      jseward@acm.org
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
31f76d27a697a7b0bf3b84490baf60623fc96a23afnjn/* Note: this is a "normal" program and not part of Valgrind proper,
32f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   and so it doesn't have to conform to Valgrind's arcane rules on
33f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   no-glibc-usage etc. */
34f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
35f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <assert.h>
36f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <ctype.h>
37f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <errno.h>
38f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <fcntl.h>
39f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <libgen.h>
40f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <stdarg.h>
41f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <stdio.h>
42f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <stdlib.h>
43f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <string.h>
44f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <sys/mman.h>
45f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <sys/param.h>
46f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <sys/stat.h>
47f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <sys/user.h>
48f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <unistd.h>
49f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <mach-o/fat.h>
50f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include <mach-o/loader.h>
51f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
52f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include "pub_core_debuglog.h"
53a192dafc5336c5e586dfce6c4e6d3f7e82aef266njn#include "pub_core_vki.h"       // Avoids warnings from pub_core_libcfile.h
54f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include "pub_core_libcproc.h"  // For VALGRIND_LIB, VALGRIND_LAUNCHER
55f76d27a697a7b0bf3b84490baf60623fc96a23afnjn#include "pub_core_ume.h"
56f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
57f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic struct {
58f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   cpu_type_t cputype;
59f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   const char *apple_name;     // e.g. x86_64
60f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   const char *valgrind_name;  // e.g. amd64
61f76d27a697a7b0bf3b84490baf60623fc96a23afnjn} valid_archs[] = {
629893a7540814a6d987e981d265d2aad6b4d27547sewardj   { CPU_TYPE_X86,       "i386",   "x86" },
639893a7540814a6d987e981d265d2aad6b4d27547sewardj   { CPU_TYPE_X86_64,    "x86_64", "amd64" },
649893a7540814a6d987e981d265d2aad6b4d27547sewardj   { CPU_TYPE_ARM,       "arm",    "arm" },
659893a7540814a6d987e981d265d2aad6b4d27547sewardj   /* Not that it's actually relevant, since we don't support PPC on
669893a7540814a6d987e981d265d2aad6b4d27547sewardj      MacOS X, but .. the Apple PPC descriptors refer to the BE
679893a7540814a6d987e981d265d2aad6b4d27547sewardj      variant, since the LE variant is something that appeared long
689893a7540814a6d987e981d265d2aad6b4d27547sewardj      after Apple dropped PPC. */
699893a7540814a6d987e981d265d2aad6b4d27547sewardj   { CPU_TYPE_POWERPC,   "ppc",    "ppc32" },
709893a7540814a6d987e981d265d2aad6b4d27547sewardj   { CPU_TYPE_POWERPC64, "ppc64",  "ppc64be" }
71f76d27a697a7b0bf3b84490baf60623fc96a23afnjn};
72f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic int valid_archs_count = sizeof(valid_archs)/sizeof(valid_archs[0]);
73f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
74f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic const char *name_for_cputype(cpu_type_t cputype)
75f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
76f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   int i;
77f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = 0; i < valid_archs_count; i++) {
78f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (valid_archs[i].cputype == cputype) {
79f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         return valid_archs[i].valgrind_name;
80f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
81f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
82f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   return NULL;
83f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
84f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
85f76d27a697a7b0bf3b84490baf60623fc96a23afnjn/* Report fatal errors */
86f76d27a697a7b0bf3b84490baf60623fc96a23afnjn__attribute__((noreturn))
87f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic void barf ( const char *format, ... )
88f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
89f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   va_list vargs;
90f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
91f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   va_start(vargs, format);
92f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   fprintf(stderr, "valgrind: ");
93f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   vfprintf(stderr, format, vargs);
94f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   fprintf(stderr, "\n");
95f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   va_end(vargs);
96f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
97f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   exit(1);
98f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /*NOTREACHED*/
99f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   assert(0);
100f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
101f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
102f76d27a697a7b0bf3b84490baf60623fc96a23afnjn/* Search the path for the client program */
103f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic const char *find_client(const char *clientname)
104f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
105f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   static char fullname[PATH_MAX];
106f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   const char *path = getenv("PATH");
107f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   const char *colon;
108f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
109f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   while (path)
110f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   {
111f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if ((colon = strchr(path, ':')) == NULL)
112f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      {
113f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         strcpy(fullname, path);
114f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         path = NULL;
115f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
116f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      else
117f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      {
118f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         memcpy(fullname, path, colon - path);
119f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         fullname[colon - path] = '\0';
120f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         path = colon + 1;
121f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
122f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
123f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      strcat(fullname, "/");
124f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      strcat(fullname, clientname);
125f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
126f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (access(fullname, R_OK|X_OK) == 0)
127f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         return fullname;
128f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
129f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
130f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   return clientname;
131f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
132f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
133f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic int fat_has_cputype(struct fat_header *fh, cpu_type_t cputype)
134f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
135f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   struct fat_arch *fa = (struct fat_arch *)(fh+1);
136f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   uint32_t nfat_arch = ntohl(fh->nfat_arch);
137f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   uint32_t i;
138f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = 0; i < nfat_arch; i++) {
139f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (ntohl(fa[i].cputype) == cputype) return 1;
140f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
141f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   return 0;
142f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
143f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
144f76d27a697a7b0bf3b84490baf60623fc96a23afnjn/* Examine the client and work out which arch it is for */
145a192dafc5336c5e586dfce6c4e6d3f7e82aef266njnstatic const char *select_arch(
146a192dafc5336c5e586dfce6c4e6d3f7e82aef266njn      const char *clientname, cpu_type_t default_cputype,
147a192dafc5336c5e586dfce6c4e6d3f7e82aef266njn      const char *default_arch)
148f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
149f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   uint8_t buf[4096];
150f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   ssize_t bytes;
151f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   int fd = open(find_client(clientname), O_RDONLY);
152f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (fd < 0) {
153f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      barf("%s: %s", clientname, strerror(errno));
154f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
155f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
156cc7b218c195fab0c0b9e9f02951c992aa6b66208njn   bytes = read(fd, buf, sizeof(buf));
157cc7b218c195fab0c0b9e9f02951c992aa6b66208njn   close(fd);
158f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (bytes != sizeof(buf)) {
159f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      return NULL;
160f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
161f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
162f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // If it's thin, return that arch.
163f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   {
164f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      struct mach_header *mh = (struct mach_header *)buf;
165f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (mh->magic == MH_MAGIC  ||  mh->magic == MH_MAGIC_64) {
166f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         return name_for_cputype(mh->cputype);
167f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      } else if (mh->magic == MH_CIGAM  ||  mh->magic == MH_CIGAM_64) {
168f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         return name_for_cputype(OSSwapInt32(mh->cputype));
169f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
170f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
171f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
172f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // If it's fat, look for a good arch.
173f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   {
174f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      struct fat_header *fh = (struct fat_header *)buf;
175f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (ntohl(fh->magic) == FAT_MAGIC) {
176f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         uint32_t nfat_arch = ntohl(fh->nfat_arch);
177f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         int i;
178f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         // If only one fat arch, use it.
179f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (nfat_arch == 1) {
180f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            struct fat_arch *fa = (struct fat_arch *)(fh+1);
181f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            return name_for_cputype(ntohl(fa->cputype));
182f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         }
183f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         // Scan fat headers for default arch.
184f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (fat_has_cputype(fh, default_cputype)) {
185f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            return default_arch;
186f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         }
187f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
188f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         // Scan fat headers for any supported arch.
189f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         for (i = 0; i < valid_archs_count; i++) {
190f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            if (fat_has_cputype(fh, valid_archs[i].cputype)) {
191f76d27a697a7b0bf3b84490baf60623fc96a23afnjn               return valid_archs[i].valgrind_name;
192f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            }
193f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         }
194f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
195f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
196f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
197f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   return NULL;
198f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
199f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
200f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
201f76d27a697a7b0bf3b84490baf60623fc96a23afnjn/* Where we expect to find all our aux files */
202f76d27a697a7b0bf3b84490baf60623fc96a23afnjnstatic const char *valgrind_lib;
203f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
204f76d27a697a7b0bf3b84490baf60623fc96a23afnjnint main(int argc, char** argv, char** envp)
205f76d27a697a7b0bf3b84490baf60623fc96a23afnjn{
206f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   int i, j, loglevel;
207f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   const char *toolname = NULL;
208f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   const char *clientname = NULL;
209f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   int clientname_arg = 0;
210f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   const char *archname = NULL;
211f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   const char *arch;
212f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   const char *default_arch;
213f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   cpu_type_t default_cputype;
214f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   char *toolfile;
215f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   char launcher_name[PATH_MAX+1];
216f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   char* new_line;
217f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   char* set_cwd;
218f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   char* cwd;
219f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   char** new_env;
220f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   char **new_argv;
221f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   int new_argc;
222f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
223f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* Start the debugging-log system ASAP.  First find out how many
224f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      "-d"s were specified.  This is a pre-scan of the command line.
225f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      At the same time, look for the tool name. */
226f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   loglevel = 0;
227f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = 1; i < argc; i++) {
228f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (argv[i][0] != '-') {
229f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         clientname = argv[i];
230f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         clientname_arg = i;
231f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         break;
232f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
233f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (0 == strcmp(argv[i], "--")) {
234f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (i+1 < argc) {
235f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            clientname = argv[i+1];
236f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            clientname_arg = i;
237f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         }
238f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         break;
239f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
240f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (0 == strcmp(argv[i], "-d"))
241f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         loglevel++;
242f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (0 == strncmp(argv[i], "--tool=", 7))
243f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         toolname = argv[i] + 7;
244f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (0 == strncmp(argv[i], "--arch=", 7))
245f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         archname = argv[i] + 7;
246f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
247f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
248f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* ... and start the debug logger.  Now we can safely emit logging
249f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      messages all through startup. */
250f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   VG_(debugLog_startup)(loglevel, "Stage 1");
251f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
252f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* Make sure we know which tool we're using */
253f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (toolname) {
254f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname);
255f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   } else {
256f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      VG_(debugLog)(1, "launcher",
257f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                       "no tool requested, defaulting to 'memcheck'\n");
258f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      toolname = "memcheck";
259f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
260f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
261f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* Find the real executable if clientname is an app bundle. */
262f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (clientname) {
263f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      struct stat st;
264f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (0 == stat(clientname, &st)  &&  (st.st_mode & S_IFDIR)) {
265f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         char *copy = strdup(clientname);
266f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         char *appname = basename(copy);
267f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         char *dot = strrchr(appname, '.');
268f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (dot) {
269f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            char *newclient;
270f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            *dot = '\0';
271f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            asprintf(&newclient, "%s/Contents/MacOS/%s", clientname, appname);
272f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            VG_(debugLog)(1, "launcher", "Using executable in app bundle: %s\n", newclient);
273f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            clientname = newclient;
274f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            argv[clientname_arg] = newclient;
275f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         }
276f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         free(copy);
277f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
278f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
279f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
280f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* Establish the correct VALGRIND_LIB. */
281f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   {  const char *cp;
282f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      cp = getenv(VALGRIND_LIB);
283f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      valgrind_lib = ( cp == NULL ? VG_LIBDIR : cp );
284cde90d34fbe5c867c96cca64955d3037fbb06441njn      VG_(debugLog)(1, "launcher", "valgrind_lib = %s\n", valgrind_lib);
285f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
286f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
287f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* Find installed architectures. Use vgpreload_core-<platform>.so as the
288f76d27a697a7b0bf3b84490baf60623fc96a23afnjn    * indicator of whether the platform is installed. */
289f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = 0; i < valid_archs_count; i++) {
290f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      char *vgpreload_core;
291f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      asprintf(&vgpreload_core, "%s/vgpreload_core-%s-darwin.so", valgrind_lib, valid_archs[i].valgrind_name);
292f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (access(vgpreload_core, R_OK|X_OK) != 0) {
293f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         VG_(debugLog)(1, "launcher", "arch '%s' IS NOT installed\n", valid_archs[i].valgrind_name);
2948df59971f203df33ee0b18c17e18873ef2fcfefcrhyskidd         memset(&valid_archs[i], 0, sizeof(valid_archs[i]));
295f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      } else {
296f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         VG_(debugLog)(1, "launcher", "arch '%s' IS installed\n", valid_archs[i].valgrind_name);
297f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
298f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      free(vgpreload_core);
299f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
300f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
301f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* Find the "default" arch (VGCONF_ARCH_PRI from configure).
302f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      This is the preferred arch from fat files and the fallback. */
303f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   default_arch = NULL;
304f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   default_cputype = 0;
305f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = 0; i < valid_archs_count; i++) {
306f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (!valid_archs[i].cputype) continue;
307f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (0 == strncmp(VG_PLATFORM, valid_archs[i].valgrind_name,
308f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                       strlen(valid_archs[i].valgrind_name)))
309f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      {
310f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         default_arch = valid_archs[i].valgrind_name;
311f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         default_cputype = valid_archs[i].cputype;
312f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         break;
313f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
314f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
315f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (i == valid_archs_count) barf("Unknown/uninstalled VG_PLATFORM '%s'", VG_PLATFORM);
316f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   assert(NULL != default_arch);
317f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   assert(0 != default_cputype);
318f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
319f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* Work out what arch to use, or use the default arch if not possible. */
320f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (archname != NULL) {
321f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      // --arch from command line
322f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      arch = NULL;
323f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      for (i = 0; i < valid_archs_count; i++) {
324f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         if (0 == strcmp(archname, valid_archs[i].apple_name)  ||
325f76d27a697a7b0bf3b84490baf60623fc96a23afnjn             0 == strcmp(archname, valid_archs[i].valgrind_name))
326f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         {
327f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            arch = valid_archs[i].valgrind_name;
328f76d27a697a7b0bf3b84490baf60623fc96a23afnjn            break;
329f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         }
330f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
331f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (i == valid_archs_count) barf("Unknown --arch '%s'", archname);
332f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      assert(NULL != arch);
333f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      VG_(debugLog)(1, "launcher", "using arch '%s' from --arch=%s\n",
334f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                    arch, archname);
335f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
336f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   else if (clientname == NULL) {
337f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      // no client executable; use default as fallback
338f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      VG_(debugLog)(1, "launcher",
339f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                       "no client specified, defaulting arch to '%s'\n",
340f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                        default_arch);
341f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      arch = default_arch;
342f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
343f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   else if ((arch = select_arch(clientname, default_cputype,default_arch))) {
344f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      // arch from client executable
345f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      VG_(debugLog)(1, "launcher", "selected arch '%s'\n", arch);
346f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
347f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   else {
348f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      // nothing found in client executable; use default as fallback
349f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      VG_(debugLog)(1, "launcher",
350f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                       "no arch detected, defaulting arch to '%s'\n",
351f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                       default_arch);
352f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      arch = default_arch;
353f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
354f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
355f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   cwd = getcwd(NULL, 0);
356f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (!cwd) barf("Current directory no longer exists.");
357f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
358f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* Figure out the name of this executable (viz, the launcher), so
359f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      we can tell stage2.  stage2 will use the name for recursive
360ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      invocations of valgrind on child processes. */
361f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   memset(launcher_name, 0, PATH_MAX+1);
362f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = 0; envp[i]; i++)
363f76d27a697a7b0bf3b84490baf60623fc96a23afnjn       ; /* executable path is after last envp item */
364f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* envp[i] == NULL ; envp[i+1] == executable_path */
365f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (envp[i+1][0] != '/') {
366f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      strcpy(launcher_name, cwd);
367f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      strcat(launcher_name, "/");
368f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
369f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (strlen(launcher_name) + strlen(envp[i+1]) > PATH_MAX)
370f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      barf("launcher path is too long");
371f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   strcat(launcher_name, envp[i+1]);
372f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   VG_(debugLog)(1, "launcher", "launcher_name = %s\n", launcher_name);
373f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
374f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */
375f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   asprintf(&new_line, VALGRIND_LAUNCHER "=%s", launcher_name);
376f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
377f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* tediously augment the env: VALGRIND_STARTUP_PWD_%PID_XYZZY=current_working_dir */
378f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   asprintf(&set_cwd, "VALGRIND_STARTUP_PWD_%u_XYZZY=%s", getppid(), cwd);
379f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
380f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // Note that Apple binaries get a secret fourth arg, "char* apple", which
381f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // contains the executable path.  Don't forget about it.
382f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (j = 0; envp[j]; j++)
383f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      ;
384f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   new_env = malloc((j+4) * sizeof(char*));
385f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (new_env == NULL)
386f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      barf("malloc of new_env failed.");
387f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = 0; i < j; i++)
388f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      new_env[i] = envp[i];
389f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   new_env[i++] = new_line;
390f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   new_env[i++] = set_cwd;
391f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   new_env[i++] = NULL;
392f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   new_env[i  ] = envp[i-2]; // the 'apple' arg == the executable_path
393f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   assert(i == j+3);
394f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
395f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* tediously edit env: hide dyld options from valgrind's captive dyld */
396f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = 0; envp[i]; i++) {
397f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (0 == strncmp(envp[i], "DYLD_", 5)) {
398f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         envp[i][0] = 'V';  /* VYLD_; changed back by initimg-darwin */
399f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
400f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
401f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
402f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   /* tediously edit argv: remove --arch= */
403f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   new_argv = malloc((1+argc) * sizeof(char *));
404f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   for (i = 0, new_argc = 0; i < argc; i++) {
405f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (0 == strncmp(argv[i], "--arch=", 7)) {
406f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         // skip
407f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      } else {
408f76d27a697a7b0bf3b84490baf60623fc96a23afnjn         new_argv[new_argc++] = argv[i];
409f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      }
410f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
411f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   new_argv[new_argc++] = NULL;
412f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
413ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   /* Build the stage2 invocation, and execve it.  Bye! */
414f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   asprintf(&toolfile, "%s/%s-%s-darwin", valgrind_lib, toolname, arch);
415f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   if (access(toolfile, R_OK|X_OK) != 0) {
416f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      barf("tool '%s' not installed (%s) (%s)", toolname, toolfile, strerror(errno));
417f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   }
418f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
419f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   VG_(debugLog)(1, "launcher", "launching %s\n", toolfile);
420f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
421f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   execve(toolfile, new_argv, new_env);
422f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
423f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   fprintf(stderr, "valgrind: failed to start tool '%s' for platform '%s-darwin': %s\n",
424f76d27a697a7b0bf3b84490baf60623fc96a23afnjn                   toolname, arch, strerror(errno));
425f76d27a697a7b0bf3b84490baf60623fc96a23afnjn
426f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   exit(1);
427f76d27a697a7b0bf3b84490baf60623fc96a23afnjn}
428