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 
26 namespace lldb_private {
27 
28 class FileAction;
29 class ProcessLaunchInfo;
30 class ProcessInstanceInfo;
31 class ProcessInstanceInfoMatch;
32 typedef std::vector<ProcessInstanceInfo> ProcessInstanceInfoList;
33 
34 // Exit Type for inferior processes
35 struct 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 
53 inline bool operator==(WaitStatus a, WaitStatus b) {
54   return a.type == b.type && a.status == b.status;
55 }
56 
57 inline 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.
63 class Host {
64 public:
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 
255 protected:
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.
261 class SystemLogHandler : public LogHandler {
262 public:
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 
269 private:
270   static char ID;
271 };
272 
273 } // namespace lldb_private
274 
275 namespace llvm {
276 template <> 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