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