blob: 81404910b9b7eeed6ffdbfb57e35b9bbbb2ab7bd [file] [log] [blame]
sewardj45f4e7c2005-09-27 19:20:21 +00001
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-2005 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 <errno.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <assert.h>
41
42#include "pub_core_debuglog.h"
43#include "pub_core_libcproc.h" // For VALGRIND_LIB, VALGRIND_LAUNCHER
44
45
46
47#define PATH_MAX 4096 /* POSIX refers to this a lot but I dunno
48 where it is defined */
49
50static void barf ( char* str )
51{
52 fprintf(stderr, "valgrind: Cannot continue: %s\n", str );
53 exit(1);
54}
55
56/* Where we expect to find all our aux files */
57static const char *valgrind_lib = VG_LIBDIR;
58
59int main(int argc, char** argv, char** envp)
60{
61 int i, j, loglevel, r;
62 const char *toolname = NULL;
63 const char *cp;
64 char *toolfile;
65 char launcher_name[PATH_MAX+1];
66 char* new_line;
67 char** new_env;
68
69 /* Start the debugging-log system ASAP. First find out how many
70 "-d"s were specified. This is a pre-scan of the command line.
71 At the same time, look for the tool name. */
72 loglevel = 0;
73 for (i = 1; i < argc; i++) {
74 if (argv[i][0] != '-')
75 break;
76 if (0 == strcmp(argv[i], "--"))
77 break;
78 if (0 == strcmp(argv[i], "-d"))
79 loglevel++;
80 if (0 == strncmp(argv[i], "--tool=", 7))
81 toolname = argv[i] + 7;
82 }
83
84 /* ... and start the debug logger. Now we can safely emit logging
85 messages all through startup. */
86 VG_(debugLog_startup)(loglevel, "Stage 1");
87
88 /* Make sure we know which tool we're using */
89 if (toolname) {
90 VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname);
91 } else {
92 VG_(debugLog)(1, "launcher",
93 "no tool requested, defaulting to 'memcheck'\n");
94 toolname = "memcheck";
95 }
96
97 /* Figure out the name of this executable (viz, the launcher), so
98 we can tell stage2. stage2 will use the name for recursive
99 invokations of valgrind on child processes. */
100 memset(launcher_name, 0, PATH_MAX+1);
101 r = readlink("/proc/self/exe", launcher_name, PATH_MAX);
sewardj98e68a42005-10-04 23:07:33 +0000102 if (r == -1) {
103 /* If /proc/self/exe can't be followed, don't give up. Instead
104 continue with an empty string for VALGRIND_LAUNCHER. In the
105 sys_execve wrapper, this is tested, and if found to be empty,
106 fail the execve. */
107 fprintf(stderr, "valgrind: warning (non-fatal): "
108 "readlink(\"/proc/self/exe\") failed.\n");
109 fprintf(stderr, "valgrind: continuing, however --trace-children=yes "
110 "will not work.\n");
111 }
sewardj45f4e7c2005-09-27 19:20:21 +0000112
113 /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */
114 new_line = malloc(strlen(VALGRIND_LAUNCHER) + 1
115 + strlen(launcher_name) + 1);
116 if (new_line == NULL)
117 barf("malloc of new_line failed.");
118 strcpy(new_line, VALGRIND_LAUNCHER);
119 strcat(new_line, "=");
120 strcat(new_line, launcher_name);
121
122 for (j = 0; envp[j]; j++)
123 ;
124 new_env = malloc((j+2) * sizeof(char*));
125 if (new_env == NULL)
126 barf("malloc of new_env failed.");
127 for (i = 0; i < j; i++)
128 new_env[i] = envp[i];
129 new_env[i++] = new_line;
130 new_env[i++] = NULL;
131 assert(i == j+2);
132
133 /* Establish the correct VALGRIND_LIB. */
134 cp = getenv(VALGRIND_LIB);
135
136 if (cp != NULL)
137 valgrind_lib = cp;
138
139 /* Build the stage2 invokation, and execve it. Bye! */
140 toolfile = malloc(strlen(valgrind_lib) + strlen(toolname) + 2);
141 if (toolfile == NULL)
142 barf("malloc of toolfile failed.");
143 sprintf(toolfile, "%s/%s", valgrind_lib, toolname);
144
145 VG_(debugLog)(1, "launcher", "launching %s\n", toolfile);
146
147 execve(toolfile, argv, new_env);
148
149 fprintf(stderr, "valgrind: failed to start tool '%s': %s\n",
150 toolname, strerror(errno));
151
152 exit(1);
153}