File: | build/llvm-toolchain-snapshot-15~++20220222111401+cfd6ba89fd9f/lldb/source/Host/common/Host.cpp |
Warning: | line 262, 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 | } |