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