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