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-2010 Julian Seward 11 jseward (at) 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 valgrind headers before system headers to avoid problems 36 with the system headers #defining things which are used as names 37 of structure members in vki headers. */ 38 39 #include "pub_core_debuglog.h" 40 #include "pub_core_vki.h" // Avoids warnings from 41 // pub_core_libcfile.h 42 #include "pub_core_libcproc.h" // For VALGRIND_LIB, VALGRIND_LAUNCHER 43 #include "pub_core_ume.h" 44 45 #include <assert.h> 46 #include <ctype.h> 47 #include <elf.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <stdarg.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <sys/mman.h> 55 #ifdef ANDROID 56 #include <linux/user.h> 57 #else 58 #include <sys/user.h> 59 #endif 60 #include <unistd.h> 61 62 63 64 #define PATH_MAX 4096 /* POSIX refers to this a lot but I dunno 65 where it is defined */ 66 67 #ifndef EM_X86_64 68 #define EM_X86_64 62 // elf.h doesn't define this on some older systems 69 #endif 70 #ifndef EM_PPC64 71 #define EM_PPC64 21 // elf.h doesn't define this on Android 72 #endif 73 74 /* Report fatal errors */ 75 __attribute__((noreturn)) 76 static void barf ( const char *format, ... ) 77 { 78 va_list vargs; 79 80 va_start(vargs, format); 81 fprintf(stderr, "valgrind: Cannot continue: "); 82 vfprintf(stderr, format, vargs); 83 fprintf(stderr, "\n"); 84 va_end(vargs); 85 86 exit(1); 87 /*NOTREACHED*/ 88 assert(0); 89 } 90 91 /* Search the path for the client program */ 92 static const char *find_client(const char *clientname) 93 { 94 static char fullname[PATH_MAX]; 95 const char *path = getenv("PATH"); 96 const char *colon; 97 98 while (path) 99 { 100 if ((colon = strchr(path, ':')) == NULL) 101 { 102 strcpy(fullname, path); 103 path = NULL; 104 } 105 else 106 { 107 memcpy(fullname, path, colon - path); 108 fullname[colon - path] = '\0'; 109 path = colon + 1; 110 } 111 112 strcat(fullname, "/"); 113 strcat(fullname, clientname); 114 115 if (access(fullname, R_OK|X_OK) == 0) 116 return fullname; 117 } 118 119 return clientname; 120 } 121 122 /* Examine the client and work out which platform it is for */ 123 static const char *select_platform(const char *clientname) 124 { 125 int fd; 126 uint8_t header[4096]; 127 ssize_t n_bytes; 128 const char *platform = NULL; 129 130 VG_(debugLog)(2, "launcher", "selecting platform for '%s'\n", clientname); 131 132 if (strchr(clientname, '/') == NULL) 133 clientname = find_client(clientname); 134 135 VG_(debugLog)(2, "launcher", "selecting platform for '%s'\n", clientname); 136 137 if ((fd = open(clientname, O_RDONLY)) < 0) 138 return NULL; 139 // barf("open(%s): %s", clientname, strerror(errno)); 140 141 VG_(debugLog)(2, "launcher", "opened '%s'\n", clientname); 142 143 n_bytes = read(fd, header, sizeof(header)); 144 close(fd); 145 if (n_bytes < 2) { 146 return NULL; 147 } 148 149 VG_(debugLog)(2, "launcher", "read %ld bytes from '%s'\n", 150 (long int)n_bytes, clientname); 151 152 if (header[0] == '#' && header[1] == '!') { 153 int i = 2; 154 char *interp = (char *)header + 2; 155 156 // Skip whitespace. 157 while (1) { 158 if (i == n_bytes) return NULL; 159 if (' ' != header[i] && '\t' != header[i]) break; 160 i++; 161 } 162 163 // Get the interpreter name. 164 interp = &header[i]; 165 while (1) { 166 if (i == n_bytes) break; 167 if (isspace(header[i])) break; 168 i++; 169 } 170 if (i == n_bytes) return NULL; 171 header[i] = '\0'; 172 173 platform = select_platform(interp); 174 175 } else if (n_bytes >= SELFMAG && memcmp(header, ELFMAG, SELFMAG) == 0) { 176 177 if (n_bytes >= sizeof(Elf32_Ehdr) && header[EI_CLASS] == ELFCLASS32) { 178 const Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header; 179 180 if (header[EI_DATA] == ELFDATA2LSB) { 181 if (ehdr->e_machine == EM_386 && 182 (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV || 183 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) { 184 platform = "x86-linux"; 185 } 186 else 187 if (ehdr->e_machine == EM_ARM && 188 (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV || 189 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) { 190 platform = "arm-linux"; 191 } 192 } 193 else if (header[EI_DATA] == ELFDATA2MSB) { 194 if (ehdr->e_machine == EM_PPC && 195 (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV || 196 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) { 197 platform = "ppc32-linux"; 198 } 199 } 200 201 } else if (n_bytes >= sizeof(Elf64_Ehdr) && header[EI_CLASS] == ELFCLASS64) { 202 const Elf64_Ehdr *ehdr = (Elf64_Ehdr *)header; 203 204 if (header[EI_DATA] == ELFDATA2LSB) { 205 if (ehdr->e_machine == EM_X86_64 && 206 (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV || 207 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) { 208 platform = "amd64-linux"; 209 } 210 } else if (header[EI_DATA] == ELFDATA2MSB) { 211 if (ehdr->e_machine == EM_PPC64 && 212 (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV || 213 ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) { 214 platform = "ppc64-linux"; 215 } 216 } 217 } 218 } 219 220 VG_(debugLog)(2, "launcher", "selected platform '%s'\n", 221 platform ? platform : "unknown"); 222 223 return platform; 224 } 225 226 /* Where we expect to find all our aux files */ 227 static const char *valgrind_lib = VG_LIBDIR; 228 229 int main(int argc, char** argv, char** envp) 230 { 231 int i, j, loglevel, r; 232 const char *toolname = NULL; 233 const char *clientname = NULL; 234 const char *platform; 235 const char *default_platform; 236 const char *cp; 237 char *toolfile; 238 char launcher_name[PATH_MAX+1]; 239 char* new_line; 240 char** new_env; 241 242 /* Start the debugging-log system ASAP. First find out how many 243 "-d"s were specified. This is a pre-scan of the command line. 244 At the same time, look for the tool name. */ 245 loglevel = 0; 246 for (i = 1; i < argc; i++) { 247 if (argv[i][0] != '-') { 248 clientname = argv[i]; 249 break; 250 } 251 if (0 == strcmp(argv[i], "--")) { 252 if (i+1 < argc) 253 clientname = argv[i+1]; 254 break; 255 } 256 if (0 == strcmp(argv[i], "-d")) 257 loglevel++; 258 if (0 == strncmp(argv[i], "--tool=", 7)) 259 toolname = argv[i] + 7; 260 } 261 262 /* ... and start the debug logger. Now we can safely emit logging 263 messages all through startup. */ 264 VG_(debugLog_startup)(loglevel, "Stage 1"); 265 266 /* Make sure we know which tool we're using */ 267 if (toolname) { 268 VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname); 269 } else { 270 VG_(debugLog)(1, "launcher", 271 "no tool requested, defaulting to 'memcheck'\n"); 272 toolname = "memcheck"; 273 } 274 275 /* Select a platform to use if we can't decide that by looking at 276 the executable (eg because it's a shell script). Note that the 277 default_platform is not necessarily either the primary or 278 secondary build target. Instead it's chosen to maximise the 279 chances that /bin/sh will work on it. Hence for a primary 280 target of ppc64-linux we still choose ppc32-linux as the default 281 target, because on most ppc64-linux setups, the basic /bin, 282 /usr/bin, etc, stuff is built in 32-bit mode, not 64-bit 283 mode. */ 284 if ((0==strcmp(VG_PLATFORM,"x86-linux")) || 285 (0==strcmp(VG_PLATFORM,"amd64-linux")) || 286 (0==strcmp(VG_PLATFORM,"ppc32-linux")) || 287 (0==strcmp(VG_PLATFORM,"ppc64-linux")) || 288 (0==strcmp(VG_PLATFORM,"arm-linux"))) 289 default_platform = VG_PLATFORM; 290 else 291 barf("Unknown VG_PLATFORM '%s'", VG_PLATFORM); 292 293 /* Work out what platform to use, or use the default platform if 294 not possible. */ 295 if (clientname == NULL) { 296 VG_(debugLog)(1, "launcher", 297 "no client specified, defaulting platform to '%s'\n", 298 default_platform); 299 platform = default_platform; 300 } else if ((platform = select_platform(clientname)) != NULL) { 301 VG_(debugLog)(1, "launcher", "selected platform '%s'\n", platform); 302 } else { 303 VG_(debugLog)(1, "launcher", 304 "no platform detected, defaulting platform to '%s'\n", 305 default_platform); 306 platform = default_platform; 307 } 308 309 /* Figure out the name of this executable (viz, the launcher), so 310 we can tell stage2. stage2 will use the name for recursive 311 invocations of valgrind on child processes. */ 312 memset(launcher_name, 0, PATH_MAX+1); 313 r = readlink("/proc/self/exe", launcher_name, PATH_MAX); 314 if (r == -1) { 315 /* If /proc/self/exe can't be followed, don't give up. Instead 316 continue with an empty string for VALGRIND_LAUNCHER. In the 317 sys_execve wrapper, this is tested, and if found to be empty, 318 fail the execve. */ 319 fprintf(stderr, "valgrind: warning (non-fatal): " 320 "readlink(\"/proc/self/exe\") failed.\n"); 321 fprintf(stderr, "valgrind: continuing, however --trace-children=yes " 322 "will not work.\n"); 323 } 324 325 /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */ 326 new_line = malloc(strlen(VALGRIND_LAUNCHER) + 1 327 + strlen(launcher_name) + 1); 328 if (new_line == NULL) 329 barf("malloc of new_line failed."); 330 strcpy(new_line, VALGRIND_LAUNCHER); 331 strcat(new_line, "="); 332 strcat(new_line, launcher_name); 333 334 for (j = 0; envp[j]; j++) 335 ; 336 new_env = malloc((j+2) * sizeof(char*)); 337 if (new_env == NULL) 338 barf("malloc of new_env failed."); 339 for (i = 0; i < j; i++) 340 new_env[i] = envp[i]; 341 new_env[i++] = new_line; 342 new_env[i++] = NULL; 343 assert(i == j+2); 344 345 /* Establish the correct VALGRIND_LIB. */ 346 cp = getenv(VALGRIND_LIB); 347 348 if (cp != NULL) 349 valgrind_lib = cp; 350 351 /* Build the stage2 invocation, and execve it. Bye! */ 352 toolfile = malloc(strlen(valgrind_lib) + strlen(toolname) + strlen(platform) + 3); 353 if (toolfile == NULL) 354 barf("malloc of toolfile failed."); 355 sprintf(toolfile, "%s/%s-%s", valgrind_lib, toolname, platform); 356 357 VG_(debugLog)(1, "launcher", "launching %s\n", toolfile); 358 359 execve(toolfile, argv, new_env); 360 361 fprintf(stderr, "valgrind: failed to start tool '%s' for platform '%s': %s\n", 362 toolname, platform, strerror(errno)); 363 364 exit(1); 365 } 366