180814287SRaphael Isemann //===-- GDBRemoteCommunicationServerPlatform.cpp --------------------------===//
2e13c2731STamas Berghammer //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e13c2731STamas Berghammer //
7e13c2731STamas Berghammer //===----------------------------------------------------------------------===//
8e13c2731STamas Berghammer
9e13c2731STamas Berghammer #include "GDBRemoteCommunicationServerPlatform.h"
10e13c2731STamas Berghammer
1176e47d48SRaphael Isemann #include <cerrno>
12e13c2731STamas Berghammer
13e13c2731STamas Berghammer #include <chrono>
146b3c8bb0SPavel Labath #include <csignal>
15b9c1b51eSKate Stone #include <cstring>
169fe526c2SOleksiy Vyalov #include <mutex>
179fe526c2SOleksiy Vyalov #include <sstream>
183d4f7655SPavel Labath #include <thread>
19e13c2731STamas Berghammer
209fe526c2SOleksiy Vyalov #include "llvm/Support/FileSystem.h"
217cb720ddSJonas Devlieghere #include "llvm/Support/JSON.h"
22c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h"
239fe526c2SOleksiy Vyalov
24e13c2731STamas Berghammer #include "lldb/Host/Config.h"
25e13c2731STamas Berghammer #include "lldb/Host/ConnectionFileDescriptor.h"
26eef758e9SPavel Labath #include "lldb/Host/FileAction.h"
27e13c2731STamas Berghammer #include "lldb/Host/Host.h"
289fe526c2SOleksiy Vyalov #include "lldb/Host/HostInfo.h"
293cd8d7b1SGongyu Deng #include "lldb/Interpreter/CommandCompletions.h"
30e13c2731STamas Berghammer #include "lldb/Target/Platform.h"
3198d0a4b3SChaoren Lin #include "lldb/Target/UnixSignals.h"
32ff5225bfSJonas Devlieghere #include "lldb/Utility/GDBRemote.h"
33c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
346f9e6901SZachary Turner #include "lldb/Utility/Log.h"
35bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
36f2a8bccfSPavel Labath #include "lldb/Utility/StructuredData.h"
373cd8d7b1SGongyu Deng #include "lldb/Utility/TildeExpressionResolver.h"
385f7e583bSPavel Labath #include "lldb/Utility/UriParser.h"
39e13c2731STamas Berghammer
409af71b38SPavel Labath #include "lldb/Utility/StringExtractorGDBRemote.h"
41e13c2731STamas Berghammer
42e13c2731STamas Berghammer using namespace lldb;
43db264a6dSTamas Berghammer using namespace lldb_private::process_gdb_remote;
447cb720ddSJonas Devlieghere using namespace lldb_private;
45e13c2731STamas Berghammer
PortMap(uint16_t min_port,uint16_t max_port)4698e87f76SDavid Spickett GDBRemoteCommunicationServerPlatform::PortMap::PortMap(uint16_t min_port,
4798e87f76SDavid Spickett uint16_t max_port) {
4898e87f76SDavid Spickett for (; min_port < max_port; ++min_port)
4998e87f76SDavid Spickett m_port_map[min_port] = LLDB_INVALID_PROCESS_ID;
5098e87f76SDavid Spickett }
5198e87f76SDavid Spickett
AllowPort(uint16_t port)5298e87f76SDavid Spickett void GDBRemoteCommunicationServerPlatform::PortMap::AllowPort(uint16_t port) {
5398e87f76SDavid Spickett // Do not modify existing mappings
5498e87f76SDavid Spickett m_port_map.insert({port, LLDB_INVALID_PROCESS_ID});
5598e87f76SDavid Spickett }
5698e87f76SDavid Spickett
5798e87f76SDavid Spickett llvm::Expected<uint16_t>
GetNextAvailablePort()5898e87f76SDavid Spickett GDBRemoteCommunicationServerPlatform::PortMap::GetNextAvailablePort() {
5998e87f76SDavid Spickett if (m_port_map.empty())
6098e87f76SDavid Spickett return 0; // Bind to port zero and get a port, we didn't have any
6198e87f76SDavid Spickett // limitations
6298e87f76SDavid Spickett
6398e87f76SDavid Spickett for (auto &pair : m_port_map) {
6498e87f76SDavid Spickett if (pair.second == LLDB_INVALID_PROCESS_ID) {
6598e87f76SDavid Spickett pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
6698e87f76SDavid Spickett return pair.first;
6798e87f76SDavid Spickett }
6898e87f76SDavid Spickett }
6998e87f76SDavid Spickett return llvm::createStringError(llvm::inconvertibleErrorCode(),
7098e87f76SDavid Spickett "No free port found in port map");
7198e87f76SDavid Spickett }
7298e87f76SDavid Spickett
AssociatePortWithProcess(uint16_t port,lldb::pid_t pid)7398e87f76SDavid Spickett bool GDBRemoteCommunicationServerPlatform::PortMap::AssociatePortWithProcess(
7498e87f76SDavid Spickett uint16_t port, lldb::pid_t pid) {
7598e87f76SDavid Spickett auto pos = m_port_map.find(port);
7698e87f76SDavid Spickett if (pos != m_port_map.end()) {
7798e87f76SDavid Spickett pos->second = pid;
7898e87f76SDavid Spickett return true;
7998e87f76SDavid Spickett }
8098e87f76SDavid Spickett return false;
8198e87f76SDavid Spickett }
8298e87f76SDavid Spickett
FreePort(uint16_t port)8398e87f76SDavid Spickett bool GDBRemoteCommunicationServerPlatform::PortMap::FreePort(uint16_t port) {
8498e87f76SDavid Spickett std::map<uint16_t, lldb::pid_t>::iterator pos = m_port_map.find(port);
8598e87f76SDavid Spickett if (pos != m_port_map.end()) {
8698e87f76SDavid Spickett pos->second = LLDB_INVALID_PROCESS_ID;
8798e87f76SDavid Spickett return true;
8898e87f76SDavid Spickett }
8998e87f76SDavid Spickett return false;
9098e87f76SDavid Spickett }
9198e87f76SDavid Spickett
FreePortForProcess(lldb::pid_t pid)9298e87f76SDavid Spickett bool GDBRemoteCommunicationServerPlatform::PortMap::FreePortForProcess(
9398e87f76SDavid Spickett lldb::pid_t pid) {
9498e87f76SDavid Spickett if (!m_port_map.empty()) {
9598e87f76SDavid Spickett for (auto &pair : m_port_map) {
9698e87f76SDavid Spickett if (pair.second == pid) {
9798e87f76SDavid Spickett pair.second = LLDB_INVALID_PROCESS_ID;
9898e87f76SDavid Spickett return true;
9998e87f76SDavid Spickett }
10098e87f76SDavid Spickett }
10198e87f76SDavid Spickett }
10298e87f76SDavid Spickett return false;
10398e87f76SDavid Spickett }
10498e87f76SDavid Spickett
empty() const10598e87f76SDavid Spickett bool GDBRemoteCommunicationServerPlatform::PortMap::empty() const {
10698e87f76SDavid Spickett return m_port_map.empty();
10798e87f76SDavid Spickett }
10898e87f76SDavid Spickett
109e13c2731STamas Berghammer // GDBRemoteCommunicationServerPlatform constructor
GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol,const char * socket_scheme)110b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
111b9c1b51eSKate Stone const Socket::SocketProtocol socket_protocol, const char *socket_scheme)
112b9c1b51eSKate Stone : GDBRemoteCommunicationServerCommon("gdb-remote.server",
113b9c1b51eSKate Stone "gdb-remote.server.rx_packet"),
114b9c1b51eSKate Stone m_socket_protocol(socket_protocol), m_socket_scheme(socket_scheme),
115b9c1b51eSKate Stone m_spawned_pids_mutex(), m_port_map(), m_port_offset(0) {
116372810f5STamas Berghammer m_pending_gdb_server.pid = LLDB_INVALID_PROCESS_ID;
117372810f5STamas Berghammer m_pending_gdb_server.port = 0;
118372810f5STamas Berghammer
119b9c1b51eSKate Stone RegisterMemberFunctionHandler(
120b9c1b51eSKate Stone StringExtractorGDBRemote::eServerPacketType_qC,
121e13c2731STamas Berghammer &GDBRemoteCommunicationServerPlatform::Handle_qC);
122b9c1b51eSKate Stone RegisterMemberFunctionHandler(
123b9c1b51eSKate Stone StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
124e13c2731STamas Berghammer &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);
125b9c1b51eSKate Stone RegisterMemberFunctionHandler(
126b9c1b51eSKate Stone StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,
127e13c2731STamas Berghammer &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);
128b9c1b51eSKate Stone RegisterMemberFunctionHandler(
129b9c1b51eSKate Stone StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer,
130ccd6cffbSTamas Berghammer &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer);
131b9c1b51eSKate Stone RegisterMemberFunctionHandler(
132b9c1b51eSKate Stone StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,
1336e4f19d4SPavel Labath &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess);
134b9c1b51eSKate Stone RegisterMemberFunctionHandler(
135b9c1b51eSKate Stone StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
136e13c2731STamas Berghammer &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
137b9c1b51eSKate Stone RegisterMemberFunctionHandler(
1383cd8d7b1SGongyu Deng StringExtractorGDBRemote::eServerPacketType_qPathComplete,
1393cd8d7b1SGongyu Deng &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete);
1403cd8d7b1SGongyu Deng RegisterMemberFunctionHandler(
141b9c1b51eSKate Stone StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
142e13c2731STamas Berghammer &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
143b9c1b51eSKate Stone RegisterMemberFunctionHandler(
144b9c1b51eSKate Stone StringExtractorGDBRemote::eServerPacketType_jSignalsInfo,
14598d0a4b3SChaoren Lin &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);
146e13c2731STamas Berghammer
147e13c2731STamas Berghammer RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
14897206d57SZachary Turner [](StringExtractorGDBRemote packet, Status &error,
149b9c1b51eSKate Stone bool &interrupt, bool &quit) {
150e13c2731STamas Berghammer error.SetErrorString("interrupt received");
151e13c2731STamas Berghammer interrupt = true;
152e13c2731STamas Berghammer return PacketResult::Success;
153e13c2731STamas Berghammer });
154e13c2731STamas Berghammer }
155e13c2731STamas Berghammer
156e13c2731STamas Berghammer // Destructor
157fd2433e1SJonas Devlieghere GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() =
158fd2433e1SJonas Devlieghere default;
159e13c2731STamas Berghammer
LaunchGDBServer(const lldb_private::Args & args,std::string hostname,lldb::pid_t & pid,llvm::Optional<uint16_t> & port,std::string & socket_name)16097206d57SZachary Turner Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
161b9c1b51eSKate Stone const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid,
162a7f8d96bSDavid Spickett llvm::Optional<uint16_t> &port, std::string &socket_name) {
163a7f8d96bSDavid Spickett if (!port) {
16498e87f76SDavid Spickett llvm::Expected<uint16_t> available_port = m_port_map.GetNextAvailablePort();
16598e87f76SDavid Spickett if (available_port)
16698e87f76SDavid Spickett port = *available_port;
16798e87f76SDavid Spickett else
16898e87f76SDavid Spickett return Status(available_port.takeError());
16998e87f76SDavid Spickett }
170e13c2731STamas Berghammer
17105097246SAdrian Prantl // Spawn a new thread to accept the port that gets bound after binding to
17205097246SAdrian Prantl // port 0 (zero).
173e13c2731STamas Berghammer
17405097246SAdrian Prantl // ignore the hostname send from the remote end, just use the ip address that
17505097246SAdrian Prantl // we're currently communicating with as the hostname
176e13c2731STamas Berghammer
177e13c2731STamas Berghammer // Spawn a debugserver and try to get the port it listens to.
178e13c2731STamas Berghammer ProcessLaunchInfo debugserver_launch_info;
179e13c2731STamas Berghammer if (hostname.empty())
180e13c2731STamas Berghammer hostname = "127.0.0.1";
181ccd6cffbSTamas Berghammer
182a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Platform);
18363e5fb76SJonas Devlieghere LLDB_LOGF(log, "Launching debugserver with: %s:%u...", hostname.c_str(),
184a7f8d96bSDavid Spickett *port);
185e13c2731STamas Berghammer
18605097246SAdrian Prantl // Do not run in a new session so that it can not linger after the platform
18705097246SAdrian Prantl // closes.
188e13c2731STamas Berghammer debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
189998bdc5bSPavel Labath debugserver_launch_info.SetMonitorProcessCallback(
190b9c1b51eSKate Stone std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped,
19112c9c4a8SPavel Labath this, std::placeholders::_1));
192e13c2731STamas Berghammer
193d5560951SAntonio Afonso std::ostringstream url;
194d5560951SAntonio Afonso // debugserver does not accept the URL scheme prefix.
195d5560951SAntonio Afonso #if !defined(__APPLE__)
196d5560951SAntonio Afonso url << m_socket_scheme << "://";
197d5560951SAntonio Afonso #endif
198a7f8d96bSDavid Spickett uint16_t *port_ptr = port.getPointer();
199d5560951SAntonio Afonso if (m_socket_protocol == Socket::ProtocolTcp) {
200ae7dd12aSPavel Labath std::string platform_uri = GetConnection()->GetURI();
2010e5a4147SMichał Górny llvm::Optional<URI> parsed_uri = URI::Parse(platform_uri);
2020e5a4147SMichał Górny url << '[' << parsed_uri->hostname.str() << "]:" << *port;
203d5560951SAntonio Afonso } else {
2049fe526c2SOleksiy Vyalov socket_name = GetDomainSocketPath("gdbserver").GetPath();
2059fe526c2SOleksiy Vyalov url << socket_name;
2069fe526c2SOleksiy Vyalov port_ptr = nullptr;
2079fe526c2SOleksiy Vyalov }
2089fe526c2SOleksiy Vyalov
20997206d57SZachary Turner Status error = StartDebugserverProcess(
210b9c1b51eSKate Stone url.str().c_str(), nullptr, debugserver_launch_info, port_ptr, &args, -1);
211e13c2731STamas Berghammer
212ccd6cffbSTamas Berghammer pid = debugserver_launch_info.GetProcessID();
213b9c1b51eSKate Stone if (pid != LLDB_INVALID_PROCESS_ID) {
21416ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
215ccd6cffbSTamas Berghammer m_spawned_pids.insert(pid);
216a7f8d96bSDavid Spickett if (*port > 0)
217a7f8d96bSDavid Spickett m_port_map.AssociatePortWithProcess(*port, pid);
218b9c1b51eSKate Stone } else {
219a7f8d96bSDavid Spickett if (*port > 0)
220a7f8d96bSDavid Spickett m_port_map.FreePort(*port);
221e13c2731STamas Berghammer }
222ccd6cffbSTamas Berghammer return error;
223ccd6cffbSTamas Berghammer }
224e13c2731STamas Berghammer
225ccd6cffbSTamas Berghammer GDBRemoteCommunication::PacketResult
Handle_qLaunchGDBServer(StringExtractorGDBRemote & packet)226b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
227b9c1b51eSKate Stone StringExtractorGDBRemote &packet) {
22805097246SAdrian Prantl // Spawn a local debugserver as a platform so we can then attach or launch a
22905097246SAdrian Prantl // process...
230ccd6cffbSTamas Berghammer
231a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Platform);
23263e5fb76SJonas Devlieghere LLDB_LOGF(log, "GDBRemoteCommunicationServerPlatform::%s() called",
233b9c1b51eSKate Stone __FUNCTION__);
234ccd6cffbSTamas Berghammer
235ccd6cffbSTamas Berghammer ConnectionFileDescriptor file_conn;
236ccd6cffbSTamas Berghammer std::string hostname;
237ccd6cffbSTamas Berghammer packet.SetFilePos(::strlen("qLaunchGDBServer;"));
23854695a33SZachary Turner llvm::StringRef name;
23954695a33SZachary Turner llvm::StringRef value;
240a7f8d96bSDavid Spickett llvm::Optional<uint16_t> port;
241b9c1b51eSKate Stone while (packet.GetNameColonValue(name, value)) {
24254695a33SZachary Turner if (name.equals("host"))
243adcd0268SBenjamin Kramer hostname = std::string(value);
244a7f8d96bSDavid Spickett else if (name.equals("port")) {
245a7f8d96bSDavid Spickett // Make the Optional valid so we can use its value
246a7f8d96bSDavid Spickett port = 0;
247ed8fceaaSKazu Hirata value.getAsInteger(0, *port);
248a7f8d96bSDavid Spickett }
249ccd6cffbSTamas Berghammer }
250ccd6cffbSTamas Berghammer
251ccd6cffbSTamas Berghammer lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
252ccd6cffbSTamas Berghammer std::string socket_name;
25397206d57SZachary Turner Status error =
254b9c1b51eSKate Stone LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name);
255b9c1b51eSKate Stone if (error.Fail()) {
25663e5fb76SJonas Devlieghere LLDB_LOGF(log,
25763e5fb76SJonas Devlieghere "GDBRemoteCommunicationServerPlatform::%s() debugserver "
258b9c1b51eSKate Stone "launch failed: %s",
259b9c1b51eSKate Stone __FUNCTION__, error.AsCString());
260ccd6cffbSTamas Berghammer return SendErrorResponse(9);
261ccd6cffbSTamas Berghammer }
262ccd6cffbSTamas Berghammer
26363e5fb76SJonas Devlieghere LLDB_LOGF(log,
26463e5fb76SJonas Devlieghere "GDBRemoteCommunicationServerPlatform::%s() debugserver "
265b9c1b51eSKate Stone "launched successfully as pid %" PRIu64,
266b9c1b51eSKate Stone __FUNCTION__, debugserver_pid);
267e13c2731STamas Berghammer
2689fe526c2SOleksiy Vyalov StreamGDBRemote response;
269a7f8d96bSDavid Spickett assert(port);
270b9c1b51eSKate Stone response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid,
271a7f8d96bSDavid Spickett *port + m_port_offset);
272b9c1b51eSKate Stone if (!socket_name.empty()) {
2739fe526c2SOleksiy Vyalov response.PutCString("socket_name:");
2747f815a9aSPavel Labath response.PutStringAsRawHex8(socket_name);
2759fe526c2SOleksiy Vyalov response.PutChar(';');
2769fe526c2SOleksiy Vyalov }
277e13c2731STamas Berghammer
27870a5ef15SZachary Turner PacketResult packet_result = SendPacketNoLock(response.GetString());
279b9c1b51eSKate Stone if (packet_result != PacketResult::Success) {
280e13c2731STamas Berghammer if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
281e55850beSAaron Smith Host::Kill(debugserver_pid, SIGINT);
282e13c2731STamas Berghammer }
283e13c2731STamas Berghammer return packet_result;
284e13c2731STamas Berghammer }
285e13c2731STamas Berghammer
286e13c2731STamas Berghammer GDBRemoteCommunication::PacketResult
Handle_qQueryGDBServer(StringExtractorGDBRemote & packet)287b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer(
288b9c1b51eSKate Stone StringExtractorGDBRemote &packet) {
2897cb720ddSJonas Devlieghere namespace json = llvm::json;
2907cb720ddSJonas Devlieghere
291ccd6cffbSTamas Berghammer if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID)
292ccd6cffbSTamas Berghammer return SendErrorResponse(4);
293ccd6cffbSTamas Berghammer
2947cb720ddSJonas Devlieghere json::Object server{{"port", m_pending_gdb_server.port}};
295ccd6cffbSTamas Berghammer
2967cb720ddSJonas Devlieghere if (!m_pending_gdb_server.socket_name.empty())
2977cb720ddSJonas Devlieghere server.try_emplace("socket_name", m_pending_gdb_server.socket_name);
2987cb720ddSJonas Devlieghere
2997cb720ddSJonas Devlieghere json::Array server_list;
3007cb720ddSJonas Devlieghere server_list.push_back(std::move(server));
301ccd6cffbSTamas Berghammer
302ccd6cffbSTamas Berghammer StreamGDBRemote response;
3037cb720ddSJonas Devlieghere response.AsRawOstream() << std::move(server_list);
304ccd6cffbSTamas Berghammer
305ccd6cffbSTamas Berghammer StreamGDBRemote escaped_response;
306c156427dSZachary Turner escaped_response.PutEscapedBytes(response.GetString().data(),
307c156427dSZachary Turner response.GetSize());
30826709df8SZachary Turner return SendPacketNoLock(escaped_response.GetString());
309ccd6cffbSTamas Berghammer }
310ccd6cffbSTamas Berghammer
311ccd6cffbSTamas Berghammer GDBRemoteCommunication::PacketResult
Handle_qKillSpawnedProcess(StringExtractorGDBRemote & packet)312b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess(
313b9c1b51eSKate Stone StringExtractorGDBRemote &packet) {
3146e4f19d4SPavel Labath packet.SetFilePos(::strlen("qKillSpawnedProcess:"));
3156e4f19d4SPavel Labath
3166e4f19d4SPavel Labath lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
3176e4f19d4SPavel Labath
31805097246SAdrian Prantl // verify that we know anything about this pid. Scope for locker
3196e4f19d4SPavel Labath {
32016ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
321b9c1b51eSKate Stone if (m_spawned_pids.find(pid) == m_spawned_pids.end()) {
3226e4f19d4SPavel Labath // not a pid we know about
3236e4f19d4SPavel Labath return SendErrorResponse(10);
3246e4f19d4SPavel Labath }
3256e4f19d4SPavel Labath }
3266e4f19d4SPavel Labath
3276e4f19d4SPavel Labath // go ahead and attempt to kill the spawned process
3286e4f19d4SPavel Labath if (KillSpawnedProcess(pid))
3296e4f19d4SPavel Labath return SendOKResponse();
3306e4f19d4SPavel Labath else
3316e4f19d4SPavel Labath return SendErrorResponse(11);
3326e4f19d4SPavel Labath }
3336e4f19d4SPavel Labath
KillSpawnedProcess(lldb::pid_t pid)334b9c1b51eSKate Stone bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) {
3356e4f19d4SPavel Labath // make sure we know about this process
3366e4f19d4SPavel Labath {
33716ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
3386e4f19d4SPavel Labath if (m_spawned_pids.find(pid) == m_spawned_pids.end())
3396e4f19d4SPavel Labath return false;
3406e4f19d4SPavel Labath }
3416e4f19d4SPavel Labath
3426e4f19d4SPavel Labath // first try a SIGTERM (standard kill)
3436e4f19d4SPavel Labath Host::Kill(pid, SIGTERM);
3446e4f19d4SPavel Labath
3456e4f19d4SPavel Labath // check if that worked
346b9c1b51eSKate Stone for (size_t i = 0; i < 10; ++i) {
3476e4f19d4SPavel Labath {
34816ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
349b9c1b51eSKate Stone if (m_spawned_pids.find(pid) == m_spawned_pids.end()) {
3506e4f19d4SPavel Labath // it is now killed
3516e4f19d4SPavel Labath return true;
3526e4f19d4SPavel Labath }
3536e4f19d4SPavel Labath }
3543d4f7655SPavel Labath std::this_thread::sleep_for(std::chrono::milliseconds(10));
3556e4f19d4SPavel Labath }
3566e4f19d4SPavel Labath
3576e4f19d4SPavel Labath {
35816ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
3596e4f19d4SPavel Labath if (m_spawned_pids.find(pid) == m_spawned_pids.end())
3606e4f19d4SPavel Labath return true;
3616e4f19d4SPavel Labath }
3626e4f19d4SPavel Labath
36305097246SAdrian Prantl // the launched process still lives. Now try killing it again, this time
36405097246SAdrian Prantl // with an unblockable signal.
3656e4f19d4SPavel Labath Host::Kill(pid, SIGKILL);
3666e4f19d4SPavel Labath
367b9c1b51eSKate Stone for (size_t i = 0; i < 10; ++i) {
3686e4f19d4SPavel Labath {
36916ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
370b9c1b51eSKate Stone if (m_spawned_pids.find(pid) == m_spawned_pids.end()) {
3716e4f19d4SPavel Labath // it is now killed
3726e4f19d4SPavel Labath return true;
3736e4f19d4SPavel Labath }
3746e4f19d4SPavel Labath }
3753d4f7655SPavel Labath std::this_thread::sleep_for(std::chrono::milliseconds(10));
3766e4f19d4SPavel Labath }
3776e4f19d4SPavel Labath
3783d4f7655SPavel Labath // check one more time after the final sleep
3796e4f19d4SPavel Labath {
38016ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
3816e4f19d4SPavel Labath if (m_spawned_pids.find(pid) == m_spawned_pids.end())
3826e4f19d4SPavel Labath return true;
3836e4f19d4SPavel Labath }
3846e4f19d4SPavel Labath
3856e4f19d4SPavel Labath // no luck - the process still lives
3866e4f19d4SPavel Labath return false;
3876e4f19d4SPavel Labath }
3886e4f19d4SPavel Labath
3896e4f19d4SPavel Labath GDBRemoteCommunication::PacketResult
Handle_qProcessInfo(StringExtractorGDBRemote & packet)390b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo(
391b9c1b51eSKate Stone StringExtractorGDBRemote &packet) {
392e13c2731STamas Berghammer lldb::pid_t pid = m_process_launch_info.GetProcessID();
393e13c2731STamas Berghammer m_process_launch_info.Clear();
394e13c2731STamas Berghammer
395e13c2731STamas Berghammer if (pid == LLDB_INVALID_PROCESS_ID)
396e13c2731STamas Berghammer return SendErrorResponse(1);
397e13c2731STamas Berghammer
398e13c2731STamas Berghammer ProcessInstanceInfo proc_info;
399e13c2731STamas Berghammer if (!Host::GetProcessInfo(pid, proc_info))
400e13c2731STamas Berghammer return SendErrorResponse(1);
401e13c2731STamas Berghammer
402e13c2731STamas Berghammer StreamString response;
403e13c2731STamas Berghammer CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
40426709df8SZachary Turner return SendPacketNoLock(response.GetString());
405e13c2731STamas Berghammer }
406e13c2731STamas Berghammer
407e13c2731STamas Berghammer GDBRemoteCommunication::PacketResult
Handle_qPathComplete(StringExtractorGDBRemote & packet)4083cd8d7b1SGongyu Deng GDBRemoteCommunicationServerPlatform::Handle_qPathComplete(
4093cd8d7b1SGongyu Deng StringExtractorGDBRemote &packet) {
4103cd8d7b1SGongyu Deng packet.SetFilePos(::strlen("qPathComplete:"));
4113cd8d7b1SGongyu Deng const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1);
4123cd8d7b1SGongyu Deng if (packet.GetChar() != ',')
4133cd8d7b1SGongyu Deng return SendErrorResponse(85);
4143cd8d7b1SGongyu Deng std::string path;
4153cd8d7b1SGongyu Deng packet.GetHexByteString(path);
4163cd8d7b1SGongyu Deng
4173cd8d7b1SGongyu Deng StringList matches;
4183cd8d7b1SGongyu Deng StandardTildeExpressionResolver resolver;
4193cd8d7b1SGongyu Deng if (only_dir)
4203cd8d7b1SGongyu Deng CommandCompletions::DiskDirectories(path, matches, resolver);
4213cd8d7b1SGongyu Deng else
4223cd8d7b1SGongyu Deng CommandCompletions::DiskFiles(path, matches, resolver);
4233cd8d7b1SGongyu Deng
4243cd8d7b1SGongyu Deng StreamString response;
4253cd8d7b1SGongyu Deng response.PutChar('M');
4263cd8d7b1SGongyu Deng llvm::StringRef separator;
4273cd8d7b1SGongyu Deng std::sort(matches.begin(), matches.end());
4283cd8d7b1SGongyu Deng for (const auto &match : matches) {
4293cd8d7b1SGongyu Deng response << separator;
4303cd8d7b1SGongyu Deng separator = ",";
4313cd8d7b1SGongyu Deng // encode result strings into hex bytes to avoid unexpected error caused by
4323cd8d7b1SGongyu Deng // special characters like '$'.
4333cd8d7b1SGongyu Deng response.PutStringAsRawHex8(match.c_str());
4343cd8d7b1SGongyu Deng }
4353cd8d7b1SGongyu Deng
4363cd8d7b1SGongyu Deng return SendPacketNoLock(response.GetString());
4373cd8d7b1SGongyu Deng }
4383cd8d7b1SGongyu Deng
4393cd8d7b1SGongyu Deng GDBRemoteCommunication::PacketResult
Handle_qGetWorkingDir(StringExtractorGDBRemote & packet)440b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir(
441b9c1b51eSKate Stone StringExtractorGDBRemote &packet) {
442e13c2731STamas Berghammer
4431d5855b1SPavel Labath llvm::SmallString<64> cwd;
4441d5855b1SPavel Labath if (std::error_code ec = llvm::sys::fs::current_path(cwd))
4451d5855b1SPavel Labath return SendErrorResponse(ec.value());
446e13c2731STamas Berghammer
447e13c2731STamas Berghammer StreamString response;
4481d5855b1SPavel Labath response.PutBytesAsRawHex8(cwd.data(), cwd.size());
44926709df8SZachary Turner return SendPacketNoLock(response.GetString());
450e13c2731STamas Berghammer }
451e13c2731STamas Berghammer
452e13c2731STamas Berghammer GDBRemoteCommunication::PacketResult
Handle_QSetWorkingDir(StringExtractorGDBRemote & packet)453b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir(
454b9c1b51eSKate Stone StringExtractorGDBRemote &packet) {
455e13c2731STamas Berghammer packet.SetFilePos(::strlen("QSetWorkingDir:"));
456e13c2731STamas Berghammer std::string path;
457e13c2731STamas Berghammer packet.GetHexByteString(path);
458e13c2731STamas Berghammer
4592d0c5b02SPavel Labath if (std::error_code ec = llvm::sys::fs::set_current_path(path))
4602d0c5b02SPavel Labath return SendErrorResponse(ec.value());
461e13c2731STamas Berghammer return SendOKResponse();
462e13c2731STamas Berghammer }
463e13c2731STamas Berghammer
464e13c2731STamas Berghammer GDBRemoteCommunication::PacketResult
Handle_qC(StringExtractorGDBRemote & packet)465b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::Handle_qC(
466b9c1b51eSKate Stone StringExtractorGDBRemote &packet) {
467b9c1b51eSKate Stone // NOTE: lldb should now be using qProcessInfo for process IDs. This path
468b9c1b51eSKate Stone // here
469e13c2731STamas Berghammer // should not be used. It is reporting process id instead of thread id. The
470e13c2731STamas Berghammer // correct answer doesn't seem to make much sense for lldb-platform.
471e13c2731STamas Berghammer // CONSIDER: flip to "unsupported".
472e13c2731STamas Berghammer lldb::pid_t pid = m_process_launch_info.GetProcessID();
473e13c2731STamas Berghammer
474e13c2731STamas Berghammer StreamString response;
475e13c2731STamas Berghammer response.Printf("QC%" PRIx64, pid);
476e13c2731STamas Berghammer
47705097246SAdrian Prantl // If we launch a process and this GDB server is acting as a platform, then
47805097246SAdrian Prantl // we need to clear the process launch state so we can start launching
47905097246SAdrian Prantl // another process. In order to launch a process a bunch or packets need to
48005097246SAdrian Prantl // be sent: environment packets, working directory, disable ASLR, and many
48105097246SAdrian Prantl // more settings. When we launch a process we then need to know when to clear
48205097246SAdrian Prantl // this information. Currently we are selecting the 'qC' packet as that
48305097246SAdrian Prantl // packet which seems to make the most sense.
484b9c1b51eSKate Stone if (pid != LLDB_INVALID_PROCESS_ID) {
485e13c2731STamas Berghammer m_process_launch_info.Clear();
486e13c2731STamas Berghammer }
487e13c2731STamas Berghammer
48826709df8SZachary Turner return SendPacketNoLock(response.GetString());
489e13c2731STamas Berghammer }
490e13c2731STamas Berghammer
49198d0a4b3SChaoren Lin GDBRemoteCommunication::PacketResult
Handle_jSignalsInfo(StringExtractorGDBRemote & packet)492b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(
493b9c1b51eSKate Stone StringExtractorGDBRemote &packet) {
49498d0a4b3SChaoren Lin StructuredData::Array signal_array;
49598d0a4b3SChaoren Lin
496a89ce43cSZachary Turner lldb::UnixSignalsSP signals = UnixSignals::CreateForHost();
49798d0a4b3SChaoren Lin for (auto signo = signals->GetFirstSignalNumber();
49898d0a4b3SChaoren Lin signo != LLDB_INVALID_SIGNAL_NUMBER;
499b9c1b51eSKate Stone signo = signals->GetNextSignalNumber(signo)) {
50098d0a4b3SChaoren Lin auto dictionary = std::make_shared<StructuredData::Dictionary>();
50198d0a4b3SChaoren Lin
50298d0a4b3SChaoren Lin dictionary->AddIntegerItem("signo", signo);
50398d0a4b3SChaoren Lin dictionary->AddStringItem("name", signals->GetSignalAsCString(signo));
50498d0a4b3SChaoren Lin
50598d0a4b3SChaoren Lin bool suppress, stop, notify;
50698d0a4b3SChaoren Lin signals->GetSignalInfo(signo, suppress, stop, notify);
50798d0a4b3SChaoren Lin dictionary->AddBooleanItem("suppress", suppress);
50898d0a4b3SChaoren Lin dictionary->AddBooleanItem("stop", stop);
50998d0a4b3SChaoren Lin dictionary->AddBooleanItem("notify", notify);
51098d0a4b3SChaoren Lin
51198d0a4b3SChaoren Lin signal_array.Push(dictionary);
51298d0a4b3SChaoren Lin }
51398d0a4b3SChaoren Lin
51498d0a4b3SChaoren Lin StreamString response;
51598d0a4b3SChaoren Lin signal_array.Dump(response);
51626709df8SZachary Turner return SendPacketNoLock(response.GetString());
51798d0a4b3SChaoren Lin }
51898d0a4b3SChaoren Lin
DebugserverProcessReaped(lldb::pid_t pid)51912c9c4a8SPavel Labath void GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped(
520b9c1b51eSKate Stone lldb::pid_t pid) {
52116ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
52298e87f76SDavid Spickett m_port_map.FreePortForProcess(pid);
523998bdc5bSPavel Labath m_spawned_pids.erase(pid);
524e13c2731STamas Berghammer }
525e13c2731STamas Berghammer
LaunchProcess()52697206d57SZachary Turner Status GDBRemoteCommunicationServerPlatform::LaunchProcess() {
527e13c2731STamas Berghammer if (!m_process_launch_info.GetArguments().GetArgumentCount())
52897206d57SZachary Turner return Status("%s: no process command line specified to launch",
529b9c1b51eSKate Stone __FUNCTION__);
530e13c2731STamas Berghammer
53105097246SAdrian Prantl // specify the process monitor if not already set. This should generally be
53205097246SAdrian Prantl // what happens since we need to reap started processes.
533e13c2731STamas Berghammer if (!m_process_launch_info.GetMonitorProcessCallback())
53412c9c4a8SPavel Labath m_process_launch_info.SetMonitorProcessCallback(std::bind(
53512c9c4a8SPavel Labath &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, this,
53612c9c4a8SPavel Labath std::placeholders::_1));
537e13c2731STamas Berghammer
53897206d57SZachary Turner Status error = Host::LaunchProcess(m_process_launch_info);
539b9c1b51eSKate Stone if (!error.Success()) {
540b9c1b51eSKate Stone fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__,
541b9c1b51eSKate Stone m_process_launch_info.GetArguments().GetArgumentAtIndex(0));
542e13c2731STamas Berghammer return error;
543e13c2731STamas Berghammer }
544e13c2731STamas Berghammer
545b9c1b51eSKate Stone printf("Launched '%s' as process %" PRIu64 "...\n",
546b9c1b51eSKate Stone m_process_launch_info.GetArguments().GetArgumentAtIndex(0),
547b9c1b51eSKate Stone m_process_launch_info.GetProcessID());
548e13c2731STamas Berghammer
54905097246SAdrian Prantl // add to list of spawned processes. On an lldb-gdbserver, we would expect
55005097246SAdrian Prantl // there to be only one.
551e13c2731STamas Berghammer const auto pid = m_process_launch_info.GetProcessID();
552b9c1b51eSKate Stone if (pid != LLDB_INVALID_PROCESS_ID) {
553e13c2731STamas Berghammer // add to spawned pids
55416ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
555e13c2731STamas Berghammer m_spawned_pids.insert(pid);
556e13c2731STamas Berghammer }
557e13c2731STamas Berghammer
558e13c2731STamas Berghammer return error;
559e13c2731STamas Berghammer }
560e13c2731STamas Berghammer
SetPortMap(PortMap && port_map)561b9c1b51eSKate Stone void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) {
562e13c2731STamas Berghammer m_port_map = port_map;
563e13c2731STamas Berghammer }
564e13c2731STamas Berghammer
GetDomainSocketDir()565b9c1b51eSKate Stone const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() {
5669fe526c2SOleksiy Vyalov static FileSpec g_domainsocket_dir;
567c5f28e2aSKamil Rytarowski static llvm::once_flag g_once_flag;
5689fe526c2SOleksiy Vyalov
569c5f28e2aSKamil Rytarowski llvm::call_once(g_once_flag, []() {
570b9c1b51eSKate Stone const char *domainsocket_dir_env =
571b9c1b51eSKate Stone ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR");
5729fe526c2SOleksiy Vyalov if (domainsocket_dir_env != nullptr)
5738f3be7a3SJonas Devlieghere g_domainsocket_dir = FileSpec(domainsocket_dir_env);
5749fe526c2SOleksiy Vyalov else
57560f028ffSPavel Labath g_domainsocket_dir = HostInfo::GetProcessTempDir();
5769fe526c2SOleksiy Vyalov });
5779fe526c2SOleksiy Vyalov
5789fe526c2SOleksiy Vyalov return g_domainsocket_dir;
5799fe526c2SOleksiy Vyalov }
5809fe526c2SOleksiy Vyalov
5819fe526c2SOleksiy Vyalov FileSpec
GetDomainSocketPath(const char * prefix)582b9c1b51eSKate Stone GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) {
583b3f44ad9SStella Stamenova llvm::SmallString<128> socket_path;
584b3f44ad9SStella Stamenova llvm::SmallString<128> socket_name(
585b9c1b51eSKate Stone (llvm::StringRef(prefix) + ".%%%%%%").str());
5869fe526c2SOleksiy Vyalov
5879fe526c2SOleksiy Vyalov FileSpec socket_path_spec(GetDomainSocketDir());
5889fe526c2SOleksiy Vyalov socket_path_spec.AppendPathComponent(socket_name.c_str());
5899fe526c2SOleksiy Vyalov
590*1b4b12a3SNico Weber llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path);
5918f3be7a3SJonas Devlieghere return FileSpec(socket_path.c_str());
5929fe526c2SOleksiy Vyalov }
5939fe526c2SOleksiy Vyalov
SetPortOffset(uint16_t port_offset)594b9c1b51eSKate Stone void GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) {
595e13c2731STamas Berghammer m_port_offset = port_offset;
596e13c2731STamas Berghammer }
597ccd6cffbSTamas Berghammer
SetPendingGdbServer(lldb::pid_t pid,uint16_t port,const std::string & socket_name)598b9c1b51eSKate Stone void GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(
599b9c1b51eSKate Stone lldb::pid_t pid, uint16_t port, const std::string &socket_name) {
600ccd6cffbSTamas Berghammer m_pending_gdb_server.pid = pid;
601ccd6cffbSTamas Berghammer m_pending_gdb_server.port = port;
602ccd6cffbSTamas Berghammer m_pending_gdb_server.socket_name = socket_name;
603ccd6cffbSTamas Berghammer }
604