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