blob: de888da0fd48fb5eb76a2fdfd508cb550ae1e3b5 [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;
36
37//----------------------------------------------------------------------
38// GDBRemoteCommunicationServerPlatform constructor
39//----------------------------------------------------------------------
40GDBRemoteCommunicationServerPlatform::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//----------------------------------------------------------------------
72GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform()
73{
74}
75
76GDBRemoteCommunication::PacketResult
77GDBRemoteCommunicationServerPlatform::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 ("LLGSPacketHandler::%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 ("qLaunchLLGSPacketHandler;"));
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 ("LLGSPacketHandler::%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 ("LLGSPacketHandler::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ());
175 }
176 return SendErrorResponse (9);
177#endif
178}
179
180GDBRemoteCommunication::PacketResult
181GDBRemoteCommunicationServerPlatform::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
198GDBRemoteCommunication::PacketResult
199GDBRemoteCommunicationServerPlatform::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
212GDBRemoteCommunication::PacketResult
213GDBRemoteCommunicationServerPlatform::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 ("LLGSPacketHandler::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
230GDBRemoteCommunication::PacketResult
231GDBRemoteCommunicationServerPlatform::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
258bool
259GDBRemoteCommunicationServerPlatform::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
266bool
267GDBRemoteCommunicationServerPlatform::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
278lldb_private::Error
279GDBRemoteCommunicationServerPlatform::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
312void
313GDBRemoteCommunicationServerPlatform::SetPortMap (PortMap &&port_map)
314{
315 m_port_map = port_map;
316}
317
318uint16_t
319GDBRemoteCommunicationServerPlatform::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
335bool
336GDBRemoteCommunicationServerPlatform::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
347bool
348GDBRemoteCommunicationServerPlatform::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
359bool
360GDBRemoteCommunicationServerPlatform::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
376void
377GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset)
378{
379 m_port_offset = port_offset;
380}