498 lines · cpp
1//===-- GDBRemoteCommunicationServerPlatform.cpp --------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "GDBRemoteCommunicationServerPlatform.h"10 11#include <cerrno>12 13#include <chrono>14#include <csignal>15#include <cstring>16#include <mutex>17#include <optional>18#include <sstream>19#include <thread>20 21#include "llvm/Support/FileSystem.h"22#include "llvm/Support/JSON.h"23#include "llvm/Support/Threading.h"24 25#include "lldb/Host/Config.h"26#include "lldb/Host/ConnectionFileDescriptor.h"27#include "lldb/Host/FileAction.h"28#include "lldb/Host/Host.h"29#include "lldb/Host/HostInfo.h"30#include "lldb/Interpreter/CommandCompletions.h"31#include "lldb/Target/Platform.h"32#include "lldb/Target/UnixSignals.h"33#include "lldb/Utility/GDBRemote.h"34#include "lldb/Utility/LLDBLog.h"35#include "lldb/Utility/Log.h"36#include "lldb/Utility/StreamString.h"37#include "lldb/Utility/StructuredData.h"38#include "lldb/Utility/TildeExpressionResolver.h"39#include "lldb/Utility/UriParser.h"40 41#include "lldb/Utility/StringExtractorGDBRemote.h"42 43using namespace lldb;44using namespace lldb_private::process_gdb_remote;45using namespace lldb_private;46 47// GDBRemoteCommunicationServerPlatform constructor48GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(49 FileSpec debugserver_path, const Socket::SocketProtocol socket_protocol,50 uint16_t gdbserver_port)51 : m_debugserver_path(std::move(debugserver_path)),52 m_socket_protocol(socket_protocol), m_gdbserver_port(gdbserver_port) {53 54 RegisterMemberFunctionHandler(55 StringExtractorGDBRemote::eServerPacketType_qC,56 &GDBRemoteCommunicationServerPlatform::Handle_qC);57 RegisterMemberFunctionHandler(58 StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,59 &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);60 RegisterMemberFunctionHandler(61 StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,62 &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);63 RegisterMemberFunctionHandler(64 StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer,65 &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer);66 RegisterMemberFunctionHandler(67 StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,68 &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess);69 RegisterMemberFunctionHandler(70 StringExtractorGDBRemote::eServerPacketType_qProcessInfo,71 &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);72 RegisterMemberFunctionHandler(73 StringExtractorGDBRemote::eServerPacketType_qPathComplete,74 &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete);75 RegisterMemberFunctionHandler(76 StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,77 &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);78 RegisterMemberFunctionHandler(79 StringExtractorGDBRemote::eServerPacketType_jSignalsInfo,80 &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);81 82 RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,83 [](StringExtractorGDBRemote packet, Status &error,84 bool &interrupt, bool &quit) {85 error = Status::FromErrorString("interrupt received");86 interrupt = true;87 return PacketResult::Success;88 });89}90 91// Destructor92GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() =93 default;94 95Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(96 const lldb_private::Args &args, lldb::pid_t &pid, std::string &socket_name,97 shared_fd_t fd) {98 Log *log = GetLog(LLDBLog::Platform);99 100 ProcessLaunchInfo debugserver_launch_info;101 // Do not run in a new session so that it can not linger after the platform102 // closes.103 debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);104 debugserver_launch_info.SetMonitorProcessCallback(105 [](lldb::pid_t, int, int) {});106 if (!FileSystem::Instance().Exists(m_debugserver_path))107 return Status::FromErrorString("debugserver does not exist");108 debugserver_launch_info.SetExecutableFile(m_debugserver_path,109 /*add_exe_file_as_first_arg=*/true);110 111 Status error;112 if (fd == SharedSocket::kInvalidFD) {113 if (m_socket_protocol == Socket::ProtocolTcp) {114 // The server will be launched after accepting the connection.115 return Status();116 }117 118 std::ostringstream url;119 // debugserver does not accept the URL scheme prefix.120#if !defined(__APPLE__)121 url << Socket::FindSchemeByProtocol(m_socket_protocol) << "://";122#endif123 socket_name = GetDomainSocketPath("gdbserver").GetPath();124 url << socket_name;125 error = StartDebugserverProcess(url.str(), debugserver_launch_info, &args);126 } else {127 if (m_socket_protocol != Socket::ProtocolTcp)128 return Status::FromErrorString("protocol must be tcp");129 error = StartDebugserverProcess(fd, debugserver_launch_info, &args);130 }131 132 if (error.Success()) {133 pid = debugserver_launch_info.GetProcessID();134 AddSpawnedProcess(pid);135 LLDB_LOGF(log,136 "GDBRemoteCommunicationServerPlatform::%s() "137 "debugserver launched successfully as pid %" PRIu64,138 __FUNCTION__, pid);139 } else {140 LLDB_LOGF(log,141 "GDBRemoteCommunicationServerPlatform::%s() "142 "debugserver launch failed: %s",143 __FUNCTION__, error.AsCString());144 }145 return error;146}147 148GDBRemoteCommunication::PacketResult149GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(150 StringExtractorGDBRemote &packet) {151 // Spawn a local debugserver as a platform so we can then attach or launch a152 // process...153 154 Log *log = GetLog(LLDBLog::Platform);155 LLDB_LOGF(log, "GDBRemoteCommunicationServerPlatform::%s() called",156 __FUNCTION__);157 158 ConnectionFileDescriptor file_conn;159 std::string hostname;160 packet.SetFilePos(::strlen("qLaunchGDBServer;"));161 llvm::StringRef name;162 llvm::StringRef value;163 std::optional<uint16_t> port;164 while (packet.GetNameColonValue(name, value)) {165 if (name == "host")166 hostname = std::string(value);167 else if (name == "port") {168 // Make the Optional valid so we can use its value169 port = 0;170 value.getAsInteger(0, *port);171 }172 }173 174 // Ignore client's hostname and the port.175 176 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;177 std::string socket_name;178 Status error = LaunchGDBServer(Args(), debugserver_pid, socket_name,179 SharedSocket::kInvalidFD);180 if (error.Fail())181 return SendErrorResponse(9); // EBADF182 183 StreamGDBRemote response;184 uint16_t gdbserver_port = socket_name.empty() ? m_gdbserver_port : 0;185 response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, gdbserver_port);186 if (!socket_name.empty()) {187 response.PutCString("socket_name:");188 response.PutStringAsRawHex8(socket_name);189 response.PutChar(';');190 }191 192 PacketResult packet_result = SendPacketNoLock(response.GetString());193 if (packet_result != PacketResult::Success) {194 if (debugserver_pid != LLDB_INVALID_PROCESS_ID)195 Host::Kill(debugserver_pid, SIGINT);196 }197 return packet_result;198}199 200GDBRemoteCommunication::PacketResult201GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer(202 StringExtractorGDBRemote &packet) {203 namespace json = llvm::json;204 205 if (!m_pending_gdb_server_socket_name)206 return SendErrorResponse(4);207 208 json::Object server{{"port", m_pending_gdb_server_socket_name->empty()209 ? m_gdbserver_port210 : 0}};211 212 if (!m_pending_gdb_server_socket_name->empty())213 server.try_emplace("socket_name", *m_pending_gdb_server_socket_name);214 215 json::Array server_list;216 server_list.push_back(std::move(server));217 218 StreamGDBRemote response;219 response.AsRawOstream() << std::move(server_list);220 221 StreamGDBRemote escaped_response;222 escaped_response.PutEscapedBytes(response.GetString().data(),223 response.GetSize());224 return SendPacketNoLock(escaped_response.GetString());225}226 227GDBRemoteCommunication::PacketResult228GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess(229 StringExtractorGDBRemote &packet) {230 packet.SetFilePos(::strlen("qKillSpawnedProcess:"));231 232 lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);233 234 // verify that we know anything about this pid.235 if (!SpawnedProcessIsRunning(pid)) {236 // not a pid we know about237 return SendErrorResponse(10);238 }239 240 // go ahead and attempt to kill the spawned process241 if (KillSpawnedProcess(pid))242 return SendOKResponse();243 else244 return SendErrorResponse(11);245}246 247void GDBRemoteCommunicationServerPlatform::AddSpawnedProcess(lldb::pid_t pid) {248 assert(pid != LLDB_INVALID_PROCESS_ID);249 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);250 m_spawned_pids.insert(pid);251}252 253bool GDBRemoteCommunicationServerPlatform::SpawnedProcessIsRunning(254 lldb::pid_t pid) {255 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);256 return (m_spawned_pids.find(pid) != m_spawned_pids.end());257}258 259bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) {260 // make sure we know about this process261 if (!SpawnedProcessIsRunning(pid)) {262 // it seems the process has been finished recently263 return true;264 }265 266 // first try a SIGTERM (standard kill)267 Host::Kill(pid, SIGTERM);268 269 // check if that worked270 for (size_t i = 0; i < 10; ++i) {271 if (!SpawnedProcessIsRunning(pid)) {272 // it is now killed273 return true;274 }275 std::this_thread::sleep_for(std::chrono::milliseconds(10));276 }277 278 if (!SpawnedProcessIsRunning(pid))279 return true;280 281 // the launched process still lives. Now try killing it again, this time282 // with an unblockable signal.283 Host::Kill(pid, SIGKILL);284 285 for (size_t i = 0; i < 10; ++i) {286 if (!SpawnedProcessIsRunning(pid)) {287 // it is now killed288 return true;289 }290 std::this_thread::sleep_for(std::chrono::milliseconds(10));291 }292 293 // check one more time after the final sleep294 return !SpawnedProcessIsRunning(pid);295}296 297GDBRemoteCommunication::PacketResult298GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo(299 StringExtractorGDBRemote &packet) {300 lldb::pid_t pid = m_process_launch_info.GetProcessID();301 m_process_launch_info.Clear();302 303 if (pid == LLDB_INVALID_PROCESS_ID)304 return SendErrorResponse(1);305 306 ProcessInstanceInfo proc_info;307 if (!Host::GetProcessInfo(pid, proc_info))308 return SendErrorResponse(1);309 310 StreamString response;311 CreateProcessInfoResponse_DebugServerStyle(proc_info, response);312 return SendPacketNoLock(response.GetString());313}314 315GDBRemoteCommunication::PacketResult316GDBRemoteCommunicationServerPlatform::Handle_qPathComplete(317 StringExtractorGDBRemote &packet) {318 packet.SetFilePos(::strlen("qPathComplete:"));319 const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1);320 if (packet.GetChar() != ',')321 return SendErrorResponse(85);322 std::string path;323 packet.GetHexByteString(path);324 325 StringList matches;326 StandardTildeExpressionResolver resolver;327 if (only_dir)328 CommandCompletions::DiskDirectories(path, matches, resolver);329 else330 CommandCompletions::DiskFiles(path, matches, resolver);331 332 StreamString response;333 response.PutChar('M');334 llvm::StringRef separator;335 std::sort(matches.begin(), matches.end());336 for (const auto &match : matches) {337 response << separator;338 separator = ",";339 // encode result strings into hex bytes to avoid unexpected error caused by340 // special characters like '$'.341 response.PutStringAsRawHex8(match.c_str());342 }343 344 return SendPacketNoLock(response.GetString());345}346 347GDBRemoteCommunication::PacketResult348GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir(349 StringExtractorGDBRemote &packet) {350 351 llvm::SmallString<64> cwd;352 if (std::error_code ec = llvm::sys::fs::current_path(cwd))353 return SendErrorResponse(ec.value());354 355 StreamString response;356 response.PutBytesAsRawHex8(cwd.data(), cwd.size());357 return SendPacketNoLock(response.GetString());358}359 360GDBRemoteCommunication::PacketResult361GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir(362 StringExtractorGDBRemote &packet) {363 packet.SetFilePos(::strlen("QSetWorkingDir:"));364 std::string path;365 packet.GetHexByteString(path);366 367 if (std::error_code ec = llvm::sys::fs::set_current_path(path))368 return SendErrorResponse(ec.value());369 return SendOKResponse();370}371 372GDBRemoteCommunication::PacketResult373GDBRemoteCommunicationServerPlatform::Handle_qC(374 StringExtractorGDBRemote &packet) {375 // NOTE: lldb should now be using qProcessInfo for process IDs. This path376 // here377 // should not be used. It is reporting process id instead of thread id. The378 // correct answer doesn't seem to make much sense for lldb-platform.379 // CONSIDER: flip to "unsupported".380 lldb::pid_t pid = m_process_launch_info.GetProcessID();381 382 StreamString response;383 response.Printf("QC%" PRIx64, pid);384 385 // If we launch a process and this GDB server is acting as a platform, then386 // we need to clear the process launch state so we can start launching387 // another process. In order to launch a process a bunch or packets need to388 // be sent: environment packets, working directory, disable ASLR, and many389 // more settings. When we launch a process we then need to know when to clear390 // this information. Currently we are selecting the 'qC' packet as that391 // packet which seems to make the most sense.392 if (pid != LLDB_INVALID_PROCESS_ID) {393 m_process_launch_info.Clear();394 }395 396 return SendPacketNoLock(response.GetString());397}398 399GDBRemoteCommunication::PacketResult400GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(401 StringExtractorGDBRemote &packet) {402 StructuredData::Array signal_array;403 404 lldb::UnixSignalsSP signals = UnixSignals::CreateForHost();405 for (auto signo = signals->GetFirstSignalNumber();406 signo != LLDB_INVALID_SIGNAL_NUMBER;407 signo = signals->GetNextSignalNumber(signo)) {408 auto dictionary = std::make_shared<StructuredData::Dictionary>();409 410 dictionary->AddIntegerItem("signo", signo);411 dictionary->AddStringItem("name", signals->GetSignalAsStringRef(signo));412 413 bool suppress, stop, notify;414 signals->GetSignalInfo(signo, suppress, stop, notify);415 dictionary->AddBooleanItem("suppress", suppress);416 dictionary->AddBooleanItem("stop", stop);417 dictionary->AddBooleanItem("notify", notify);418 419 signal_array.Push(dictionary);420 }421 422 StreamString response;423 signal_array.Dump(response);424 return SendPacketNoLock(response.GetString());425}426 427void GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped(428 lldb::pid_t pid) {429 std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);430 m_spawned_pids.erase(pid);431}432 433Status GDBRemoteCommunicationServerPlatform::LaunchProcess() {434 if (!m_process_launch_info.GetArguments().GetArgumentCount())435 return Status::FromErrorStringWithFormat(436 "%s: no process command line specified to launch", __FUNCTION__);437 438 // specify the process monitor if not already set. This should generally be439 // what happens since we need to reap started processes.440 if (!m_process_launch_info.GetMonitorProcessCallback())441 m_process_launch_info.SetMonitorProcessCallback(std::bind(442 &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, this,443 std::placeholders::_1));444 445 Status error = Host::LaunchProcess(m_process_launch_info);446 if (!error.Success()) {447 fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__,448 m_process_launch_info.GetArguments().GetArgumentAtIndex(0));449 return error;450 }451 452 printf("Launched '%s' as process %" PRIu64 "...\n",453 m_process_launch_info.GetArguments().GetArgumentAtIndex(0),454 m_process_launch_info.GetProcessID());455 456 // add to list of spawned processes. On an lldb-gdbserver, we would expect457 // there to be only one.458 const auto pid = m_process_launch_info.GetProcessID();459 AddSpawnedProcess(pid);460 461 return error;462}463 464const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() {465 static FileSpec g_domainsocket_dir;466 static llvm::once_flag g_once_flag;467 468 llvm::call_once(g_once_flag, []() {469 const char *domainsocket_dir_env =470 ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR");471 if (domainsocket_dir_env != nullptr)472 g_domainsocket_dir = FileSpec(domainsocket_dir_env);473 else474 g_domainsocket_dir = HostInfo::GetProcessTempDir();475 });476 477 return g_domainsocket_dir;478}479 480FileSpec481GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) {482 llvm::SmallString<128> socket_path;483 llvm::SmallString<128> socket_name(484 (llvm::StringRef(prefix) + ".%%%%%%").str());485 486 FileSpec socket_path_spec(GetDomainSocketDir());487 socket_path_spec.AppendPathComponent(socket_name.c_str());488 489 llvm::sys::fs::createUniqueFile(socket_path_spec.GetPath().c_str(),490 socket_path);491 return FileSpec(socket_path.c_str());492}493 494void GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(495 const std::string &socket_name) {496 m_pending_gdb_server_socket_name = socket_name;497}498