1 //===-- GDBRemoteCommunicationServerPlatform.cpp ----------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "GDBRemoteCommunicationServerPlatform.h" 11 12 #include <errno.h> 13 14 // C Includes 15 // C++ Includes 16 #include <cstring> 17 #include <chrono> 18 19 // Other libraries and framework includes 20 #include "lldb/Core/Log.h" 21 #include "lldb/Core/StreamString.h" 22 #include "lldb/Host/Config.h" 23 #include "lldb/Host/ConnectionFileDescriptor.h" 24 #include "lldb/Host/Host.h" 25 #include "lldb/Host/StringConvert.h" 26 #include "lldb/Target/FileAction.h" 27 #include "lldb/Target/Platform.h" 28 #include "lldb/Target/Process.h" 29 30 // Project includes 31 #include "Utility/StringExtractorGDBRemote.h" 32 #include "Utility/UriParser.h" 33 34 using namespace lldb; 35 using namespace lldb_private; 36 37 //---------------------------------------------------------------------- 38 // GDBRemoteCommunicationServerPlatform constructor 39 //---------------------------------------------------------------------- 40 GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform() : 41 GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"), 42 m_platform_sp (Platform::GetHostPlatform ()), 43 m_port_map (), 44 m_port_offset(0) 45 { 46 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, 47 &GDBRemoteCommunicationServerPlatform::Handle_qC); 48 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, 49 &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir); 50 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer, 51 &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer); 52 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo, 53 &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); 54 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, 55 &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); 56 57 RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, 58 [this](StringExtractorGDBRemote packet, 59 Error &error, 60 bool &interrupt, 61 bool &quit) 62 { 63 error.SetErrorString("interrupt received"); 64 interrupt = true; 65 return PacketResult::Success; 66 }); 67 } 68 69 //---------------------------------------------------------------------- 70 // Destructor 71 //---------------------------------------------------------------------- 72 GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() 73 { 74 } 75 76 GDBRemoteCommunication::PacketResult 77 GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) 78 { 79 #ifdef _WIN32 80 return SendErrorResponse(9); 81 #else 82 // Spawn a local debugserver as a platform so we can then attach or launch 83 // a process... 84 85 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 86 if (log) 87 log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); 88 89 // Sleep and wait a bit for debugserver to start to listen... 90 ConnectionFileDescriptor file_conn; 91 std::string hostname; 92 // TODO: /tmp/ should not be hardcoded. User might want to override /tmp 93 // with the TMPDIR environment variable 94 packet.SetFilePos(::strlen ("qLaunchGDBServer;")); 95 std::string name; 96 std::string value; 97 uint16_t port = UINT16_MAX; 98 while (packet.GetNameColonValue(name, value)) 99 { 100 if (name.compare ("host") == 0) 101 hostname.swap(value); 102 else if (name.compare ("port") == 0) 103 port = StringConvert::ToUInt32(value.c_str(), 0, 0); 104 } 105 if (port == UINT16_MAX) 106 port = GetNextAvailablePort(); 107 108 // Spawn a new thread to accept the port that gets bound after 109 // binding to port 0 (zero). 110 111 // ignore the hostname send from the remote end, just use the ip address 112 // that we're currently communicating with as the hostname 113 114 // Spawn a debugserver and try to get the port it listens to. 115 ProcessLaunchInfo debugserver_launch_info; 116 if (hostname.empty()) 117 hostname = "127.0.0.1"; 118 if (log) 119 log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port); 120 121 // Do not run in a new session so that it can not linger after the 122 // platform closes. 123 debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); 124 debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); 125 126 std::string platform_scheme; 127 std::string platform_ip; 128 int platform_port; 129 std::string platform_path; 130 bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path); 131 assert(ok); 132 Error error = StartDebugserverProcess ( 133 platform_ip.c_str(), 134 port, 135 debugserver_launch_info, 136 port); 137 138 lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); 139 140 141 if (debugserver_pid != LLDB_INVALID_PROCESS_ID) 142 { 143 Mutex::Locker locker (m_spawned_pids_mutex); 144 m_spawned_pids.insert(debugserver_pid); 145 if (port > 0) 146 AssociatePortWithProcess(port, debugserver_pid); 147 } 148 else 149 { 150 if (port > 0) 151 FreePort (port); 152 } 153 154 if (error.Success()) 155 { 156 if (log) 157 log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); 158 159 char response[256]; 160 const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); 161 assert (response_len < (int)sizeof(response)); 162 PacketResult packet_result = SendPacketNoLock (response, response_len); 163 164 if (packet_result != PacketResult::Success) 165 { 166 if (debugserver_pid != LLDB_INVALID_PROCESS_ID) 167 ::kill (debugserver_pid, SIGINT); 168 } 169 return packet_result; 170 } 171 else 172 { 173 if (log) 174 log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); 175 } 176 return SendErrorResponse (9); 177 #endif 178 } 179 180 GDBRemoteCommunication::PacketResult 181 GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo (StringExtractorGDBRemote &packet) 182 { 183 lldb::pid_t pid = m_process_launch_info.GetProcessID (); 184 m_process_launch_info.Clear (); 185 186 if (pid == LLDB_INVALID_PROCESS_ID) 187 return SendErrorResponse (1); 188 189 ProcessInstanceInfo proc_info; 190 if (!Host::GetProcessInfo (pid, proc_info)) 191 return SendErrorResponse (1); 192 193 StreamString response; 194 CreateProcessInfoResponse_DebugServerStyle(proc_info, response); 195 return SendPacketNoLock (response.GetData (), response.GetSize ()); 196 } 197 198 GDBRemoteCommunication::PacketResult 199 GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) 200 { 201 // If this packet is sent to a platform, then change the current working directory 202 203 char cwd[PATH_MAX]; 204 if (getcwd(cwd, sizeof(cwd)) == NULL) 205 return SendErrorResponse(errno); 206 207 StreamString response; 208 response.PutBytesAsRawHex8(cwd, strlen(cwd)); 209 return SendPacketNoLock(response.GetData(), response.GetSize()); 210 } 211 212 GDBRemoteCommunication::PacketResult 213 GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) 214 { 215 packet.SetFilePos (::strlen ("QSetWorkingDir:")); 216 std::string path; 217 packet.GetHexByteString (path); 218 219 #ifdef _WIN32 220 // Not implemented on Windows 221 return SendUnimplementedResponse ("GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir unimplemented"); 222 #else 223 // If this packet is sent to a platform, then change the current working directory 224 if (::chdir(path.c_str()) != 0) 225 return SendErrorResponse (errno); 226 return SendOKResponse (); 227 #endif 228 } 229 230 GDBRemoteCommunication::PacketResult 231 GDBRemoteCommunicationServerPlatform::Handle_qC (StringExtractorGDBRemote &packet) 232 { 233 // NOTE: lldb should now be using qProcessInfo for process IDs. This path here 234 // should not be used. It is reporting process id instead of thread id. The 235 // correct answer doesn't seem to make much sense for lldb-platform. 236 // CONSIDER: flip to "unsupported". 237 lldb::pid_t pid = m_process_launch_info.GetProcessID(); 238 239 StreamString response; 240 response.Printf("QC%" PRIx64, pid); 241 242 // If we launch a process and this GDB server is acting as a platform, 243 // then we need to clear the process launch state so we can start 244 // launching another process. In order to launch a process a bunch or 245 // packets need to be sent: environment packets, working directory, 246 // disable ASLR, and many more settings. When we launch a process we 247 // then need to know when to clear this information. Currently we are 248 // selecting the 'qC' packet as that packet which seems to make the most 249 // sense. 250 if (pid != LLDB_INVALID_PROCESS_ID) 251 { 252 m_process_launch_info.Clear(); 253 } 254 255 return SendPacketNoLock (response.GetData(), response.GetSize()); 256 } 257 258 bool 259 GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped (lldb::pid_t pid) 260 { 261 Mutex::Locker locker (m_spawned_pids_mutex); 262 FreePortForProcess(pid); 263 return m_spawned_pids.erase(pid) > 0; 264 } 265 266 bool 267 GDBRemoteCommunicationServerPlatform::ReapDebugserverProcess (void *callback_baton, 268 lldb::pid_t pid, 269 bool exited, 270 int signal, // Zero for no signal 271 int status) // Exit value of process if signal is zero 272 { 273 GDBRemoteCommunicationServerPlatform *server = (GDBRemoteCommunicationServerPlatform *)callback_baton; 274 server->DebugserverProcessReaped (pid); 275 return true; 276 } 277 278 lldb_private::Error 279 GDBRemoteCommunicationServerPlatform::LaunchProcess () 280 { 281 if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) 282 return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); 283 284 // specify the process monitor if not already set. This should 285 // generally be what happens since we need to reap started 286 // processes. 287 if (!m_process_launch_info.GetMonitorProcessCallback ()) 288 m_process_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); 289 290 lldb_private::Error error = m_platform_sp->LaunchProcess (m_process_launch_info); 291 if (!error.Success ()) 292 { 293 fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); 294 return error; 295 } 296 297 printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID()); 298 299 // add to list of spawned processes. On an lldb-gdbserver, we 300 // would expect there to be only one. 301 const auto pid = m_process_launch_info.GetProcessID(); 302 if (pid != LLDB_INVALID_PROCESS_ID) 303 { 304 // add to spawned pids 305 Mutex::Locker locker (m_spawned_pids_mutex); 306 m_spawned_pids.insert(pid); 307 } 308 309 return error; 310 } 311 312 void 313 GDBRemoteCommunicationServerPlatform::SetPortMap (PortMap &&port_map) 314 { 315 m_port_map = port_map; 316 } 317 318 uint16_t 319 GDBRemoteCommunicationServerPlatform::GetNextAvailablePort () 320 { 321 if (m_port_map.empty()) 322 return 0; // Bind to port zero and get a port, we didn't have any limitations 323 324 for (auto &pair : m_port_map) 325 { 326 if (pair.second == LLDB_INVALID_PROCESS_ID) 327 { 328 pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; 329 return pair.first; 330 } 331 } 332 return UINT16_MAX; 333 } 334 335 bool 336 GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess (uint16_t port, lldb::pid_t pid) 337 { 338 PortMap::iterator pos = m_port_map.find(port); 339 if (pos != m_port_map.end()) 340 { 341 pos->second = pid; 342 return true; 343 } 344 return false; 345 } 346 347 bool 348 GDBRemoteCommunicationServerPlatform::FreePort (uint16_t port) 349 { 350 PortMap::iterator pos = m_port_map.find(port); 351 if (pos != m_port_map.end()) 352 { 353 pos->second = LLDB_INVALID_PROCESS_ID; 354 return true; 355 } 356 return false; 357 } 358 359 bool 360 GDBRemoteCommunicationServerPlatform::FreePortForProcess (lldb::pid_t pid) 361 { 362 if (!m_port_map.empty()) 363 { 364 for (auto &pair : m_port_map) 365 { 366 if (pair.second == pid) 367 { 368 pair.second = LLDB_INVALID_PROCESS_ID; 369 return true; 370 } 371 } 372 } 373 return false; 374 } 375 376 void 377 GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset) 378 { 379 m_port_offset = port_offset; 380 } 381