blob: 592d7f7f27c13ff8ec4bee9a02b15d5ca82bc31c [file] [log] [blame]
Tamas Berghammere13c2732015-02-11 10:29:30 +00001//===-- 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"
Chaoren Lin98d0a4b2015-07-14 01:09:28 +000022#include "lldb/Core/StructuredData.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000023#include "lldb/Host/Config.h"
24#include "lldb/Host/ConnectionFileDescriptor.h"
25#include "lldb/Host/Host.h"
26#include "lldb/Host/StringConvert.h"
27#include "lldb/Target/FileAction.h"
28#include "lldb/Target/Platform.h"
29#include "lldb/Target/Process.h"
Chaoren Lin98d0a4b2015-07-14 01:09:28 +000030#include "lldb/Target/UnixSignals.h"
Tamas Berghammere13c2732015-02-11 10:29:30 +000031
32// Project includes
33#include "Utility/StringExtractorGDBRemote.h"
34#include "Utility/UriParser.h"
35
36using namespace lldb;
37using namespace lldb_private;
Tamas Berghammerdb264a62015-03-31 09:52:22 +000038using namespace lldb_private::process_gdb_remote;
Tamas Berghammere13c2732015-02-11 10:29:30 +000039
40//----------------------------------------------------------------------
41// GDBRemoteCommunicationServerPlatform constructor
42//----------------------------------------------------------------------
43GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform() :
44 GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"),
Pavel Labath6e4f19d2015-07-29 12:33:31 +000045 m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
Tamas Berghammere13c2732015-02-11 10:29:30 +000046 m_platform_sp (Platform::GetHostPlatform ()),
47 m_port_map (),
48 m_port_offset(0)
49{
50 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
51 &GDBRemoteCommunicationServerPlatform::Handle_qC);
52 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
53 &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);
54 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,
55 &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);
Pavel Labath6e4f19d2015-07-29 12:33:31 +000056 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,
57 &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess);
Tamas Berghammere13c2732015-02-11 10:29:30 +000058 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
59 &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
60 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
61 &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
Chaoren Lin98d0a4b2015-07-14 01:09:28 +000062 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jSignalsInfo,
63 &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);
Tamas Berghammere13c2732015-02-11 10:29:30 +000064
65 RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
66 [this](StringExtractorGDBRemote packet,
67 Error &error,
68 bool &interrupt,
69 bool &quit)
70 {
71 error.SetErrorString("interrupt received");
72 interrupt = true;
73 return PacketResult::Success;
74 });
75}
76
77//----------------------------------------------------------------------
78// Destructor
79//----------------------------------------------------------------------
80GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform()
81{
82}
83
84GDBRemoteCommunication::PacketResult
85GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
86{
87#ifdef _WIN32
88 return SendErrorResponse(9);
89#else
90 // Spawn a local debugserver as a platform so we can then attach or launch
91 // a process...
92
93 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
94 if (log)
Oleksiy Vyalovc282ebd2015-02-24 22:23:39 +000095 log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__);
Tamas Berghammere13c2732015-02-11 10:29:30 +000096
97 // Sleep and wait a bit for debugserver to start to listen...
98 ConnectionFileDescriptor file_conn;
99 std::string hostname;
100 // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
101 // with the TMPDIR environment variable
Oleksiy Vyalovc282ebd2015-02-24 22:23:39 +0000102 packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
Tamas Berghammere13c2732015-02-11 10:29:30 +0000103 std::string name;
104 std::string value;
105 uint16_t port = UINT16_MAX;
106 while (packet.GetNameColonValue(name, value))
107 {
108 if (name.compare ("host") == 0)
109 hostname.swap(value);
110 else if (name.compare ("port") == 0)
111 port = StringConvert::ToUInt32(value.c_str(), 0, 0);
112 }
113 if (port == UINT16_MAX)
114 port = GetNextAvailablePort();
115
116 // Spawn a new thread to accept the port that gets bound after
117 // binding to port 0 (zero).
118
119 // ignore the hostname send from the remote end, just use the ip address
120 // that we're currently communicating with as the hostname
121
122 // Spawn a debugserver and try to get the port it listens to.
123 ProcessLaunchInfo debugserver_launch_info;
124 if (hostname.empty())
125 hostname = "127.0.0.1";
126 if (log)
Vince Harron8b335672015-05-12 01:10:56 +0000127 log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000128
129 // Do not run in a new session so that it can not linger after the
130 // platform closes.
131 debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
132 debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
133
134 std::string platform_scheme;
135 std::string platform_ip;
136 int platform_port;
137 std::string platform_path;
138 bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path);
Bruce Mitchener8a67bf72015-07-24 00:23:29 +0000139 UNUSED_IF_ASSERT_DISABLED(ok);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000140 assert(ok);
Greg Clayton6988abc2015-10-19 20:44:01 +0000141 Error error = StartDebugserverProcess (platform_ip.c_str(),
142 port,
143 nullptr,
144 debugserver_launch_info,
145 port);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000146
147 lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
148
149
150 if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
151 {
152 Mutex::Locker locker (m_spawned_pids_mutex);
153 m_spawned_pids.insert(debugserver_pid);
154 if (port > 0)
155 AssociatePortWithProcess(port, debugserver_pid);
156 }
157 else
158 {
159 if (port > 0)
160 FreePort (port);
161 }
162
163 if (error.Success())
164 {
165 if (log)
Oleksiy Vyalov946e39a2015-02-25 01:11:38 +0000166 log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000167
168 char response[256];
169 const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
170 assert (response_len < (int)sizeof(response));
171 PacketResult packet_result = SendPacketNoLock (response, response_len);
172
173 if (packet_result != PacketResult::Success)
174 {
175 if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
176 ::kill (debugserver_pid, SIGINT);
177 }
178 return packet_result;
179 }
180 else
181 {
182 if (log)
Oleksiy Vyalov946e39a2015-02-25 01:11:38 +0000183 log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ());
Tamas Berghammere13c2732015-02-11 10:29:30 +0000184 }
185 return SendErrorResponse (9);
186#endif
187}
188
189GDBRemoteCommunication::PacketResult
Pavel Labath6e4f19d2015-07-29 12:33:31 +0000190GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
191{
192 packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
193
194 lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
195
196 // verify that we know anything about this pid.
197 // Scope for locker
198 {
199 Mutex::Locker locker (m_spawned_pids_mutex);
200 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
201 {
202 // not a pid we know about
203 return SendErrorResponse (10);
204 }
205 }
206
207 // go ahead and attempt to kill the spawned process
208 if (KillSpawnedProcess (pid))
209 return SendOKResponse ();
210 else
211 return SendErrorResponse (11);
212}
213
214bool
215GDBRemoteCommunicationServerPlatform::KillSpawnedProcess (lldb::pid_t pid)
216{
217 // make sure we know about this process
218 {
219 Mutex::Locker locker (m_spawned_pids_mutex);
220 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
221 return false;
222 }
223
224 // first try a SIGTERM (standard kill)
225 Host::Kill (pid, SIGTERM);
226
227 // check if that worked
228 for (size_t i=0; i<10; ++i)
229 {
230 {
231 Mutex::Locker locker (m_spawned_pids_mutex);
232 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
233 {
234 // it is now killed
235 return true;
236 }
237 }
238 usleep (10000);
239 }
240
241 // check one more time after the final usleep
242 {
243 Mutex::Locker locker (m_spawned_pids_mutex);
244 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
245 return true;
246 }
247
248 // the launched process still lives. Now try killing it again,
249 // this time with an unblockable signal.
250 Host::Kill (pid, SIGKILL);
251
252 for (size_t i=0; i<10; ++i)
253 {
254 {
255 Mutex::Locker locker (m_spawned_pids_mutex);
256 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
257 {
258 // it is now killed
259 return true;
260 }
261 }
262 usleep (10000);
263 }
264
265 // check one more time after the final usleep
266 // Scope for locker
267 {
268 Mutex::Locker locker (m_spawned_pids_mutex);
269 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
270 return true;
271 }
272
273 // no luck - the process still lives
274 return false;
275}
276
277GDBRemoteCommunication::PacketResult
Tamas Berghammere13c2732015-02-11 10:29:30 +0000278GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
279{
280 lldb::pid_t pid = m_process_launch_info.GetProcessID ();
281 m_process_launch_info.Clear ();
282
283 if (pid == LLDB_INVALID_PROCESS_ID)
284 return SendErrorResponse (1);
285
286 ProcessInstanceInfo proc_info;
287 if (!Host::GetProcessInfo (pid, proc_info))
288 return SendErrorResponse (1);
289
290 StreamString response;
291 CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
292 return SendPacketNoLock (response.GetData (), response.GetSize ());
293}
294
295GDBRemoteCommunication::PacketResult
296GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
297{
298 // If this packet is sent to a platform, then change the current working directory
299
300 char cwd[PATH_MAX];
301 if (getcwd(cwd, sizeof(cwd)) == NULL)
302 return SendErrorResponse(errno);
303
304 StreamString response;
305 response.PutBytesAsRawHex8(cwd, strlen(cwd));
306 return SendPacketNoLock(response.GetData(), response.GetSize());
307}
308
309GDBRemoteCommunication::PacketResult
310GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
311{
312 packet.SetFilePos (::strlen ("QSetWorkingDir:"));
313 std::string path;
314 packet.GetHexByteString (path);
315
Tamas Berghammere13c2732015-02-11 10:29:30 +0000316 // If this packet is sent to a platform, then change the current working directory
317 if (::chdir(path.c_str()) != 0)
318 return SendErrorResponse (errno);
319 return SendOKResponse ();
Tamas Berghammere13c2732015-02-11 10:29:30 +0000320}
321
322GDBRemoteCommunication::PacketResult
323GDBRemoteCommunicationServerPlatform::Handle_qC (StringExtractorGDBRemote &packet)
324{
325 // NOTE: lldb should now be using qProcessInfo for process IDs. This path here
326 // should not be used. It is reporting process id instead of thread id. The
327 // correct answer doesn't seem to make much sense for lldb-platform.
328 // CONSIDER: flip to "unsupported".
329 lldb::pid_t pid = m_process_launch_info.GetProcessID();
330
331 StreamString response;
332 response.Printf("QC%" PRIx64, pid);
333
334 // If we launch a process and this GDB server is acting as a platform,
335 // then we need to clear the process launch state so we can start
336 // launching another process. In order to launch a process a bunch or
337 // packets need to be sent: environment packets, working directory,
338 // disable ASLR, and many more settings. When we launch a process we
339 // then need to know when to clear this information. Currently we are
340 // selecting the 'qC' packet as that packet which seems to make the most
341 // sense.
342 if (pid != LLDB_INVALID_PROCESS_ID)
343 {
344 m_process_launch_info.Clear();
345 }
346
347 return SendPacketNoLock (response.GetData(), response.GetSize());
348}
349
Chaoren Lin98d0a4b2015-07-14 01:09:28 +0000350GDBRemoteCommunication::PacketResult
351GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(StringExtractorGDBRemote &packet)
352{
353 StructuredData::Array signal_array;
354
355 const auto &signals = Host::GetUnixSignals();
356 for (auto signo = signals->GetFirstSignalNumber();
357 signo != LLDB_INVALID_SIGNAL_NUMBER;
358 signo = signals->GetNextSignalNumber(signo))
359 {
360 auto dictionary = std::make_shared<StructuredData::Dictionary>();
361
362 dictionary->AddIntegerItem("signo", signo);
363 dictionary->AddStringItem("name", signals->GetSignalAsCString(signo));
364
365 bool suppress, stop, notify;
366 signals->GetSignalInfo(signo, suppress, stop, notify);
367 dictionary->AddBooleanItem("suppress", suppress);
368 dictionary->AddBooleanItem("stop", stop);
369 dictionary->AddBooleanItem("notify", notify);
370
371 signal_array.Push(dictionary);
372 }
373
374 StreamString response;
375 signal_array.Dump(response);
376 return SendPacketNoLock(response.GetData(), response.GetSize());
377}
378
Tamas Berghammere13c2732015-02-11 10:29:30 +0000379bool
380GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped (lldb::pid_t pid)
381{
382 Mutex::Locker locker (m_spawned_pids_mutex);
383 FreePortForProcess(pid);
384 return m_spawned_pids.erase(pid) > 0;
385}
386
387bool
388GDBRemoteCommunicationServerPlatform::ReapDebugserverProcess (void *callback_baton,
389 lldb::pid_t pid,
390 bool exited,
391 int signal, // Zero for no signal
392 int status) // Exit value of process if signal is zero
393{
394 GDBRemoteCommunicationServerPlatform *server = (GDBRemoteCommunicationServerPlatform *)callback_baton;
395 server->DebugserverProcessReaped (pid);
396 return true;
397}
398
Tamas Berghammerdb264a62015-03-31 09:52:22 +0000399Error
Tamas Berghammere13c2732015-02-11 10:29:30 +0000400GDBRemoteCommunicationServerPlatform::LaunchProcess ()
401{
402 if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
Tamas Berghammerdb264a62015-03-31 09:52:22 +0000403 return Error ("%s: no process command line specified to launch", __FUNCTION__);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000404
405 // specify the process monitor if not already set. This should
406 // generally be what happens since we need to reap started
407 // processes.
408 if (!m_process_launch_info.GetMonitorProcessCallback ())
409 m_process_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
410
Tamas Berghammerdb264a62015-03-31 09:52:22 +0000411 Error error = m_platform_sp->LaunchProcess (m_process_launch_info);
Tamas Berghammere13c2732015-02-11 10:29:30 +0000412 if (!error.Success ())
413 {
414 fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
415 return error;
416 }
417
418 printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID());
419
420 // add to list of spawned processes. On an lldb-gdbserver, we
421 // would expect there to be only one.
422 const auto pid = m_process_launch_info.GetProcessID();
423 if (pid != LLDB_INVALID_PROCESS_ID)
424 {
425 // add to spawned pids
426 Mutex::Locker locker (m_spawned_pids_mutex);
427 m_spawned_pids.insert(pid);
428 }
429
430 return error;
431}
432
433void
434GDBRemoteCommunicationServerPlatform::SetPortMap (PortMap &&port_map)
435{
436 m_port_map = port_map;
437}
438
439uint16_t
440GDBRemoteCommunicationServerPlatform::GetNextAvailablePort ()
441{
442 if (m_port_map.empty())
443 return 0; // Bind to port zero and get a port, we didn't have any limitations
444
445 for (auto &pair : m_port_map)
446 {
447 if (pair.second == LLDB_INVALID_PROCESS_ID)
448 {
449 pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
450 return pair.first;
451 }
452 }
453 return UINT16_MAX;
454}
455
456bool
457GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess (uint16_t port, lldb::pid_t pid)
458{
459 PortMap::iterator pos = m_port_map.find(port);
460 if (pos != m_port_map.end())
461 {
462 pos->second = pid;
463 return true;
464 }
465 return false;
466}
467
468bool
469GDBRemoteCommunicationServerPlatform::FreePort (uint16_t port)
470{
471 PortMap::iterator pos = m_port_map.find(port);
472 if (pos != m_port_map.end())
473 {
474 pos->second = LLDB_INVALID_PROCESS_ID;
475 return true;
476 }
477 return false;
478}
479
480bool
481GDBRemoteCommunicationServerPlatform::FreePortForProcess (lldb::pid_t pid)
482{
483 if (!m_port_map.empty())
484 {
485 for (auto &pair : m_port_map)
486 {
487 if (pair.second == pid)
488 {
489 pair.second = LLDB_INVALID_PROCESS_ID;
490 return true;
491 }
492 }
493 }
494 return false;
495}
496
497void
498GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset)
499{
500 m_port_offset = port_offset;
501}