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 | |
25 | namespace lldb_private { |
26 | |
27 | class FileAction; |
28 | class ProcessLaunchInfo; |
29 | class ProcessInstanceInfo; |
30 | class ProcessInstanceInfoMatch; |
31 | typedef std::vector<ProcessInstanceInfo> ProcessInstanceInfoList; |
32 | |
33 | // Exit Type for inferior processes |
34 | struct 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 | |
52 | inline bool operator==(WaitStatus a, WaitStatus b) { |
53 | return a.type == b.type && a.status == b.status; |
54 | } |
55 | |
56 | inline 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. |
62 | class Host { |
63 | public: |
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 | |
267 | protected: |
268 | static uint32_t FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, |
269 | ProcessInstanceInfoList &proc_infos); |
270 | }; |
271 | |
272 | } // namespace lldb_private |
273 | |
274 | namespace llvm { |
275 | template <> 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 | |