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