1//===-- Host.h --------------------------------------------------*- C++ -*-===//
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#ifndef LLDB_HOST_HOST_H
10#define LLDB_HOST_HOST_H
11
12#include "lldb/Host/File.h"
13#include "lldb/Host/HostThread.h"
14#include "lldb/Utility/Environment.h"
15#include "lldb/Utility/FileSpec.h"
16#include "lldb/Utility/Log.h"
17#include "lldb/Utility/Timeout.h"
18#include "lldb/lldb-private-forward.h"
19#include "lldb/lldb-private.h"
20#include <cerrno>
21#include <cstdarg>
22#include <map>
23#include <string>
24#include <type_traits>
25
26namespace lldb_private {
27
28class FileAction;
29class ProcessLaunchInfo;
30class ProcessInstanceInfo;
31class ProcessInstanceInfoMatch;
32typedef std::vector<ProcessInstanceInfo> ProcessInstanceInfoList;
33
34// Exit Type for inferior processes
35struct WaitStatus {
36  enum Type : uint8_t {
37    Exit,   // The status represents the return code from normal
38            // program exit (i.e. WIFEXITED() was true)
39    Signal, // The status represents the signal number that caused
40            // the program to exit (i.e. WIFSIGNALED() was true)
41    Stop,   // The status represents the signal number that caused the
42            // program to stop (i.e. WIFSTOPPED() was true)
43  };
44
45  Type type;
46  uint8_t status;
47
48  WaitStatus(Type type, uint8_t status) : type(type), status(status) {}
49
50  static WaitStatus Decode(int wstatus);
51};
52
53inline bool operator==(WaitStatus a, WaitStatus b) {
54  return a.type == b.type && a.status == b.status;
55}
56
57inline bool operator!=(WaitStatus a, WaitStatus b) { return !(a == b); }
58
59/// \class Host Host.h "lldb/Host/Host.h"
60/// A class that provides host computer information.
61///
62/// Host is a class that answers information about the host operating system.
63class Host {
64public:
65  typedef std::function<void(lldb::pid_t pid,
66                             int signal,  // Zero for no signal
67                             int status)> // Exit value of process if signal is
68                                          // zero
69      MonitorChildProcessCallback;
70
71  /// Start monitoring a child process.
72  ///
73  /// Allows easy monitoring of child processes. \a callback will be called
74  /// when the child process exits or if it dies from a signal.
75  ///
76  /// \param[in] callback
77  ///     A function callback to call when a child receives a signal
78  ///     or exits.
79  ///
80  /// \param[in] pid
81  ///     The process ID of a child process to monitor.
82  ///
83  /// \return
84  ///     A thread handle that can be used to cancel the thread that
85  ///     was spawned to monitor \a pid.
86  static llvm::Expected<HostThread>
87  StartMonitoringChildProcess(const MonitorChildProcessCallback &callback,
88                              lldb::pid_t pid);
89
90  /// Emit the given message to the operating system log.
91  static void SystemLog(llvm::StringRef message);
92
93  /// Get the process ID for the calling process.
94  ///
95  /// \return
96  ///     The process ID for the current process.
97  static lldb::pid_t GetCurrentProcessID();
98
99  static void Kill(lldb::pid_t pid, int signo);
100
101  /// Get the thread token (the one returned by ThreadCreate when the thread
102  /// was created) for the calling thread in the current process.
103  ///
104  /// \return
105  ///     The thread token for the calling thread in the current process.
106  static lldb::thread_t GetCurrentThread();
107
108  static const char *GetSignalAsCString(int signo);
109
110  /// Given an address in the current process (the process that is running the
111  /// LLDB code), return the name of the module that it comes from. This can
112  /// be useful when you need to know the path to the shared library that your
113  /// code is running in for loading resources that are relative to your
114  /// binary.
115  ///
116  /// \param[in] host_addr
117  ///     The pointer to some code in the current process.
118  ///
119  /// \return
120  ///     \b A file spec with the module that contains \a host_addr,
121  ///     which may be invalid if \a host_addr doesn't fall into
122  ///     any valid module address range.
123  static FileSpec GetModuleFileSpecForHostAddress(const void *host_addr);
124
125  /// If you have an executable that is in a bundle and want to get back to
126  /// the bundle directory from the path itself, this function will change a
127  /// path to a file within a bundle to the bundle directory itself.
128  ///
129  /// \param[in] file
130  ///     A file spec that might point to a file in a bundle.
131  ///
132  /// \param[out] bundle_directory
133  ///     An object will be filled in with the bundle directory for
134  ///     the bundle when \b true is returned. Otherwise \a file is
135  ///     left untouched and \b false is returned.
136  ///
137  /// \return
138  ///     \b true if \a file was resolved in \a bundle_directory,
139  ///     \b false otherwise.
140  static bool GetBundleDirectory(const FileSpec &file,
141                                 FileSpec &bundle_directory);
142
143  /// When executable files may live within a directory, where the directory
144  /// represents an executable bundle (like the MacOSX app bundles), then
145  /// locate the executable within the containing bundle.
146  ///
147  /// \param[in,out] file
148  ///     A file spec that currently points to the bundle that will
149  ///     be filled in with the executable path within the bundle
150  ///     if \b true is returned. Otherwise \a file is left untouched.
151  ///
152  /// \return
153  ///     \b true if \a file was resolved, \b false if this function
154  ///     was not able to resolve the path.
155  static bool ResolveExecutableInBundle(FileSpec &file);
156
157  static uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info,
158                                ProcessInstanceInfoList &proc_infos);
159
160  typedef std::map<lldb::pid_t, bool> TidMap;
161  typedef std::pair<lldb::pid_t, bool> TidPair;
162  static bool FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach);
163
164  static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info);
165
166  /// Launch the process specified in launch_info. The monitoring callback in
167  /// launch_info must be set, and it will be called when the process
168  /// terminates.
169  static Status LaunchProcess(ProcessLaunchInfo &launch_info);
170
171  /// Perform expansion of the command-line for this launch info This can
172  /// potentially involve wildcard expansion
173  /// environment variable replacement, and whatever other
174  /// argument magic the platform defines as part of its typical
175  /// user experience
176  static Status ShellExpandArguments(ProcessLaunchInfo &launch_info);
177
178  /// Run a shell command.
179  /// \arg command  shouldn't be empty
180  /// \arg working_dir Pass empty FileSpec to use the current working directory
181  /// \arg status_ptr  Pass NULL if you don't want the process exit status
182  /// \arg signo_ptr   Pass NULL if you don't want the signal that caused the
183  ///                  process to exit
184  /// \arg command_output  Pass NULL if you don't want the command output
185  /// \arg hide_stderr if this is false, redirect stderr to stdout
186  static Status RunShellCommand(llvm::StringRef command,
187                                const FileSpec &working_dir, int *status_ptr,
188                                int *signo_ptr, std::string *command_output,
189                                const Timeout<std::micro> &timeout,
190                                bool run_in_shell = true,
191                                bool hide_stderr = false);
192
193  /// Run a shell command.
194  /// \arg shell  Pass an empty string if you want to use the default shell
195  /// interpreter \arg command \arg working_dir  Pass empty FileSpec to use the
196  /// current working directory \arg status_ptr   Pass NULL if you don't want
197  /// the process exit status \arg signo_ptr    Pass NULL if you don't want the
198  /// signal that caused
199  ///                   the process to exit
200  /// \arg command_output  Pass NULL if you don't want the command output
201  /// \arg hide_stderr  If this is \b false, redirect stderr to stdout
202  static Status RunShellCommand(llvm::StringRef shell, llvm::StringRef command,
203                                const FileSpec &working_dir, int *status_ptr,
204                                int *signo_ptr, std::string *command_output,
205                                const Timeout<std::micro> &timeout,
206                                bool run_in_shell = true,
207                                bool hide_stderr = false);
208
209  /// Run a shell command.
210  /// \arg working_dir Pass empty FileSpec to use the current working directory
211  /// \arg status_ptr  Pass NULL if you don't want the process exit status
212  /// \arg signo_ptr   Pass NULL if you don't want the signal that caused the
213  ///                  process to exit
214  /// \arg command_output  Pass NULL if you don't want the command output
215  /// \arg hide_stderr if this is false, redirect stderr to stdout
216  static Status RunShellCommand(const Args &args, const FileSpec &working_dir,
217                                int *status_ptr, int *signo_ptr,
218                                std::string *command_output,
219                                const Timeout<std::micro> &timeout,
220                                bool run_in_shell = true,
221                                bool hide_stderr = false);
222
223  /// Run a shell command.
224  /// \arg shell            Pass an empty string if you want to use the default
225  /// shell interpreter \arg command \arg working_dir Pass empty FileSpec to use
226  /// the current working directory \arg status_ptr    Pass NULL if you don't
227  /// want the process exit status \arg signo_ptr     Pass NULL if you don't
228  /// want the signal that caused the
229  ///               process to exit
230  /// \arg command_output  Pass NULL if you don't want the command output
231  /// \arg hide_stderr If this is \b false, redirect stderr to stdout
232  static Status RunShellCommand(llvm::StringRef shell, const Args &args,
233                                const FileSpec &working_dir, int *status_ptr,
234                                int *signo_ptr, std::string *command_output,
235                                const Timeout<std::micro> &timeout,
236                                bool run_in_shell = true,
237                                bool hide_stderr = false);
238
239  static llvm::Error OpenFileInExternalEditor(llvm::StringRef editor,
240                                              const FileSpec &file_spec,
241                                              uint32_t line_no);
242
243  /// Check if we're running in an interactive graphical session.
244  ///
245  /// \return
246  ///     True if we're running in an interactive graphical session. False if
247  ///     we're not or don't know.
248  static bool IsInteractiveGraphicSession();
249
250  static Environment GetEnvironment();
251
252  static std::unique_ptr<Connection>
253  CreateDefaultConnection(llvm::StringRef url);
254
255protected:
256  static uint32_t FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
257                                    ProcessInstanceInfoList &proc_infos);
258};
259
260/// Log handler that emits log messages to the operating system log.
261class SystemLogHandler : public LogHandler {
262public:
263  SystemLogHandler();
264  void Emit(llvm::StringRef message) override;
265
266  bool isA(const void *ClassID) const override { return ClassID == &ID; }
267  static bool classof(const LogHandler *obj) { return obj->isA(&ID); }
268
269private:
270  static char ID;
271};
272
273} // namespace lldb_private
274
275namespace llvm {
276template <> struct format_provider<lldb_private::WaitStatus> {
277  /// Options = "" gives a human readable description of the status Options =
278  /// "g" gives a gdb-remote protocol status (e.g., X09)
279  static void format(const lldb_private::WaitStatus &WS, raw_ostream &OS,
280                     llvm::StringRef Options);
281};
282} // namespace llvm
283
284#endif // LLDB_HOST_HOST_H
285