1ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov//===-- sanitizer_symbolizer_posix_libcdep.cc -----------------------------===//
2ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov//
3ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov//                     The LLVM Compiler Infrastructure
4ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov//
5ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov// This file is distributed under the University of Illinois Open Source
6ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov// License. See LICENSE.TXT for details.
7ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov//
8ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov//===----------------------------------------------------------------------===//
9ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov//
10ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov// This file is shared between AddressSanitizer and ThreadSanitizer
11ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov// run-time libraries.
12ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov// POSIX-specific implementation of symbolizer parts.
13ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov//===----------------------------------------------------------------------===//
14ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
15ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov#include "sanitizer_platform.h"
16ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov#if SANITIZER_POSIX
17ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov#include "sanitizer_common.h"
18ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov#include "sanitizer_internal_defs.h"
19ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov#include "sanitizer_symbolizer.h"
20ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
21ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov#include <errno.h>
22ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov#include <sys/wait.h>
23ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov#include <unistd.h>
24ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
25ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonovnamespace __sanitizer {
26ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
2752d08d8412bfa4ccfa38384d781b51e8774807a7Alexey Samsonov#if defined(__x86_64__)
2852d08d8412bfa4ccfa38384d781b51e8774807a7Alexey Samsonovstatic const char* const kSymbolizerArch = "--default-arch=x86_64";
2952d08d8412bfa4ccfa38384d781b51e8774807a7Alexey Samsonov#elif defined(__i386__)
3052d08d8412bfa4ccfa38384d781b51e8774807a7Alexey Samsonovstatic const char* const kSymbolizerArch = "--default-arch=i386";
317aaaee4cab08096d46e9886c5fea8564732ad2ffAlexey Samsonov#elif defined(__powerpc64__)
327aaaee4cab08096d46e9886c5fea8564732ad2ffAlexey Samsonovstatic const char* const kSymbolizerArch = "--default-arch=powerpc64";
3352d08d8412bfa4ccfa38384d781b51e8774807a7Alexey Samsonov#else
347aaaee4cab08096d46e9886c5fea8564732ad2ffAlexey Samsonovstatic const char* const kSymbolizerArch = "--default-arch=unknown";
3552d08d8412bfa4ccfa38384d781b51e8774807a7Alexey Samsonov#endif
3652d08d8412bfa4ccfa38384d781b51e8774807a7Alexey Samsonov
37ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonovbool StartSymbolizerSubprocess(const char *path_to_symbolizer,
38ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov                               int *input_fd, int *output_fd) {
39ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  if (!FileExists(path_to_symbolizer)) {
40ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    Report("WARNING: invalid path to external symbolizer!\n");
41ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    return false;
42ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  }
43ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
44ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  int *infd = NULL;
45ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  int *outfd = NULL;
46ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  // The client program may close its stdin and/or stdout and/or stderr
47ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
48ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  // In this case the communication between the forked processes may be
49ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  // broken if either the parent or the child tries to close or duplicate
50ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  // these descriptors. The loop below produces two pairs of file
51ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  // descriptors, each greater than 2 (stderr).
52ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  int sock_pair[5][2];
53ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  for (int i = 0; i < 5; i++) {
54ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    if (pipe(sock_pair[i]) == -1) {
55ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov      for (int j = 0; j < i; j++) {
56ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov        internal_close(sock_pair[j][0]);
57ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov        internal_close(sock_pair[j][1]);
58ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov      }
59ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov      Report("WARNING: Can't create a socket pair to start "
60ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov             "external symbolizer (errno: %d)\n", errno);
61ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov      return false;
62ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
63ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov      if (infd == NULL) {
64ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov        infd = sock_pair[i];
65ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov      } else {
66ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov        outfd = sock_pair[i];
67ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov        for (int j = 0; j < i; j++) {
68ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov          if (sock_pair[j] == infd) continue;
69ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov          internal_close(sock_pair[j][0]);
70ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov          internal_close(sock_pair[j][1]);
71ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov        }
72ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov        break;
73ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov      }
74ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    }
75ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  }
76ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  CHECK(infd);
77ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  CHECK(outfd);
78ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
79ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  int pid = fork();
80ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  if (pid == -1) {
81ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    // Fork() failed.
82ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(infd[0]);
83ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(infd[1]);
84ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(outfd[0]);
85ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(outfd[1]);
86ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    Report("WARNING: failed to fork external symbolizer "
87ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov           " (errno: %d)\n", errno);
88ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    return false;
89ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  } else if (pid == 0) {
90ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    // Child subprocess.
91ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(STDOUT_FILENO);
92ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(STDIN_FILENO);
93ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_dup2(outfd[0], STDIN_FILENO);
94ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_dup2(infd[1], STDOUT_FILENO);
95ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(outfd[0]);
96ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(outfd[1]);
97ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(infd[0]);
98ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal_close(infd[1]);
99ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    for (int fd = getdtablesize(); fd > 2; fd--)
100ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov      internal_close(fd);
10152d08d8412bfa4ccfa38384d781b51e8774807a7Alexey Samsonov    execl(path_to_symbolizer, path_to_symbolizer, kSymbolizerArch, (char*)0);
102ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    internal__exit(1);
103ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  }
104ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
105ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  // Continue execution in parent process.
106ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  internal_close(outfd[0]);
107ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  internal_close(infd[1]);
108ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  *input_fd = infd[0];
109ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  *output_fd = outfd[1];
110ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
111ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  // Check that symbolizer subprocess started successfully.
112ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  int pid_status;
113ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  SleepForMillis(kSymbolizerStartupTimeMillis);
114ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
115ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  if (exited_pid != 0) {
116ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    // Either waitpid failed, or child has already exited.
117ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    Report("WARNING: external symbolizer didn't start up correctly!\n");
118ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov    return false;
119ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  }
120ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
121ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov  return true;
122ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov}
123ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
124ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
125ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov}  // namespace __sanitizer
126ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov
127ff0ce7fbdba7d02dd06bbb1ba1003c50355513dfAlexey Samsonov#endif  // SANITIZER_POSIX
128