Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 1 | //===-- sanitizer_file.cc ------------------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===---------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file is shared between AddressSanitizer and ThreadSanitizer |
| 11 | // run-time libraries. It defines filesystem-related interfaces. This |
| 12 | // is separate from sanitizer_common.cc so that it's simpler to disable |
| 13 | // all the filesystem support code for a port that doesn't use it. |
| 14 | // |
| 15 | //===---------------------------------------------------------------------===// |
| 16 | |
Vitaly Buka | 51ca757 | 2017-08-01 21:28:39 +0000 | [diff] [blame] | 17 | #include "sanitizer_platform.h" |
| 18 | |
| 19 | #if !SANITIZER_FUCHSIA |
| 20 | |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 21 | #include "sanitizer_common.h" |
| 22 | #include "sanitizer_file.h" |
| 23 | |
| 24 | namespace __sanitizer { |
| 25 | |
| 26 | void CatastrophicErrorWrite(const char *buffer, uptr length) { |
| 27 | WriteToFile(kStderrFd, buffer, length); |
| 28 | } |
| 29 | |
| 30 | StaticSpinMutex report_file_mu; |
| 31 | ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; |
| 32 | |
| 33 | void RawWrite(const char *buffer) { |
| 34 | report_file.Write(buffer, internal_strlen(buffer)); |
| 35 | } |
| 36 | |
| 37 | void ReportFile::ReopenIfNecessary() { |
| 38 | mu->CheckLocked(); |
| 39 | if (fd == kStdoutFd || fd == kStderrFd) return; |
| 40 | |
| 41 | uptr pid = internal_getpid(); |
| 42 | // If in tracer, use the parent's file. |
| 43 | if (pid == stoptheworld_tracer_pid) |
| 44 | pid = stoptheworld_tracer_ppid; |
| 45 | if (fd != kInvalidFd) { |
| 46 | // If the report file is already opened by the current process, |
| 47 | // do nothing. Otherwise the report file was opened by the parent |
| 48 | // process, close it now. |
| 49 | if (fd_pid == pid) |
| 50 | return; |
| 51 | else |
| 52 | CloseFile(fd); |
| 53 | } |
| 54 | |
| 55 | const char *exe_name = GetProcessName(); |
| 56 | if (common_flags()->log_exe_name && exe_name) { |
| 57 | internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, |
| 58 | exe_name, pid); |
| 59 | } else { |
| 60 | internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); |
| 61 | } |
| 62 | fd = OpenFile(full_path, WrOnly); |
| 63 | if (fd == kInvalidFd) { |
| 64 | const char *ErrorMsgPrefix = "ERROR: Can't open file: "; |
| 65 | WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); |
| 66 | WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); |
| 67 | Die(); |
| 68 | } |
| 69 | fd_pid = pid; |
| 70 | } |
| 71 | |
| 72 | void ReportFile::SetReportPath(const char *path) { |
| 73 | if (!path) |
| 74 | return; |
| 75 | uptr len = internal_strlen(path); |
| 76 | if (len > sizeof(path_prefix) - 100) { |
| 77 | Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", |
| 78 | path[0], path[1], path[2], path[3], |
| 79 | path[4], path[5], path[6], path[7]); |
| 80 | Die(); |
| 81 | } |
| 82 | |
| 83 | SpinMutexLock l(mu); |
| 84 | if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) |
| 85 | CloseFile(fd); |
| 86 | fd = kInvalidFd; |
| 87 | if (internal_strcmp(path, "stdout") == 0) { |
| 88 | fd = kStdoutFd; |
| 89 | } else if (internal_strcmp(path, "stderr") == 0) { |
| 90 | fd = kStderrFd; |
| 91 | } else { |
| 92 | internal_snprintf(path_prefix, kMaxPathLength, "%s", path); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, |
| 97 | uptr *read_len, uptr max_len, error_t *errno_p) { |
| 98 | uptr PageSize = GetPageSizeCached(); |
| 99 | uptr kMinFileLen = PageSize; |
| 100 | *buff = nullptr; |
| 101 | *buff_size = 0; |
| 102 | *read_len = 0; |
| 103 | // The files we usually open are not seekable, so try different buffer sizes. |
| 104 | for (uptr size = kMinFileLen; size <= max_len; size *= 2) { |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 105 | UnmapOrDie(*buff, *buff_size); |
| 106 | *buff = (char*)MmapOrDie(size, __func__); |
| 107 | *buff_size = size; |
Vitaly Buka | 6b13684 | 2018-05-08 18:32:53 +0000 | [diff] [blame^] | 108 | fd_t fd = OpenFile(file_name, RdOnly, errno_p); |
| 109 | if (fd == kInvalidFd) |
| 110 | return false; |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 111 | *read_len = 0; |
| 112 | // Read up to one page at a time. |
| 113 | bool reached_eof = false; |
| 114 | while (*read_len + PageSize <= size) { |
| 115 | uptr just_read; |
| 116 | if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { |
| 117 | UnmapOrDie(*buff, *buff_size); |
Vitaly Buka | 6b13684 | 2018-05-08 18:32:53 +0000 | [diff] [blame^] | 118 | CloseFile(fd); |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 119 | return false; |
| 120 | } |
| 121 | if (just_read == 0) { |
| 122 | reached_eof = true; |
| 123 | break; |
| 124 | } |
| 125 | *read_len += just_read; |
| 126 | } |
| 127 | CloseFile(fd); |
| 128 | if (reached_eof) // We've read the whole file. |
| 129 | break; |
| 130 | } |
| 131 | return true; |
| 132 | } |
| 133 | |
| 134 | static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; |
| 135 | |
| 136 | char *FindPathToBinary(const char *name) { |
| 137 | if (FileExists(name)) { |
| 138 | return internal_strdup(name); |
| 139 | } |
| 140 | |
| 141 | const char *path = GetEnv("PATH"); |
| 142 | if (!path) |
| 143 | return nullptr; |
| 144 | uptr name_len = internal_strlen(name); |
Vitaly Buka | 2a20955 | 2018-05-07 05:56:36 +0000 | [diff] [blame] | 145 | InternalMmapVector<char> buffer(kMaxPathLength); |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 146 | const char *beg = path; |
| 147 | while (true) { |
| 148 | const char *end = internal_strchrnul(beg, kPathSeparator); |
| 149 | uptr prefix_len = end - beg; |
| 150 | if (prefix_len + name_len + 2 <= kMaxPathLength) { |
| 151 | internal_memcpy(buffer.data(), beg, prefix_len); |
| 152 | buffer[prefix_len] = '/'; |
| 153 | internal_memcpy(&buffer[prefix_len + 1], name, name_len); |
| 154 | buffer[prefix_len + 1 + name_len] = '\0'; |
| 155 | if (FileExists(buffer.data())) |
| 156 | return internal_strdup(buffer.data()); |
| 157 | } |
| 158 | if (*end == '\0') break; |
| 159 | beg = end + 1; |
| 160 | } |
| 161 | return nullptr; |
| 162 | } |
| 163 | |
| 164 | } // namespace __sanitizer |
| 165 | |
| 166 | using namespace __sanitizer; // NOLINT |
| 167 | |
| 168 | extern "C" { |
| 169 | void __sanitizer_set_report_path(const char *path) { |
| 170 | report_file.SetReportPath(path); |
| 171 | } |
| 172 | |
| 173 | void __sanitizer_set_report_fd(void *fd) { |
| 174 | report_file.fd = (fd_t)reinterpret_cast<uptr>(fd); |
| 175 | report_file.fd_pid = internal_getpid(); |
| 176 | } |
| 177 | } // extern "C" |
Vitaly Buka | 51ca757 | 2017-08-01 21:28:39 +0000 | [diff] [blame] | 178 | |
| 179 | #endif // !SANITIZER_FUCHSIA |