File: | tools/lldb/source/Host/common/Host.cpp |
Warning: | line 271, column 15 Use of memory after it is freed |
1 | //===-- Host.cpp ------------------------------------------------*- C++ -*-===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | ||||
10 | // C includes | |||
11 | #include <errno(*__errno_location ()).h> | |||
12 | #include <limits.h> | |||
13 | #include <stdlib.h> | |||
14 | #include <sys/types.h> | |||
15 | #ifndef _WIN32 | |||
16 | #include <dlfcn.h> | |||
17 | #include <grp.h> | |||
18 | #include <netdb.h> | |||
19 | #include <pwd.h> | |||
20 | #include <sys/stat.h> | |||
21 | #include <unistd.h> | |||
22 | #endif | |||
23 | ||||
24 | #if defined(__APPLE__) | |||
25 | #include <mach-o/dyld.h> | |||
26 | #include <mach/mach_init.h> | |||
27 | #include <mach/mach_port.h> | |||
28 | #endif | |||
29 | ||||
30 | #if defined(__linux__1) || defined(__FreeBSD__) || \ | |||
31 | defined(__FreeBSD_kernel__) || defined(__APPLE__) || \ | |||
32 | defined(__NetBSD__) || defined(__OpenBSD__) | |||
33 | #if !defined(__ANDROID__) | |||
34 | #include <spawn.h> | |||
35 | #endif | |||
36 | #include <sys/syscall.h> | |||
37 | #include <sys/wait.h> | |||
38 | #endif | |||
39 | ||||
40 | #if defined(__FreeBSD__) | |||
41 | #include <pthread_np.h> | |||
42 | #endif | |||
43 | ||||
44 | #if defined(__NetBSD__) | |||
45 | #include <lwp.h> | |||
46 | #endif | |||
47 | ||||
48 | // C++ Includes | |||
49 | ||||
50 | // Other libraries and framework includes | |||
51 | // Project includes | |||
52 | ||||
53 | #include "lldb/Core/ArchSpec.h" | |||
54 | #include "lldb/Host/Host.h" | |||
55 | #include "lldb/Host/HostInfo.h" | |||
56 | #include "lldb/Host/HostProcess.h" | |||
57 | #include "lldb/Host/MonitoringProcessLauncher.h" | |||
58 | #include "lldb/Host/Predicate.h" | |||
59 | #include "lldb/Host/ProcessLauncher.h" | |||
60 | #include "lldb/Host/ThreadLauncher.h" | |||
61 | #include "lldb/Target/FileAction.h" | |||
62 | #include "lldb/Target/ProcessLaunchInfo.h" | |||
63 | #include "lldb/Target/UnixSignals.h" | |||
64 | #include "lldb/Utility/CleanUp.h" | |||
65 | #include "lldb/Utility/DataBufferLLVM.h" | |||
66 | #include "lldb/Utility/FileSpec.h" | |||
67 | #include "lldb/Utility/Log.h" | |||
68 | #include "lldb/Utility/Status.h" | |||
69 | #include "lldb/lldb-private-forward.h" | |||
70 | #include "llvm/ADT/SmallString.h" | |||
71 | #include "llvm/Support/FileSystem.h" | |||
72 | ||||
73 | #if defined(_WIN32) | |||
74 | #include "lldb/Host/windows/ProcessLauncherWindows.h" | |||
75 | #elif defined(__linux__1) || defined(__NetBSD__) | |||
76 | #include "lldb/Host/posix/ProcessLauncherPosixFork.h" | |||
77 | #else | |||
78 | #include "lldb/Host/posix/ProcessLauncherPosix.h" | |||
79 | #endif | |||
80 | ||||
81 | #if defined(__APPLE__) | |||
82 | #ifndef _POSIX_SPAWN_DISABLE_ASLR | |||
83 | #define _POSIX_SPAWN_DISABLE_ASLR 0x0100 | |||
84 | #endif | |||
85 | ||||
86 | extern "C" { | |||
87 | int __pthread_chdir(const char *path); | |||
88 | int __pthread_fchdir(int fildes); | |||
89 | } | |||
90 | ||||
91 | #endif | |||
92 | ||||
93 | using namespace lldb; | |||
94 | using namespace lldb_private; | |||
95 | ||||
96 | #if !defined(__APPLE__) && !defined(_WIN32) | |||
97 | struct MonitorInfo { | |||
98 | lldb::pid_t pid; // The process ID to monitor | |||
99 | Host::MonitorChildProcessCallback | |||
100 | callback; // The callback function to call when "pid" exits or signals | |||
101 | bool monitor_signals; // If true, call the callback when "pid" gets signaled. | |||
102 | }; | |||
103 | ||||
104 | static thread_result_t MonitorChildProcessThreadFunction(void *arg); | |||
105 | ||||
106 | HostThread Host::StartMonitoringChildProcess( | |||
107 | const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, | |||
108 | bool monitor_signals) { | |||
109 | MonitorInfo *info_ptr = new MonitorInfo(); | |||
110 | ||||
111 | info_ptr->pid = pid; | |||
112 | info_ptr->callback = callback; | |||
113 | info_ptr->monitor_signals = monitor_signals; | |||
114 | ||||
115 | char thread_name[256]; | |||
116 | ::snprintf(thread_name, sizeof(thread_name), | |||
117 | "<lldb.host.wait4(pid=%" PRIu64"l" "u" ")>", pid); | |||
118 | return ThreadLauncher::LaunchThread( | |||
119 | thread_name, MonitorChildProcessThreadFunction, info_ptr, NULL__null); | |||
120 | } | |||
121 | ||||
122 | #ifndef __linux__1 | |||
123 | //------------------------------------------------------------------ | |||
124 | // Scoped class that will disable thread canceling when it is | |||
125 | // constructed, and exception safely restore the previous value it | |||
126 | // when it goes out of scope. | |||
127 | //------------------------------------------------------------------ | |||
128 | class ScopedPThreadCancelDisabler { | |||
129 | public: | |||
130 | ScopedPThreadCancelDisabler() { | |||
131 | // Disable the ability for this thread to be cancelled | |||
132 | int err = ::pthread_setcancelstate(PTHREAD_CANCEL_DISABLEPTHREAD_CANCEL_DISABLE, &m_old_state); | |||
133 | if (err != 0) | |||
134 | m_old_state = -1; | |||
135 | } | |||
136 | ||||
137 | ~ScopedPThreadCancelDisabler() { | |||
138 | // Restore the ability for this thread to be cancelled to what it | |||
139 | // previously was. | |||
140 | if (m_old_state != -1) | |||
141 | ::pthread_setcancelstate(m_old_state, 0); | |||
142 | } | |||
143 | ||||
144 | private: | |||
145 | int m_old_state; // Save the old cancelability state. | |||
146 | }; | |||
147 | #endif // __linux__ | |||
148 | ||||
149 | #ifdef __linux__1 | |||
150 | #if defined(__GNUC__4) && (__GNUC__4 < 4 || (__GNUC__4 == 4 && __GNUC_MINOR__2 < 8)) | |||
151 | static __thread volatile sig_atomic_t g_usr1_called; | |||
152 | #else | |||
153 | static thread_local volatile sig_atomic_t g_usr1_called; | |||
154 | #endif | |||
155 | ||||
156 | static void SigUsr1Handler(int) { g_usr1_called = 1; } | |||
157 | #endif // __linux__ | |||
158 | ||||
159 | static bool CheckForMonitorCancellation() { | |||
160 | #ifdef __linux__1 | |||
161 | if (g_usr1_called) { | |||
162 | g_usr1_called = 0; | |||
163 | return true; | |||
164 | } | |||
165 | #else | |||
166 | ::pthread_testcancel(); | |||
167 | #endif | |||
168 | return false; | |||
169 | } | |||
170 | ||||
171 | static thread_result_t MonitorChildProcessThreadFunction(void *arg) { | |||
172 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS(1u << 1))); | |||
173 | const char *function = __FUNCTION__; | |||
174 | if (log) | |||
| ||||
175 | log->Printf("%s (arg = %p) thread starting...", function, arg); | |||
176 | ||||
177 | MonitorInfo *info = (MonitorInfo *)arg; | |||
178 | ||||
179 | const Host::MonitorChildProcessCallback callback = info->callback; | |||
180 | const bool monitor_signals = info->monitor_signals; | |||
181 | ||||
182 | assert(info->pid <= UINT32_MAX)((info->pid <= (4294967295U)) ? static_cast<void> (0) : __assert_fail ("info->pid <= UINT32_MAX", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , 182, __PRETTY_FUNCTION__)); | |||
183 | const ::pid_t pid = monitor_signals ? -1 * getpgid(info->pid) : info->pid; | |||
184 | ||||
185 | delete info; | |||
186 | ||||
187 | int status = -1; | |||
188 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) | |||
189 | #define __WALL0x40000000 0 | |||
190 | #endif | |||
191 | const int options = __WALL0x40000000; | |||
192 | ||||
193 | #ifdef __linux__1 | |||
194 | // This signal is only used to interrupt the thread from waitpid | |||
195 | struct sigaction sigUsr1Action; | |||
196 | memset(&sigUsr1Action, 0, sizeof(sigUsr1Action)); | |||
197 | sigUsr1Action.sa_handler__sigaction_handler.sa_handler = SigUsr1Handler; | |||
198 | ::sigaction(SIGUSR110, &sigUsr1Action, nullptr); | |||
199 | #endif // __linux__ | |||
200 | ||||
201 | while (1) { | |||
202 | log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS(1u << 1)); | |||
203 | if (log) | |||
204 | log->Printf("%s ::waitpid (pid = %" PRIi32"i" ", &status, options = %i)...", | |||
205 | function, pid, options); | |||
206 | ||||
207 | if (CheckForMonitorCancellation()) | |||
208 | break; | |||
209 | ||||
210 | // Get signals from all children with same process group of pid | |||
211 | const ::pid_t wait_pid = ::waitpid(pid, &status, options); | |||
212 | ||||
213 | if (CheckForMonitorCancellation()) | |||
214 | break; | |||
215 | ||||
216 | if (wait_pid == -1) { | |||
217 | if (errno(*__errno_location ()) == EINTR4) | |||
218 | continue; | |||
219 | else { | |||
220 | if (log) | |||
221 | log->Printf( | |||
222 | "%s (arg = %p) thread exiting because waitpid failed (%s)...", | |||
223 | __FUNCTION__, arg, strerror(errno(*__errno_location ()))); | |||
224 | break; | |||
225 | } | |||
226 | } else if (wait_pid > 0) { | |||
227 | bool exited = false; | |||
228 | int signal = 0; | |||
229 | int exit_status = 0; | |||
230 | const char *status_cstr = NULL__null; | |||
231 | if (WIFSTOPPED(status)(((status) & 0xff) == 0x7f)) { | |||
232 | signal = WSTOPSIG(status)(((status) & 0xff00) >> 8); | |||
233 | status_cstr = "STOPPED"; | |||
234 | } else if (WIFEXITED(status)(((status) & 0x7f) == 0)) { | |||
235 | exit_status = WEXITSTATUS(status)(((status) & 0xff00) >> 8); | |||
236 | status_cstr = "EXITED"; | |||
237 | exited = true; | |||
238 | } else if (WIFSIGNALED(status)(((signed char) (((status) & 0x7f) + 1) >> 1) > 0 )) { | |||
239 | signal = WTERMSIG(status)((status) & 0x7f); | |||
240 | status_cstr = "SIGNALED"; | |||
241 | if (wait_pid == abs(pid)) { | |||
242 | exited = true; | |||
243 | exit_status = -1; | |||
244 | } | |||
245 | } else { | |||
246 | status_cstr = "(\?\?\?)"; | |||
247 | } | |||
248 | ||||
249 | // Scope for pthread_cancel_disabler | |||
250 | { | |||
251 | #ifndef __linux__1 | |||
252 | ScopedPThreadCancelDisabler pthread_cancel_disabler; | |||
253 | #endif | |||
254 | ||||
255 | log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS(1u << 1)); | |||
256 | if (log) | |||
257 | log->Printf("%s ::waitpid (pid = %" PRIi32"i" | |||
258 | ", &status, options = %i) => pid = %" PRIi32"i" | |||
259 | ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", | |||
260 | function, pid, options, wait_pid, status, status_cstr, | |||
261 | signal, exit_status); | |||
262 | ||||
263 | if (exited || (signal != 0 && monitor_signals)) { | |||
264 | bool callback_return = false; | |||
265 | if (callback) | |||
266 | callback_return = callback(wait_pid, exited, signal, exit_status); | |||
267 | ||||
268 | // If our process exited, then this thread should exit | |||
269 | if (exited && wait_pid == abs(pid)) { | |||
270 | if (log) | |||
271 | log->Printf("%s (arg = %p) thread exiting because pid received " | |||
| ||||
272 | "exit signal...", | |||
273 | __FUNCTION__, arg); | |||
274 | break; | |||
275 | } | |||
276 | // If the callback returns true, it means this process should | |||
277 | // exit | |||
278 | if (callback_return) { | |||
279 | if (log) | |||
280 | log->Printf("%s (arg = %p) thread exiting because callback " | |||
281 | "returned true...", | |||
282 | __FUNCTION__, arg); | |||
283 | break; | |||
284 | } | |||
285 | } | |||
286 | } | |||
287 | } | |||
288 | } | |||
289 | ||||
290 | log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS(1u << 1)); | |||
291 | if (log) | |||
292 | log->Printf("%s (arg = %p) thread exiting...", __FUNCTION__, arg); | |||
293 | ||||
294 | return NULL__null; | |||
295 | } | |||
296 | ||||
297 | #endif // #if !defined (__APPLE__) && !defined (_WIN32) | |||
298 | ||||
299 | #if !defined(__APPLE__) | |||
300 | ||||
301 | void Host::SystemLog(SystemLogType type, const char *format, va_list args) { | |||
302 | vfprintf(stderrstderr, format, args); | |||
303 | } | |||
304 | ||||
305 | #endif | |||
306 | ||||
307 | void Host::SystemLog(SystemLogType type, const char *format, ...) { | |||
308 | va_list args; | |||
309 | va_start(args, format)__builtin_va_start(args, format); | |||
310 | SystemLog(type, format, args); | |||
311 | va_end(args)__builtin_va_end(args); | |||
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(SIGPOLL29) | |||
337 | #if !defined(SIGIO29) || (SIGPOLL29 != SIGIO29) | |||
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 SIGPOLL29: | |||
341 | return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported) | |||
342 | #endif | |||
343 | #endif | |||
344 | #if defined(SIGEMT) | |||
345 | case SIGEMT: | |||
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 SIGBUS7: | |||
353 | return "SIGBUS"; // 10 bus error | |||
354 | case SIGSEGV11: | |||
355 | return "SIGSEGV"; // 11 segmentation violation | |||
356 | case SIGSYS31: | |||
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 SIGURG23: | |||
365 | return "SIGURG"; // 16 urgent condition on IO channel | |||
366 | case SIGSTOP19: | |||
367 | return "SIGSTOP"; // 17 sendable stop signal not from tty | |||
368 | case SIGTSTP20: | |||
369 | return "SIGTSTP"; // 18 stop signal from tty | |||
370 | case SIGCONT18: | |||
371 | return "SIGCONT"; // 19 continue a stopped process | |||
372 | case SIGCHLD17: | |||
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(SIGIO29) | |||
379 | case SIGIO29: | |||
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(SIGINFO) | |||
395 | case SIGINFO: | |||
396 | return "SIGINFO"; // 29 information request | |||
397 | #endif | |||
398 | case SIGUSR110: | |||
399 | return "SIGUSR1"; // 30 user defined signal 1 | |||
400 | case SIGUSR212: | |||
401 | return "SIGUSR2"; // 31 user defined signal 2 | |||
402 | default: | |||
403 | break; | |||
404 | } | |||
405 | return NULL__null; | |||
406 | } | |||
407 | ||||
408 | #endif | |||
409 | ||||
410 | #ifndef _WIN32 | |||
411 | ||||
412 | lldb::thread_key_t | |||
413 | Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) { | |||
414 | pthread_key_t key; | |||
415 | ::pthread_key_create(&key, callback); | |||
416 | return key; | |||
417 | } | |||
418 | ||||
419 | void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) { | |||
420 | return ::pthread_getspecific(key); | |||
421 | } | |||
422 | ||||
423 | void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) { | |||
424 | ::pthread_setspecific(key, value); | |||
425 | } | |||
426 | ||||
427 | #endif | |||
428 | ||||
429 | #if !defined(__APPLE__) // see Host.mm | |||
430 | ||||
431 | bool Host::GetBundleDirectory(const FileSpec &file, FileSpec &bundle) { | |||
432 | bundle.Clear(); | |||
433 | return false; | |||
434 | } | |||
435 | ||||
436 | bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } | |||
437 | #endif | |||
438 | ||||
439 | #ifndef _WIN32 | |||
440 | ||||
441 | FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { | |||
442 | FileSpec module_filespec; | |||
443 | #if !defined(__ANDROID__) | |||
444 | Dl_info info; | |||
445 | if (::dladdr(host_addr, &info)) { | |||
446 | if (info.dli_fname) | |||
447 | module_filespec.SetFile(info.dli_fname, true); | |||
448 | } | |||
449 | #endif | |||
450 | return module_filespec; | |||
451 | } | |||
452 | ||||
453 | #endif | |||
454 | ||||
455 | #if !defined(__linux__1) | |||
456 | bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { | |||
457 | return false; | |||
458 | } | |||
459 | #endif | |||
460 | ||||
461 | struct ShellInfo { | |||
462 | ShellInfo() | |||
463 | : process_reaped(false), pid(LLDB_INVALID_PROCESS_ID0), signo(-1), | |||
464 | status(-1) {} | |||
465 | ||||
466 | lldb_private::Predicate<bool> process_reaped; | |||
467 | lldb::pid_t pid; | |||
468 | int signo; | |||
469 | int status; | |||
470 | }; | |||
471 | ||||
472 | static bool | |||
473 | MonitorShellCommand(std::shared_ptr<ShellInfo> shell_info, lldb::pid_t pid, | |||
474 | bool exited, // True if the process did exit | |||
475 | int signo, // Zero for no signal | |||
476 | int status) // Exit value of process if signal is zero | |||
477 | { | |||
478 | shell_info->pid = pid; | |||
479 | shell_info->signo = signo; | |||
480 | shell_info->status = status; | |||
481 | // Let the thread running Host::RunShellCommand() know that the process | |||
482 | // exited and that ShellInfo has been filled in by broadcasting to it | |||
483 | shell_info->process_reaped.SetValue(true, eBroadcastAlways); | |||
484 | return true; | |||
485 | } | |||
486 | ||||
487 | Status Host::RunShellCommand(const char *command, const FileSpec &working_dir, | |||
488 | int *status_ptr, int *signo_ptr, | |||
489 | std::string *command_output_ptr, | |||
490 | uint32_t timeout_sec, bool run_in_default_shell) { | |||
491 | return RunShellCommand(Args(command), working_dir, status_ptr, signo_ptr, | |||
492 | command_output_ptr, timeout_sec, run_in_default_shell); | |||
493 | } | |||
494 | ||||
495 | Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir, | |||
496 | int *status_ptr, int *signo_ptr, | |||
497 | std::string *command_output_ptr, | |||
498 | uint32_t timeout_sec, bool run_in_default_shell) { | |||
499 | Status error; | |||
500 | ProcessLaunchInfo launch_info; | |||
501 | launch_info.SetArchitecture(HostInfo::GetArchitecture()); | |||
502 | if (run_in_default_shell) { | |||
503 | // Run the command in a shell | |||
504 | launch_info.SetShell(HostInfo::GetDefaultShell()); | |||
505 | launch_info.GetArguments().AppendArguments(args); | |||
506 | const bool localhost = true; | |||
507 | const bool will_debug = false; | |||
508 | const bool first_arg_is_full_shell_command = false; | |||
509 | launch_info.ConvertArgumentsForLaunchingInShell( | |||
510 | error, localhost, will_debug, first_arg_is_full_shell_command, 0); | |||
511 | } else { | |||
512 | // No shell, just run it | |||
513 | const bool first_arg_is_executable = true; | |||
514 | launch_info.SetArguments(args, first_arg_is_executable); | |||
515 | } | |||
516 | ||||
517 | if (working_dir) | |||
518 | launch_info.SetWorkingDirectory(working_dir); | |||
519 | llvm::SmallString<PATH_MAX4096> output_file_path; | |||
520 | ||||
521 | if (command_output_ptr) { | |||
522 | // Create a temporary file to get the stdout/stderr and redirect the | |||
523 | // output of the command into this file. We will later read this file | |||
524 | // if all goes well and fill the data into "command_output_ptr" | |||
525 | FileSpec tmpdir_file_spec; | |||
526 | if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { | |||
527 | tmpdir_file_spec.AppendPathComponent("lldb-shell-output.%%%%%%"); | |||
528 | llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(), | |||
529 | output_file_path); | |||
530 | } else { | |||
531 | llvm::sys::fs::createTemporaryFile("lldb-shell-output.%%%%%%", "", | |||
532 | output_file_path); | |||
533 | } | |||
534 | } | |||
535 | ||||
536 | FileSpec output_file_spec{output_file_path.c_str(), false}; | |||
537 | ||||
538 | launch_info.AppendSuppressFileAction(STDIN_FILENO0, true, false); | |||
539 | if (output_file_spec) { | |||
540 | launch_info.AppendOpenFileAction(STDOUT_FILENO1, output_file_spec, false, | |||
541 | true); | |||
542 | launch_info.AppendDuplicateFileAction(STDOUT_FILENO1, STDERR_FILENO2); | |||
543 | } else { | |||
544 | launch_info.AppendSuppressFileAction(STDOUT_FILENO1, false, true); | |||
545 | launch_info.AppendSuppressFileAction(STDERR_FILENO2, false, true); | |||
546 | } | |||
547 | ||||
548 | std::shared_ptr<ShellInfo> shell_info_sp(new ShellInfo()); | |||
549 | const bool monitor_signals = false; | |||
550 | launch_info.SetMonitorProcessCallback( | |||
551 | std::bind(MonitorShellCommand, shell_info_sp, std::placeholders::_1, | |||
552 | std::placeholders::_2, std::placeholders::_3, | |||
553 | std::placeholders::_4), | |||
554 | monitor_signals); | |||
555 | ||||
556 | error = LaunchProcess(launch_info); | |||
557 | const lldb::pid_t pid = launch_info.GetProcessID(); | |||
558 | ||||
559 | if (error.Success() && pid == LLDB_INVALID_PROCESS_ID0) | |||
560 | error.SetErrorString("failed to get process ID"); | |||
561 | ||||
562 | if (error.Success()) { | |||
563 | bool timed_out = false; | |||
564 | shell_info_sp->process_reaped.WaitForValueEqualTo( | |||
565 | true, std::chrono::seconds(timeout_sec), &timed_out); | |||
566 | if (timed_out) { | |||
567 | error.SetErrorString("timed out waiting for shell command to complete"); | |||
568 | ||||
569 | // Kill the process since it didn't complete within the timeout specified | |||
570 | Kill(pid, SIGKILL9); | |||
571 | // Wait for the monitor callback to get the message | |||
572 | timed_out = false; | |||
573 | shell_info_sp->process_reaped.WaitForValueEqualTo( | |||
574 | true, std::chrono::seconds(1), &timed_out); | |||
575 | } else { | |||
576 | if (status_ptr) | |||
577 | *status_ptr = shell_info_sp->status; | |||
578 | ||||
579 | if (signo_ptr) | |||
580 | *signo_ptr = shell_info_sp->signo; | |||
581 | ||||
582 | if (command_output_ptr) { | |||
583 | command_output_ptr->clear(); | |||
584 | uint64_t file_size = output_file_spec.GetByteSize(); | |||
585 | if (file_size > 0) { | |||
586 | if (file_size > command_output_ptr->max_size()) { | |||
587 | error.SetErrorStringWithFormat( | |||
588 | "shell command output is too large to fit into a std::string"); | |||
589 | } else { | |||
590 | auto Buffer = | |||
591 | DataBufferLLVM::CreateFromPath(output_file_spec.GetPath()); | |||
592 | if (error.Success()) | |||
593 | command_output_ptr->assign(Buffer->GetChars(), | |||
594 | Buffer->GetByteSize()); | |||
595 | } | |||
596 | } | |||
597 | } | |||
598 | } | |||
599 | } | |||
600 | ||||
601 | llvm::sys::fs::remove(output_file_spec.GetPath()); | |||
602 | return error; | |||
603 | } | |||
604 | ||||
605 | // LaunchProcessPosixSpawn for Apple, Linux, FreeBSD, NetBSD and other GLIBC | |||
606 | // systems | |||
607 | ||||
608 | #if defined(__APPLE__) || defined(__linux__1) || defined(__FreeBSD__) || \ | |||
609 | defined(__GLIBC__2) || defined(__NetBSD__) | |||
610 | #if !defined(__ANDROID__) | |||
611 | // this method needs to be visible to macosx/Host.cpp and | |||
612 | // common/Host.cpp. | |||
613 | ||||
614 | short Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) { | |||
615 | short flags = POSIX_SPAWN_SETSIGDEF0x04 | POSIX_SPAWN_SETSIGMASK0x08; | |||
616 | ||||
617 | #if defined(__APPLE__) | |||
618 | if (launch_info.GetFlags().Test(eLaunchFlagExec)) | |||
619 | flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag | |||
620 | ||||
621 | if (launch_info.GetFlags().Test(eLaunchFlagDebug)) | |||
622 | flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag | |||
623 | ||||
624 | if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) | |||
625 | flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag | |||
626 | ||||
627 | if (launch_info.GetLaunchInSeparateProcessGroup()) | |||
628 | flags |= POSIX_SPAWN_SETPGROUP0x02; | |||
629 | ||||
630 | #ifdef POSIX_SPAWN_CLOEXEC_DEFAULT | |||
631 | #if defined(__APPLE__) && (defined(__x86_64__1) || defined(__i386__)) | |||
632 | static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate; | |||
633 | if (g_use_close_on_exec_flag == eLazyBoolCalculate) { | |||
634 | g_use_close_on_exec_flag = eLazyBoolNo; | |||
635 | ||||
636 | uint32_t major, minor, update; | |||
637 | if (HostInfo::GetOSVersion(major, minor, update)) { | |||
638 | // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or | |||
639 | // earlier | |||
640 | if (major > 10 || (major == 10 && minor > 7)) { | |||
641 | // Only enable for 10.8 and later OS versions | |||
642 | g_use_close_on_exec_flag = eLazyBoolYes; | |||
643 | } | |||
644 | } | |||
645 | } | |||
646 | #else | |||
647 | static LazyBool g_use_close_on_exec_flag = eLazyBoolYes; | |||
648 | #endif | |||
649 | // Close all files exception those with file actions if this is supported. | |||
650 | if (g_use_close_on_exec_flag == eLazyBoolYes) | |||
651 | flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; | |||
652 | #endif | |||
653 | #endif // #if defined (__APPLE__) | |||
654 | return flags; | |||
655 | } | |||
656 | ||||
657 | Status Host::LaunchProcessPosixSpawn(const char *exe_path, | |||
658 | const ProcessLaunchInfo &launch_info, | |||
659 | lldb::pid_t &pid) { | |||
660 | Status error; | |||
661 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST(1u << 14) | | |||
662 | LIBLLDB_LOG_PROCESS(1u << 1))); | |||
663 | ||||
664 | posix_spawnattr_t attr; | |||
665 | error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX); | |||
666 | ||||
667 | if (error.Fail()) { | |||
668 | LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnattr_init ( &attr )" , error); } while (0); | |||
669 | return error; | |||
670 | } | |||
671 | ||||
672 | // Make a quick class that will cleanup the posix spawn attributes in case | |||
673 | // we return in the middle of this function. | |||
674 | lldb_utility::CleanUp<posix_spawnattr_t *, int> posix_spawnattr_cleanup( | |||
675 | &attr, posix_spawnattr_destroy); | |||
676 | ||||
677 | sigset_t no_signals; | |||
678 | sigset_t all_signals; | |||
679 | sigemptyset(&no_signals); | |||
680 | sigfillset(&all_signals); | |||
681 | ::posix_spawnattr_setsigmask(&attr, &no_signals); | |||
682 | #if defined(__linux__1) || defined(__FreeBSD__) || defined(__NetBSD__) | |||
683 | ::posix_spawnattr_setsigdefault(&attr, &no_signals); | |||
684 | #else | |||
685 | ::posix_spawnattr_setsigdefault(&attr, &all_signals); | |||
686 | #endif | |||
687 | ||||
688 | short flags = GetPosixspawnFlags(launch_info); | |||
689 | ||||
690 | error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX); | |||
691 | if (error.Fail()) { | |||
692 | LLDB_LOG(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )" , error, flags); } while (0) | |||
693 | "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )" , error, flags); } while (0) | |||
694 | error, flags)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )" , error, flags); } while (0); | |||
695 | return error; | |||
696 | } | |||
697 | ||||
698 | // posix_spawnattr_setbinpref_np appears to be an Apple extension per: | |||
699 | // http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/ | |||
700 | #if defined(__APPLE__) && !defined(__arm__) | |||
701 | ||||
702 | // Don't set the binpref if a shell was provided. After all, that's only | |||
703 | // going to affect what version of the shell | |||
704 | // is launched, not what fork of the binary is launched. We insert "arch | |||
705 | // --arch <ARCH> as part of the shell invocation | |||
706 | // to do that job on OSX. | |||
707 | ||||
708 | if (launch_info.GetShell() == nullptr) { | |||
709 | // We don't need to do this for ARM, and we really shouldn't now that we | |||
710 | // have multiple CPU subtypes and no posix_spawnattr call that allows us | |||
711 | // to set which CPU subtype to launch... | |||
712 | const ArchSpec &arch_spec = launch_info.GetArchitecture(); | |||
713 | cpu_type_t cpu = arch_spec.GetMachOCPUType(); | |||
714 | cpu_type_t sub = arch_spec.GetMachOCPUSubType(); | |||
715 | if (cpu != 0 && cpu != static_cast<cpu_type_t>(UINT32_MAX(4294967295U)) && | |||
716 | cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE(0xFFFFFFFEu)) && | |||
717 | !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try | |||
718 | // to set the CPU type or we will fail | |||
719 | { | |||
720 | size_t ocount = 0; | |||
721 | error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount), | |||
722 | eErrorTypePOSIX); | |||
723 | if (error.Fail()) | |||
724 | LLDB_LOG(log, "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, " "cpu_type = {1:x}, count => {2} )", error, cpu, ocount); } while (0) | |||
725 | "cpu_type = {1:x}, count => {2} )",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, " "cpu_type = {1:x}, count => {2} )", error, cpu, ocount); } while (0) | |||
726 | error, cpu, ocount)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, " "cpu_type = {1:x}, count => {2} )", error, cpu, ocount); } while (0); | |||
727 | ||||
728 | if (error.Fail() || ocount != 1) | |||
729 | return error; | |||
730 | } | |||
731 | } | |||
732 | ||||
733 | #endif | |||
734 | ||||
735 | const char *tmp_argv[2]; | |||
736 | char *const *argv = const_cast<char *const *>( | |||
737 | launch_info.GetArguments().GetConstArgumentVector()); | |||
738 | char *const *envp = const_cast<char *const *>( | |||
739 | launch_info.GetEnvironmentEntries().GetConstArgumentVector()); | |||
740 | if (argv == NULL__null) { | |||
741 | // posix_spawn gets very unhappy if it doesn't have at least the program | |||
742 | // name in argv[0]. One of the side affects I have noticed is the | |||
743 | // environment | |||
744 | // variables don't make it into the child process if "argv == NULL"!!! | |||
745 | tmp_argv[0] = exe_path; | |||
746 | tmp_argv[1] = NULL__null; | |||
747 | argv = const_cast<char *const *>(tmp_argv); | |||
748 | } | |||
749 | ||||
750 | #if !defined(__APPLE__) | |||
751 | // manage the working directory | |||
752 | char current_dir[PATH_MAX4096]; | |||
753 | current_dir[0] = '\0'; | |||
754 | #endif | |||
755 | ||||
756 | FileSpec working_dir{launch_info.GetWorkingDirectory()}; | |||
757 | if (working_dir) { | |||
758 | #if defined(__APPLE__) | |||
759 | // Set the working directory on this thread only | |||
760 | if (__pthread_chdir(working_dir.GetCString()) < 0) { | |||
761 | if (errno(*__errno_location ()) == ENOENT2) { | |||
762 | error.SetErrorStringWithFormat("No such file or directory: %s", | |||
763 | working_dir.GetCString()); | |||
764 | } else if (errno(*__errno_location ()) == ENOTDIR20) { | |||
765 | error.SetErrorStringWithFormat("Path doesn't name a directory: %s", | |||
766 | working_dir.GetCString()); | |||
767 | } else { | |||
768 | error.SetErrorStringWithFormat("An unknown error occurred when " | |||
769 | "changing directory for process " | |||
770 | "execution."); | |||
771 | } | |||
772 | return error; | |||
773 | } | |||
774 | #else | |||
775 | if (::getcwd(current_dir, sizeof(current_dir)) == NULL__null) { | |||
776 | error.SetError(errno(*__errno_location ()), eErrorTypePOSIX); | |||
777 | LLDB_LOG(log, "error: {0}, unable to save the current directory", error)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, unable to save the current directory" , error); } while (0); | |||
778 | return error; | |||
779 | } | |||
780 | ||||
781 | if (::chdir(working_dir.GetCString()) == -1) { | |||
782 | error.SetError(errno(*__errno_location ()), eErrorTypePOSIX); | |||
783 | LLDB_LOG(log, "error: {0}, unable to change working directory to {1}",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, unable to change working directory to {1}" , error, working_dir); } while (0) | |||
784 | error, working_dir)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, unable to change working directory to {1}" , error, working_dir); } while (0); | |||
785 | return error; | |||
786 | } | |||
787 | #endif | |||
788 | } | |||
789 | ||||
790 | ::pid_t result_pid = LLDB_INVALID_PROCESS_ID0; | |||
791 | const size_t num_file_actions = launch_info.GetNumFileActions(); | |||
792 | if (num_file_actions > 0) { | |||
793 | posix_spawn_file_actions_t file_actions; | |||
794 | error.SetError(::posix_spawn_file_actions_init(&file_actions), | |||
795 | eErrorTypePOSIX); | |||
796 | if (error.Fail()) { | |||
797 | LLDB_LOG(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )" , error); } while (0) | |||
798 | "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )" , error); } while (0) | |||
799 | error)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )" , error); } while (0); | |||
800 | return error; | |||
801 | } | |||
802 | ||||
803 | // Make a quick class that will cleanup the posix spawn attributes in case | |||
804 | // we return in the middle of this function. | |||
805 | lldb_utility::CleanUp<posix_spawn_file_actions_t *, int> | |||
806 | posix_spawn_file_actions_cleanup(&file_actions, | |||
807 | posix_spawn_file_actions_destroy); | |||
808 | ||||
809 | for (size_t i = 0; i < num_file_actions; ++i) { | |||
810 | const FileAction *launch_file_action = | |||
811 | launch_info.GetFileActionAtIndex(i); | |||
812 | if (launch_file_action) { | |||
813 | if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, | |||
814 | error)) | |||
815 | return error; | |||
816 | } | |||
817 | } | |||
818 | ||||
819 | error.SetError( | |||
820 | ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), | |||
821 | eErrorTypePOSIX); | |||
822 | ||||
823 | if (error.Fail()) { | |||
824 | LLDB_LOG(log, "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', " "file_actions = {3}, " "attr = {4}, argv = {5}, envp = {6} )" , error, result_pid, exe_path, &file_actions, &attr, argv , envp); } while (0) | |||
825 | "file_actions = {3}, "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', " "file_actions = {3}, " "attr = {4}, argv = {5}, envp = {6} )" , error, result_pid, exe_path, &file_actions, &attr, argv , envp); } while (0) | |||
826 | "attr = {4}, argv = {5}, envp = {6} )",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', " "file_actions = {3}, " "attr = {4}, argv = {5}, envp = {6} )" , error, result_pid, exe_path, &file_actions, &attr, argv , envp); } while (0) | |||
827 | error, result_pid, exe_path, &file_actions, &attr, argv, envp)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', " "file_actions = {3}, " "attr = {4}, argv = {5}, envp = {6} )" , error, result_pid, exe_path, &file_actions, &attr, argv , envp); } while (0); | |||
828 | if (log) { | |||
829 | for (int ii = 0; argv[ii]; ++ii) | |||
830 | LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii])do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "argv[{0}] = '{1}'", ii, argv[ii]); } while ( 0); | |||
831 | } | |||
832 | } | |||
833 | ||||
834 | } else { | |||
835 | error.SetError( | |||
836 | ::posix_spawnp(&result_pid, exe_path, NULL__null, &attr, argv, envp), | |||
837 | eErrorTypePOSIX); | |||
838 | ||||
839 | if (error.Fail()) { | |||
840 | LLDB_LOG(log, "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', " "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )", error, result_pid, exe_path, &attr, argv, envp); } while (0) | |||
841 | "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', " "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )", error, result_pid, exe_path, &attr, argv, envp); } while (0) | |||
842 | error, result_pid, exe_path, &attr, argv, envp)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', " "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )", error, result_pid, exe_path, &attr, argv, envp); } while (0); | |||
843 | if (log) { | |||
844 | for (int ii = 0; argv[ii]; ++ii) | |||
845 | LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii])do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "argv[{0}] = '{1}'", ii, argv[ii]); } while ( 0); | |||
846 | } | |||
847 | } | |||
848 | } | |||
849 | pid = result_pid; | |||
850 | ||||
851 | if (working_dir) { | |||
852 | #if defined(__APPLE__) | |||
853 | // No more thread specific current working directory | |||
854 | __pthread_fchdir(-1); | |||
855 | #else | |||
856 | if (::chdir(current_dir) == -1 && error.Success()) { | |||
857 | error.SetError(errno(*__errno_location ()), eErrorTypePOSIX); | |||
858 | LLDB_LOG(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, unable to change current directory back to {1}" , error, current_dir); } while (0) | |||
859 | "error: {0}, unable to change current directory back to {1}",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, unable to change current directory back to {1}" , error, current_dir); } while (0) | |||
860 | error, current_dir)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, unable to change current directory back to {1}" , error, current_dir); } while (0); | |||
861 | } | |||
862 | #endif | |||
863 | } | |||
864 | ||||
865 | return error; | |||
866 | } | |||
867 | ||||
868 | bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, | |||
869 | Log *log, Status &error) { | |||
870 | if (info == NULL__null) | |||
871 | return false; | |||
872 | ||||
873 | posix_spawn_file_actions_t *file_actions = | |||
874 | reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions); | |||
875 | ||||
876 | switch (info->GetAction()) { | |||
877 | case FileAction::eFileActionNone: | |||
878 | error.Clear(); | |||
879 | break; | |||
880 | ||||
881 | case FileAction::eFileActionClose: | |||
882 | if (info->GetFD() == -1) | |||
883 | error.SetErrorString( | |||
884 | "invalid fd for posix_spawn_file_actions_addclose(...)"); | |||
885 | else { | |||
886 | error.SetError( | |||
887 | ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), | |||
888 | eErrorTypePOSIX); | |||
889 | if (error.Fail()) | |||
890 | LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_addclose "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_addclose " "(action={1}, fd={2})", error, file_actions, info->GetFD( )); } while (0) | |||
891 | "(action={1}, fd={2})",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_addclose " "(action={1}, fd={2})", error, file_actions, info->GetFD( )); } while (0) | |||
892 | error, file_actions, info->GetFD())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_addclose " "(action={1}, fd={2})", error, file_actions, info->GetFD( )); } while (0); | |||
893 | } | |||
894 | break; | |||
895 | ||||
896 | case FileAction::eFileActionDuplicate: | |||
897 | if (info->GetFD() == -1) | |||
898 | error.SetErrorString( | |||
899 | "invalid fd for posix_spawn_file_actions_adddup2(...)"); | |||
900 | else if (info->GetActionArgument() == -1) | |||
901 | error.SetErrorString( | |||
902 | "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)"); | |||
903 | else { | |||
904 | error.SetError( | |||
905 | ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), | |||
906 | info->GetActionArgument()), | |||
907 | eErrorTypePOSIX); | |||
908 | if (error.Fail()) | |||
909 | LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_adddup2 "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_adddup2 " "(action={1}, fd={2}, dup_fd={3})", error, file_actions, info ->GetFD(), info->GetActionArgument()); } while (0) | |||
910 | "(action={1}, fd={2}, dup_fd={3})",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_adddup2 " "(action={1}, fd={2}, dup_fd={3})", error, file_actions, info ->GetFD(), info->GetActionArgument()); } while (0) | |||
911 | error, file_actions, info->GetFD(), info->GetActionArgument())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_adddup2 " "(action={1}, fd={2}, dup_fd={3})", error, file_actions, info ->GetFD(), info->GetActionArgument()); } while (0); | |||
912 | } | |||
913 | break; | |||
914 | ||||
915 | case FileAction::eFileActionOpen: | |||
916 | if (info->GetFD() == -1) | |||
917 | error.SetErrorString( | |||
918 | "invalid fd in posix_spawn_file_actions_addopen(...)"); | |||
919 | else { | |||
920 | int oflag = info->GetActionArgument(); | |||
921 | ||||
922 | mode_t mode = 0; | |||
923 | ||||
924 | if (oflag & O_CREAT0100) | |||
925 | mode = 0640; | |||
926 | ||||
927 | error.SetError(::posix_spawn_file_actions_addopen( | |||
928 | file_actions, info->GetFD(), | |||
929 | info->GetPath().str().c_str(), oflag, mode), | |||
930 | eErrorTypePOSIX); | |||
931 | if (error.Fail()) | |||
932 | LLDB_LOG(do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_addopen (action={1}, " "fd={2}, path='{3}', oflag={4}, mode={5})", error, file_actions , info->GetFD(), info->GetPath(), oflag, mode); } while (0) | |||
933 | log, "error: {0}, posix_spawn_file_actions_addopen (action={1}, "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_addopen (action={1}, " "fd={2}, path='{3}', oflag={4}, mode={5})", error, file_actions , info->GetFD(), info->GetPath(), oflag, mode); } while (0) | |||
934 | "fd={2}, path='{3}', oflag={4}, mode={5})",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_addopen (action={1}, " "fd={2}, path='{3}', oflag={4}, mode={5})", error, file_actions , info->GetFD(), info->GetPath(), oflag, mode); } while (0) | |||
935 | error, file_actions, info->GetFD(), info->GetPath(), oflag, mode)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Host/common/Host.cpp" , __FUNCTION__, "error: {0}, posix_spawn_file_actions_addopen (action={1}, " "fd={2}, path='{3}', oflag={4}, mode={5})", error, file_actions , info->GetFD(), info->GetPath(), oflag, mode); } while (0); | |||
936 | } | |||
937 | break; | |||
938 | } | |||
939 | return error.Success(); | |||
940 | } | |||
941 | #endif // !defined(__ANDROID__) | |||
942 | #endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || | |||
943 | // defined (__GLIBC__) || defined(__NetBSD__) | |||
944 | ||||
945 | #if defined(__linux__1) || defined(__FreeBSD__) || defined(__GLIBC__2) || \ | |||
946 | defined(__NetBSD__) || defined(_WIN32) | |||
947 | // The functions below implement process launching via posix_spawn() for Linux, | |||
948 | // FreeBSD and NetBSD. | |||
949 | ||||
950 | Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) { | |||
951 | std::unique_ptr<ProcessLauncher> delegate_launcher; | |||
952 | #if defined(_WIN32) | |||
953 | delegate_launcher.reset(new ProcessLauncherWindows()); | |||
954 | #elif defined(__linux__1) || defined(__NetBSD__) | |||
955 | delegate_launcher.reset(new ProcessLauncherPosixFork()); | |||
956 | #else | |||
957 | delegate_launcher.reset(new ProcessLauncherPosix()); | |||
958 | #endif | |||
959 | MonitoringProcessLauncher launcher(std::move(delegate_launcher)); | |||
960 | ||||
961 | Status error; | |||
962 | HostProcess process = launcher.LaunchProcess(launch_info, error); | |||
963 | ||||
964 | // TODO(zturner): It would be better if the entire HostProcess were returned | |||
965 | // instead of writing | |||
966 | // it into this structure. | |||
967 | launch_info.SetProcessID(process.GetProcessId()); | |||
968 | ||||
969 | return error; | |||
970 | } | |||
971 | #endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) | |||
972 | ||||
973 | #ifndef _WIN32 | |||
974 | void Host::Kill(lldb::pid_t pid, int signo) { ::kill(pid, signo); } | |||
975 | ||||
976 | #endif | |||
977 | ||||
978 | #if !defined(__APPLE__) | |||
979 | bool Host::OpenFileInExternalEditor(const FileSpec &file_spec, | |||
980 | uint32_t line_no) { | |||
981 | return false; | |||
982 | } | |||
983 | ||||
984 | #endif | |||
985 | ||||
986 | const UnixSignalsSP &Host::GetUnixSignals() { | |||
987 | static const auto s_unix_signals_sp = | |||
988 | UnixSignals::Create(HostInfo::GetArchitecture()); | |||
989 | return s_unix_signals_sp; | |||
990 | } |