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 | } |