~bkerensa/ubuntu/raring/valgrind/merge-from-deb

« back to all changes in this revision

Viewing changes to coregrind/launcher.c

  • Committer: Bazaar Package Importer
  • Author(s): Andrés Roldán
  • Date: 2008-06-13 02:31:40 UTC
  • mto: (1.4.1 upstream) (2.2.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: james.westby@ubuntu.com-20080613023140-iwk33rz9rhvfkr96
Import upstream version 3.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
/*--------------------------------------------------------------------*/
3
 
/*--- Launching valgrind                              m_launcher.c ---*/
4
 
/*--------------------------------------------------------------------*/
5
 
 
6
 
/*
7
 
   This file is part of Valgrind, a dynamic binary instrumentation
8
 
   framework.
9
 
 
10
 
   Copyright (C) 2000-2006 Julian Seward 
11
 
      jseward@acm.org
12
 
 
13
 
   This program is free software; you can redistribute it and/or
14
 
   modify it under the terms of the GNU General Public License as
15
 
   published by the Free Software Foundation; either version 2 of the
16
 
   License, or (at your option) any later version.
17
 
 
18
 
   This program is distributed in the hope that it will be useful, but
19
 
   WITHOUT ANY WARRANTY; without even the implied warranty of
20
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21
 
   General Public License for more details.
22
 
 
23
 
   You should have received a copy of the GNU General Public License
24
 
   along with this program; if not, write to the Free Software
25
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26
 
   02111-1307, USA.
27
 
 
28
 
   The GNU General Public License is contained in the file COPYING.
29
 
*/
30
 
 
31
 
/* Note: this is a "normal" program and not part of Valgrind proper,
32
 
   and so it doesn't have to conform to Valgrind's arcane rules on
33
 
   no-glibc-usage etc. */
34
 
 
35
 
#include <assert.h>
36
 
#include <ctype.h>
37
 
#include <elf.h>
38
 
#include <errno.h>
39
 
#include <fcntl.h>
40
 
#include <stdarg.h>
41
 
#include <stdio.h>
42
 
#include <stdlib.h>
43
 
#include <string.h>
44
 
#include <sys/mman.h>
45
 
#include <sys/user.h>
46
 
#include <unistd.h>
47
 
 
48
 
#include "pub_core_debuglog.h"
49
 
#include "pub_core_libcproc.h"  // For VALGRIND_LIB, VALGRIND_LAUNCHER
50
 
#include "pub_core_ume.h"
51
 
 
52
 
 
53
 
 
54
 
#define PATH_MAX 4096 /* POSIX refers to this a lot but I dunno
55
 
                         where it is defined */
56
 
 
57
 
#ifndef EM_X86_64
58
 
#define EM_X86_64 62    // elf.h doesn't define this on some older systems
59
 
#endif
60
 
 
61
 
/* Report fatal errors */
62
 
__attribute__((noreturn))
63
 
static void barf ( const char *format, ... )
64
 
{
65
 
   va_list vargs;
66
 
 
67
 
   va_start(vargs, format);
68
 
   fprintf(stderr, "valgrind: Cannot continue: ");
69
 
   vfprintf(stderr, format, vargs);
70
 
   fprintf(stderr, "\n");
71
 
   va_end(vargs);
72
 
 
73
 
   exit(1);
74
 
   /*NOTREACHED*/
75
 
   assert(0);
76
 
}
77
 
 
78
 
/* Search the path for the client program */
79
 
static const char *find_client(const char *clientname)
80
 
{
81
 
   static char fullname[PATH_MAX];
82
 
   const char *path = getenv("PATH");
83
 
   const char *colon;
84
 
 
85
 
   while (path)
86
 
   {
87
 
      if ((colon = strchr(path, ':')) == NULL)
88
 
      {
89
 
         strcpy(fullname, path);
90
 
         path = NULL;
91
 
      }
92
 
      else
93
 
      {
94
 
         memcpy(fullname, path, colon - path);
95
 
         fullname[colon - path] = '\0';
96
 
         path = colon + 1;
97
 
      }
98
 
 
99
 
      strcat(fullname, "/");
100
 
      strcat(fullname, clientname);
101
 
 
102
 
      if (access(fullname, R_OK|X_OK) == 0)
103
 
         return fullname;
104
 
   }
105
 
 
106
 
   return clientname;
107
 
}
108
 
 
109
 
/* Examine the client and work out which platform it is for */
110
 
static const char *select_platform(const char *clientname)
111
 
{
112
 
   int fd;
113
 
   unsigned char *header;
114
 
   const char *platform = NULL;
115
 
   long pagesize = sysconf(_SC_PAGESIZE);
116
 
 
117
 
   if (strchr(clientname, '/') == NULL)
118
 
      clientname = find_client(clientname);
119
 
 
120
 
   if ((fd = open(clientname, O_RDONLY)) < 0)
121
 
      return NULL;
122
 
   //   barf("open(%s): %s", clientname, strerror(errno));
123
 
 
124
 
   if ((header = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
125
 
      return NULL;
126
 
   //   barf("mmap(%s): %s", clientname, strerror(errno));
127
 
 
128
 
   close(fd);
129
 
 
130
 
   if (header[0] == '#' && header[1] == '!') {
131
 
      char *interp = (char *)header + 2;
132
 
      char *interpend;
133
 
 
134
 
      while (*interp == ' ' || *interp == '\t')
135
 
         interp++;
136
 
 
137
 
      for (interpend = interp; !isspace(*interpend); interpend++)
138
 
         ;
139
 
 
140
 
      *interpend = '\0';
141
 
 
142
 
      platform = select_platform(interp);
143
 
   } else if (memcmp(header, ELFMAG, SELFMAG) == 0) {
144
 
 
145
 
      if (header[EI_CLASS] == ELFCLASS32) {
146
 
         const Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
147
 
 
148
 
         if (header[EI_DATA] == ELFDATA2LSB) {
149
 
            if (ehdr->e_machine == EM_386 &&
150
 
                ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV) {
151
 
               platform = "x86-linux";
152
 
            }
153
 
         }
154
 
         else if (header[EI_DATA] == ELFDATA2MSB) {
155
 
            if (ehdr->e_machine == EM_PPC &&
156
 
                ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV) {
157
 
               platform = "ppc32-linux";
158
 
            }
159
 
         }
160
 
      } else if (header[EI_CLASS] == ELFCLASS64) {
161
 
         const Elf64_Ehdr *ehdr = (Elf64_Ehdr *)header;
162
 
 
163
 
         if (header[EI_DATA] == ELFDATA2LSB) {
164
 
            if (ehdr->e_machine == EM_X86_64 &&
165
 
                ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV) {
166
 
               platform = "amd64-linux";
167
 
            }
168
 
         } else if (header[EI_DATA] == ELFDATA2MSB) {
169
 
            if (ehdr->e_machine == EM_PPC64 &&
170
 
                ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV) {
171
 
               platform = "ppc64-linux";
172
 
            }
173
 
         }
174
 
      }
175
 
   }
176
 
 
177
 
   munmap(header, pagesize);
178
 
 
179
 
   return platform;
180
 
}
181
 
 
182
 
/* Where we expect to find all our aux files */
183
 
static const char *valgrind_lib = VG_LIBDIR;
184
 
 
185
 
int main(int argc, char** argv, char** envp)
186
 
{
187
 
   int i, j, loglevel, r;
188
 
   const char *toolname = NULL;
189
 
   const char *clientname = NULL;
190
 
   const char *platform;
191
 
   const char *default_platform;
192
 
   const char *cp;
193
 
   char *toolfile;
194
 
   char launcher_name[PATH_MAX+1];
195
 
   char* new_line;
196
 
   char** new_env;
197
 
 
198
 
   /* Start the debugging-log system ASAP.  First find out how many 
199
 
      "-d"s were specified.  This is a pre-scan of the command line.
200
 
      At the same time, look for the tool name. */
201
 
   loglevel = 0;
202
 
   for (i = 1; i < argc; i++) {
203
 
      if (argv[i][0] != '-') {
204
 
         clientname = argv[i];
205
 
         break;
206
 
      }
207
 
      if (0 == strcmp(argv[i], "--")) {
208
 
         if (i+1 < argc)
209
 
            clientname = argv[i+1];
210
 
         break;
211
 
      }
212
 
      if (0 == strcmp(argv[i], "-d")) 
213
 
         loglevel++;
214
 
      if (0 == strncmp(argv[i], "--tool=", 7)) 
215
 
         toolname = argv[i] + 7;
216
 
   }
217
 
 
218
 
   /* ... and start the debug logger.  Now we can safely emit logging
219
 
      messages all through startup. */
220
 
   VG_(debugLog_startup)(loglevel, "Stage 1");
221
 
 
222
 
   /* Make sure we know which tool we're using */
223
 
   if (toolname) {
224
 
      VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname);
225
 
   } else {
226
 
      VG_(debugLog)(1, "launcher", 
227
 
                       "no tool requested, defaulting to 'memcheck'\n");
228
 
      toolname = "memcheck";
229
 
   }
230
 
 
231
 
   /* Select a platform to use if we can't decide that by looking at
232
 
      the executable (eg because it's a shell script).  Note that the
233
 
      default_platform is not necessarily either the primary or
234
 
      secondary build target.  Instead it's chosen to maximise the
235
 
      chances that /bin/sh will work on it.  Hence for a primary
236
 
      target of ppc64-linux we still choose ppc32-linux as the default
237
 
      target, because on most ppc64-linux setups, the basic /bin,
238
 
      /usr/bin, etc, stuff is built in 32-bit mode, not 64-bit
239
 
      mode. */
240
 
   if (0==strcmp(VG_PLATFORM,"x86-linux"))
241
 
      default_platform = "x86-linux";
242
 
   else if (0==strcmp(VG_PLATFORM,"amd64-linux"))
243
 
      default_platform = "amd64-linux";
244
 
   else if (0==strcmp(VG_PLATFORM,"ppc32-linux"))
245
 
      default_platform = "ppc32-linux";
246
 
   else if (0==strcmp(VG_PLATFORM,"ppc64-linux"))
247
 
      default_platform = "ppc32-linux";
248
 
   else
249
 
      barf("Unknown VG_PLATFORM '%s'", VG_PLATFORM);
250
 
 
251
 
   /* Work out what platform to use, or use the default platform if
252
 
      not possible. */
253
 
   if (clientname == NULL) {
254
 
      VG_(debugLog)(1, "launcher", 
255
 
                       "no client specified, defaulting platform to '%s'\n",
256
 
                        default_platform);
257
 
      platform = default_platform;
258
 
   } else if ((platform = select_platform(clientname)) != NULL) {
259
 
      VG_(debugLog)(1, "launcher", "selected platform '%s'\n", platform);
260
 
   } else {
261
 
      VG_(debugLog)(1, "launcher", 
262
 
                       "no platform detected, defaulting platform to '%s'\n",
263
 
                       default_platform);
264
 
      platform = default_platform;
265
 
   }
266
 
   
267
 
   /* Figure out the name of this executable (viz, the launcher), so
268
 
      we can tell stage2.  stage2 will use the name for recursive
269
 
      invokations of valgrind on child processes. */
270
 
   memset(launcher_name, 0, PATH_MAX+1);
271
 
   r = readlink("/proc/self/exe", launcher_name, PATH_MAX);
272
 
   if (r == -1) {
273
 
      /* If /proc/self/exe can't be followed, don't give up.  Instead
274
 
         continue with an empty string for VALGRIND_LAUNCHER.  In the
275
 
         sys_execve wrapper, this is tested, and if found to be empty,
276
 
         fail the execve. */
277
 
      fprintf(stderr, "valgrind: warning (non-fatal): "
278
 
                      "readlink(\"/proc/self/exe\") failed.\n");
279
 
      fprintf(stderr, "valgrind: continuing, however --trace-children=yes "
280
 
                      "will not work.\n");
281
 
   }
282
 
 
283
 
   /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */
284
 
   new_line = malloc(strlen(VALGRIND_LAUNCHER) + 1 
285
 
                     + strlen(launcher_name) + 1);
286
 
   if (new_line == NULL)
287
 
      barf("malloc of new_line failed.");
288
 
   strcpy(new_line, VALGRIND_LAUNCHER);
289
 
   strcat(new_line, "=");
290
 
   strcat(new_line, launcher_name);
291
 
 
292
 
   for (j = 0; envp[j]; j++)
293
 
      ;
294
 
   new_env = malloc((j+2) * sizeof(char*));
295
 
   if (new_env == NULL)
296
 
      barf("malloc of new_env failed.");
297
 
   for (i = 0; i < j; i++)
298
 
      new_env[i] = envp[i];
299
 
   new_env[i++] = new_line;
300
 
   new_env[i++] = NULL;
301
 
   assert(i == j+2);
302
 
 
303
 
   /* Establish the correct VALGRIND_LIB. */
304
 
   cp = getenv(VALGRIND_LIB);
305
 
 
306
 
   if (cp != NULL)
307
 
      valgrind_lib = cp;
308
 
 
309
 
   /* Build the stage2 invokation, and execve it.  Bye! */
310
 
   toolfile = malloc(strlen(valgrind_lib) + strlen(toolname) + strlen(platform) + 3);
311
 
   if (toolfile == NULL)
312
 
      barf("malloc of toolfile failed.");
313
 
   sprintf(toolfile, "%s/%s/%s", valgrind_lib, platform, toolname);
314
 
 
315
 
   VG_(debugLog)(1, "launcher", "launching %s\n", toolfile);
316
 
 
317
 
   execve(toolfile, argv, new_env);
318
 
 
319
 
   fprintf(stderr, "valgrind: failed to start tool '%s' for platform '%s': %s\n",
320
 
                   toolname, platform, strerror(errno));
321
 
 
322
 
   exit(1);
323
 
}