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
15#ifndef _WIN32
16#include <dlfcn.h>
17#include <grp.h>
18#include <netdb.h>
19#include <pwd.h>
20#include <spawn.h>
21#include <sys/stat.h>
22#include <sys/wait.h>
23#include <unistd.h>
24#endif
25
26#if defined(__APPLE__)
27#include <mach-o/dyld.h>
28#include <mach/mach_init.h>
29#include <mach/mach_port.h>
30#endif
31
32#if defined(__FreeBSD__)
33#include <pthread_np.h>
34#endif
35
36#if defined(__NetBSD__)
37#include <lwp.h>
38#endif
39
40#include <csignal>
41
42#include "lldb/Host/FileAction.h"
43#include "lldb/Host/FileSystem.h"
44#include "lldb/Host/Host.h"
45#include "lldb/Host/HostInfo.h"
46#include "lldb/Host/HostProcess.h"
47#include "lldb/Host/MonitoringProcessLauncher.h"
48#include "lldb/Host/ProcessLaunchInfo.h"
49#include "lldb/Host/ProcessLauncher.h"
50#include "lldb/Host/ThreadLauncher.h"
51#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
52#include "lldb/Utility/FileSpec.h"
53#include "lldb/Utility/LLDBLog.h"
54#include "lldb/Utility/Log.h"
55#include "lldb/Utility/Predicate.h"
56#include "lldb/Utility/Status.h"
57#include "lldb/lldb-private-forward.h"
58#include "llvm/ADT/SmallString.h"
59#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
60#include "llvm/Support/Errno.h"
61#include "llvm/Support/FileSystem.h"
62
63#if defined(_WIN32)
64#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
65#include "lldb/Host/windows/ProcessLauncherWindows.h"
66#else
67#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
68#endif
69
70#if defined(__APPLE__)
71#ifndef _POSIX_SPAWN_DISABLE_ASLR
72#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
73#endif
74
75extern "C" {
76int __pthread_chdir(const char *path);
77int __pthread_fchdir(int fildes);
78}
79
80#endif
81
82using namespace lldb;
83using namespace lldb_private;
84
85#if !defined(__APPLE__)
86// The system log is currently only meaningful on Darwin, where this means
87// os_log. The meaning of a "system log" isn't as clear on other platforms, and
88// therefore we don't providate a default implementation. Vendors are free to
89// to implement this function if they have a use for it.
90void Host::SystemLog(Severity severity, llvm::StringRef message) {}
91#endif
92
93static constexpr Log::Category g_categories[] = {
94 {{"system"}, {"system log"}, SystemLog::System}};
95
96static Log::Channel g_system_channel(g_categories, SystemLog::System);
97static Log g_system_log(g_system_channel);
98
99template <> Log::Channel &lldb_private::LogChannelFor<SystemLog>() {
100 return g_system_channel;
101}
102
103void LogChannelSystem::Initialize() {
104 g_system_log.Enable(handler_sp: std::make_shared<SystemLogHandler>());
105}
106
107void LogChannelSystem::Terminate() { g_system_log.Disable(); }
108
109#if !defined(__APPLE__) && !defined(_WIN32)
110extern "C" char **environ;
111
112Environment Host::GetEnvironment() { return Environment(environ); }
113
114static thread_result_t
115MonitorChildProcessThreadFunction(::pid_t pid,
116 Host::MonitorChildProcessCallback callback);
117
118llvm::Expected<HostThread> Host::StartMonitoringChildProcess(
119 const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid) {
120 char thread_name[256];
121 ::snprintf(s: thread_name, maxlen: sizeof(thread_name),
122 format: "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
123 assert(pid <= UINT32_MAX);
124 return ThreadLauncher::LaunchThread(name: thread_name, thread_function: [pid, callback] {
125 return MonitorChildProcessThreadFunction(pid, callback);
126 });
127}
128
129#ifndef __linux__
130// Scoped class that will disable thread canceling when it is constructed, and
131// exception safely restore the previous value it when it goes out of scope.
132class ScopedPThreadCancelDisabler {
133public:
134 ScopedPThreadCancelDisabler() {
135 // Disable the ability for this thread to be cancelled
136 int err = ::pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &m_old_state);
137 if (err != 0)
138 m_old_state = -1;
139 }
140
141 ~ScopedPThreadCancelDisabler() {
142 // Restore the ability for this thread to be cancelled to what it
143 // previously was.
144 if (m_old_state != -1)
145 ::pthread_setcancelstate(m_old_state, 0);
146 }
147
148private:
149 int m_old_state; // Save the old cancelability state.
150};
151#endif // __linux__
152
153#ifdef __linux__
154static thread_local volatile sig_atomic_t g_usr1_called;
155
156static void SigUsr1Handler(int) { g_usr1_called = 1; }
157#endif // __linux__
158
159static bool CheckForMonitorCancellation() {
160#ifdef __linux__
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
171static thread_result_t
172MonitorChildProcessThreadFunction(::pid_t pid,
173 Host::MonitorChildProcessCallback callback) {
174 Log *log = GetLog(mask: LLDBLog::Process);
175 LLDB_LOG(log, "pid = {0}", pid);
176
177 int status = -1;
178
179#ifdef __linux__
180 // This signal is only used to interrupt the thread from waitpid
181 struct sigaction sigUsr1Action;
182 memset(s: &sigUsr1Action, c: 0, n: sizeof(sigUsr1Action));
183 sigUsr1Action.sa_handler = SigUsr1Handler;
184 ::sigaction(SIGUSR1, act: &sigUsr1Action, oact: nullptr);
185#endif // __linux__
186
187 while (true) {
188 log = GetLog(mask: LLDBLog::Process);
189 LLDB_LOG(log, "::waitpid({0}, &status, 0)...", pid);
190
191 if (CheckForMonitorCancellation())
192 return nullptr;
193
194 const ::pid_t wait_pid = ::waitpid(pid: pid, stat_loc: &status, options: 0);
195
196 LLDB_LOG(log, "::waitpid({0}, &status, 0) => pid = {1}, status = {2:x}",
197 pid, wait_pid, status);
198
199 if (CheckForMonitorCancellation())
200 return nullptr;
201
202 if (wait_pid != -1)
203 break;
204 if (errno != EINTR) {
205 LLDB_LOG(log, "pid = {0}, thread exiting because waitpid failed ({1})...",
206 pid, llvm::sys::StrError());
207 return nullptr;
208 }
209 }
210
211 int signal = 0;
212 int exit_status = 0;
213 if (WIFEXITED(status)) {
214 exit_status = WEXITSTATUS(status);
215 } else if (WIFSIGNALED(status)) {
216 signal = WTERMSIG(status);
217 exit_status = -1;
218 } else {
219 llvm_unreachable("Unknown status");
220 }
221
222 // Scope for pthread_cancel_disabler
223 {
224#ifndef __linux__
225 ScopedPThreadCancelDisabler pthread_cancel_disabler;
226#endif
227
228 if (callback)
229 callback(pid, signal, exit_status);
230 }
231
232 LLDB_LOG(GetLog(LLDBLog::Process), "pid = {0} thread exiting...", pid);
233 return nullptr;
234}
235
236#endif // #if !defined (__APPLE__) && !defined (_WIN32)
237
238lldb::pid_t Host::GetCurrentProcessID() { return ::getpid(); }
239
240#ifndef _WIN32
241
242lldb::thread_t Host::GetCurrentThread() {
243 return lldb::thread_t(pthread_self());
244}
245
246const char *Host::GetSignalAsCString(int signo) {
247 switch (signo) {
248 case SIGHUP:
249 return "SIGHUP"; // 1 hangup
250 case SIGINT:
251 return "SIGINT"; // 2 interrupt
252 case SIGQUIT:
253 return "SIGQUIT"; // 3 quit
254 case SIGILL:
255 return "SIGILL"; // 4 illegal instruction (not reset when caught)
256 case SIGTRAP:
257 return "SIGTRAP"; // 5 trace trap (not reset when caught)
258 case SIGABRT:
259 return "SIGABRT"; // 6 abort()
260#if defined(SIGPOLL)
261#if !defined(SIGIO) || (SIGPOLL != SIGIO)
262 // Under some GNU/Linux, SIGPOLL and SIGIO are the same. Causing the build to
263 // fail with 'multiple define cases with same value'
264 case SIGPOLL:
265 return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported)
266#endif
267#endif
268#if defined(SIGEMT)
269 case SIGEMT:
270 return "SIGEMT"; // 7 EMT instruction
271#endif
272 case SIGFPE:
273 return "SIGFPE"; // 8 floating point exception
274 case SIGKILL:
275 return "SIGKILL"; // 9 kill (cannot be caught or ignored)
276 case SIGBUS:
277 return "SIGBUS"; // 10 bus error
278 case SIGSEGV:
279 return "SIGSEGV"; // 11 segmentation violation
280 case SIGSYS:
281 return "SIGSYS"; // 12 bad argument to system call
282 case SIGPIPE:
283 return "SIGPIPE"; // 13 write on a pipe with no one to read it
284 case SIGALRM:
285 return "SIGALRM"; // 14 alarm clock
286 case SIGTERM:
287 return "SIGTERM"; // 15 software termination signal from kill
288 case SIGURG:
289 return "SIGURG"; // 16 urgent condition on IO channel
290 case SIGSTOP:
291 return "SIGSTOP"; // 17 sendable stop signal not from tty
292 case SIGTSTP:
293 return "SIGTSTP"; // 18 stop signal from tty
294 case SIGCONT:
295 return "SIGCONT"; // 19 continue a stopped process
296 case SIGCHLD:
297 return "SIGCHLD"; // 20 to parent on child stop or exit
298 case SIGTTIN:
299 return "SIGTTIN"; // 21 to readers pgrp upon background tty read
300 case SIGTTOU:
301 return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local&LTOSTOP)
302#if defined(SIGIO)
303 case SIGIO:
304 return "SIGIO"; // 23 input/output possible signal
305#endif
306 case SIGXCPU:
307 return "SIGXCPU"; // 24 exceeded CPU time limit
308 case SIGXFSZ:
309 return "SIGXFSZ"; // 25 exceeded file size limit
310 case SIGVTALRM:
311 return "SIGVTALRM"; // 26 virtual time alarm
312 case SIGPROF:
313 return "SIGPROF"; // 27 profiling time alarm
314#if defined(SIGWINCH)
315 case SIGWINCH:
316 return "SIGWINCH"; // 28 window size changes
317#endif
318#if defined(SIGINFO)
319 case SIGINFO:
320 return "SIGINFO"; // 29 information request
321#endif
322 case SIGUSR1:
323 return "SIGUSR1"; // 30 user defined signal 1
324 case SIGUSR2:
325 return "SIGUSR2"; // 31 user defined signal 2
326 default:
327 break;
328 }
329 return nullptr;
330}
331
332#endif
333
334#if !defined(__APPLE__) // see Host.mm
335
336bool Host::GetBundleDirectory(const FileSpec &file, FileSpec &bundle) {
337 bundle.Clear();
338 return false;
339}
340
341bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; }
342#endif
343
344#ifndef _WIN32
345
346FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) {
347 FileSpec module_filespec;
348 Dl_info info;
349 if (::dladdr(address: host_addr, info: &info)) {
350 if (info.dli_fname) {
351 module_filespec.SetFile(path: info.dli_fname, style: FileSpec::Style::native);
352 FileSystem::Instance().Resolve(file_spec&: module_filespec);
353 }
354 }
355 return module_filespec;
356}
357
358#endif
359
360#if !defined(__linux__)
361bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {
362 return false;
363}
364#endif
365
366struct ShellInfo {
367 ShellInfo() : process_reaped(false) {}
368
369 lldb_private::Predicate<bool> process_reaped;
370 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
371 int signo = -1;
372 int status = -1;
373};
374
375static void
376MonitorShellCommand(std::shared_ptr<ShellInfo> shell_info, lldb::pid_t pid,
377 int signo, // Zero for no signal
378 int status) // Exit value of process if signal is zero
379{
380 shell_info->pid = pid;
381 shell_info->signo = signo;
382 shell_info->status = status;
383 // Let the thread running Host::RunShellCommand() know that the process
384 // exited and that ShellInfo has been filled in by broadcasting to it
385 shell_info->process_reaped.SetValue(value: true, broadcast_type: eBroadcastAlways);
386}
387
388Status Host::RunShellCommand(llvm::StringRef command,
389 const FileSpec &working_dir, int *status_ptr,
390 int *signo_ptr, std::string *command_output_ptr,
391 const Timeout<std::micro> &timeout,
392 bool run_in_shell, bool hide_stderr) {
393 return RunShellCommand(shell: llvm::StringRef(), args: Args(command), working_dir,
394 status_ptr, signo_ptr, command_output: command_output_ptr, timeout,
395 run_in_shell, hide_stderr);
396}
397
398Status Host::RunShellCommand(llvm::StringRef shell_path,
399 llvm::StringRef command,
400 const FileSpec &working_dir, int *status_ptr,
401 int *signo_ptr, std::string *command_output_ptr,
402 const Timeout<std::micro> &timeout,
403 bool run_in_shell, bool hide_stderr) {
404 return RunShellCommand(shell: shell_path, args: Args(command), working_dir, status_ptr,
405 signo_ptr, command_output: command_output_ptr, timeout, run_in_shell,
406 hide_stderr);
407}
408
409Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir,
410 int *status_ptr, int *signo_ptr,
411 std::string *command_output_ptr,
412 const Timeout<std::micro> &timeout,
413 bool run_in_shell, bool hide_stderr) {
414 return RunShellCommand(shell: llvm::StringRef(), args, working_dir, status_ptr,
415 signo_ptr, command_output: command_output_ptr, timeout, run_in_shell,
416 hide_stderr);
417}
418
419Status Host::RunShellCommand(llvm::StringRef shell_path, const Args &args,
420 const FileSpec &working_dir, int *status_ptr,
421 int *signo_ptr, std::string *command_output_ptr,
422 const Timeout<std::micro> &timeout,
423 bool run_in_shell, bool hide_stderr) {
424 Status error;
425 ProcessLaunchInfo launch_info;
426 launch_info.SetArchitecture(HostInfo::GetArchitecture());
427 if (run_in_shell) {
428 // Run the command in a shell
429 FileSpec shell = HostInfo::GetDefaultShell();
430 if (!shell_path.empty())
431 shell.SetPath(shell_path);
432
433 launch_info.SetShell(shell);
434 launch_info.GetArguments().AppendArguments(rhs: args);
435 const bool will_debug = false;
436 const bool first_arg_is_full_shell_command = false;
437 launch_info.ConvertArgumentsForLaunchingInShell(
438 error, will_debug, first_arg_is_full_shell_command, num_resumes: 0);
439 } else {
440 // No shell, just run it
441 const bool first_arg_is_executable = true;
442 launch_info.SetArguments(args, first_arg_is_executable);
443 }
444
445 launch_info.GetEnvironment() = Host::GetEnvironment();
446
447 if (working_dir)
448 launch_info.SetWorkingDirectory(working_dir);
449 llvm::SmallString<64> output_file_path;
450
451 if (command_output_ptr) {
452 // Create a temporary file to get the stdout/stderr and redirect the output
453 // of the command into this file. We will later read this file if all goes
454 // well and fill the data into "command_output_ptr"
455 if (FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir()) {
456 tmpdir_file_spec.AppendPathComponent(component: "lldb-shell-output.%%%%%%");
457 llvm::sys::fs::createUniqueFile(Model: tmpdir_file_spec.GetPath(),
458 ResultPath&: output_file_path);
459 } else {
460 llvm::sys::fs::createTemporaryFile(Prefix: "lldb-shell-output.%%%%%%", Suffix: "",
461 ResultPath&: output_file_path);
462 }
463 }
464
465 FileSpec output_file_spec(output_file_path.str());
466 // Set up file descriptors.
467 launch_info.AppendSuppressFileAction(STDIN_FILENO, read: true, write: false);
468 if (output_file_spec)
469 launch_info.AppendOpenFileAction(STDOUT_FILENO, file_spec: output_file_spec, read: false,
470 write: true);
471 else
472 launch_info.AppendSuppressFileAction(STDOUT_FILENO, read: false, write: true);
473
474 if (output_file_spec && !hide_stderr)
475 launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
476 else
477 launch_info.AppendSuppressFileAction(STDERR_FILENO, read: false, write: true);
478
479 std::shared_ptr<ShellInfo> shell_info_sp(new ShellInfo());
480 launch_info.SetMonitorProcessCallback(
481 std::bind(f&: MonitorShellCommand, args&: shell_info_sp, args: std::placeholders::_1,
482 args: std::placeholders::_2, args: std::placeholders::_3));
483
484 error = LaunchProcess(launch_info);
485 const lldb::pid_t pid = launch_info.GetProcessID();
486
487 if (error.Success() && pid == LLDB_INVALID_PROCESS_ID)
488 error = Status::FromErrorString(str: "failed to get process ID");
489
490 if (error.Success()) {
491 if (!shell_info_sp->process_reaped.WaitForValueEqualTo(value: true, timeout)) {
492 error = Status::FromErrorString(
493 str: "timed out waiting for shell command to complete");
494
495 // Kill the process since it didn't complete within the timeout specified
496 Kill(pid, SIGKILL);
497 // Wait for the monitor callback to get the message
498 shell_info_sp->process_reaped.WaitForValueEqualTo(
499 value: true, timeout: std::chrono::seconds(1));
500 } else {
501 if (status_ptr)
502 *status_ptr = shell_info_sp->status;
503
504 if (signo_ptr)
505 *signo_ptr = shell_info_sp->signo;
506
507 if (command_output_ptr) {
508 command_output_ptr->clear();
509 uint64_t file_size =
510 FileSystem::Instance().GetByteSize(file_spec: output_file_spec);
511 if (file_size > 0) {
512 if (file_size > command_output_ptr->max_size()) {
513 error = Status::FromErrorStringWithFormat(
514 format: "shell command output is too large to fit into a std::string");
515 } else {
516 WritableDataBufferSP Buffer =
517 FileSystem::Instance().CreateWritableDataBuffer(
518 file_spec: output_file_spec);
519 if (error.Success())
520 command_output_ptr->assign(
521 s: reinterpret_cast<char *>(Buffer->GetBytes()),
522 n: Buffer->GetByteSize());
523 }
524 }
525 }
526 }
527 }
528
529 llvm::sys::fs::remove(path: output_file_spec.GetPath());
530 return error;
531}
532
533// The functions below implement process launching for non-Apple-based
534// platforms
535#if !defined(__APPLE__)
536Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
537 std::unique_ptr<ProcessLauncher> delegate_launcher;
538#if defined(_WIN32)
539 delegate_launcher.reset(new ProcessLauncherWindows());
540#else
541 delegate_launcher.reset(p: new ProcessLauncherPosixFork());
542#endif
543 MonitoringProcessLauncher launcher(std::move(delegate_launcher));
544
545 Status error;
546 HostProcess process = launcher.LaunchProcess(launch_info, error);
547
548 // TODO(zturner): It would be better if the entire HostProcess were returned
549 // instead of writing it into this structure.
550 launch_info.SetProcessID(process.GetProcessId());
551
552 return error;
553}
554#endif // !defined(__APPLE__)
555
556#ifndef _WIN32
557void Host::Kill(lldb::pid_t pid, int signo) { ::kill(pid: pid, sig: signo); }
558
559#endif
560
561#if !defined(__APPLE__)
562llvm::Error Host::OpenFileInExternalEditor(llvm::StringRef editor,
563 const FileSpec &file_spec,
564 uint32_t line_no) {
565 return llvm::errorCodeToError(
566 EC: std::error_code(ENOTSUP, std::system_category()));
567}
568
569bool Host::IsInteractiveGraphicSession() { return false; }
570#endif
571
572std::unique_ptr<Connection> Host::CreateDefaultConnection(llvm::StringRef url) {
573#if defined(_WIN32)
574 if (url.starts_with("file://"))
575 return std::unique_ptr<Connection>(new ConnectionGenericFile());
576#endif
577 return std::unique_ptr<Connection>(new ConnectionFileDescriptor());
578}
579
580#if defined(LLVM_ON_UNIX)
581WaitStatus WaitStatus::Decode(int wstatus) {
582 if (WIFEXITED(wstatus))
583 return {Exit, uint8_t(WEXITSTATUS(wstatus))};
584 else if (WIFSIGNALED(wstatus))
585 return {Signal, uint8_t(WTERMSIG(wstatus))};
586 else if (WIFSTOPPED(wstatus))
587 return {Stop, uint8_t(WSTOPSIG(wstatus))};
588 llvm_unreachable("Unknown wait status");
589}
590#endif
591
592void llvm::format_provider<WaitStatus>::format(const WaitStatus &WS,
593 raw_ostream &OS,
594 StringRef Options) {
595 if (Options == "g") {
596 char type;
597 switch (WS.type) {
598 case WaitStatus::Exit:
599 type = 'W';
600 break;
601 case WaitStatus::Signal:
602 type = 'X';
603 break;
604 case WaitStatus::Stop:
605 type = 'S';
606 break;
607 }
608 OS << formatv(Fmt: "{0}{1:x-2}", Vals&: type, Vals: WS.status);
609 return;
610 }
611
612 assert(Options.empty());
613 const char *desc;
614 switch (WS.type) {
615 case WaitStatus::Exit:
616 desc = "Exited with status";
617 break;
618 case WaitStatus::Signal:
619 desc = "Killed by signal";
620 break;
621 case WaitStatus::Stop:
622 desc = "Stopped by signal";
623 break;
624 }
625 OS << desc << " " << int(WS.status);
626}
627
628uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
629 ProcessInstanceInfoList &process_infos) {
630 return FindProcessesImpl(match_info, proc_infos&: process_infos);
631}
632
633char SystemLogHandler::ID;
634
635SystemLogHandler::SystemLogHandler() {}
636
637void SystemLogHandler::Emit(llvm::StringRef message) {
638 Host::SystemLog(severity: lldb::eSeverityInfo, message);
639}
640

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of lldb/source/Host/common/Host.cpp