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 WaitStatusWaitStatus47 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