Bug Summary

File:src/gnu/usr.bin/clang/liblldbHostCommon/../../../llvm/lldb/source/Host/common/Host.cpp
Warning:line 269, column 13
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

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