1 //===-- GDBRemoteCommunicationServerCommon.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 "GDBRemoteCommunicationServerCommon.h" 11 12 #include <errno.h> 13 14 // C Includes 15 // C++ Includes 16 #include <cstring> 17 #include <chrono> 18 19 // Other libraries and framework includes 20 #include "llvm/ADT/Triple.h" 21 #include "lldb/Core/Log.h" 22 #include "lldb/Core/StreamGDBRemote.h" 23 #include "lldb/Core/StreamString.h" 24 #include "lldb/Host/Config.h" 25 #include "lldb/Host/Endian.h" 26 #include "lldb/Host/File.h" 27 #include "lldb/Host/FileSystem.h" 28 #include "lldb/Host/Host.h" 29 #include "lldb/Host/HostInfo.h" 30 #include "lldb/Host/StringConvert.h" 31 #include "lldb/Interpreter/Args.h" 32 #include "lldb/Target/FileAction.h" 33 #include "lldb/Target/Platform.h" 34 #include "lldb/Target/Process.h" 35 36 // Project includes 37 #include "ProcessGDBRemoteLog.h" 38 #include "Utility/StringExtractorGDBRemote.h" 39 40 using namespace lldb; 41 using namespace lldb_private; 42 43 //---------------------------------------------------------------------- 44 // GDBRemoteCommunicationServerCommon constructor 45 //---------------------------------------------------------------------- 46 GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name) : 47 GDBRemoteCommunicationServer (comm_name, listener_name), 48 m_spawned_pids (), 49 m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), 50 m_process_launch_info (), 51 m_process_launch_error (), 52 m_proc_infos (), 53 m_proc_infos_index (0), 54 m_thread_suffix_supported (false), 55 m_list_threads_in_stop_reply (false) 56 { 57 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A, 58 &GDBRemoteCommunicationServerCommon::Handle_A); 59 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironment, 60 &GDBRemoteCommunicationServerCommon::Handle_QEnvironment); 61 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfProcessInfo, 62 &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo); 63 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGroupName, 64 &GDBRemoteCommunicationServerCommon::Handle_qGroupName); 65 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qHostInfo, 66 &GDBRemoteCommunicationServerCommon::Handle_qHostInfo); 67 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, 68 &GDBRemoteCommunicationServerCommon::Handle_qKillSpawnedProcess); 69 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QLaunchArch, 70 &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch); 71 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess, 72 &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess); 73 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, 74 &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply); 75 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod, 76 &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod); 77 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir, 78 &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir); 79 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_shell, 80 &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell); 81 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID, 82 &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID); 83 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError, 84 &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError); 85 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDERR, 86 &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR); 87 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDIN, 88 &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN); 89 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT, 90 &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT); 91 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSpeedTest, 92 &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest); 93 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsProcessInfo, 94 &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo); 95 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode, 96 &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode); 97 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSupported, 98 &GDBRemoteCommunicationServerCommon::Handle_qSupported); 99 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported, 100 &GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported); 101 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qUserName, 102 &GDBRemoteCommunicationServerCommon::Handle_qUserName); 103 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_close, 104 &GDBRemoteCommunicationServerCommon::Handle_vFile_Close); 105 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_exists, 106 &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists); 107 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_md5, 108 &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5); 109 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_mode, 110 &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode); 111 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_open, 112 &GDBRemoteCommunicationServerCommon::Handle_vFile_Open); 113 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pread, 114 &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead); 115 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pwrite, 116 &GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite); 117 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_size, 118 &GDBRemoteCommunicationServerCommon::Handle_vFile_Size); 119 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_stat, 120 &GDBRemoteCommunicationServerCommon::Handle_vFile_Stat); 121 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_symlink, 122 &GDBRemoteCommunicationServerCommon::Handle_vFile_symlink); 123 RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_unlink, 124 &GDBRemoteCommunicationServerCommon::Handle_vFile_unlink); 125 } 126 127 //---------------------------------------------------------------------- 128 // Destructor 129 //---------------------------------------------------------------------- 130 GDBRemoteCommunicationServerCommon::~GDBRemoteCommunicationServerCommon() 131 { 132 } 133 134 GDBRemoteCommunication::PacketResult 135 GDBRemoteCommunicationServerCommon::Handle_qHostInfo (StringExtractorGDBRemote &packet) 136 { 137 StreamString response; 138 139 // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 140 141 ArchSpec host_arch(HostInfo::GetArchitecture()); 142 const llvm::Triple &host_triple = host_arch.GetTriple(); 143 response.PutCString("triple:"); 144 response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); 145 response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); 146 147 const char* distribution_id = host_arch.GetDistributionId ().AsCString (); 148 if (distribution_id) 149 { 150 response.PutCString("distribution_id:"); 151 response.PutCStringAsRawHex8(distribution_id); 152 response.PutCString(";"); 153 } 154 155 // Only send out MachO info when lldb-platform/llgs is running on a MachO host. 156 #if defined(__APPLE__) 157 uint32_t cpu = host_arch.GetMachOCPUType(); 158 uint32_t sub = host_arch.GetMachOCPUSubType(); 159 if (cpu != LLDB_INVALID_CPUTYPE) 160 response.Printf ("cputype:%u;", cpu); 161 if (sub != LLDB_INVALID_CPUTYPE) 162 response.Printf ("cpusubtype:%u;", sub); 163 164 if (cpu == ArchSpec::kCore_arm_any) 165 response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. 166 else 167 response.Printf("watchpoint_exceptions_received:after;"); 168 #else 169 response.Printf("watchpoint_exceptions_received:after;"); 170 #endif 171 172 switch (lldb::endian::InlHostByteOrder()) 173 { 174 case eByteOrderBig: response.PutCString ("endian:big;"); break; 175 case eByteOrderLittle: response.PutCString ("endian:little;"); break; 176 case eByteOrderPDP: response.PutCString ("endian:pdp;"); break; 177 default: response.PutCString ("endian:unknown;"); break; 178 } 179 180 uint32_t major = UINT32_MAX; 181 uint32_t minor = UINT32_MAX; 182 uint32_t update = UINT32_MAX; 183 if (HostInfo::GetOSVersion(major, minor, update)) 184 { 185 if (major != UINT32_MAX) 186 { 187 response.Printf("os_version:%u", major); 188 if (minor != UINT32_MAX) 189 { 190 response.Printf(".%u", minor); 191 if (update != UINT32_MAX) 192 response.Printf(".%u", update); 193 } 194 response.PutChar(';'); 195 } 196 } 197 198 std::string s; 199 if (HostInfo::GetOSBuildString(s)) 200 { 201 response.PutCString ("os_build:"); 202 response.PutCStringAsRawHex8(s.c_str()); 203 response.PutChar(';'); 204 } 205 if (HostInfo::GetOSKernelDescription(s)) 206 { 207 response.PutCString ("os_kernel:"); 208 response.PutCStringAsRawHex8(s.c_str()); 209 response.PutChar(';'); 210 } 211 212 #if defined(__APPLE__) 213 214 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 215 // For iOS devices, we are connected through a USB Mux so we never pretend 216 // to actually have a hostname as far as the remote lldb that is connecting 217 // to this lldb-platform is concerned 218 response.PutCString ("hostname:"); 219 response.PutCStringAsRawHex8("127.0.0.1"); 220 response.PutChar(';'); 221 #else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 222 if (HostInfo::GetHostname(s)) 223 { 224 response.PutCString ("hostname:"); 225 response.PutCStringAsRawHex8(s.c_str()); 226 response.PutChar(';'); 227 } 228 #endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 229 230 #else // #if defined(__APPLE__) 231 if (HostInfo::GetHostname(s)) 232 { 233 response.PutCString ("hostname:"); 234 response.PutCStringAsRawHex8(s.c_str()); 235 response.PutChar(';'); 236 } 237 #endif // #if defined(__APPLE__) 238 239 return SendPacketNoLock (response.GetData(), response.GetSize()); 240 } 241 242 GDBRemoteCommunication::PacketResult 243 GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) 244 { 245 // Packet format: "qProcessInfoPID:%i" where %i is the pid 246 packet.SetFilePos (::strlen ("qProcessInfoPID:")); 247 lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID); 248 if (pid != LLDB_INVALID_PROCESS_ID) 249 { 250 ProcessInstanceInfo proc_info; 251 if (Host::GetProcessInfo (pid, proc_info)) 252 { 253 StreamString response; 254 CreateProcessInfoResponse (proc_info, response); 255 return SendPacketNoLock (response.GetData(), response.GetSize()); 256 } 257 } 258 return SendErrorResponse (1); 259 } 260 261 GDBRemoteCommunication::PacketResult 262 GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) 263 { 264 m_proc_infos_index = 0; 265 m_proc_infos.Clear(); 266 267 ProcessInstanceInfoMatch match_info; 268 packet.SetFilePos(::strlen ("qfProcessInfo")); 269 if (packet.GetChar() == ':') 270 { 271 272 std::string key; 273 std::string value; 274 while (packet.GetNameColonValue(key, value)) 275 { 276 bool success = true; 277 if (key.compare("name") == 0) 278 { 279 StringExtractor extractor; 280 extractor.GetStringRef().swap(value); 281 extractor.GetHexByteString (value); 282 match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false); 283 } 284 else if (key.compare("name_match") == 0) 285 { 286 if (value.compare("equals") == 0) 287 { 288 match_info.SetNameMatchType (eNameMatchEquals); 289 } 290 else if (value.compare("starts_with") == 0) 291 { 292 match_info.SetNameMatchType (eNameMatchStartsWith); 293 } 294 else if (value.compare("ends_with") == 0) 295 { 296 match_info.SetNameMatchType (eNameMatchEndsWith); 297 } 298 else if (value.compare("contains") == 0) 299 { 300 match_info.SetNameMatchType (eNameMatchContains); 301 } 302 else if (value.compare("regex") == 0) 303 { 304 match_info.SetNameMatchType (eNameMatchRegularExpression); 305 } 306 else 307 { 308 success = false; 309 } 310 } 311 else if (key.compare("pid") == 0) 312 { 313 match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); 314 } 315 else if (key.compare("parent_pid") == 0) 316 { 317 match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); 318 } 319 else if (key.compare("uid") == 0) 320 { 321 match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); 322 } 323 else if (key.compare("gid") == 0) 324 { 325 match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); 326 } 327 else if (key.compare("euid") == 0) 328 { 329 match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); 330 } 331 else if (key.compare("egid") == 0) 332 { 333 match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); 334 } 335 else if (key.compare("all_users") == 0) 336 { 337 match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success)); 338 } 339 else if (key.compare("triple") == 0) 340 { 341 match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL); 342 } 343 else 344 { 345 success = false; 346 } 347 348 if (!success) 349 return SendErrorResponse (2); 350 } 351 } 352 353 if (Host::FindProcesses (match_info, m_proc_infos)) 354 { 355 // We found something, return the first item by calling the get 356 // subsequent process info packet handler... 357 return Handle_qsProcessInfo (packet); 358 } 359 return SendErrorResponse (3); 360 } 361 362 GDBRemoteCommunication::PacketResult 363 GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo (StringExtractorGDBRemote &packet) 364 { 365 if (m_proc_infos_index < m_proc_infos.GetSize()) 366 { 367 StreamString response; 368 CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); 369 ++m_proc_infos_index; 370 return SendPacketNoLock (response.GetData(), response.GetSize()); 371 } 372 return SendErrorResponse (4); 373 } 374 375 GDBRemoteCommunication::PacketResult 376 GDBRemoteCommunicationServerCommon::Handle_qUserName (StringExtractorGDBRemote &packet) 377 { 378 #if !defined(LLDB_DISABLE_POSIX) 379 // Packet format: "qUserName:%i" where %i is the uid 380 packet.SetFilePos(::strlen ("qUserName:")); 381 uint32_t uid = packet.GetU32 (UINT32_MAX); 382 if (uid != UINT32_MAX) 383 { 384 std::string name; 385 if (HostInfo::LookupUserName(uid, name)) 386 { 387 StreamString response; 388 response.PutCStringAsRawHex8 (name.c_str()); 389 return SendPacketNoLock (response.GetData(), response.GetSize()); 390 } 391 } 392 #endif 393 return SendErrorResponse (5); 394 395 } 396 397 GDBRemoteCommunication::PacketResult 398 GDBRemoteCommunicationServerCommon::Handle_qGroupName (StringExtractorGDBRemote &packet) 399 { 400 #if !defined(LLDB_DISABLE_POSIX) 401 // Packet format: "qGroupName:%i" where %i is the gid 402 packet.SetFilePos(::strlen ("qGroupName:")); 403 uint32_t gid = packet.GetU32 (UINT32_MAX); 404 if (gid != UINT32_MAX) 405 { 406 std::string name; 407 if (HostInfo::LookupGroupName(gid, name)) 408 { 409 StreamString response; 410 response.PutCStringAsRawHex8 (name.c_str()); 411 return SendPacketNoLock (response.GetData(), response.GetSize()); 412 } 413 } 414 #endif 415 return SendErrorResponse (6); 416 } 417 418 GDBRemoteCommunication::PacketResult 419 GDBRemoteCommunicationServerCommon::Handle_qSpeedTest (StringExtractorGDBRemote &packet) 420 { 421 packet.SetFilePos(::strlen ("qSpeedTest:")); 422 423 std::string key; 424 std::string value; 425 bool success = packet.GetNameColonValue(key, value); 426 if (success && key.compare("response_size") == 0) 427 { 428 uint32_t response_size = StringConvert::ToUInt32(value.c_str(), 0, 0, &success); 429 if (success) 430 { 431 if (response_size == 0) 432 return SendOKResponse(); 433 StreamString response; 434 uint32_t bytes_left = response_size; 435 response.PutCString("data:"); 436 while (bytes_left > 0) 437 { 438 if (bytes_left >= 26) 439 { 440 response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 441 bytes_left -= 26; 442 } 443 else 444 { 445 response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 446 bytes_left = 0; 447 } 448 } 449 return SendPacketNoLock (response.GetData(), response.GetSize()); 450 } 451 } 452 return SendErrorResponse (7); 453 } 454 455 GDBRemoteCommunication::PacketResult 456 GDBRemoteCommunicationServerCommon::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) 457 { 458 packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); 459 460 lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); 461 462 // verify that we know anything about this pid. 463 // Scope for locker 464 { 465 Mutex::Locker locker (m_spawned_pids_mutex); 466 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) 467 { 468 // not a pid we know about 469 return SendErrorResponse (10); 470 } 471 } 472 473 // go ahead and attempt to kill the spawned process 474 if (KillSpawnedProcess (pid)) 475 return SendOKResponse (); 476 else 477 return SendErrorResponse (11); 478 } 479 480 bool 481 GDBRemoteCommunicationServerCommon::KillSpawnedProcess (lldb::pid_t pid) 482 { 483 // make sure we know about this process 484 { 485 Mutex::Locker locker (m_spawned_pids_mutex); 486 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) 487 return false; 488 } 489 490 // first try a SIGTERM (standard kill) 491 Host::Kill (pid, SIGTERM); 492 493 // check if that worked 494 for (size_t i=0; i<10; ++i) 495 { 496 { 497 Mutex::Locker locker (m_spawned_pids_mutex); 498 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) 499 { 500 // it is now killed 501 return true; 502 } 503 } 504 usleep (10000); 505 } 506 507 // check one more time after the final usleep 508 { 509 Mutex::Locker locker (m_spawned_pids_mutex); 510 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) 511 return true; 512 } 513 514 // the launched process still lives. Now try killing it again, 515 // this time with an unblockable signal. 516 Host::Kill (pid, SIGKILL); 517 518 for (size_t i=0; i<10; ++i) 519 { 520 { 521 Mutex::Locker locker (m_spawned_pids_mutex); 522 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) 523 { 524 // it is now killed 525 return true; 526 } 527 } 528 usleep (10000); 529 } 530 531 // check one more time after the final usleep 532 // Scope for locker 533 { 534 Mutex::Locker locker (m_spawned_pids_mutex); 535 if (m_spawned_pids.find(pid) == m_spawned_pids.end()) 536 return true; 537 } 538 539 // no luck - the process still lives 540 return false; 541 } 542 543 GDBRemoteCommunication::PacketResult 544 GDBRemoteCommunicationServerCommon::Handle_vFile_Open (StringExtractorGDBRemote &packet) 545 { 546 packet.SetFilePos(::strlen("vFile:open:")); 547 std::string path; 548 packet.GetHexByteStringTerminatedBy(path,','); 549 if (!path.empty()) 550 { 551 if (packet.GetChar() == ',') 552 { 553 uint32_t flags = packet.GetHexMaxU32(false, 0); 554 if (packet.GetChar() == ',') 555 { 556 mode_t mode = packet.GetHexMaxU32(false, 0600); 557 Error error; 558 int fd = ::open (path.c_str(), flags, mode); 559 const int save_errno = fd == -1 ? errno : 0; 560 StreamString response; 561 response.PutChar('F'); 562 response.Printf("%i", fd); 563 if (save_errno) 564 response.Printf(",%i", save_errno); 565 return SendPacketNoLock(response.GetData(), response.GetSize()); 566 } 567 } 568 } 569 return SendErrorResponse(18); 570 } 571 572 GDBRemoteCommunication::PacketResult 573 GDBRemoteCommunicationServerCommon::Handle_vFile_Close (StringExtractorGDBRemote &packet) 574 { 575 packet.SetFilePos(::strlen("vFile:close:")); 576 int fd = packet.GetS32(-1); 577 Error error; 578 int err = -1; 579 int save_errno = 0; 580 if (fd >= 0) 581 { 582 err = close(fd); 583 save_errno = err == -1 ? errno : 0; 584 } 585 else 586 { 587 save_errno = EINVAL; 588 } 589 StreamString response; 590 response.PutChar('F'); 591 response.Printf("%i", err); 592 if (save_errno) 593 response.Printf(",%i", save_errno); 594 return SendPacketNoLock(response.GetData(), response.GetSize()); 595 } 596 597 GDBRemoteCommunication::PacketResult 598 GDBRemoteCommunicationServerCommon::Handle_vFile_pRead (StringExtractorGDBRemote &packet) 599 { 600 #ifdef _WIN32 601 // Not implemented on Windows 602 return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pRead() unimplemented"); 603 #else 604 StreamGDBRemote response; 605 packet.SetFilePos(::strlen("vFile:pread:")); 606 int fd = packet.GetS32(-1); 607 if (packet.GetChar() == ',') 608 { 609 uint64_t count = packet.GetU64(UINT64_MAX); 610 if (packet.GetChar() == ',') 611 { 612 uint64_t offset = packet.GetU64(UINT32_MAX); 613 if (count == UINT64_MAX) 614 { 615 response.Printf("F-1:%i", EINVAL); 616 return SendPacketNoLock(response.GetData(), response.GetSize()); 617 } 618 619 std::string buffer(count, 0); 620 const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); 621 const int save_errno = bytes_read == -1 ? errno : 0; 622 response.PutChar('F'); 623 response.Printf("%zi", bytes_read); 624 if (save_errno) 625 response.Printf(",%i", save_errno); 626 else 627 { 628 response.PutChar(';'); 629 response.PutEscapedBytes(&buffer[0], bytes_read); 630 } 631 return SendPacketNoLock(response.GetData(), response.GetSize()); 632 } 633 } 634 return SendErrorResponse(21); 635 636 #endif 637 } 638 639 GDBRemoteCommunication::PacketResult 640 GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) 641 { 642 #ifdef _WIN32 643 return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite() unimplemented"); 644 #else 645 packet.SetFilePos(::strlen("vFile:pwrite:")); 646 647 StreamGDBRemote response; 648 response.PutChar('F'); 649 650 int fd = packet.GetU32(UINT32_MAX); 651 if (packet.GetChar() == ',') 652 { 653 off_t offset = packet.GetU64(UINT32_MAX); 654 if (packet.GetChar() == ',') 655 { 656 std::string buffer; 657 if (packet.GetEscapedBinaryData(buffer)) 658 { 659 const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); 660 const int save_errno = bytes_written == -1 ? errno : 0; 661 response.Printf("%zi", bytes_written); 662 if (save_errno) 663 response.Printf(",%i", save_errno); 664 } 665 else 666 { 667 response.Printf ("-1,%i", EINVAL); 668 } 669 return SendPacketNoLock(response.GetData(), response.GetSize()); 670 } 671 } 672 return SendErrorResponse(27); 673 #endif 674 } 675 676 GDBRemoteCommunication::PacketResult 677 GDBRemoteCommunicationServerCommon::Handle_vFile_Size (StringExtractorGDBRemote &packet) 678 { 679 packet.SetFilePos(::strlen("vFile:size:")); 680 std::string path; 681 packet.GetHexByteString(path); 682 if (!path.empty()) 683 { 684 lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false)); 685 StreamString response; 686 response.PutChar('F'); 687 response.PutHex64(retcode); 688 if (retcode == UINT64_MAX) 689 { 690 response.PutChar(','); 691 response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() 692 } 693 return SendPacketNoLock(response.GetData(), response.GetSize()); 694 } 695 return SendErrorResponse(22); 696 } 697 698 GDBRemoteCommunication::PacketResult 699 GDBRemoteCommunicationServerCommon::Handle_vFile_Mode (StringExtractorGDBRemote &packet) 700 { 701 packet.SetFilePos(::strlen("vFile:mode:")); 702 std::string path; 703 packet.GetHexByteString(path); 704 if (!path.empty()) 705 { 706 Error error; 707 const uint32_t mode = File::GetPermissions(path.c_str(), error); 708 StreamString response; 709 response.Printf("F%u", mode); 710 if (mode == 0 || error.Fail()) 711 response.Printf(",%i", (int)error.GetError()); 712 return SendPacketNoLock(response.GetData(), response.GetSize()); 713 } 714 return SendErrorResponse(23); 715 } 716 717 GDBRemoteCommunication::PacketResult 718 GDBRemoteCommunicationServerCommon::Handle_vFile_Exists (StringExtractorGDBRemote &packet) 719 { 720 packet.SetFilePos(::strlen("vFile:exists:")); 721 std::string path; 722 packet.GetHexByteString(path); 723 if (!path.empty()) 724 { 725 bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false)); 726 StreamString response; 727 response.PutChar('F'); 728 response.PutChar(','); 729 if (retcode) 730 response.PutChar('1'); 731 else 732 response.PutChar('0'); 733 return SendPacketNoLock(response.GetData(), response.GetSize()); 734 } 735 return SendErrorResponse(24); 736 } 737 738 GDBRemoteCommunication::PacketResult 739 GDBRemoteCommunicationServerCommon::Handle_vFile_symlink (StringExtractorGDBRemote &packet) 740 { 741 packet.SetFilePos(::strlen("vFile:symlink:")); 742 std::string dst, src; 743 packet.GetHexByteStringTerminatedBy(dst, ','); 744 packet.GetChar(); // Skip ',' char 745 packet.GetHexByteString(src); 746 Error error = FileSystem::Symlink(src.c_str(), dst.c_str()); 747 StreamString response; 748 response.Printf("F%u,%u", error.GetError(), error.GetError()); 749 return SendPacketNoLock(response.GetData(), response.GetSize()); 750 } 751 752 GDBRemoteCommunication::PacketResult 753 GDBRemoteCommunicationServerCommon::Handle_vFile_unlink (StringExtractorGDBRemote &packet) 754 { 755 packet.SetFilePos(::strlen("vFile:unlink:")); 756 std::string path; 757 packet.GetHexByteString(path); 758 Error error = FileSystem::Unlink(path.c_str()); 759 StreamString response; 760 response.Printf("F%u,%u", error.GetError(), error.GetError()); 761 return SendPacketNoLock(response.GetData(), response.GetSize()); 762 } 763 764 GDBRemoteCommunication::PacketResult 765 GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) 766 { 767 packet.SetFilePos(::strlen("qPlatform_shell:")); 768 std::string path; 769 std::string working_dir; 770 packet.GetHexByteStringTerminatedBy(path,','); 771 if (!path.empty()) 772 { 773 if (packet.GetChar() == ',') 774 { 775 // FIXME: add timeout to qPlatform_shell packet 776 // uint32_t timeout = packet.GetHexMaxU32(false, 32); 777 uint32_t timeout = 10; 778 if (packet.GetChar() == ',') 779 packet.GetHexByteString(working_dir); 780 int status, signo; 781 std::string output; 782 Error err = Host::RunShellCommand(path.c_str(), 783 working_dir.empty() ? NULL : working_dir.c_str(), 784 &status, &signo, &output, timeout); 785 StreamGDBRemote response; 786 if (err.Fail()) 787 { 788 response.PutCString("F,"); 789 response.PutHex32(UINT32_MAX); 790 } 791 else 792 { 793 response.PutCString("F,"); 794 response.PutHex32(status); 795 response.PutChar(','); 796 response.PutHex32(signo); 797 response.PutChar(','); 798 response.PutEscapedBytes(output.c_str(), output.size()); 799 } 800 return SendPacketNoLock(response.GetData(), response.GetSize()); 801 } 802 } 803 return SendErrorResponse(24); 804 } 805 806 807 GDBRemoteCommunication::PacketResult 808 GDBRemoteCommunicationServerCommon::Handle_vFile_Stat (StringExtractorGDBRemote &packet) 809 { 810 return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_Stat() unimplemented"); 811 } 812 813 GDBRemoteCommunication::PacketResult 814 GDBRemoteCommunicationServerCommon::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) 815 { 816 packet.SetFilePos(::strlen("vFile:MD5:")); 817 std::string path; 818 packet.GetHexByteString(path); 819 if (!path.empty()) 820 { 821 uint64_t a,b; 822 StreamGDBRemote response; 823 if (FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b) == false) 824 { 825 response.PutCString("F,"); 826 response.PutCString("x"); 827 } 828 else 829 { 830 response.PutCString("F,"); 831 response.PutHex64(a); 832 response.PutHex64(b); 833 } 834 return SendPacketNoLock(response.GetData(), response.GetSize()); 835 } 836 return SendErrorResponse(25); 837 } 838 839 GDBRemoteCommunication::PacketResult 840 GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) 841 { 842 packet.SetFilePos(::strlen("qPlatform_mkdir:")); 843 mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); 844 if (packet.GetChar() == ',') 845 { 846 std::string path; 847 packet.GetHexByteString(path); 848 Error error = FileSystem::MakeDirectory(path.c_str(), mode); 849 if (error.Success()) 850 return SendPacketNoLock ("OK", 2); 851 else 852 return SendErrorResponse(error.GetError()); 853 } 854 return SendErrorResponse(20); 855 } 856 857 GDBRemoteCommunication::PacketResult 858 GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) 859 { 860 packet.SetFilePos(::strlen("qPlatform_chmod:")); 861 862 mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); 863 if (packet.GetChar() == ',') 864 { 865 std::string path; 866 packet.GetHexByteString(path); 867 Error error = FileSystem::SetFilePermissions(path.c_str(), mode); 868 if (error.Success()) 869 return SendPacketNoLock ("OK", 2); 870 else 871 return SendErrorResponse(error.GetError()); 872 } 873 return SendErrorResponse(19); 874 } 875 876 GDBRemoteCommunication::PacketResult 877 GDBRemoteCommunicationServerCommon::Handle_qSupported (StringExtractorGDBRemote &packet) 878 { 879 StreamGDBRemote response; 880 881 // Features common to lldb-platform and llgs. 882 uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less 883 response.Printf ("PacketSize=%x", max_packet_size); 884 885 response.PutCString (";QStartNoAckMode+"); 886 response.PutCString (";QThreadSuffixSupported+"); 887 response.PutCString (";QListThreadsInStopReply+"); 888 #if defined(__linux__) 889 response.PutCString (";qXfer:auxv:read+"); 890 #endif 891 892 return SendPacketNoLock(response.GetData(), response.GetSize()); 893 } 894 895 GDBRemoteCommunication::PacketResult 896 GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet) 897 { 898 m_thread_suffix_supported = true; 899 return SendOKResponse(); 900 } 901 902 GDBRemoteCommunication::PacketResult 903 GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet) 904 { 905 m_list_threads_in_stop_reply = true; 906 return SendOKResponse(); 907 } 908 909 GDBRemoteCommunication::PacketResult 910 GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet) 911 { 912 packet.SetFilePos(::strlen ("QSetDetachOnError:")); 913 if (packet.GetU32(0)) 914 m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError); 915 else 916 m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError); 917 return SendOKResponse (); 918 } 919 920 GDBRemoteCommunication::PacketResult 921 GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) 922 { 923 // Send response first before changing m_send_acks to we ack this packet 924 PacketResult packet_result = SendOKResponse (); 925 m_send_acks = false; 926 return packet_result; 927 } 928 929 GDBRemoteCommunication::PacketResult 930 GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) 931 { 932 packet.SetFilePos(::strlen ("QSetSTDIN:")); 933 FileAction file_action; 934 std::string path; 935 packet.GetHexByteString(path); 936 const bool read = false; 937 const bool write = true; 938 if (file_action.Open(STDIN_FILENO, path.c_str(), read, write)) 939 { 940 m_process_launch_info.AppendFileAction(file_action); 941 return SendOKResponse (); 942 } 943 return SendErrorResponse (15); 944 } 945 946 GDBRemoteCommunication::PacketResult 947 GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) 948 { 949 packet.SetFilePos(::strlen ("QSetSTDOUT:")); 950 FileAction file_action; 951 std::string path; 952 packet.GetHexByteString(path); 953 const bool read = true; 954 const bool write = false; 955 if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write)) 956 { 957 m_process_launch_info.AppendFileAction(file_action); 958 return SendOKResponse (); 959 } 960 return SendErrorResponse (16); 961 } 962 963 GDBRemoteCommunication::PacketResult 964 GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) 965 { 966 packet.SetFilePos(::strlen ("QSetSTDERR:")); 967 FileAction file_action; 968 std::string path; 969 packet.GetHexByteString(path); 970 const bool read = true; 971 const bool write = false; 972 if (file_action.Open(STDERR_FILENO, path.c_str(), read, write)) 973 { 974 m_process_launch_info.AppendFileAction(file_action); 975 return SendOKResponse (); 976 } 977 return SendErrorResponse (17); 978 } 979 980 GDBRemoteCommunication::PacketResult 981 GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet) 982 { 983 if (m_process_launch_error.Success()) 984 return SendOKResponse(); 985 StreamString response; 986 response.PutChar('E'); 987 response.PutCString(m_process_launch_error.AsCString("<unknown error>")); 988 return SendPacketNoLock (response.GetData(), response.GetSize()); 989 } 990 991 GDBRemoteCommunication::PacketResult 992 GDBRemoteCommunicationServerCommon::Handle_QEnvironment (StringExtractorGDBRemote &packet) 993 { 994 packet.SetFilePos(::strlen ("QEnvironment:")); 995 const uint32_t bytes_left = packet.GetBytesLeft(); 996 if (bytes_left > 0) 997 { 998 m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); 999 return SendOKResponse (); 1000 } 1001 return SendErrorResponse (12); 1002 } 1003 1004 GDBRemoteCommunication::PacketResult 1005 GDBRemoteCommunicationServerCommon::Handle_QLaunchArch (StringExtractorGDBRemote &packet) 1006 { 1007 packet.SetFilePos(::strlen ("QLaunchArch:")); 1008 const uint32_t bytes_left = packet.GetBytesLeft(); 1009 if (bytes_left > 0) 1010 { 1011 const char* arch_triple = packet.Peek(); 1012 ArchSpec arch_spec(arch_triple,NULL); 1013 m_process_launch_info.SetArchitecture(arch_spec); 1014 return SendOKResponse(); 1015 } 1016 return SendErrorResponse(13); 1017 } 1018 1019 GDBRemoteCommunication::PacketResult 1020 GDBRemoteCommunicationServerCommon::Handle_A (StringExtractorGDBRemote &packet) 1021 { 1022 // The 'A' packet is the most over designed packet ever here with 1023 // redundant argument indexes, redundant argument lengths and needed hex 1024 // encoded argument string values. Really all that is needed is a comma 1025 // separated hex encoded argument value list, but we will stay true to the 1026 // documented version of the 'A' packet here... 1027 1028 Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); 1029 int actual_arg_index = 0; 1030 1031 packet.SetFilePos(1); // Skip the 'A' 1032 bool success = true; 1033 while (success && packet.GetBytesLeft() > 0) 1034 { 1035 // Decode the decimal argument string length. This length is the 1036 // number of hex nibbles in the argument string value. 1037 const uint32_t arg_len = packet.GetU32(UINT32_MAX); 1038 if (arg_len == UINT32_MAX) 1039 success = false; 1040 else 1041 { 1042 // Make sure the argument hex string length is followed by a comma 1043 if (packet.GetChar() != ',') 1044 success = false; 1045 else 1046 { 1047 // Decode the argument index. We ignore this really because 1048 // who would really send down the arguments in a random order??? 1049 const uint32_t arg_idx = packet.GetU32(UINT32_MAX); 1050 if (arg_idx == UINT32_MAX) 1051 success = false; 1052 else 1053 { 1054 // Make sure the argument index is followed by a comma 1055 if (packet.GetChar() != ',') 1056 success = false; 1057 else 1058 { 1059 // Decode the argument string value from hex bytes 1060 // back into a UTF8 string and make sure the length 1061 // matches the one supplied in the packet 1062 std::string arg; 1063 if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) 1064 success = false; 1065 else 1066 { 1067 // If there are any bytes left 1068 if (packet.GetBytesLeft()) 1069 { 1070 if (packet.GetChar() != ',') 1071 success = false; 1072 } 1073 1074 if (success) 1075 { 1076 if (arg_idx == 0) 1077 m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); 1078 m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); 1079 if (log) 1080 log->Printf ("LLGSPacketHandler::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ()); 1081 ++actual_arg_index; 1082 } 1083 } 1084 } 1085 } 1086 } 1087 } 1088 } 1089 1090 if (success) 1091 { 1092 m_process_launch_error = LaunchProcess (); 1093 if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) 1094 { 1095 return SendOKResponse (); 1096 } 1097 else 1098 { 1099 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); 1100 if (log) 1101 log->Printf("LLGSPacketHandler::%s failed to launch exe: %s", 1102 __FUNCTION__, 1103 m_process_launch_error.AsCString()); 1104 1105 } 1106 } 1107 return SendErrorResponse (8); 1108 } 1109 1110 void 1111 GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, 1112 StreamString &response) 1113 { 1114 response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;", 1115 proc_info.GetProcessID(), 1116 proc_info.GetParentProcessID(), 1117 proc_info.GetUserID(), 1118 proc_info.GetGroupID(), 1119 proc_info.GetEffectiveUserID(), 1120 proc_info.GetEffectiveGroupID()); 1121 response.PutCString ("name:"); 1122 response.PutCStringAsRawHex8(proc_info.GetName()); 1123 response.PutChar(';'); 1124 const ArchSpec &proc_arch = proc_info.GetArchitecture(); 1125 if (proc_arch.IsValid()) 1126 { 1127 const llvm::Triple &proc_triple = proc_arch.GetTriple(); 1128 response.PutCString("triple:"); 1129 response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); 1130 response.PutChar(';'); 1131 } 1132 } 1133 1134 void 1135 GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse_DebugServerStyle ( 1136 const ProcessInstanceInfo &proc_info, StreamString &response) 1137 { 1138 response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", 1139 proc_info.GetProcessID(), 1140 proc_info.GetParentProcessID(), 1141 proc_info.GetUserID(), 1142 proc_info.GetGroupID(), 1143 proc_info.GetEffectiveUserID(), 1144 proc_info.GetEffectiveGroupID()); 1145 1146 const ArchSpec &proc_arch = proc_info.GetArchitecture(); 1147 if (proc_arch.IsValid()) 1148 { 1149 const llvm::Triple &proc_triple = proc_arch.GetTriple(); 1150 #if defined(__APPLE__) 1151 // We'll send cputype/cpusubtype. 1152 const uint32_t cpu_type = proc_arch.GetMachOCPUType(); 1153 if (cpu_type != 0) 1154 response.Printf ("cputype:%" PRIx32 ";", cpu_type); 1155 1156 const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); 1157 if (cpu_subtype != 0) 1158 response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype); 1159 1160 const std::string vendor = proc_triple.getVendorName (); 1161 if (!vendor.empty ()) 1162 response.Printf ("vendor:%s;", vendor.c_str ()); 1163 #else 1164 // We'll send the triple. 1165 response.PutCString("triple:"); 1166 response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); 1167 response.PutChar(';'); 1168 #endif 1169 std::string ostype = proc_triple.getOSName (); 1170 // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. 1171 if (proc_triple.getVendor () == llvm::Triple::Apple) 1172 { 1173 switch (proc_triple.getArch ()) 1174 { 1175 case llvm::Triple::arm: 1176 case llvm::Triple::aarch64: 1177 ostype = "ios"; 1178 break; 1179 default: 1180 // No change. 1181 break; 1182 } 1183 } 1184 response.Printf ("ostype:%s;", ostype.c_str ()); 1185 1186 1187 switch (proc_arch.GetByteOrder ()) 1188 { 1189 case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break; 1190 case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break; 1191 case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break; 1192 default: 1193 // Nothing. 1194 break; 1195 } 1196 1197 if (proc_triple.isArch64Bit ()) 1198 response.PutCString ("ptrsize:8;"); 1199 else if (proc_triple.isArch32Bit ()) 1200 response.PutCString ("ptrsize:4;"); 1201 else if (proc_triple.isArch16Bit ()) 1202 response.PutCString ("ptrsize:2;"); 1203 } 1204 } 1205