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