1695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian/* -*- mode: C; c-basic-offset: 3; -*- */
245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
345f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--------------------------------------------------------------------*/
445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--- Launching valgrind                              m_launcher.c ---*/
545f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*--------------------------------------------------------------------*/
645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
745f4e7c91119c7d01a59f5e827c67841632c9314sewardj/*
845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   This file is part of Valgrind, a dynamic binary instrumentation
945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   framework.
1045f4e7c91119c7d01a59f5e827c67841632c9314sewardj
110f157ddb404bcde7815a1c5bf2d7e41c114f3d73sewardj   Copyright (C) 2000-2013 Julian Seward
1245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      jseward@acm.org
1345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   This program is free software; you can redistribute it and/or
1545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   modify it under the terms of the GNU General Public License as
1645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   published by the Free Software Foundation; either version 2 of the
1745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   License, or (at your option) any later version.
1845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
1945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   This program is distributed in the hope that it will be useful, but
2045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   WITHOUT ANY WARRANTY; without even the implied warranty of
2145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   General Public License for more details.
2345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
2445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   You should have received a copy of the GNU General Public License
2545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   along with this program; if not, write to the Free Software
2645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
2745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   02111-1307, USA.
2845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
2945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   The GNU General Public License is contained in the file COPYING.
3045f4e7c91119c7d01a59f5e827c67841632c9314sewardj*/
3145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
3245f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Note: this is a "normal" program and not part of Valgrind proper,
3345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   and so it doesn't have to conform to Valgrind's arcane rules on
3445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   no-glibc-usage etc. */
3545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
365c46da8ce1e919595193a653584dfae7174b28e0tom/* Include valgrind headers before system headers to avoid problems
375c46da8ce1e919595193a653584dfae7174b28e0tom   with the system headers #defining things which are used as names
385c46da8ce1e919595193a653584dfae7174b28e0tom   of structure members in vki headers. */
395c46da8ce1e919595193a653584dfae7174b28e0tom
405c46da8ce1e919595193a653584dfae7174b28e0tom#include "pub_core_debuglog.h"
415c46da8ce1e919595193a653584dfae7174b28e0tom#include "pub_core_vki.h"       // Avoids warnings from
425c46da8ce1e919595193a653584dfae7174b28e0tom                                // pub_core_libcfile.h
435c46da8ce1e919595193a653584dfae7174b28e0tom#include "pub_core_libcproc.h"  // For VALGRIND_LIB, VALGRIND_LAUNCHER
445c46da8ce1e919595193a653584dfae7174b28e0tom#include "pub_core_ume.h"
455c46da8ce1e919595193a653584dfae7174b28e0tom
46fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom#include <assert.h>
47fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom#include <ctype.h>
48fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom#include <elf.h>
4945f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include <errno.h>
50fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom#include <fcntl.h>
5145f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include <stdio.h>
5245f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include <stdlib.h>
5345f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include <string.h>
5445f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include <unistd.h>
5545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
56a879a47ce7c2ec18b76ffce49f0e662164539e18tom#ifndef EM_X86_64
5781e60b25fa661addf0a6566486aca909a19bd2c6njn#define EM_X86_64 62    // elf.h doesn't define this on some older systems
5881e60b25fa661addf0a6566486aca909a19bd2c6njn#endif
59a879a47ce7c2ec18b76ffce49f0e662164539e18tom
60f0c1250e324f6684757c6a15545366447ef1d64fsewardj#ifndef EM_AARCH64
61f0c1250e324f6684757c6a15545366447ef1d64fsewardj#define EM_AARCH64 183  // ditto
62f0c1250e324f6684757c6a15545366447ef1d64fsewardj#endif
63f0c1250e324f6684757c6a15545366447ef1d64fsewardj
64ed12bf2b073b1681265e956b7727553f904e5a54sewardj#ifndef EM_PPC64
65ed12bf2b073b1681265e956b7727553f904e5a54sewardj#define EM_PPC64 21  // ditto
66ed12bf2b073b1681265e956b7727553f904e5a54sewardj#endif
67ed12bf2b073b1681265e956b7727553f904e5a54sewardj
68112711afefcfcd43680c7c4aa8d38ef180e8811esewardj#ifndef EM_TILEGX
69112711afefcfcd43680c7c4aa8d38ef180e8811esewardj#define EM_TILEGX 191
70112711afefcfcd43680c7c4aa8d38ef180e8811esewardj#endif
71112711afefcfcd43680c7c4aa8d38ef180e8811esewardj
72fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom/* Report fatal errors */
738813eef4f290add8e7d66db4deae8cedddcb68bcsewardj__attribute__((noreturn))
74fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtomstatic void barf ( const char *format, ... )
7545f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
76fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   va_list vargs;
77fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
78fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   va_start(vargs, format);
79fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   fprintf(stderr, "valgrind: Cannot continue: ");
80fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   vfprintf(stderr, format, vargs);
81fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   fprintf(stderr, "\n");
82fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   va_end(vargs);
83fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
8445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   exit(1);
858813eef4f290add8e7d66db4deae8cedddcb68bcsewardj   /*NOTREACHED*/
868813eef4f290add8e7d66db4deae8cedddcb68bcsewardj   assert(0);
8745f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
8845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
89fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom/* Search the path for the client program */
90fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtomstatic const char *find_client(const char *clientname)
91fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom{
92b593be39d80165efa84ee5f1fb42adb9f79b6c1fflorian   char *fullname;
93fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   const char *path = getenv("PATH");
94fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   const char *colon;
95fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
96b593be39d80165efa84ee5f1fb42adb9f79b6c1fflorian   assert(clientname != NULL);
97b593be39d80165efa84ee5f1fb42adb9f79b6c1fflorian
98b593be39d80165efa84ee5f1fb42adb9f79b6c1fflorian   if (path == NULL) return clientname;
99b593be39d80165efa84ee5f1fb42adb9f79b6c1fflorian
1001ae53537439204ae45e6b00ea788fc8fbc06f859florian   /* Make the size of the FULLNAME buffer large enough. */
1011ae53537439204ae45e6b00ea788fc8fbc06f859florian   unsigned need = strlen(path) + strlen("/") + strlen(clientname) + 1;
1021ae53537439204ae45e6b00ea788fc8fbc06f859florian
1031ae53537439204ae45e6b00ea788fc8fbc06f859florian   fullname = malloc(need);
1041ae53537439204ae45e6b00ea788fc8fbc06f859florian   if (fullname == NULL)
1051ae53537439204ae45e6b00ea788fc8fbc06f859florian      barf("malloc of fullname failed.");
1061ae53537439204ae45e6b00ea788fc8fbc06f859florian
107fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   while (path)
108fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   {
109fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      if ((colon = strchr(path, ':')) == NULL)
110fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      {
111fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom         strcpy(fullname, path);
112fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom         path = NULL;
113fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      }
114fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      else
115fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      {
1161ae53537439204ae45e6b00ea788fc8fbc06f859florian         strncpy(fullname, path, colon - path);
117fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom         fullname[colon - path] = '\0';
118fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom         path = colon + 1;
119fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      }
120fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
121fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      strcat(fullname, "/");
122fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      strcat(fullname, clientname);
123fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
124fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      if (access(fullname, R_OK|X_OK) == 0)
125fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom         return fullname;
126fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   }
127b593be39d80165efa84ee5f1fb42adb9f79b6c1fflorian   free(fullname);
128fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
129fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   return clientname;
130fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom}
131fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
132fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom/* Examine the client and work out which platform it is for */
133fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtomstatic const char *select_platform(const char *clientname)
134fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom{
135fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   int fd;
13619f91bbaedb4caef8a60ce94b0f507193cc0bc10florian   char header[4096];
13758899e8e2af51859289d0badea881b7b72c3fb13njn   ssize_t n_bytes;
138fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   const char *platform = NULL;
139fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
1401edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom   VG_(debugLog)(2, "launcher", "selecting platform for '%s'\n", clientname);
1411edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom
142fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   if (strchr(clientname, '/') == NULL)
143fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      clientname = find_client(clientname);
144fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
1451edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom   VG_(debugLog)(2, "launcher", "selecting platform for '%s'\n", clientname);
1461edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom
147fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   if ((fd = open(clientname, O_RDONLY)) < 0)
148fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      return NULL;
149fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   //   barf("open(%s): %s", clientname, strerror(errno));
150fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
1511edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom   VG_(debugLog)(2, "launcher", "opened '%s'\n", clientname);
1521edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom
15358899e8e2af51859289d0badea881b7b72c3fb13njn   n_bytes = read(fd, header, sizeof(header));
154fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   close(fd);
15558899e8e2af51859289d0badea881b7b72c3fb13njn   if (n_bytes < 2) {
15633e57a7bcf079398e9003f892a853037f9bd5de0njn      return NULL;
15733e57a7bcf079398e9003f892a853037f9bd5de0njn   }
158fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
1596431e308474c88cd5da785b639816cc4321db4c7sewardj   VG_(debugLog)(2, "launcher", "read %ld bytes from '%s'\n",
1606431e308474c88cd5da785b639816cc4321db4c7sewardj                    (long int)n_bytes, clientname);
1611edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom
162fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   if (header[0] == '#' && header[1] == '!') {
16358899e8e2af51859289d0badea881b7b72c3fb13njn      int i = 2;
164fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
165695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      STATIC_ASSERT(VKI_BINPRM_BUF_SIZE < sizeof header);
166695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      if (n_bytes > VKI_BINPRM_BUF_SIZE)
167695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian         n_bytes = VKI_BINPRM_BUF_SIZE - 1;
168695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      header[n_bytes] = '\0';
169695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      char *eol = strchr(header, '\n');
170695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      if (eol != NULL)
171695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian         *eol = '\0';
172695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian
17358899e8e2af51859289d0badea881b7b72c3fb13njn      // Skip whitespace.
174695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      while  (header[i] == ' '|| header[i] == '\t')
17558899e8e2af51859289d0badea881b7b72c3fb13njn         i++;
176fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
17758899e8e2af51859289d0badea881b7b72c3fb13njn      // Get the interpreter name.
178695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      const char *interp = header + i;
179695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian
180695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      if (header[i] == '\0') {
181695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian         // No interpreter was found; fall back to default shell
182695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian#  if defined(VGPV_arm_linux_android) \
183695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      || defined(VGPV_x86_linux_android) \
184695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      || defined(VGPV_mips32_linux_android) \
185695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      || defined(VGPV_arm64_linux_android)
186695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian         interp = "/system/bin/sh";
187695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian#  else
188695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian         interp = "/bin/sh";
189695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian#  endif
190695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian      } else {
191695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian         while (header[i]) {
192695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian            if (header[i] == ' ' || header[i] == '\t') break;
193695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian            i++;
194695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian         }
195695dde81fe9ba126d9a1a57cb38dcccf95426e3eflorian         header[i] = '\0';
19658899e8e2af51859289d0badea881b7b72c3fb13njn      }
197fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
198fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      platform = select_platform(interp);
1992108204443f84bfa733397be519bdcf6810c5127cerion
20058899e8e2af51859289d0badea881b7b72c3fb13njn   } else if (n_bytes >= SELFMAG && memcmp(header, ELFMAG, SELFMAG) == 0) {
20158899e8e2af51859289d0badea881b7b72c3fb13njn
20258899e8e2af51859289d0badea881b7b72c3fb13njn      if (n_bytes >= sizeof(Elf32_Ehdr) && header[EI_CLASS] == ELFCLASS32) {
2032108204443f84bfa733397be519bdcf6810c5127cerion         const Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
2042108204443f84bfa733397be519bdcf6810c5127cerion
2052108204443f84bfa733397be519bdcf6810c5127cerion         if (header[EI_DATA] == ELFDATA2LSB) {
2062108204443f84bfa733397be519bdcf6810c5127cerion            if (ehdr->e_machine == EM_386 &&
2074ff8f6cd403fa8be4a39b576dd1273ae96500d2atom                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
2084ff8f6cd403fa8be4a39b576dd1273ae96500d2atom                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
2092108204443f84bfa733397be519bdcf6810c5127cerion               platform = "x86-linux";
2102108204443f84bfa733397be519bdcf6810c5127cerion            }
21159570ffbe31930ab4d678754daaeec0715117a3dsewardj            else
21259570ffbe31930ab4d678754daaeec0715117a3dsewardj            if (ehdr->e_machine == EM_ARM &&
21359570ffbe31930ab4d678754daaeec0715117a3dsewardj                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
21459570ffbe31930ab4d678754daaeec0715117a3dsewardj                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
21559570ffbe31930ab4d678754daaeec0715117a3dsewardj               platform = "arm-linux";
21659570ffbe31930ab4d678754daaeec0715117a3dsewardj            }
2175db15403e889d4db339b342bc2a824ef0bfaa654sewardj            else
2185db15403e889d4db339b342bc2a824ef0bfaa654sewardj            if (ehdr->e_machine == EM_MIPS &&
2195db15403e889d4db339b342bc2a824ef0bfaa654sewardj                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
2205db15403e889d4db339b342bc2a824ef0bfaa654sewardj                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
2215db15403e889d4db339b342bc2a824ef0bfaa654sewardj               platform = "mips32-linux";
2225db15403e889d4db339b342bc2a824ef0bfaa654sewardj            }
2232108204443f84bfa733397be519bdcf6810c5127cerion         }
2242108204443f84bfa733397be519bdcf6810c5127cerion         else if (header[EI_DATA] == ELFDATA2MSB) {
2252108204443f84bfa733397be519bdcf6810c5127cerion            if (ehdr->e_machine == EM_PPC &&
2264ff8f6cd403fa8be4a39b576dd1273ae96500d2atom                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
2274ff8f6cd403fa8be4a39b576dd1273ae96500d2atom                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
2282108204443f84bfa733397be519bdcf6810c5127cerion               platform = "ppc32-linux";
2292108204443f84bfa733397be519bdcf6810c5127cerion            }
2305db15403e889d4db339b342bc2a824ef0bfaa654sewardj            else
2315db15403e889d4db339b342bc2a824ef0bfaa654sewardj            if (ehdr->e_machine == EM_MIPS &&
2325db15403e889d4db339b342bc2a824ef0bfaa654sewardj                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
2335db15403e889d4db339b342bc2a824ef0bfaa654sewardj                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
2345db15403e889d4db339b342bc2a824ef0bfaa654sewardj               platform = "mips32-linux";
2355db15403e889d4db339b342bc2a824ef0bfaa654sewardj            }
2362108204443f84bfa733397be519bdcf6810c5127cerion         }
23759570ffbe31930ab4d678754daaeec0715117a3dsewardj
23858899e8e2af51859289d0badea881b7b72c3fb13njn      } else if (n_bytes >= sizeof(Elf64_Ehdr) && header[EI_CLASS] == ELFCLASS64) {
2392108204443f84bfa733397be519bdcf6810c5127cerion         const Elf64_Ehdr *ehdr = (Elf64_Ehdr *)header;
2402108204443f84bfa733397be519bdcf6810c5127cerion
2412108204443f84bfa733397be519bdcf6810c5127cerion         if (header[EI_DATA] == ELFDATA2LSB) {
2422108204443f84bfa733397be519bdcf6810c5127cerion            if (ehdr->e_machine == EM_X86_64 &&
2434ff8f6cd403fa8be4a39b576dd1273ae96500d2atom                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
2444ff8f6cd403fa8be4a39b576dd1273ae96500d2atom                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
2452108204443f84bfa733397be519bdcf6810c5127cerion               platform = "amd64-linux";
2464df0bfc0614379192c780c944415dc420d9cfe8epetarj            } else if (ehdr->e_machine == EM_MIPS &&
2474df0bfc0614379192c780c944415dc420d9cfe8epetarj                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
2484df0bfc0614379192c780c944415dc420d9cfe8epetarj                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
2494df0bfc0614379192c780c944415dc420d9cfe8epetarj               platform = "mips64-linux";
250112711afefcfcd43680c7c4aa8d38ef180e8811esewardj            } else if (ehdr->e_machine == EM_TILEGX &&
251112711afefcfcd43680c7c4aa8d38ef180e8811esewardj                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
252112711afefcfcd43680c7c4aa8d38ef180e8811esewardj                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
253112711afefcfcd43680c7c4aa8d38ef180e8811esewardj               platform = "tilegx-linux";
254f0c1250e324f6684757c6a15545366447ef1d64fsewardj            } else if (ehdr->e_machine == EM_AARCH64 &&
255f0c1250e324f6684757c6a15545366447ef1d64fsewardj                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
256f0c1250e324f6684757c6a15545366447ef1d64fsewardj                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
257f0c1250e324f6684757c6a15545366447ef1d64fsewardj               platform = "arm64-linux";
258582d58245637ab05272d89fb94b12fd0f18fa0f8carll            } else if (ehdr->e_machine == EM_PPC64 &&
259582d58245637ab05272d89fb94b12fd0f18fa0f8carll                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
260582d58245637ab05272d89fb94b12fd0f18fa0f8carll                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
261582d58245637ab05272d89fb94b12fd0f18fa0f8carll               platform = "ppc64le-linux";
2622108204443f84bfa733397be519bdcf6810c5127cerion            }
2632108204443f84bfa733397be519bdcf6810c5127cerion         } else if (header[EI_DATA] == ELFDATA2MSB) {
2649c6b05db45362b1afb981aa8298ab12ab4027b1adejanj#           if !defined(VGPV_arm_linux_android) \
2659c6b05db45362b1afb981aa8298ab12ab4027b1adejanj               && !defined(VGPV_x86_linux_android) \
26626ed419d60369d0545510eba0832566e24452e1esewardj               && !defined(VGPV_mips32_linux_android) \
26726ed419d60369d0545510eba0832566e24452e1esewardj               && !defined(VGPV_arm64_linux_android)
2682108204443f84bfa733397be519bdcf6810c5127cerion            if (ehdr->e_machine == EM_PPC64 &&
2694ff8f6cd403fa8be4a39b576dd1273ae96500d2atom                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
2704ff8f6cd403fa8be4a39b576dd1273ae96500d2atom                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
271cae0cc22b83ffb260ee8379e92099c5a701944cbcarll               platform = "ppc64be-linux";
272ca8d94ac2e864f3034f39c2e45d78a32cfcdb2bbsewardj            }
273ca8d94ac2e864f3034f39c2e45d78a32cfcdb2bbsewardj            else
274ca8d94ac2e864f3034f39c2e45d78a32cfcdb2bbsewardj            if (ehdr->e_machine == EM_S390 &&
275ca8d94ac2e864f3034f39c2e45d78a32cfcdb2bbsewardj                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
276ca8d94ac2e864f3034f39c2e45d78a32cfcdb2bbsewardj                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
277b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj               platform = "s390x-linux";
2784df0bfc0614379192c780c944415dc420d9cfe8epetarj            } else if (ehdr->e_machine == EM_MIPS &&
2794df0bfc0614379192c780c944415dc420d9cfe8epetarj                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
2804df0bfc0614379192c780c944415dc420d9cfe8epetarj                 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
2814df0bfc0614379192c780c944415dc420d9cfe8epetarj               platform = "mips64-linux";
2822108204443f84bfa733397be519bdcf6810c5127cerion            }
283ca8d94ac2e864f3034f39c2e45d78a32cfcdb2bbsewardj#           endif
2842108204443f84bfa733397be519bdcf6810c5127cerion         }
285fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      }
286fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   }
287fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
2881edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom   VG_(debugLog)(2, "launcher", "selected platform '%s'\n",
2891edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom                 platform ? platform : "unknown");
2901edc55a25a2f28cdc0cc72e3e18f5cc0c4eb927etom
291fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   return platform;
292fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom}
293fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
29445f4e7c91119c7d01a59f5e827c67841632c9314sewardj/* Where we expect to find all our aux files */
29545f4e7c91119c7d01a59f5e827c67841632c9314sewardjstatic const char *valgrind_lib = VG_LIBDIR;
29645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
29745f4e7c91119c7d01a59f5e827c67841632c9314sewardjint main(int argc, char** argv, char** envp)
29845f4e7c91119c7d01a59f5e827c67841632c9314sewardj{
29945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   int i, j, loglevel, r;
30045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   const char *toolname = NULL;
301fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   const char *clientname = NULL;
302fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   const char *platform;
3038813eef4f290add8e7d66db4deae8cedddcb68bcsewardj   const char *default_platform;
30445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   const char *cp;
30545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   char *toolfile;
3060c89e9b0812fb26324a5c5a392bbce01ae92582dflorian   const char *launcher_name;
30745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   char* new_line;
30845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   char** new_env;
30945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
31045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Start the debugging-log system ASAP.  First find out how many
31145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      "-d"s were specified.  This is a pre-scan of the command line.
31245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      At the same time, look for the tool name. */
31345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   loglevel = 0;
31445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = 1; i < argc; i++) {
315fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      if (argv[i][0] != '-') {
316fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom         clientname = argv[i];
31745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
318fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      }
319fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      if (0 == strcmp(argv[i], "--")) {
320fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom         if (i+1 < argc)
321fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom            clientname = argv[i+1];
32245f4e7c91119c7d01a59f5e827c67841632c9314sewardj         break;
323fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      }
32445f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (0 == strcmp(argv[i], "-d"))
32545f4e7c91119c7d01a59f5e827c67841632c9314sewardj         loglevel++;
32645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      if (0 == strncmp(argv[i], "--tool=", 7))
32745f4e7c91119c7d01a59f5e827c67841632c9314sewardj         toolname = argv[i] + 7;
32845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
32945f4e7c91119c7d01a59f5e827c67841632c9314sewardj
33045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* ... and start the debug logger.  Now we can safely emit logging
33145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      messages all through startup. */
33245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog_startup)(loglevel, "Stage 1");
33345f4e7c91119c7d01a59f5e827c67841632c9314sewardj
33445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Make sure we know which tool we're using */
33545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (toolname) {
33645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname);
33745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   } else {
33845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      VG_(debugLog)(1, "launcher",
33945f4e7c91119c7d01a59f5e827c67841632c9314sewardj                       "no tool requested, defaulting to 'memcheck'\n");
34045f4e7c91119c7d01a59f5e827c67841632c9314sewardj      toolname = "memcheck";
34145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   }
34245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
3438813eef4f290add8e7d66db4deae8cedddcb68bcsewardj   /* Select a platform to use if we can't decide that by looking at
344e8ffbc22ce035642f85f59f27fb87152805e641eflorian      the executable (eg because it's a shell script).  VG_PLATFORM is the
345e8ffbc22ce035642f85f59f27fb87152805e641eflorian      default_platform. Its value is defined in coregrind/Makefile.am and
346e8ffbc22ce035642f85f59f27fb87152805e641eflorian      typically it is the primary build target. Unless the primary build
347e8ffbc22ce035642f85f59f27fb87152805e641eflorian      target is not built is not built in which case VG_PLATFORM is the
348e8ffbc22ce035642f85f59f27fb87152805e641eflorian      secondary build target. */
349f0c1250e324f6684757c6a15545366447ef1d64fsewardj   if ((0==strcmp(VG_PLATFORM,"x86-linux"))    ||
350f0c1250e324f6684757c6a15545366447ef1d64fsewardj       (0==strcmp(VG_PLATFORM,"amd64-linux"))  ||
351f0c1250e324f6684757c6a15545366447ef1d64fsewardj       (0==strcmp(VG_PLATFORM,"ppc32-linux"))  ||
352cae0cc22b83ffb260ee8379e92099c5a701944cbcarll       (0==strcmp(VG_PLATFORM,"ppc64be-linux"))  ||
353582d58245637ab05272d89fb94b12fd0f18fa0f8carll       (0==strcmp(VG_PLATFORM,"ppc64le-linux"))  ||
354f0c1250e324f6684757c6a15545366447ef1d64fsewardj       (0==strcmp(VG_PLATFORM,"arm-linux"))    ||
355f0c1250e324f6684757c6a15545366447ef1d64fsewardj       (0==strcmp(VG_PLATFORM,"arm64-linux"))  ||
356f0c1250e324f6684757c6a15545366447ef1d64fsewardj       (0==strcmp(VG_PLATFORM,"s390x-linux"))  ||
357112711afefcfcd43680c7c4aa8d38ef180e8811esewardj       (0==strcmp(VG_PLATFORM,"tilegx-linux")) ||
3584df0bfc0614379192c780c944415dc420d9cfe8epetarj       (0==strcmp(VG_PLATFORM,"mips32-linux")) ||
3594df0bfc0614379192c780c944415dc420d9cfe8epetarj       (0==strcmp(VG_PLATFORM,"mips64-linux")))
3604f350d1b47ccaa7a579b52cafa6f75ffe04f415cnjn      default_platform = VG_PLATFORM;
3618813eef4f290add8e7d66db4deae8cedddcb68bcsewardj   else
3628813eef4f290add8e7d66db4deae8cedddcb68bcsewardj      barf("Unknown VG_PLATFORM '%s'", VG_PLATFORM);
3638813eef4f290add8e7d66db4deae8cedddcb68bcsewardj
3648813eef4f290add8e7d66db4deae8cedddcb68bcsewardj   /* Work out what platform to use, or use the default platform if
3658813eef4f290add8e7d66db4deae8cedddcb68bcsewardj      not possible. */
366fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   if (clientname == NULL) {
3678813eef4f290add8e7d66db4deae8cedddcb68bcsewardj      VG_(debugLog)(1, "launcher",
3688813eef4f290add8e7d66db4deae8cedddcb68bcsewardj                       "no client specified, defaulting platform to '%s'\n",
3698813eef4f290add8e7d66db4deae8cedddcb68bcsewardj                        default_platform);
3708813eef4f290add8e7d66db4deae8cedddcb68bcsewardj      platform = default_platform;
371fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   } else if ((platform = select_platform(clientname)) != NULL) {
372fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom      VG_(debugLog)(1, "launcher", "selected platform '%s'\n", platform);
373fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   } else {
3748813eef4f290add8e7d66db4deae8cedddcb68bcsewardj      VG_(debugLog)(1, "launcher",
3758813eef4f290add8e7d66db4deae8cedddcb68bcsewardj                       "no platform detected, defaulting platform to '%s'\n",
3768813eef4f290add8e7d66db4deae8cedddcb68bcsewardj                       default_platform);
3778813eef4f290add8e7d66db4deae8cedddcb68bcsewardj      platform = default_platform;
378fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   }
379fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom
38045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Figure out the name of this executable (viz, the launcher), so
38145f4e7c91119c7d01a59f5e827c67841632c9314sewardj      we can tell stage2.  stage2 will use the name for recursive
38258899e8e2af51859289d0badea881b7b72c3fb13njn      invocations of valgrind on child processes. */
3830c89e9b0812fb26324a5c5a392bbce01ae92582dflorian   unsigned bufsiz = 0;
3840c89e9b0812fb26324a5c5a392bbce01ae92582dflorian   char *buf = NULL;
3850c89e9b0812fb26324a5c5a392bbce01ae92582dflorian
3860c89e9b0812fb26324a5c5a392bbce01ae92582dflorian   while (42) {
3870c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      bufsiz += 500;
3880c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      buf = realloc(buf, bufsiz);
3890c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      if (buf == NULL)
3900c89e9b0812fb26324a5c5a392bbce01ae92582dflorian         barf("realloc of buf failed.");
3910c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      r = readlink("/proc/self/exe", buf, bufsiz);
3920c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      if (r == -1) {
3930c89e9b0812fb26324a5c5a392bbce01ae92582dflorian        /* If /proc/self/exe can't be followed, don't give up.  Instead
3940c89e9b0812fb26324a5c5a392bbce01ae92582dflorian           continue with an empty string for VALGRIND_LAUNCHER.  In the
3950c89e9b0812fb26324a5c5a392bbce01ae92582dflorian           sys_execve wrapper, this is tested, and if found to be empty,
3960c89e9b0812fb26324a5c5a392bbce01ae92582dflorian           fail the execve. */
3970c89e9b0812fb26324a5c5a392bbce01ae92582dflorian        fprintf(stderr, "valgrind: warning (non-fatal): "
3980c89e9b0812fb26324a5c5a392bbce01ae92582dflorian                "readlink(\"/proc/self/exe\") failed.\n");
3990c89e9b0812fb26324a5c5a392bbce01ae92582dflorian        fprintf(stderr, "valgrind: continuing, however --trace-children=yes "
4000c89e9b0812fb26324a5c5a392bbce01ae92582dflorian                "will not work.\n");
4010c89e9b0812fb26324a5c5a392bbce01ae92582dflorian        launcher_name = "";
4020c89e9b0812fb26324a5c5a392bbce01ae92582dflorian        break;
4030c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      }
4040c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      if (r == bufsiz) continue;   // buffer to small; retry
4050c89e9b0812fb26324a5c5a392bbce01ae92582dflorian
4060c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      assert(r < bufsiz);   // paranoia
4070c89e9b0812fb26324a5c5a392bbce01ae92582dflorian
4080c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      buf[r] = '\0';
4090c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      launcher_name = buf;
4100c89e9b0812fb26324a5c5a392bbce01ae92582dflorian      break;
41198e68a4db8df087243c5f095cddb7b34adb2d19bsewardj   }
41245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
41345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */
41445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   new_line = malloc(strlen(VALGRIND_LAUNCHER) + 1
41545f4e7c91119c7d01a59f5e827c67841632c9314sewardj                     + strlen(launcher_name) + 1);
41645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (new_line == NULL)
41745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      barf("malloc of new_line failed.");
41845f4e7c91119c7d01a59f5e827c67841632c9314sewardj   strcpy(new_line, VALGRIND_LAUNCHER);
41945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   strcat(new_line, "=");
42045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   strcat(new_line, launcher_name);
42145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
42245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (j = 0; envp[j]; j++)
42345f4e7c91119c7d01a59f5e827c67841632c9314sewardj      ;
42445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   new_env = malloc((j+2) * sizeof(char*));
42545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (new_env == NULL)
42645f4e7c91119c7d01a59f5e827c67841632c9314sewardj      barf("malloc of new_env failed.");
42745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   for (i = 0; i < j; i++)
42845f4e7c91119c7d01a59f5e827c67841632c9314sewardj      new_env[i] = envp[i];
42945f4e7c91119c7d01a59f5e827c67841632c9314sewardj   new_env[i++] = new_line;
43045f4e7c91119c7d01a59f5e827c67841632c9314sewardj   new_env[i++] = NULL;
43145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   assert(i == j+2);
43245f4e7c91119c7d01a59f5e827c67841632c9314sewardj
43345f4e7c91119c7d01a59f5e827c67841632c9314sewardj   /* Establish the correct VALGRIND_LIB. */
43445f4e7c91119c7d01a59f5e827c67841632c9314sewardj   cp = getenv(VALGRIND_LIB);
43545f4e7c91119c7d01a59f5e827c67841632c9314sewardj
43645f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (cp != NULL)
43745f4e7c91119c7d01a59f5e827c67841632c9314sewardj      valgrind_lib = cp;
43845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
43958899e8e2af51859289d0badea881b7b72c3fb13njn   /* Build the stage2 invocation, and execve it.  Bye! */
440fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   toolfile = malloc(strlen(valgrind_lib) + strlen(toolname) + strlen(platform) + 3);
44145f4e7c91119c7d01a59f5e827c67841632c9314sewardj   if (toolfile == NULL)
44245f4e7c91119c7d01a59f5e827c67841632c9314sewardj      barf("malloc of toolfile failed.");
4436bf365c2d4e55cb109d20e0a8f90dc121bdc003fnjn   sprintf(toolfile, "%s/%s-%s", valgrind_lib, toolname, platform);
44445f4e7c91119c7d01a59f5e827c67841632c9314sewardj
44545f4e7c91119c7d01a59f5e827c67841632c9314sewardj   VG_(debugLog)(1, "launcher", "launching %s\n", toolfile);
44645f4e7c91119c7d01a59f5e827c67841632c9314sewardj
44745f4e7c91119c7d01a59f5e827c67841632c9314sewardj   execve(toolfile, argv, new_env);
44845f4e7c91119c7d01a59f5e827c67841632c9314sewardj
449fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom   fprintf(stderr, "valgrind: failed to start tool '%s' for platform '%s': %s\n",
450fb7bcde4e3d8afdcd267b4da904f777cfd8ed1bbtom                   toolname, platform, strerror(errno));
45145f4e7c91119c7d01a59f5e827c67841632c9314sewardj
45245f4e7c91119c7d01a59f5e827c67841632c9314sewardj   exit(1);
45345f4e7c91119c7d01a59f5e827c67841632c9314sewardj}
454