PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/external/valgrind/main/coregrind/launcher-linux.c

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