| File: | src/gnu/usr.bin/clang/liblldbHostCommon/../../../llvm/lldb/source/Host/common/Host.cpp |
| Warning: | line 269, column 13 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | //===-- Host.cpp ----------------------------------------------------------===// | ||||
| 2 | // | ||||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
| 6 | // | ||||
| 7 | //===----------------------------------------------------------------------===// | ||||
| 8 | |||||
| 9 | // C includes | ||||
| 10 | #include <cerrno> | ||||
| 11 | #include <climits> | ||||
| 12 | #include <cstdlib> | ||||
| 13 | #include <sys/types.h> | ||||
| 14 | #ifndef _WIN32 | ||||
| 15 | #include <dlfcn.h> | ||||
| 16 | #include <grp.h> | ||||
| 17 | #include <netdb.h> | ||||
| 18 | #include <pwd.h> | ||||
| 19 | #include <sys/stat.h> | ||||
| 20 | #include <unistd.h> | ||||
| 21 | #endif | ||||
| 22 | |||||
| 23 | #if defined(__APPLE__) | ||||
| 24 | #include <mach-o/dyld.h> | ||||
| 25 | #include <mach/mach_init.h> | ||||
| 26 | #include <mach/mach_port.h> | ||||
| 27 | #endif | ||||
| 28 | |||||
| 29 | #if defined(__linux__) || defined(__FreeBSD__) || \ | ||||
| 30 | defined(__FreeBSD_kernel__) || defined(__APPLE__) || \ | ||||
| 31 | defined(__NetBSD__) || defined(__OpenBSD__1) || defined(__EMSCRIPTEN__) | ||||
| 32 | #if !defined(__ANDROID__) | ||||
| 33 | #include <spawn.h> | ||||
| 34 | #endif | ||||
| 35 | #include <sys/syscall.h> | ||||
| 36 | #include <sys/wait.h> | ||||
| 37 | #endif | ||||
| 38 | |||||
| 39 | #if defined(__FreeBSD__) | ||||
| 40 | #include <pthread_np.h> | ||||
| 41 | #endif | ||||
| 42 | |||||
| 43 | #if defined(__NetBSD__) | ||||
| 44 | #include <lwp.h> | ||||
| 45 | #endif | ||||
| 46 | |||||
| 47 | #include <csignal> | ||||
| 48 | |||||
| 49 | #include "lldb/Host/FileAction.h" | ||||
| 50 | #include "lldb/Host/FileSystem.h" | ||||
| 51 | #include "lldb/Host/Host.h" | ||||
| 52 | #include "lldb/Host/HostInfo.h" | ||||
| 53 | #include "lldb/Host/HostProcess.h" | ||||
| 54 | #include "lldb/Host/MonitoringProcessLauncher.h" | ||||
| 55 | #include "lldb/Host/ProcessLaunchInfo.h" | ||||
| 56 | #include "lldb/Host/ProcessLauncher.h" | ||||
| 57 | #include "lldb/Host/ThreadLauncher.h" | ||||
| 58 | #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" | ||||
| 59 | #include "lldb/Utility/DataBufferLLVM.h" | ||||
| 60 | #include "lldb/Utility/FileSpec.h" | ||||
| 61 | #include "lldb/Utility/Log.h" | ||||
| 62 | #include "lldb/Utility/Predicate.h" | ||||
| 63 | #include "lldb/Utility/ReproducerProvider.h" | ||||
| 64 | #include "lldb/Utility/Status.h" | ||||
| 65 | #include "lldb/lldb-private-forward.h" | ||||
| 66 | #include "llvm/ADT/SmallString.h" | ||||
| 67 | #include "llvm/ADT/StringSwitch.h" | ||||
| 68 | #include "llvm/Support/Errno.h" | ||||
| 69 | #include "llvm/Support/FileSystem.h" | ||||
| 70 | |||||
| 71 | #if defined(_WIN32) | ||||
| 72 | #include "lldb/Host/windows/ConnectionGenericFileWindows.h" | ||||
| 73 | #include "lldb/Host/windows/ProcessLauncherWindows.h" | ||||
| 74 | #else | ||||
| 75 | #include "lldb/Host/posix/ProcessLauncherPosixFork.h" | ||||
| 76 | #endif | ||||
| 77 | |||||
| 78 | #if defined(__APPLE__) | ||||
| 79 | #ifndef _POSIX_SPAWN_DISABLE_ASLR | ||||
| 80 | #define _POSIX_SPAWN_DISABLE_ASLR 0x0100 | ||||
| 81 | #endif | ||||
| 82 | |||||
| 83 | extern "C" { | ||||
| 84 | int __pthread_chdir(const char *path); | ||||
| 85 | int __pthread_fchdir(int fildes); | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | #endif | ||||
| 89 | |||||
| 90 | using namespace lldb; | ||||
| 91 | using namespace lldb_private; | ||||
| 92 | |||||
| 93 | #if !defined(__APPLE__) && !defined(_WIN32) | ||||
| 94 | struct MonitorInfo { | ||||
| 95 | lldb::pid_t pid; // The process ID to monitor | ||||
| 96 | Host::MonitorChildProcessCallback | ||||
| 97 | callback; // The callback function to call when "pid" exits or signals | ||||
| 98 | bool monitor_signals; // If true, call the callback when "pid" gets signaled. | ||||
| 99 | }; | ||||
| 100 | |||||
| 101 | static thread_result_t MonitorChildProcessThreadFunction(void *arg); | ||||
| 102 | |||||
| 103 | llvm::Expected<HostThread> Host::StartMonitoringChildProcess( | ||||
| 104 | const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, | ||||
| 105 | bool monitor_signals) { | ||||
| 106 | MonitorInfo *info_ptr = new MonitorInfo(); | ||||
| 107 | |||||
| 108 | info_ptr->pid = pid; | ||||
| 109 | info_ptr->callback = callback; | ||||
| 110 | info_ptr->monitor_signals = monitor_signals; | ||||
| 111 | |||||
| 112 | char thread_name[256]; | ||||
| 113 | ::snprintf(thread_name, sizeof(thread_name), | ||||
| 114 | "<lldb.host.wait4(pid=%" PRIu64"llu" ")>", pid); | ||||
| 115 | return ThreadLauncher::LaunchThread( | ||||
| 116 | thread_name, MonitorChildProcessThreadFunction, info_ptr, 0); | ||||
| 117 | } | ||||
| 118 | |||||
| 119 | #ifndef __linux__ | ||||
| 120 | // Scoped class that will disable thread canceling when it is constructed, and | ||||
| 121 | // exception safely restore the previous value it when it goes out of scope. | ||||
| 122 | class ScopedPThreadCancelDisabler { | ||||
| 123 | public: | ||||
| 124 | ScopedPThreadCancelDisabler() { | ||||
| 125 | // Disable the ability for this thread to be cancelled | ||||
| 126 | int err = ::pthread_setcancelstate(PTHREAD_CANCEL_DISABLE1, &m_old_state); | ||||
| 127 | if (err != 0) | ||||
| 128 | m_old_state = -1; | ||||
| 129 | } | ||||
| 130 | |||||
| 131 | ~ScopedPThreadCancelDisabler() { | ||||
| 132 | // Restore the ability for this thread to be cancelled to what it | ||||
| 133 | // previously was. | ||||
| 134 | if (m_old_state != -1) | ||||
| 135 | ::pthread_setcancelstate(m_old_state, 0); | ||||
| 136 | } | ||||
| 137 | |||||
| 138 | private: | ||||
| 139 | int m_old_state; // Save the old cancelability state. | ||||
| 140 | }; | ||||
| 141 | #endif // __linux__ | ||||
| 142 | |||||
| 143 | #ifdef __linux__ | ||||
| 144 | #if defined(__GNUC__4) && (__GNUC__4 < 4 || (__GNUC__4 == 4 && __GNUC_MINOR__2 < 8)) | ||||
| 145 | static __thread volatile sig_atomic_t g_usr1_called; | ||||
| 146 | #else | ||||
| 147 | static thread_local volatile sig_atomic_t g_usr1_called; | ||||
| 148 | #endif | ||||
| 149 | |||||
| 150 | static void SigUsr1Handler(int) { g_usr1_called = 1; } | ||||
| 151 | #endif // __linux__ | ||||
| 152 | |||||
| 153 | static bool CheckForMonitorCancellation() { | ||||
| 154 | #ifdef __linux__ | ||||
| 155 | if (g_usr1_called) { | ||||
| 156 | g_usr1_called = 0; | ||||
| 157 | return true; | ||||
| 158 | } | ||||
| 159 | #else | ||||
| 160 | ::pthread_testcancel(); | ||||
| 161 | #endif | ||||
| 162 | return false; | ||||
| 163 | } | ||||
| 164 | |||||
| 165 | static thread_result_t MonitorChildProcessThreadFunction(void *arg) { | ||||
| 166 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS(1u << 1))); | ||||
| 167 | const char *function = __FUNCTION__; | ||||
| 168 | LLDB_LOGF(log, "%s (arg = %p) thread starting...", function, arg)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread starting...", function , arg); } while (0); | ||||
| |||||
| 169 | |||||
| 170 | MonitorInfo *info = (MonitorInfo *)arg; | ||||
| 171 | |||||
| 172 | const Host::MonitorChildProcessCallback callback = info->callback; | ||||
| 173 | const bool monitor_signals = info->monitor_signals; | ||||
| 174 | |||||
| 175 | assert(info->pid <= UINT32_MAX)((void)0); | ||||
| 176 | const ::pid_t pid = monitor_signals ? -1 * getpgid(info->pid) : info->pid; | ||||
| 177 | |||||
| 178 | delete info; | ||||
| 179 | |||||
| 180 | int status = -1; | ||||
| 181 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__1) | ||||
| 182 | #define __WALL0 0 | ||||
| 183 | #endif | ||||
| 184 | const int options = __WALL0; | ||||
| 185 | |||||
| 186 | #ifdef __linux__ | ||||
| 187 | // This signal is only used to interrupt the thread from waitpid | ||||
| 188 | struct sigaction sigUsr1Action; | ||||
| 189 | memset(&sigUsr1Action, 0, sizeof(sigUsr1Action)); | ||||
| 190 | sigUsr1Action.sa_handler__sigaction_u.__sa_handler = SigUsr1Handler; | ||||
| 191 | ::sigaction(SIGUSR130, &sigUsr1Action, nullptr); | ||||
| 192 | #endif // __linux__ | ||||
| 193 | |||||
| 194 | while (1) { | ||||
| 195 | log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS(1u << 1)); | ||||
| 196 | LLDB_LOGF(log, "%s ::waitpid (pid = %" PRIi32 ", &status, options = %i)...",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s ::waitpid (pid = %" "i" ", &status, options = %i)..." , function, pid, options); } while (0) | ||||
| 197 | function, pid, options)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s ::waitpid (pid = %" "i" ", &status, options = %i)..." , function, pid, options); } while (0); | ||||
| 198 | |||||
| 199 | if (CheckForMonitorCancellation()) | ||||
| 200 | break; | ||||
| 201 | |||||
| 202 | // Get signals from all children with same process group of pid | ||||
| 203 | const ::pid_t wait_pid = ::waitpid(pid, &status, options); | ||||
| 204 | |||||
| 205 | if (CheckForMonitorCancellation()) | ||||
| 206 | break; | ||||
| 207 | |||||
| 208 | if (wait_pid == -1) { | ||||
| 209 | if (errno(*__errno()) == EINTR4) | ||||
| 210 | continue; | ||||
| 211 | else { | ||||
| 212 | LLDB_LOG(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbHostCommon/../../../llvm/lldb/source/Host/common/Host.cpp" , __func__, "arg = {0}, thread exiting because waitpid failed ({1})..." , arg, llvm::sys::StrError()); } while (0) | ||||
| 213 | "arg = {0}, thread exiting because waitpid failed ({1})...",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbHostCommon/../../../llvm/lldb/source/Host/common/Host.cpp" , __func__, "arg = {0}, thread exiting because waitpid failed ({1})..." , arg, llvm::sys::StrError()); } while (0) | ||||
| 214 | arg, llvm::sys::StrError())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbHostCommon/../../../llvm/lldb/source/Host/common/Host.cpp" , __func__, "arg = {0}, thread exiting because waitpid failed ({1})..." , arg, llvm::sys::StrError()); } while (0); | ||||
| 215 | break; | ||||
| 216 | } | ||||
| 217 | } else if (wait_pid > 0) { | ||||
| 218 | bool exited = false; | ||||
| 219 | int signal = 0; | ||||
| 220 | int exit_status = 0; | ||||
| 221 | const char *status_cstr = nullptr; | ||||
| 222 | if (WIFSTOPPED(status)(((status) & 0xff) == 0177)) { | ||||
| 223 | signal = WSTOPSIG(status)(int)(((unsigned)(status) >> 8) & 0xff); | ||||
| 224 | status_cstr = "STOPPED"; | ||||
| 225 | } else if (WIFEXITED(status)(((status) & 0177) == 0)) { | ||||
| 226 | exit_status = WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff); | ||||
| 227 | status_cstr = "EXITED"; | ||||
| 228 | exited = true; | ||||
| 229 | } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177 ) != 0)) { | ||||
| 230 | signal = WTERMSIG(status)(((status) & 0177)); | ||||
| 231 | status_cstr = "SIGNALED"; | ||||
| 232 | if (wait_pid == abs(pid)) { | ||||
| 233 | exited = true; | ||||
| 234 | exit_status = -1; | ||||
| 235 | } | ||||
| 236 | } else { | ||||
| 237 | status_cstr = "(\?\?\?)"; | ||||
| 238 | } | ||||
| 239 | |||||
| 240 | // Scope for pthread_cancel_disabler | ||||
| 241 | { | ||||
| 242 | #ifndef __linux__ | ||||
| 243 | ScopedPThreadCancelDisabler pthread_cancel_disabler; | ||||
| 244 | #endif | ||||
| 245 | |||||
| 246 | log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS(1u << 1)); | ||||
| 247 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s ::waitpid (pid = %" "i" ", &status, options = %i) => pid = %" "i" ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", function, pid, options, wait_pid, status, status_cstr, signal , exit_status); } while (0) | ||||
| 248 | "%s ::waitpid (pid = %" PRIi32do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s ::waitpid (pid = %" "i" ", &status, options = %i) => pid = %" "i" ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", function, pid, options, wait_pid, status, status_cstr, signal , exit_status); } while (0) | ||||
| 249 | ", &status, options = %i) => pid = %" PRIi32do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s ::waitpid (pid = %" "i" ", &status, options = %i) => pid = %" "i" ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", function, pid, options, wait_pid, status, status_cstr, signal , exit_status); } while (0) | ||||
| 250 | ", status = 0x%8.8x (%s), signal = %i, exit_state = %i",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s ::waitpid (pid = %" "i" ", &status, options = %i) => pid = %" "i" ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", function, pid, options, wait_pid, status, status_cstr, signal , exit_status); } while (0) | ||||
| 251 | function, pid, options, wait_pid, status, status_cstr, signal,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s ::waitpid (pid = %" "i" ", &status, options = %i) => pid = %" "i" ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", function, pid, options, wait_pid, status, status_cstr, signal , exit_status); } while (0) | ||||
| 252 | exit_status)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s ::waitpid (pid = %" "i" ", &status, options = %i) => pid = %" "i" ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", function, pid, options, wait_pid, status, status_cstr, signal , exit_status); } while (0); | ||||
| 253 | |||||
| 254 | if (exited
| ||||
| 255 | bool callback_return = false; | ||||
| 256 | if (callback) | ||||
| 257 | callback_return = callback(wait_pid, exited, signal, exit_status); | ||||
| 258 | |||||
| 259 | // If our process exited, then this thread should exit | ||||
| 260 | if (exited
| ||||
| 261 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread exiting because pid received " "exit signal...", __FUNCTION__, arg); } while (0) | ||||
| 262 | "%s (arg = %p) thread exiting because pid received "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread exiting because pid received " "exit signal...", __FUNCTION__, arg); } while (0) | ||||
| 263 | "exit signal...",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread exiting because pid received " "exit signal...", __FUNCTION__, arg); } while (0) | ||||
| 264 | __FUNCTION__, arg)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread exiting because pid received " "exit signal...", __FUNCTION__, arg); } while (0); | ||||
| 265 | break; | ||||
| 266 | } | ||||
| 267 | // If the callback returns true, it means this process should exit | ||||
| 268 | if (callback_return) { | ||||
| 269 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread exiting because callback " "returned true...", __FUNCTION__, arg); } while (0) | ||||
| |||||
| 270 | "%s (arg = %p) thread exiting because callback "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread exiting because callback " "returned true...", __FUNCTION__, arg); } while (0) | ||||
| 271 | "returned true...",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread exiting because callback " "returned true...", __FUNCTION__, arg); } while (0) | ||||
| 272 | __FUNCTION__, arg)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread exiting because callback " "returned true...", __FUNCTION__, arg); } while (0); | ||||
| 273 | break; | ||||
| 274 | } | ||||
| 275 | } | ||||
| 276 | } | ||||
| 277 | } | ||||
| 278 | } | ||||
| 279 | |||||
| 280 | log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS(1u << 1)); | ||||
| 281 | LLDB_LOGF(log, "%s (arg = %p) thread exiting...", __FUNCTION__, arg)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%s (arg = %p) thread exiting...", __FUNCTION__ , arg); } while (0); | ||||
| 282 | |||||
| 283 | return nullptr; | ||||
| 284 | } | ||||
| 285 | |||||
| 286 | #endif // #if !defined (__APPLE__) && !defined (_WIN32) | ||||
| 287 | |||||
| 288 | #if !defined(__APPLE__) | ||||
| 289 | |||||
| 290 | void Host::SystemLog(SystemLogType type, const char *format, va_list args) { | ||||
| 291 | vfprintf(stderr(&__sF[2]), format, args); | ||||
| 292 | } | ||||
| 293 | |||||
| 294 | #endif | ||||
| 295 | |||||
| 296 | void Host::SystemLog(SystemLogType type, const char *format, ...) { | ||||
| 297 | { | ||||
| 298 | va_list args; | ||||
| 299 | va_start(args, format)__builtin_va_start(args, format); | ||||
| 300 | SystemLog(type, format, args); | ||||
| 301 | va_end(args)__builtin_va_end(args); | ||||
| 302 | } | ||||
| 303 | |||||
| 304 | Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST(1u << 14))); | ||||
| 305 | if (log && log->GetVerbose()) { | ||||
| 306 | // Log to log channel. This allows testcases to grep for log output. | ||||
| 307 | va_list args; | ||||
| 308 | va_start(args, format)__builtin_va_start(args, format); | ||||
| 309 | log->VAPrintf(format, args); | ||||
| 310 | va_end(args)__builtin_va_end(args); | ||||
| 311 | } | ||||
| 312 | } | ||||
| 313 | |||||
| 314 | lldb::pid_t Host::GetCurrentProcessID() { return ::getpid(); } | ||||
| 315 | |||||
| 316 | #ifndef _WIN32 | ||||
| 317 | |||||
| 318 | lldb::thread_t Host::GetCurrentThread() { | ||||
| 319 | return lldb::thread_t(pthread_self()); | ||||
| 320 | } | ||||
| 321 | |||||
| 322 | const char *Host::GetSignalAsCString(int signo) { | ||||
| 323 | switch (signo) { | ||||
| 324 | case SIGHUP1: | ||||
| 325 | return "SIGHUP"; // 1 hangup | ||||
| 326 | case SIGINT2: | ||||
| 327 | return "SIGINT"; // 2 interrupt | ||||
| 328 | case SIGQUIT3: | ||||
| 329 | return "SIGQUIT"; // 3 quit | ||||
| 330 | case SIGILL4: | ||||
| 331 | return "SIGILL"; // 4 illegal instruction (not reset when caught) | ||||
| 332 | case SIGTRAP5: | ||||
| 333 | return "SIGTRAP"; // 5 trace trap (not reset when caught) | ||||
| 334 | case SIGABRT6: | ||||
| 335 | return "SIGABRT"; // 6 abort() | ||||
| 336 | #if defined(SIGPOLL) | ||||
| 337 | #if !defined(SIGIO23) || (SIGPOLL != SIGIO23) | ||||
| 338 | // Under some GNU/Linux, SIGPOLL and SIGIO are the same. Causing the build to | ||||
| 339 | // fail with 'multiple define cases with same value' | ||||
| 340 | case SIGPOLL: | ||||
| 341 | return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported) | ||||
| 342 | #endif | ||||
| 343 | #endif | ||||
| 344 | #if defined(SIGEMT7) | ||||
| 345 | case SIGEMT7: | ||||
| 346 | return "SIGEMT"; // 7 EMT instruction | ||||
| 347 | #endif | ||||
| 348 | case SIGFPE8: | ||||
| 349 | return "SIGFPE"; // 8 floating point exception | ||||
| 350 | case SIGKILL9: | ||||
| 351 | return "SIGKILL"; // 9 kill (cannot be caught or ignored) | ||||
| 352 | case SIGBUS10: | ||||
| 353 | return "SIGBUS"; // 10 bus error | ||||
| 354 | case SIGSEGV11: | ||||
| 355 | return "SIGSEGV"; // 11 segmentation violation | ||||
| 356 | case SIGSYS12: | ||||
| 357 | return "SIGSYS"; // 12 bad argument to system call | ||||
| 358 | case SIGPIPE13: | ||||
| 359 | return "SIGPIPE"; // 13 write on a pipe with no one to read it | ||||
| 360 | case SIGALRM14: | ||||
| 361 | return "SIGALRM"; // 14 alarm clock | ||||
| 362 | case SIGTERM15: | ||||
| 363 | return "SIGTERM"; // 15 software termination signal from kill | ||||
| 364 | case SIGURG16: | ||||
| 365 | return "SIGURG"; // 16 urgent condition on IO channel | ||||
| 366 | case SIGSTOP17: | ||||
| 367 | return "SIGSTOP"; // 17 sendable stop signal not from tty | ||||
| 368 | case SIGTSTP18: | ||||
| 369 | return "SIGTSTP"; // 18 stop signal from tty | ||||
| 370 | case SIGCONT19: | ||||
| 371 | return "SIGCONT"; // 19 continue a stopped process | ||||
| 372 | case SIGCHLD20: | ||||
| 373 | return "SIGCHLD"; // 20 to parent on child stop or exit | ||||
| 374 | case SIGTTIN21: | ||||
| 375 | return "SIGTTIN"; // 21 to readers pgrp upon background tty read | ||||
| 376 | case SIGTTOU22: | ||||
| 377 | return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local<OSTOP) | ||||
| 378 | #if defined(SIGIO23) | ||||
| 379 | case SIGIO23: | ||||
| 380 | return "SIGIO"; // 23 input/output possible signal | ||||
| 381 | #endif | ||||
| 382 | case SIGXCPU24: | ||||
| 383 | return "SIGXCPU"; // 24 exceeded CPU time limit | ||||
| 384 | case SIGXFSZ25: | ||||
| 385 | return "SIGXFSZ"; // 25 exceeded file size limit | ||||
| 386 | case SIGVTALRM26: | ||||
| 387 | return "SIGVTALRM"; // 26 virtual time alarm | ||||
| 388 | case SIGPROF27: | ||||
| 389 | return "SIGPROF"; // 27 profiling time alarm | ||||
| 390 | #if defined(SIGWINCH28) | ||||
| 391 | case SIGWINCH28: | ||||
| 392 | return "SIGWINCH"; // 28 window size changes | ||||
| 393 | #endif | ||||
| 394 | #if defined(SIGINFO29) | ||||
| 395 | case SIGINFO29: | ||||
| 396 | return "SIGINFO"; // 29 information request | ||||
| 397 | #endif | ||||
| 398 | case SIGUSR130: | ||||
| 399 | return "SIGUSR1"; // 30 user defined signal 1 | ||||
| 400 | case SIGUSR231: | ||||
| 401 | return "SIGUSR2"; // 31 user defined signal 2 | ||||
| 402 | default: | ||||
| 403 | break; | ||||
| 404 | } | ||||
| 405 | return nullptr; | ||||
| 406 | } | ||||
| 407 | |||||
| 408 | #endif | ||||
| 409 | |||||
| 410 | #if !defined(__APPLE__) // see Host.mm | ||||
| 411 | |||||
| 412 | bool Host::GetBundleDirectory(const FileSpec &file, FileSpec &bundle) { | ||||
| 413 | bundle.Clear(); | ||||
| 414 | return false; | ||||
| 415 | } | ||||
| 416 | |||||
| 417 | bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } | ||||
| 418 | #endif | ||||
| 419 | |||||
| 420 | #ifndef _WIN32 | ||||
| 421 | |||||
| 422 | FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { | ||||
| 423 | FileSpec module_filespec; | ||||
| 424 | #if !defined(__ANDROID__) | ||||
| 425 | Dl_info info; | ||||
| 426 | if (::dladdr(host_addr, &info)) { | ||||
| 427 | if (info.dli_fname) { | ||||
| 428 | module_filespec.SetFile(info.dli_fname, FileSpec::Style::native); | ||||
| 429 | FileSystem::Instance().Resolve(module_filespec); | ||||
| 430 | } | ||||
| 431 | } | ||||
| 432 | #endif | ||||
| 433 | return module_filespec; | ||||
| 434 | } | ||||
| 435 | |||||
| 436 | #endif | ||||
| 437 | |||||
| 438 | #if !defined(__linux__) | ||||
| 439 | bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { | ||||
| 440 | return false; | ||||
| 441 | } | ||||
| 442 | #endif | ||||
| 443 | |||||
| 444 | struct ShellInfo { | ||||
| 445 | ShellInfo() : process_reaped(false) {} | ||||
| 446 | |||||
| 447 | lldb_private::Predicate<bool> process_reaped; | ||||
| 448 | lldb::pid_t pid = LLDB_INVALID_PROCESS_ID0; | ||||
| 449 | int signo = -1; | ||||
| 450 | int status = -1; | ||||
| 451 | }; | ||||
| 452 | |||||
| 453 | static bool | ||||
| 454 | MonitorShellCommand(std::shared_ptr<ShellInfo> shell_info, lldb::pid_t pid, | ||||
| 455 | bool exited, // True if the process did exit | ||||
| 456 | int signo, // Zero for no signal | ||||
| 457 | int status) // Exit value of process if signal is zero | ||||
| 458 | { | ||||
| 459 | shell_info->pid = pid; | ||||
| 460 | shell_info->signo = signo; | ||||
| 461 | shell_info->status = status; | ||||
| 462 | // Let the thread running Host::RunShellCommand() know that the process | ||||
| 463 | // exited and that ShellInfo has been filled in by broadcasting to it | ||||
| 464 | shell_info->process_reaped.SetValue(true, eBroadcastAlways); | ||||
| 465 | return true; | ||||
| 466 | } | ||||
| 467 | |||||
| 468 | Status Host::RunShellCommand(llvm::StringRef command, | ||||
| 469 | const FileSpec &working_dir, int *status_ptr, | ||||
| 470 | int *signo_ptr, std::string *command_output_ptr, | ||||
| 471 | const Timeout<std::micro> &timeout, | ||||
| 472 | bool run_in_shell, bool hide_stderr) { | ||||
| 473 | return RunShellCommand(llvm::StringRef(), Args(command), working_dir, | ||||
| 474 | status_ptr, signo_ptr, command_output_ptr, timeout, | ||||
| 475 | run_in_shell, hide_stderr); | ||||
| 476 | } | ||||
| 477 | |||||
| 478 | Status Host::RunShellCommand(llvm::StringRef shell_path, | ||||
| 479 | llvm::StringRef command, | ||||
| 480 | const FileSpec &working_dir, int *status_ptr, | ||||
| 481 | int *signo_ptr, std::string *command_output_ptr, | ||||
| 482 | const Timeout<std::micro> &timeout, | ||||
| 483 | bool run_in_shell, bool hide_stderr) { | ||||
| 484 | return RunShellCommand(shell_path, Args(command), working_dir, status_ptr, | ||||
| 485 | signo_ptr, command_output_ptr, timeout, run_in_shell, | ||||
| 486 | hide_stderr); | ||||
| 487 | } | ||||
| 488 | |||||
| 489 | Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir, | ||||
| 490 | int *status_ptr, int *signo_ptr, | ||||
| 491 | std::string *command_output_ptr, | ||||
| 492 | const Timeout<std::micro> &timeout, | ||||
| 493 | bool run_in_shell, bool hide_stderr) { | ||||
| 494 | return RunShellCommand(llvm::StringRef(), args, working_dir, status_ptr, | ||||
| 495 | signo_ptr, command_output_ptr, timeout, run_in_shell, | ||||
| 496 | hide_stderr); | ||||
| 497 | } | ||||
| 498 | |||||
| 499 | Status Host::RunShellCommand(llvm::StringRef shell_path, const Args &args, | ||||
| 500 | const FileSpec &working_dir, int *status_ptr, | ||||
| 501 | int *signo_ptr, std::string *command_output_ptr, | ||||
| 502 | const Timeout<std::micro> &timeout, | ||||
| 503 | bool run_in_shell, bool hide_stderr) { | ||||
| 504 | Status error; | ||||
| 505 | ProcessLaunchInfo launch_info; | ||||
| 506 | launch_info.SetArchitecture(HostInfo::GetArchitecture()); | ||||
| 507 | if (run_in_shell) { | ||||
| 508 | // Run the command in a shell | ||||
| 509 | FileSpec shell = HostInfo::GetDefaultShell(); | ||||
| 510 | if (!shell_path.empty()) | ||||
| 511 | shell.SetPath(shell_path); | ||||
| 512 | |||||
| 513 | launch_info.SetShell(shell); | ||||
| 514 | launch_info.GetArguments().AppendArguments(args); | ||||
| 515 | const bool will_debug = false; | ||||
| 516 | const bool first_arg_is_full_shell_command = false; | ||||
| 517 | launch_info.ConvertArgumentsForLaunchingInShell( | ||||
| 518 | error, will_debug, first_arg_is_full_shell_command, 0); | ||||
| 519 | } else { | ||||
| 520 | // No shell, just run it | ||||
| 521 | const bool first_arg_is_executable = true; | ||||
| 522 | launch_info.SetArguments(args, first_arg_is_executable); | ||||
| 523 | } | ||||
| 524 | |||||
| 525 | launch_info.GetEnvironment() = Host::GetEnvironment(); | ||||
| 526 | |||||
| 527 | if (working_dir) | ||||
| 528 | launch_info.SetWorkingDirectory(working_dir); | ||||
| 529 | llvm::SmallString<64> output_file_path; | ||||
| 530 | |||||
| 531 | if (command_output_ptr) { | ||||
| 532 | // Create a temporary file to get the stdout/stderr and redirect the output | ||||
| 533 | // of the command into this file. We will later read this file if all goes | ||||
| 534 | // well and fill the data into "command_output_ptr" | ||||
| 535 | if (FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir()) { | ||||
| 536 | tmpdir_file_spec.AppendPathComponent("lldb-shell-output.%%%%%%"); | ||||
| 537 | llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(), | ||||
| 538 | output_file_path); | ||||
| 539 | } else { | ||||
| 540 | llvm::sys::fs::createTemporaryFile("lldb-shell-output.%%%%%%", "", | ||||
| 541 | output_file_path); | ||||
| 542 | } | ||||
| 543 | } | ||||
| 544 | |||||
| 545 | FileSpec output_file_spec(output_file_path.str()); | ||||
| 546 | // Set up file descriptors. | ||||
| 547 | launch_info.AppendSuppressFileAction(STDIN_FILENO0, true, false); | ||||
| 548 | if (output_file_spec) | ||||
| 549 | launch_info.AppendOpenFileAction(STDOUT_FILENO1, output_file_spec, false, | ||||
| 550 | true); | ||||
| 551 | else | ||||
| 552 | launch_info.AppendSuppressFileAction(STDOUT_FILENO1, false, true); | ||||
| 553 | |||||
| 554 | if (output_file_spec && !hide_stderr) | ||||
| 555 | launch_info.AppendDuplicateFileAction(STDOUT_FILENO1, STDERR_FILENO2); | ||||
| 556 | else | ||||
| 557 | launch_info.AppendSuppressFileAction(STDERR_FILENO2, false, true); | ||||
| 558 | |||||
| 559 | std::shared_ptr<ShellInfo> shell_info_sp(new ShellInfo()); | ||||
| 560 | const bool monitor_signals = false; | ||||
| 561 | launch_info.SetMonitorProcessCallback( | ||||
| 562 | std::bind(MonitorShellCommand, shell_info_sp, std::placeholders::_1, | ||||
| 563 | std::placeholders::_2, std::placeholders::_3, | ||||
| 564 | std::placeholders::_4), | ||||
| 565 | monitor_signals); | ||||
| 566 | |||||
| 567 | error = LaunchProcess(launch_info); | ||||
| 568 | const lldb::pid_t pid = launch_info.GetProcessID(); | ||||
| 569 | |||||
| 570 | if (error.Success() && pid == LLDB_INVALID_PROCESS_ID0) | ||||
| 571 | error.SetErrorString("failed to get process ID"); | ||||
| 572 | |||||
| 573 | if (error.Success()) { | ||||
| 574 | if (!shell_info_sp->process_reaped.WaitForValueEqualTo(true, timeout)) { | ||||
| 575 | error.SetErrorString("timed out waiting for shell command to complete"); | ||||
| 576 | |||||
| 577 | // Kill the process since it didn't complete within the timeout specified | ||||
| 578 | Kill(pid, SIGKILL9); | ||||
| 579 | // Wait for the monitor callback to get the message | ||||
| 580 | shell_info_sp->process_reaped.WaitForValueEqualTo( | ||||
| 581 | true, std::chrono::seconds(1)); | ||||
| 582 | } else { | ||||
| 583 | if (status_ptr) | ||||
| 584 | *status_ptr = shell_info_sp->status; | ||||
| 585 | |||||
| 586 | if (signo_ptr) | ||||
| 587 | *signo_ptr = shell_info_sp->signo; | ||||
| 588 | |||||
| 589 | if (command_output_ptr) { | ||||
| 590 | command_output_ptr->clear(); | ||||
| 591 | uint64_t file_size = | ||||
| 592 | FileSystem::Instance().GetByteSize(output_file_spec); | ||||
| 593 | if (file_size > 0) { | ||||
| 594 | if (file_size > command_output_ptr->max_size()) { | ||||
| 595 | error.SetErrorStringWithFormat( | ||||
| 596 | "shell command output is too large to fit into a std::string"); | ||||
| 597 | } else { | ||||
| 598 | auto Buffer = | ||||
| 599 | FileSystem::Instance().CreateDataBuffer(output_file_spec); | ||||
| 600 | if (error.Success()) | ||||
| 601 | command_output_ptr->assign(Buffer->GetChars(), | ||||
| 602 | Buffer->GetByteSize()); | ||||
| 603 | } | ||||
| 604 | } | ||||
| 605 | } | ||||
| 606 | } | ||||
| 607 | } | ||||
| 608 | |||||
| 609 | llvm::sys::fs::remove(output_file_spec.GetPath()); | ||||
| 610 | return error; | ||||
| 611 | } | ||||
| 612 | |||||
| 613 | // The functions below implement process launching for non-Apple-based | ||||
| 614 | // platforms | ||||
| 615 | #if !defined(__APPLE__) | ||||
| 616 | Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) { | ||||
| 617 | std::unique_ptr<ProcessLauncher> delegate_launcher; | ||||
| 618 | #if defined(_WIN32) | ||||
| 619 | delegate_launcher.reset(new ProcessLauncherWindows()); | ||||
| 620 | #else | ||||
| 621 | delegate_launcher.reset(new ProcessLauncherPosixFork()); | ||||
| 622 | #endif | ||||
| 623 | MonitoringProcessLauncher launcher(std::move(delegate_launcher)); | ||||
| 624 | |||||
| 625 | Status error; | ||||
| 626 | HostProcess process = launcher.LaunchProcess(launch_info, error); | ||||
| 627 | |||||
| 628 | // TODO(zturner): It would be better if the entire HostProcess were returned | ||||
| 629 | // instead of writing it into this structure. | ||||
| 630 | launch_info.SetProcessID(process.GetProcessId()); | ||||
| 631 | |||||
| 632 | return error; | ||||
| 633 | } | ||||
| 634 | #endif // !defined(__APPLE__) | ||||
| 635 | |||||
| 636 | #ifndef _WIN32 | ||||
| 637 | void Host::Kill(lldb::pid_t pid, int signo) { ::kill(pid, signo); } | ||||
| 638 | |||||
| 639 | #endif | ||||
| 640 | |||||
| 641 | #if !defined(__APPLE__) | ||||
| 642 | bool Host::OpenFileInExternalEditor(const FileSpec &file_spec, | ||||
| 643 | uint32_t line_no) { | ||||
| 644 | return false; | ||||
| 645 | } | ||||
| 646 | |||||
| 647 | #endif | ||||
| 648 | |||||
| 649 | std::unique_ptr<Connection> Host::CreateDefaultConnection(llvm::StringRef url) { | ||||
| 650 | #if defined(_WIN32) | ||||
| 651 | if (url.startswith("file://")) | ||||
| 652 | return std::unique_ptr<Connection>(new ConnectionGenericFile()); | ||||
| 653 | #endif | ||||
| 654 | return std::unique_ptr<Connection>(new ConnectionFileDescriptor()); | ||||
| 655 | } | ||||
| 656 | |||||
| 657 | #if defined(LLVM_ON_UNIX1) | ||||
| 658 | WaitStatus WaitStatus::Decode(int wstatus) { | ||||
| 659 | if (WIFEXITED(wstatus)(((wstatus) & 0177) == 0)) | ||||
| 660 | return {Exit, uint8_t(WEXITSTATUS(wstatus)(int)(((unsigned)(wstatus) >> 8) & 0xff))}; | ||||
| 661 | else if (WIFSIGNALED(wstatus)(((wstatus) & 0177) != 0177 && ((wstatus) & 0177 ) != 0)) | ||||
| 662 | return {Signal, uint8_t(WTERMSIG(wstatus)(((wstatus) & 0177)))}; | ||||
| 663 | else if (WIFSTOPPED(wstatus)(((wstatus) & 0xff) == 0177)) | ||||
| 664 | return {Stop, uint8_t(WSTOPSIG(wstatus)(int)(((unsigned)(wstatus) >> 8) & 0xff))}; | ||||
| 665 | llvm_unreachable("Unknown wait status")__builtin_unreachable(); | ||||
| 666 | } | ||||
| 667 | #endif | ||||
| 668 | |||||
| 669 | void llvm::format_provider<WaitStatus>::format(const WaitStatus &WS, | ||||
| 670 | raw_ostream &OS, | ||||
| 671 | StringRef Options) { | ||||
| 672 | if (Options == "g") { | ||||
| 673 | char type; | ||||
| 674 | switch (WS.type) { | ||||
| 675 | case WaitStatus::Exit: | ||||
| 676 | type = 'W'; | ||||
| 677 | break; | ||||
| 678 | case WaitStatus::Signal: | ||||
| 679 | type = 'X'; | ||||
| 680 | break; | ||||
| 681 | case WaitStatus::Stop: | ||||
| 682 | type = 'S'; | ||||
| 683 | break; | ||||
| 684 | } | ||||
| 685 | OS << formatv("{0}{1:x-2}", type, WS.status); | ||||
| 686 | return; | ||||
| 687 | } | ||||
| 688 | |||||
| 689 | assert(Options.empty())((void)0); | ||||
| 690 | const char *desc; | ||||
| 691 | switch(WS.type) { | ||||
| 692 | case WaitStatus::Exit: | ||||
| 693 | desc = "Exited with status"; | ||||
| 694 | break; | ||||
| 695 | case WaitStatus::Signal: | ||||
| 696 | desc = "Killed by signal"; | ||||
| 697 | break; | ||||
| 698 | case WaitStatus::Stop: | ||||
| 699 | desc = "Stopped by signal"; | ||||
| 700 | break; | ||||
| 701 | } | ||||
| 702 | OS << desc << " " << int(WS.status); | ||||
| 703 | } | ||||
| 704 | |||||
| 705 | uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, | ||||
| 706 | ProcessInstanceInfoList &process_infos) { | ||||
| 707 | |||||
| 708 | if (llvm::Optional<ProcessInstanceInfoList> infos = | ||||
| 709 | repro::GetReplayProcessInstanceInfoList()) { | ||||
| 710 | process_infos = *infos; | ||||
| 711 | return process_infos.size(); | ||||
| 712 | } | ||||
| 713 | |||||
| 714 | uint32_t result = FindProcessesImpl(match_info, process_infos); | ||||
| 715 | |||||
| 716 | if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { | ||||
| 717 | g->GetOrCreate<repro::ProcessInfoProvider>() | ||||
| 718 | .GetNewProcessInfoRecorder() | ||||
| 719 | ->Record(process_infos); | ||||
| 720 | } | ||||
| 721 | |||||
| 722 | return result; | ||||
| 723 | } |