xref: /llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (revision 00fe87b4888b230325edd96a4c2df866d91da64e)
1 //===-- GDBRemoteCommunicationServer.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 <errno.h>
11 
12 #include "GDBRemoteCommunicationServer.h"
13 #include "lldb/Core/StreamGDBRemote.h"
14 
15 // C Includes
16 // C++ Includes
17 // Other libraries and framework includes
18 #include "llvm/ADT/Triple.h"
19 #include "lldb/Interpreter/Args.h"
20 #include "lldb/Core/ConnectionFileDescriptor.h"
21 #include "lldb/Core/Log.h"
22 #include "lldb/Core/State.h"
23 #include "lldb/Core/StreamString.h"
24 #include "lldb/Host/Endian.h"
25 #include "lldb/Host/File.h"
26 #include "lldb/Host/Host.h"
27 #include "lldb/Host/TimeValue.h"
28 #include "lldb/Target/Process.h"
29 
30 // Project includes
31 #include "Utility/StringExtractorGDBRemote.h"
32 #include "ProcessGDBRemote.h"
33 #include "ProcessGDBRemoteLog.h"
34 
35 using namespace lldb;
36 using namespace lldb_private;
37 
38 //----------------------------------------------------------------------
39 // GDBRemoteCommunicationServer constructor
40 //----------------------------------------------------------------------
41 GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
42     GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform),
43     m_async_thread (LLDB_INVALID_HOST_THREAD),
44     m_process_launch_info (),
45     m_process_launch_error (),
46     m_spawned_pids (),
47     m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
48     m_proc_infos (),
49     m_proc_infos_index (0),
50     m_port_map (),
51     m_port_offset(0)
52 {
53 }
54 
55 //----------------------------------------------------------------------
56 // Destructor
57 //----------------------------------------------------------------------
58 GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer()
59 {
60 }
61 
62 
63 //void *
64 //GDBRemoteCommunicationServer::AsyncThread (void *arg)
65 //{
66 //    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
67 //
68 //    Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
69 //    if (log)
70 //        log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
71 //
72 //    StringExtractorGDBRemote packet;
73 //
74 //    while ()
75 //    {
76 //        if (packet.
77 //    }
78 //
79 //    if (log)
80 //        log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
81 //
82 //    process->m_async_thread = LLDB_INVALID_HOST_THREAD;
83 //    return NULL;
84 //}
85 //
86 bool
87 GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
88                                                         Error &error,
89                                                         bool &interrupt,
90                                                         bool &quit)
91 {
92     StringExtractorGDBRemote packet;
93     if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec))
94     {
95         const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
96         switch (packet_type)
97         {
98             case StringExtractorGDBRemote::eServerPacketType_nack:
99             case StringExtractorGDBRemote::eServerPacketType_ack:
100                 break;
101 
102             case StringExtractorGDBRemote::eServerPacketType_invalid:
103                 error.SetErrorString("invalid packet");
104                 quit = true;
105                 break;
106 
107             case StringExtractorGDBRemote::eServerPacketType_interrupt:
108                 error.SetErrorString("interrupt received");
109                 interrupt = true;
110                 break;
111 
112             default:
113             case StringExtractorGDBRemote::eServerPacketType_unimplemented:
114                 return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0;
115 
116             case StringExtractorGDBRemote::eServerPacketType_A:
117                 return Handle_A (packet);
118 
119             case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo:
120                 return Handle_qfProcessInfo (packet);
121 
122             case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo:
123                 return Handle_qsProcessInfo (packet);
124 
125             case StringExtractorGDBRemote::eServerPacketType_qC:
126                 return Handle_qC (packet);
127 
128             case StringExtractorGDBRemote::eServerPacketType_qHostInfo:
129                 return Handle_qHostInfo (packet);
130 
131             case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
132                 return Handle_qLaunchGDBServer (packet);
133 
134             case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess:
135                 return Handle_qKillSpawnedProcess (packet);
136 
137             case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
138                 return Handle_qLaunchSuccess (packet);
139 
140             case StringExtractorGDBRemote::eServerPacketType_qGroupName:
141                 return Handle_qGroupName (packet);
142 
143             case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
144                 return Handle_qProcessInfoPID (packet);
145 
146             case StringExtractorGDBRemote::eServerPacketType_qSpeedTest:
147                 return Handle_qSpeedTest (packet);
148 
149             case StringExtractorGDBRemote::eServerPacketType_qUserName:
150                 return Handle_qUserName (packet);
151 
152             case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir:
153                 return Handle_qGetWorkingDir(packet);
154 
155             case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
156                 return Handle_QEnvironment (packet);
157 
158             case StringExtractorGDBRemote::eServerPacketType_QLaunchArch:
159                 return Handle_QLaunchArch (packet);
160 
161             case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
162                 return Handle_QSetDisableASLR (packet);
163 
164             case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN:
165                 return Handle_QSetSTDIN (packet);
166 
167             case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT:
168                 return Handle_QSetSTDOUT (packet);
169 
170             case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR:
171                 return Handle_QSetSTDERR (packet);
172 
173             case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir:
174                 return Handle_QSetWorkingDir (packet);
175 
176             case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
177                 return Handle_QStartNoAckMode (packet);
178 
179             case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir:
180                 return Handle_qPlatform_mkdir (packet);
181 
182             case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod:
183                 return Handle_qPlatform_chmod (packet);
184 
185             case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell:
186                 return Handle_qPlatform_shell (packet);
187 
188             case StringExtractorGDBRemote::eServerPacketType_vFile_open:
189                 return Handle_vFile_Open (packet);
190 
191             case StringExtractorGDBRemote::eServerPacketType_vFile_close:
192                 return Handle_vFile_Close (packet);
193 
194             case StringExtractorGDBRemote::eServerPacketType_vFile_pread:
195                 return Handle_vFile_pRead (packet);
196 
197             case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite:
198                 return Handle_vFile_pWrite (packet);
199 
200             case StringExtractorGDBRemote::eServerPacketType_vFile_size:
201                 return Handle_vFile_Size (packet);
202 
203             case StringExtractorGDBRemote::eServerPacketType_vFile_mode:
204                 return Handle_vFile_Mode (packet);
205 
206             case StringExtractorGDBRemote::eServerPacketType_vFile_exists:
207                 return Handle_vFile_Exists (packet);
208 
209             case StringExtractorGDBRemote::eServerPacketType_vFile_stat:
210                 return Handle_vFile_Stat (packet);
211 
212             case StringExtractorGDBRemote::eServerPacketType_vFile_md5:
213                 return Handle_vFile_MD5 (packet);
214 
215             case StringExtractorGDBRemote::eServerPacketType_vFile_symlink:
216                 return Handle_vFile_symlink (packet);
217 
218             case StringExtractorGDBRemote::eServerPacketType_vFile_unlink:
219                 return Handle_vFile_unlink (packet);
220         }
221         return true;
222     }
223     else
224     {
225         if (!IsConnected())
226             error.SetErrorString("lost connection");
227         else
228             error.SetErrorString("timeout");
229     }
230 
231     return false;
232 }
233 
234 size_t
235 GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
236 {
237     // TODO: Log the packet we aren't handling...
238     return SendPacketNoLock ("", 0);
239 }
240 
241 size_t
242 GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
243 {
244     char packet[16];
245     int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err);
246     assert (packet_len < (int)sizeof(packet));
247     return SendPacketNoLock (packet, packet_len);
248 }
249 
250 
251 size_t
252 GDBRemoteCommunicationServer::SendOKResponse ()
253 {
254     return SendPacketNoLock ("OK", 2);
255 }
256 
257 bool
258 GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr)
259 {
260     return GetAck();
261 }
262 
263 bool
264 GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet)
265 {
266     StreamString response;
267 
268     // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
269 
270     ArchSpec host_arch (Host::GetArchitecture ());
271     const llvm::Triple &host_triple = host_arch.GetTriple();
272     response.PutCString("triple:");
273     response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
274     response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
275 
276     uint32_t cpu = host_arch.GetMachOCPUType();
277     uint32_t sub = host_arch.GetMachOCPUSubType();
278     if (cpu != LLDB_INVALID_CPUTYPE)
279         response.Printf ("cputype:%u;", cpu);
280     if (sub != LLDB_INVALID_CPUTYPE)
281         response.Printf ("cpusubtype:%u;", sub);
282 
283     if (cpu == ArchSpec::kCore_arm_any)
284         response.Printf("watchpoint_exceptions_received:before;");   // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
285     else
286         response.Printf("watchpoint_exceptions_received:after;");
287 
288     switch (lldb::endian::InlHostByteOrder())
289     {
290     case eByteOrderBig:     response.PutCString ("endian:big;"); break;
291     case eByteOrderLittle:  response.PutCString ("endian:little;"); break;
292     case eByteOrderPDP:     response.PutCString ("endian:pdp;"); break;
293     default:                response.PutCString ("endian:unknown;"); break;
294     }
295 
296     uint32_t major = UINT32_MAX;
297     uint32_t minor = UINT32_MAX;
298     uint32_t update = UINT32_MAX;
299     if (Host::GetOSVersion (major, minor, update))
300     {
301         if (major != UINT32_MAX)
302         {
303             response.Printf("os_version:%u", major);
304             if (minor != UINT32_MAX)
305             {
306                 response.Printf(".%u", minor);
307                 if (update != UINT32_MAX)
308                     response.Printf(".%u", update);
309             }
310             response.PutChar(';');
311         }
312     }
313 
314     std::string s;
315     if (Host::GetOSBuildString (s))
316     {
317         response.PutCString ("os_build:");
318         response.PutCStringAsRawHex8(s.c_str());
319         response.PutChar(';');
320     }
321     if (Host::GetOSKernelDescription (s))
322     {
323         response.PutCString ("os_kernel:");
324         response.PutCStringAsRawHex8(s.c_str());
325         response.PutChar(';');
326     }
327 #if defined(__APPLE__)
328 
329 #if defined(__arm__)
330     // For iOS devices, we are connected through a USB Mux so we never pretend
331     // to actually have a hostname as far as the remote lldb that is connecting
332     // to this lldb-platform is concerned
333     response.PutCString ("hostname:");
334     response.PutCStringAsRawHex8("localhost");
335     response.PutChar(';');
336 #else   // #if defined(__arm__)
337     if (Host::GetHostname (s))
338     {
339         response.PutCString ("hostname:");
340         response.PutCStringAsRawHex8(s.c_str());
341         response.PutChar(';');
342     }
343 
344 #endif  // #if defined(__arm__)
345 
346 #else   // #if defined(__APPLE__)
347     if (Host::GetHostname (s))
348     {
349         response.PutCString ("hostname:");
350         response.PutCStringAsRawHex8(s.c_str());
351         response.PutChar(';');
352     }
353 #endif  // #if defined(__APPLE__)
354 
355     return SendPacketNoLock (response.GetData(), response.GetSize()) > 0;
356 }
357 
358 static void
359 CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response)
360 {
361     response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
362                      proc_info.GetProcessID(),
363                      proc_info.GetParentProcessID(),
364                      proc_info.GetUserID(),
365                      proc_info.GetGroupID(),
366                      proc_info.GetEffectiveUserID(),
367                      proc_info.GetEffectiveGroupID());
368     response.PutCString ("name:");
369     response.PutCStringAsRawHex8(proc_info.GetName());
370     response.PutChar(';');
371     const ArchSpec &proc_arch = proc_info.GetArchitecture();
372     if (proc_arch.IsValid())
373     {
374         const llvm::Triple &proc_triple = proc_arch.GetTriple();
375         response.PutCString("triple:");
376         response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
377         response.PutChar(';');
378     }
379 }
380 
381 bool
382 GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
383 {
384     // Packet format: "qProcessInfoPID:%i" where %i is the pid
385     packet.SetFilePos(::strlen ("qProcessInfoPID:"));
386     lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
387     if (pid != LLDB_INVALID_PROCESS_ID)
388     {
389         ProcessInstanceInfo proc_info;
390         if (Host::GetProcessInfo(pid, proc_info))
391         {
392             StreamString response;
393             CreateProcessInfoResponse (proc_info, response);
394             return SendPacketNoLock (response.GetData(), response.GetSize());
395         }
396     }
397     return SendErrorResponse (1);
398 }
399 
400 bool
401 GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
402 {
403     m_proc_infos_index = 0;
404     m_proc_infos.Clear();
405 
406     ProcessInstanceInfoMatch match_info;
407     packet.SetFilePos(::strlen ("qfProcessInfo"));
408     if (packet.GetChar() == ':')
409     {
410 
411         std::string key;
412         std::string value;
413         while (packet.GetNameColonValue(key, value))
414         {
415             bool success = true;
416             if (key.compare("name") == 0)
417             {
418                 StringExtractor extractor;
419                 extractor.GetStringRef().swap(value);
420                 extractor.GetHexByteString (value);
421                 match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
422             }
423             else if (key.compare("name_match") == 0)
424             {
425                 if (value.compare("equals") == 0)
426                 {
427                     match_info.SetNameMatchType (eNameMatchEquals);
428                 }
429                 else if (value.compare("starts_with") == 0)
430                 {
431                     match_info.SetNameMatchType (eNameMatchStartsWith);
432                 }
433                 else if (value.compare("ends_with") == 0)
434                 {
435                     match_info.SetNameMatchType (eNameMatchEndsWith);
436                 }
437                 else if (value.compare("contains") == 0)
438                 {
439                     match_info.SetNameMatchType (eNameMatchContains);
440                 }
441                 else if (value.compare("regex") == 0)
442                 {
443                     match_info.SetNameMatchType (eNameMatchRegularExpression);
444                 }
445                 else
446                 {
447                     success = false;
448                 }
449             }
450             else if (key.compare("pid") == 0)
451             {
452                 match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
453             }
454             else if (key.compare("parent_pid") == 0)
455             {
456                 match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
457             }
458             else if (key.compare("uid") == 0)
459             {
460                 match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
461             }
462             else if (key.compare("gid") == 0)
463             {
464                 match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
465             }
466             else if (key.compare("euid") == 0)
467             {
468                 match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
469             }
470             else if (key.compare("egid") == 0)
471             {
472                 match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
473             }
474             else if (key.compare("all_users") == 0)
475             {
476                 match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
477             }
478             else if (key.compare("triple") == 0)
479             {
480                 match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
481             }
482             else
483             {
484                 success = false;
485             }
486 
487             if (!success)
488                 return SendErrorResponse (2);
489         }
490     }
491 
492     if (Host::FindProcesses (match_info, m_proc_infos))
493     {
494         // We found something, return the first item by calling the get
495         // subsequent process info packet handler...
496         return Handle_qsProcessInfo (packet);
497     }
498     return SendErrorResponse (3);
499 }
500 
501 bool
502 GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
503 {
504     if (m_proc_infos_index < m_proc_infos.GetSize())
505     {
506         StreamString response;
507         CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
508         ++m_proc_infos_index;
509         return SendPacketNoLock (response.GetData(), response.GetSize());
510     }
511     return SendErrorResponse (4);
512 }
513 
514 bool
515 GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)
516 {
517     // Packet format: "qUserName:%i" where %i is the uid
518     packet.SetFilePos(::strlen ("qUserName:"));
519     uint32_t uid = packet.GetU32 (UINT32_MAX);
520     if (uid != UINT32_MAX)
521     {
522         std::string name;
523         if (Host::GetUserName (uid, name))
524         {
525             StreamString response;
526             response.PutCStringAsRawHex8 (name.c_str());
527             return SendPacketNoLock (response.GetData(), response.GetSize());
528         }
529     }
530     return SendErrorResponse (5);
531 
532 }
533 
534 bool
535 GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)
536 {
537     // Packet format: "qGroupName:%i" where %i is the gid
538     packet.SetFilePos(::strlen ("qGroupName:"));
539     uint32_t gid = packet.GetU32 (UINT32_MAX);
540     if (gid != UINT32_MAX)
541     {
542         std::string name;
543         if (Host::GetGroupName (gid, name))
544         {
545             StreamString response;
546             response.PutCStringAsRawHex8 (name.c_str());
547             return SendPacketNoLock (response.GetData(), response.GetSize());
548         }
549     }
550     return SendErrorResponse (6);
551 }
552 
553 bool
554 GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
555 {
556     packet.SetFilePos(::strlen ("qSpeedTest:"));
557 
558     std::string key;
559     std::string value;
560     bool success = packet.GetNameColonValue(key, value);
561     if (success && key.compare("response_size") == 0)
562     {
563         uint32_t response_size = Args::StringToUInt32(value.c_str(), 0, 0, &success);
564         if (success)
565         {
566             if (response_size == 0)
567                 return SendOKResponse();
568             StreamString response;
569             uint32_t bytes_left = response_size;
570             response.PutCString("data:");
571             while (bytes_left > 0)
572             {
573                 if (bytes_left >= 26)
574                 {
575                     response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
576                     bytes_left -= 26;
577                 }
578                 else
579                 {
580                     response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
581                     bytes_left = 0;
582                 }
583             }
584             return SendPacketNoLock (response.GetData(), response.GetSize());
585         }
586     }
587     return SendErrorResponse (7);
588 }
589 
590 
591 static void *
592 AcceptPortFromInferior (void *arg)
593 {
594     const char *connect_url = (const char *)arg;
595     ConnectionFileDescriptor file_conn;
596     Error error;
597     if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
598     {
599         char pid_str[256];
600         ::memset (pid_str, 0, sizeof(pid_str));
601         ConnectionStatus status;
602         const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL);
603         if (pid_str_len > 0)
604         {
605             int pid = atoi (pid_str);
606             return (void *)(intptr_t)pid;
607         }
608     }
609     return NULL;
610 }
611 //
612 //static bool
613 //WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
614 //{
615 //    const int time_delta_usecs = 100000;
616 //    const int num_retries = timeout_in_seconds/time_delta_usecs;
617 //    for (int i=0; i<num_retries; i++)
618 //    {
619 //        struct proc_bsdinfo bsd_info;
620 //        int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
621 //                                    (uint64_t) 0,
622 //                                    &bsd_info,
623 //                                    PROC_PIDTBSDINFO_SIZE);
624 //
625 //        switch (error)
626 //        {
627 //            case EINVAL:
628 //            case ENOTSUP:
629 //            case ESRCH:
630 //            case EPERM:
631 //                return false;
632 //
633 //            default:
634 //                break;
635 //
636 //            case 0:
637 //                if (bsd_info.pbi_status == SSTOP)
638 //                    return true;
639 //        }
640 //        ::usleep (time_delta_usecs);
641 //    }
642 //    return false;
643 //}
644 
645 bool
646 GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
647 {
648     // The 'A' packet is the most over designed packet ever here with
649     // redundant argument indexes, redundant argument lengths and needed hex
650     // encoded argument string values. Really all that is needed is a comma
651     // separated hex encoded argument value list, but we will stay true to the
652     // documented version of the 'A' packet here...
653 
654     packet.SetFilePos(1); // Skip the 'A'
655     bool success = true;
656     while (success && packet.GetBytesLeft() > 0)
657     {
658         // Decode the decimal argument string length. This length is the
659         // number of hex nibbles in the argument string value.
660         const uint32_t arg_len = packet.GetU32(UINT32_MAX);
661         if (arg_len == UINT32_MAX)
662             success = false;
663         else
664         {
665             // Make sure the argument hex string length is followed by a comma
666             if (packet.GetChar() != ',')
667                 success = false;
668             else
669             {
670                 // Decode the argument index. We ignore this really becuase
671                 // who would really send down the arguments in a random order???
672                 const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
673                 if (arg_idx == UINT32_MAX)
674                     success = false;
675                 else
676                 {
677                     // Make sure the argument index is followed by a comma
678                     if (packet.GetChar() != ',')
679                         success = false;
680                     else
681                     {
682                         // Decode the argument string value from hex bytes
683                         // back into a UTF8 string and make sure the length
684                         // matches the one supplied in the packet
685                         std::string arg;
686                         if (packet.GetHexByteString(arg) != (arg_len / 2))
687                             success = false;
688                         else
689                         {
690                             // If there are any bytes lft
691                             if (packet.GetBytesLeft())
692                             {
693                                 if (packet.GetChar() != ',')
694                                     success = false;
695                             }
696 
697                             if (success)
698                             {
699                                 if (arg_idx == 0)
700                                     m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
701                                 m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
702                             }
703                         }
704                     }
705                 }
706             }
707         }
708     }
709 
710     if (success)
711     {
712         m_process_launch_info.GetFlags().Set (eLaunchFlagDebug);
713         m_process_launch_error = Host::LaunchProcess (m_process_launch_info);
714         if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
715         {
716             return SendOKResponse ();
717         }
718     }
719     return SendErrorResponse (8);
720 }
721 
722 bool
723 GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
724 {
725     lldb::pid_t pid = m_process_launch_info.GetProcessID();
726     StreamString response;
727     response.Printf("QC%" PRIx64, pid);
728     if (m_is_platform)
729     {
730         // If we launch a process and this GDB server is acting as a platform,
731         // then we need to clear the process launch state so we can start
732         // launching another process. In order to launch a process a bunch or
733         // packets need to be sent: environment packets, working directory,
734         // disable ASLR, and many more settings. When we launch a process we
735         // then need to know when to clear this information. Currently we are
736         // selecting the 'qC' packet as that packet which seems to make the most
737         // sense.
738         if (pid != LLDB_INVALID_PROCESS_ID)
739         {
740             m_process_launch_info.Clear();
741         }
742     }
743     return SendPacketNoLock (response.GetData(), response.GetSize());
744 }
745 
746 bool
747 GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
748 {
749     Mutex::Locker locker (m_spawned_pids_mutex);
750     FreePortForProcess(pid);
751     return m_spawned_pids.erase(pid) > 0;
752 }
753 bool
754 GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton,
755                                                       lldb::pid_t pid,
756                                                       bool exited,
757                                                       int signal,    // Zero for no signal
758                                                       int status)    // Exit value of process if signal is zero
759 {
760     GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
761     server->DebugserverProcessReaped (pid);
762     return true;
763 }
764 
765 bool
766 GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
767 {
768 #ifdef _WIN32
769     // No unix sockets on windows
770     return false;
771 #else
772     // Spawn a local debugserver as a platform so we can then attach or launch
773     // a process...
774 
775     if (m_is_platform)
776     {
777         // Sleep and wait a bit for debugserver to start to listen...
778         ConnectionFileDescriptor file_conn;
779         Error error;
780         std::string hostname;
781         // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
782         // with the TMPDIR environnement variable
783         packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
784         std::string name;
785         std::string value;
786         uint16_t port = UINT16_MAX;
787         while (packet.GetNameColonValue(name, value))
788         {
789             if (name.compare ("host") == 0)
790                 hostname.swap(value);
791             else if (name.compare ("port") == 0)
792                 port = Args::StringToUInt32(value.c_str(), 0, 0);
793         }
794         if (port == UINT16_MAX)
795             port = GetNextAvailablePort();
796 
797         // Spawn a new thread to accept the port that gets bound after
798         // binding to port 0 (zero).
799 
800         if (error.Success())
801         {
802             // Spawn a debugserver and try to get the port it listens to.
803             ProcessLaunchInfo debugserver_launch_info;
804             StreamString host_and_port;
805             if (hostname.empty())
806                 hostname = "localhost";
807             host_and_port.Printf("%s:%u", hostname.c_str(), port);
808             const char *host_and_port_cstr = host_and_port.GetString().c_str();
809             Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
810             if (log)
811                 log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr);
812 
813             debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
814 
815             error = StartDebugserverProcess (host_and_port_cstr,
816                                              debugserver_launch_info,
817                                              port);
818 
819             lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
820 
821 
822             if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
823             {
824                 Mutex::Locker locker (m_spawned_pids_mutex);
825                 m_spawned_pids.insert(debugserver_pid);
826                 if (port > 0)
827                     AssociatePortWithProcess(port, debugserver_pid);
828             }
829             else
830             {
831                 if (port > 0)
832                     FreePort (port);
833             }
834 
835             if (error.Success())
836             {
837                 bool success = false;
838 
839                 char response[256];
840                 const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
841                 assert (response_len < sizeof(response));
842                 success = SendPacketNoLock (response, response_len) > 0;
843 
844                 if (!success)
845                 {
846                     if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
847                         ::kill (debugserver_pid, SIGINT);
848                 }
849                 return success;
850             }
851         }
852     }
853     return SendErrorResponse (9);
854 #endif
855 }
856 
857 bool
858 GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
859 {
860     // Spawn a local debugserver as a platform so we can then attach or launch
861     // a process...
862 
863     if (m_is_platform)
864     {
865         packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
866 
867         lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
868 
869         // Scope for locker
870         {
871             Mutex::Locker locker (m_spawned_pids_mutex);
872             if (m_spawned_pids.find(pid) == m_spawned_pids.end())
873                 return SendErrorResponse (10);
874         }
875         Host::Kill (pid, SIGTERM);
876 
877         for (size_t i=0; i<10; ++i)
878         {
879             // Scope for locker
880             {
881                 Mutex::Locker locker (m_spawned_pids_mutex);
882                 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
883                     return SendOKResponse();
884             }
885             usleep (10000);
886         }
887 
888         // Scope for locker
889         {
890             Mutex::Locker locker (m_spawned_pids_mutex);
891             if (m_spawned_pids.find(pid) == m_spawned_pids.end())
892                 return SendOKResponse();
893         }
894         Host::Kill (pid, SIGKILL);
895 
896         for (size_t i=0; i<10; ++i)
897         {
898             // Scope for locker
899             {
900                 Mutex::Locker locker (m_spawned_pids_mutex);
901                 if (m_spawned_pids.find(pid) == m_spawned_pids.end())
902                     return SendOKResponse();
903             }
904             usleep (10000);
905         }
906     }
907     return SendErrorResponse (11);
908 }
909 
910 bool
911 GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
912 {
913     if (m_process_launch_error.Success())
914         return SendOKResponse();
915     StreamString response;
916     response.PutChar('E');
917     response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
918     return SendPacketNoLock (response.GetData(), response.GetSize());
919 }
920 
921 bool
922 GDBRemoteCommunicationServer::Handle_QEnvironment  (StringExtractorGDBRemote &packet)
923 {
924     packet.SetFilePos(::strlen ("QEnvironment:"));
925     const uint32_t bytes_left = packet.GetBytesLeft();
926     if (bytes_left > 0)
927     {
928         m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
929         return SendOKResponse ();
930     }
931     return SendErrorResponse (12);
932 }
933 
934 bool
935 GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
936 {
937     packet.SetFilePos(::strlen ("QLaunchArch:"));
938     const uint32_t bytes_left = packet.GetBytesLeft();
939     if (bytes_left > 0)
940     {
941         const char* arch_triple = packet.Peek();
942         ArchSpec arch_spec(arch_triple,NULL);
943         m_process_launch_info.SetArchitecture(arch_spec);
944         return SendOKResponse();
945     }
946     return SendErrorResponse(13);
947 }
948 
949 bool
950 GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
951 {
952     packet.SetFilePos(::strlen ("QSetDisableASLR:"));
953     if (packet.GetU32(0))
954         m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
955     else
956         m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
957     return SendOKResponse ();
958 }
959 
960 bool
961 GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
962 {
963     packet.SetFilePos(::strlen ("QSetWorkingDir:"));
964     std::string path;
965     packet.GetHexByteString(path);
966     if (m_is_platform)
967     {
968 #ifdef _WIN32
969         // Not implemented on Windows
970         return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented");
971 #else
972         // If this packet is sent to a platform, then change the current working directory
973         if (::chdir(path.c_str()) != 0)
974             return SendErrorResponse(errno);
975 #endif
976     }
977     else
978     {
979         m_process_launch_info.SwapWorkingDirectory (path);
980     }
981     return SendOKResponse ();
982 }
983 
984 bool
985 GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
986 {
987     StreamString response;
988 
989     if (m_is_platform)
990     {
991         // If this packet is sent to a platform, then change the current working directory
992         char cwd[PATH_MAX];
993         if (getcwd(cwd, sizeof(cwd)) == NULL)
994         {
995             return SendErrorResponse(errno);
996         }
997         else
998         {
999             response.PutBytesAsRawHex8(cwd, strlen(cwd));
1000             SendPacketNoLock(response.GetData(), response.GetSize());
1001             return true;
1002         }
1003     }
1004     else
1005     {
1006         const char *working_dir = m_process_launch_info.GetWorkingDirectory();
1007         if (working_dir && working_dir[0])
1008         {
1009             response.PutBytesAsRawHex8(working_dir, strlen(working_dir));
1010             SendPacketNoLock(response.GetData(), response.GetSize());
1011             return true;
1012         }
1013         else
1014         {
1015             return SendErrorResponse(14);
1016         }
1017     }
1018 }
1019 
1020 bool
1021 GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
1022 {
1023     packet.SetFilePos(::strlen ("QSetSTDIN:"));
1024     ProcessLaunchInfo::FileAction file_action;
1025     std::string path;
1026     packet.GetHexByteString(path);
1027     const bool read = false;
1028     const bool write = true;
1029     if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
1030     {
1031         m_process_launch_info.AppendFileAction(file_action);
1032         return SendOKResponse ();
1033     }
1034     return SendErrorResponse (15);
1035 }
1036 
1037 bool
1038 GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
1039 {
1040     packet.SetFilePos(::strlen ("QSetSTDOUT:"));
1041     ProcessLaunchInfo::FileAction file_action;
1042     std::string path;
1043     packet.GetHexByteString(path);
1044     const bool read = true;
1045     const bool write = false;
1046     if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
1047     {
1048         m_process_launch_info.AppendFileAction(file_action);
1049         return SendOKResponse ();
1050     }
1051     return SendErrorResponse (16);
1052 }
1053 
1054 bool
1055 GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
1056 {
1057     packet.SetFilePos(::strlen ("QSetSTDERR:"));
1058     ProcessLaunchInfo::FileAction file_action;
1059     std::string path;
1060     packet.GetHexByteString(path);
1061     const bool read = true;
1062     const bool write = false;
1063     if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
1064     {
1065         m_process_launch_info.AppendFileAction(file_action);
1066         return SendOKResponse ();
1067     }
1068     return SendErrorResponse (17);
1069 }
1070 
1071 bool
1072 GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
1073 {
1074     // Send response first before changing m_send_acks to we ack this packet
1075     SendOKResponse ();
1076     m_send_acks = false;
1077     return true;
1078 }
1079 
1080 bool
1081 GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
1082 {
1083     packet.SetFilePos(::strlen("qPlatform_mkdir:"));
1084     mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
1085     if (packet.GetChar() == ',')
1086     {
1087         std::string path;
1088         packet.GetHexByteString(path);
1089         Error error = Host::MakeDirectory(path.c_str(),mode);
1090         if (error.Success())
1091             return SendPacketNoLock ("OK", 2);
1092         else
1093             return SendErrorResponse(error.GetError());
1094     }
1095     return SendErrorResponse(20);
1096 }
1097 
1098 bool
1099 GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
1100 {
1101     packet.SetFilePos(::strlen("qPlatform_chmod:"));
1102 
1103     mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
1104     if (packet.GetChar() == ',')
1105     {
1106         std::string path;
1107         packet.GetHexByteString(path);
1108         Error error = Host::SetFilePermissions (path.c_str(), mode);
1109         if (error.Success())
1110             return SendPacketNoLock ("OK", 2);
1111         else
1112             return SendErrorResponse(error.GetError());
1113     }
1114     return SendErrorResponse(19);
1115 }
1116 
1117 bool
1118 GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)
1119 {
1120     packet.SetFilePos(::strlen("vFile:open:"));
1121     std::string path;
1122     packet.GetHexByteStringTerminatedBy(path,',');
1123     if (!path.empty())
1124     {
1125         if (packet.GetChar() == ',')
1126         {
1127             uint32_t flags = packet.GetHexMaxU32(false, 0);
1128             if (packet.GetChar() == ',')
1129             {
1130                 mode_t mode = packet.GetHexMaxU32(false, 0600);
1131                 Error error;
1132                 int fd = ::open (path.c_str(), flags, mode);
1133                 const int save_errno = fd == -1 ? errno : 0;
1134                 StreamString response;
1135                 response.PutChar('F');
1136                 response.Printf("%i", fd);
1137                 if (save_errno)
1138                     response.Printf(",%i", save_errno);
1139                 return SendPacketNoLock(response.GetData(), response.GetSize());
1140             }
1141         }
1142     }
1143     return SendErrorResponse(18);
1144 }
1145 
1146 bool
1147 GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)
1148 {
1149     packet.SetFilePos(::strlen("vFile:close:"));
1150     int fd = packet.GetS32(-1);
1151     Error error;
1152     int err = -1;
1153     int save_errno = 0;
1154     if (fd >= 0)
1155     {
1156         err = close(fd);
1157         save_errno = err == -1 ? errno : 0;
1158     }
1159     else
1160     {
1161         save_errno = EINVAL;
1162     }
1163     StreamString response;
1164     response.PutChar('F');
1165     response.Printf("%i", err);
1166     if (save_errno)
1167         response.Printf(",%i", save_errno);
1168     return SendPacketNoLock(response.GetData(), response.GetSize());
1169 }
1170 
1171 bool
1172 GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
1173 {
1174 #ifdef _WIN32
1175     // Not implemented on Windows
1176     return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented");
1177 #else
1178     StreamGDBRemote response;
1179     packet.SetFilePos(::strlen("vFile:pread:"));
1180     int fd = packet.GetS32(-1);
1181     if (packet.GetChar() == ',')
1182     {
1183         uint64_t count = packet.GetU64(UINT64_MAX);
1184         if (packet.GetChar() == ',')
1185         {
1186             uint64_t offset = packet.GetU64(UINT32_MAX);
1187             if (count == UINT64_MAX)
1188             {
1189                 response.Printf("F-1:%i", EINVAL);
1190                 return SendPacketNoLock(response.GetData(), response.GetSize());
1191             }
1192 
1193             std::string buffer(count, 0);
1194             const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
1195             const int save_errno = bytes_read == -1 ? errno : 0;
1196             response.PutChar('F');
1197             response.Printf("%zi", bytes_read);
1198             if (save_errno)
1199                 response.Printf(",%i", save_errno);
1200             else
1201             {
1202                 response.PutChar(';');
1203                 response.PutEscapedBytes(&buffer[0], bytes_read);
1204             }
1205             return SendPacketNoLock(response.GetData(), response.GetSize());
1206         }
1207     }
1208     return SendErrorResponse(21);
1209 
1210 #endif
1211 }
1212 
1213 bool
1214 GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
1215 {
1216 #ifdef _WIN32
1217     return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented");
1218 #else
1219     packet.SetFilePos(::strlen("vFile:pwrite:"));
1220 
1221     StreamGDBRemote response;
1222     response.PutChar('F');
1223 
1224     int fd = packet.GetU32(UINT32_MAX);
1225     if (packet.GetChar() == ',')
1226     {
1227         off_t offset = packet.GetU64(UINT32_MAX);
1228         if (packet.GetChar() == ',')
1229         {
1230             std::string buffer;
1231             if (packet.GetEscapedBinaryData(buffer))
1232             {
1233                 const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
1234                 const int save_errno = bytes_written == -1 ? errno : 0;
1235                 response.Printf("%zi", bytes_written);
1236                 if (save_errno)
1237                     response.Printf(",%i", save_errno);
1238             }
1239             else
1240             {
1241                 response.Printf ("-1,%i", EINVAL);
1242             }
1243             return SendPacketNoLock(response.GetData(), response.GetSize());
1244         }
1245     }
1246     return SendErrorResponse(27);
1247 #endif
1248 }
1249 
1250 bool
1251 GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)
1252 {
1253     packet.SetFilePos(::strlen("vFile:size:"));
1254     std::string path;
1255     packet.GetHexByteString(path);
1256     if (!path.empty())
1257     {
1258         lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
1259         StreamString response;
1260         response.PutChar('F');
1261         response.PutHex64(retcode);
1262         if (retcode == UINT64_MAX)
1263         {
1264             response.PutChar(',');
1265             response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
1266         }
1267         return SendPacketNoLock(response.GetData(), response.GetSize());
1268     }
1269     return SendErrorResponse(22);
1270 }
1271 
1272 bool
1273 GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
1274 {
1275     packet.SetFilePos(::strlen("vFile:mode:"));
1276     std::string path;
1277     packet.GetHexByteString(path);
1278     if (!path.empty())
1279     {
1280         Error error;
1281         const uint32_t mode = File::GetPermissions(path.c_str(), error);
1282         StreamString response;
1283         response.Printf("F%u", mode);
1284         if (mode == 0 || error.Fail())
1285             response.Printf(",%i", (int)error.GetError());
1286         return SendPacketNoLock(response.GetData(), response.GetSize());
1287     }
1288     return SendErrorResponse(23);
1289 }
1290 
1291 bool
1292 GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
1293 {
1294     packet.SetFilePos(::strlen("vFile:exists:"));
1295     std::string path;
1296     packet.GetHexByteString(path);
1297     if (!path.empty())
1298     {
1299         bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
1300         StreamString response;
1301         response.PutChar('F');
1302         response.PutChar(',');
1303         if (retcode)
1304             response.PutChar('1');
1305         else
1306             response.PutChar('0');
1307         return SendPacketNoLock(response.GetData(), response.GetSize());
1308     }
1309     return SendErrorResponse(24);
1310 }
1311 
1312 bool
1313 GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
1314 {
1315     packet.SetFilePos(::strlen("vFile:symlink:"));
1316     std::string dst, src;
1317     packet.GetHexByteStringTerminatedBy(dst, ',');
1318     packet.GetChar(); // Skip ',' char
1319     packet.GetHexByteString(src);
1320     Error error = Host::Symlink(src.c_str(), dst.c_str());
1321     StreamString response;
1322     response.Printf("F%u,%u", error.GetError(), error.GetError());
1323     return SendPacketNoLock(response.GetData(), response.GetSize());
1324 }
1325 
1326 bool
1327 GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
1328 {
1329     packet.SetFilePos(::strlen("vFile:unlink:"));
1330     std::string path;
1331     packet.GetHexByteString(path);
1332     Error error = Host::Unlink(path.c_str());
1333     StreamString response;
1334     response.Printf("F%u,%u", error.GetError(), error.GetError());
1335     return SendPacketNoLock(response.GetData(), response.GetSize());
1336 }
1337 
1338 bool
1339 GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)
1340 {
1341     packet.SetFilePos(::strlen("qPlatform_shell:"));
1342     std::string path;
1343     std::string working_dir;
1344     packet.GetHexByteStringTerminatedBy(path,',');
1345     if (!path.empty())
1346     {
1347         if (packet.GetChar() == ',')
1348         {
1349             // FIXME: add timeout to qPlatform_shell packet
1350             // uint32_t timeout = packet.GetHexMaxU32(false, 32);
1351             uint32_t timeout = 10;
1352             if (packet.GetChar() == ',')
1353                 packet.GetHexByteString(working_dir);
1354             int status, signo;
1355             std::string output;
1356             Error err = Host::RunShellCommand(path.c_str(),
1357                                               working_dir.empty() ? NULL : working_dir.c_str(),
1358                                               &status, &signo, &output, timeout);
1359             StreamGDBRemote response;
1360             if (err.Fail())
1361             {
1362                 response.PutCString("F,");
1363                 response.PutHex32(UINT32_MAX);
1364             }
1365             else
1366             {
1367                 response.PutCString("F,");
1368                 response.PutHex32(status);
1369                 response.PutChar(',');
1370                 response.PutHex32(signo);
1371                 response.PutChar(',');
1372                 response.PutEscapedBytes(output.c_str(), output.size());
1373             }
1374             return SendPacketNoLock(response.GetData(), response.GetSize());
1375         }
1376     }
1377     return SendErrorResponse(24);
1378 }
1379 
1380 bool
1381 GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
1382 {
1383     return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented");
1384 }
1385 
1386 bool
1387 GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
1388 {
1389     packet.SetFilePos(::strlen("vFile:MD5:"));
1390     std::string path;
1391     packet.GetHexByteString(path);
1392     if (!path.empty())
1393     {
1394         uint64_t a,b;
1395         StreamGDBRemote response;
1396         if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
1397         {
1398             response.PutCString("F,");
1399             response.PutCString("x");
1400         }
1401         else
1402         {
1403             response.PutCString("F,");
1404             response.PutHex64(a);
1405             response.PutHex64(b);
1406         }
1407         return SendPacketNoLock(response.GetData(), response.GetSize());
1408     }
1409     return SendErrorResponse(25);
1410 }
1411 
1412