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 850 StreamGDBRemote response; 851 response.Printf("F%u", error.GetError()); 852 853 return SendPacketNoLock(response.GetData(), response.GetSize()); 854 } 855 return SendErrorResponse(20); 856 } 857 858 GDBRemoteCommunication::PacketResult 859 GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) 860 { 861 packet.SetFilePos(::strlen("qPlatform_chmod:")); 862 863 mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); 864 if (packet.GetChar() == ',') 865 { 866 std::string path; 867 packet.GetHexByteString(path); 868 Error error = FileSystem::SetFilePermissions(path.c_str(), mode); 869 870 StreamGDBRemote response; 871 response.Printf("F%u", error.GetError()); 872 873 return SendPacketNoLock(response.GetData(), response.GetSize()); 874 } 875 return SendErrorResponse(19); 876 } 877 878 GDBRemoteCommunication::PacketResult 879 GDBRemoteCommunicationServerCommon::Handle_qSupported (StringExtractorGDBRemote &packet) 880 { 881 StreamGDBRemote response; 882 883 // Features common to lldb-platform and llgs. 884 uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less 885 response.Printf ("PacketSize=%x", max_packet_size); 886 887 response.PutCString (";QStartNoAckMode+"); 888 response.PutCString (";QThreadSuffixSupported+"); 889 response.PutCString (";QListThreadsInStopReply+"); 890 #if defined(__linux__) 891 response.PutCString (";qXfer:auxv:read+"); 892 #endif 893 894 return SendPacketNoLock(response.GetData(), response.GetSize()); 895 } 896 897 GDBRemoteCommunication::PacketResult 898 GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet) 899 { 900 m_thread_suffix_supported = true; 901 return SendOKResponse(); 902 } 903 904 GDBRemoteCommunication::PacketResult 905 GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet) 906 { 907 m_list_threads_in_stop_reply = true; 908 return SendOKResponse(); 909 } 910 911 GDBRemoteCommunication::PacketResult 912 GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet) 913 { 914 packet.SetFilePos(::strlen ("QSetDetachOnError:")); 915 if (packet.GetU32(0)) 916 m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError); 917 else 918 m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError); 919 return SendOKResponse (); 920 } 921 922 GDBRemoteCommunication::PacketResult 923 GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) 924 { 925 // Send response first before changing m_send_acks to we ack this packet 926 PacketResult packet_result = SendOKResponse (); 927 m_send_acks = false; 928 return packet_result; 929 } 930 931 GDBRemoteCommunication::PacketResult 932 GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) 933 { 934 packet.SetFilePos(::strlen ("QSetSTDIN:")); 935 FileAction file_action; 936 std::string path; 937 packet.GetHexByteString(path); 938 const bool read = false; 939 const bool write = true; 940 if (file_action.Open(STDIN_FILENO, path.c_str(), read, write)) 941 { 942 m_process_launch_info.AppendFileAction(file_action); 943 return SendOKResponse (); 944 } 945 return SendErrorResponse (15); 946 } 947 948 GDBRemoteCommunication::PacketResult 949 GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) 950 { 951 packet.SetFilePos(::strlen ("QSetSTDOUT:")); 952 FileAction file_action; 953 std::string path; 954 packet.GetHexByteString(path); 955 const bool read = true; 956 const bool write = false; 957 if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write)) 958 { 959 m_process_launch_info.AppendFileAction(file_action); 960 return SendOKResponse (); 961 } 962 return SendErrorResponse (16); 963 } 964 965 GDBRemoteCommunication::PacketResult 966 GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) 967 { 968 packet.SetFilePos(::strlen ("QSetSTDERR:")); 969 FileAction file_action; 970 std::string path; 971 packet.GetHexByteString(path); 972 const bool read = true; 973 const bool write = false; 974 if (file_action.Open(STDERR_FILENO, path.c_str(), read, write)) 975 { 976 m_process_launch_info.AppendFileAction(file_action); 977 return SendOKResponse (); 978 } 979 return SendErrorResponse (17); 980 } 981 982 GDBRemoteCommunication::PacketResult 983 GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet) 984 { 985 if (m_process_launch_error.Success()) 986 return SendOKResponse(); 987 StreamString response; 988 response.PutChar('E'); 989 response.PutCString(m_process_launch_error.AsCString("<unknown error>")); 990 return SendPacketNoLock (response.GetData(), response.GetSize()); 991 } 992 993 GDBRemoteCommunication::PacketResult 994 GDBRemoteCommunicationServerCommon::Handle_QEnvironment (StringExtractorGDBRemote &packet) 995 { 996 packet.SetFilePos(::strlen ("QEnvironment:")); 997 const uint32_t bytes_left = packet.GetBytesLeft(); 998 if (bytes_left > 0) 999 { 1000 m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); 1001 return SendOKResponse (); 1002 } 1003 return SendErrorResponse (12); 1004 } 1005 1006 GDBRemoteCommunication::PacketResult 1007 GDBRemoteCommunicationServerCommon::Handle_QLaunchArch (StringExtractorGDBRemote &packet) 1008 { 1009 packet.SetFilePos(::strlen ("QLaunchArch:")); 1010 const uint32_t bytes_left = packet.GetBytesLeft(); 1011 if (bytes_left > 0) 1012 { 1013 const char* arch_triple = packet.Peek(); 1014 ArchSpec arch_spec(arch_triple,NULL); 1015 m_process_launch_info.SetArchitecture(arch_spec); 1016 return SendOKResponse(); 1017 } 1018 return SendErrorResponse(13); 1019 } 1020 1021 GDBRemoteCommunication::PacketResult 1022 GDBRemoteCommunicationServerCommon::Handle_A (StringExtractorGDBRemote &packet) 1023 { 1024 // The 'A' packet is the most over designed packet ever here with 1025 // redundant argument indexes, redundant argument lengths and needed hex 1026 // encoded argument string values. Really all that is needed is a comma 1027 // separated hex encoded argument value list, but we will stay true to the 1028 // documented version of the 'A' packet here... 1029 1030 Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); 1031 int actual_arg_index = 0; 1032 1033 packet.SetFilePos(1); // Skip the 'A' 1034 bool success = true; 1035 while (success && packet.GetBytesLeft() > 0) 1036 { 1037 // Decode the decimal argument string length. This length is the 1038 // number of hex nibbles in the argument string value. 1039 const uint32_t arg_len = packet.GetU32(UINT32_MAX); 1040 if (arg_len == UINT32_MAX) 1041 success = false; 1042 else 1043 { 1044 // Make sure the argument hex string length is followed by a comma 1045 if (packet.GetChar() != ',') 1046 success = false; 1047 else 1048 { 1049 // Decode the argument index. We ignore this really because 1050 // who would really send down the arguments in a random order??? 1051 const uint32_t arg_idx = packet.GetU32(UINT32_MAX); 1052 if (arg_idx == UINT32_MAX) 1053 success = false; 1054 else 1055 { 1056 // Make sure the argument index is followed by a comma 1057 if (packet.GetChar() != ',') 1058 success = false; 1059 else 1060 { 1061 // Decode the argument string value from hex bytes 1062 // back into a UTF8 string and make sure the length 1063 // matches the one supplied in the packet 1064 std::string arg; 1065 if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) 1066 success = false; 1067 else 1068 { 1069 // If there are any bytes left 1070 if (packet.GetBytesLeft()) 1071 { 1072 if (packet.GetChar() != ',') 1073 success = false; 1074 } 1075 1076 if (success) 1077 { 1078 if (arg_idx == 0) 1079 m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); 1080 m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); 1081 if (log) 1082 log->Printf ("LLGSPacketHandler::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ()); 1083 ++actual_arg_index; 1084 } 1085 } 1086 } 1087 } 1088 } 1089 } 1090 } 1091 1092 if (success) 1093 { 1094 m_process_launch_error = LaunchProcess (); 1095 if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) 1096 { 1097 return SendOKResponse (); 1098 } 1099 else 1100 { 1101 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); 1102 if (log) 1103 log->Printf("LLGSPacketHandler::%s failed to launch exe: %s", 1104 __FUNCTION__, 1105 m_process_launch_error.AsCString()); 1106 1107 } 1108 } 1109 return SendErrorResponse (8); 1110 } 1111 1112 void 1113 GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, 1114 StreamString &response) 1115 { 1116 response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;", 1117 proc_info.GetProcessID(), 1118 proc_info.GetParentProcessID(), 1119 proc_info.GetUserID(), 1120 proc_info.GetGroupID(), 1121 proc_info.GetEffectiveUserID(), 1122 proc_info.GetEffectiveGroupID()); 1123 response.PutCString ("name:"); 1124 response.PutCStringAsRawHex8(proc_info.GetName()); 1125 response.PutChar(';'); 1126 const ArchSpec &proc_arch = proc_info.GetArchitecture(); 1127 if (proc_arch.IsValid()) 1128 { 1129 const llvm::Triple &proc_triple = proc_arch.GetTriple(); 1130 response.PutCString("triple:"); 1131 response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); 1132 response.PutChar(';'); 1133 } 1134 } 1135 1136 void 1137 GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse_DebugServerStyle ( 1138 const ProcessInstanceInfo &proc_info, StreamString &response) 1139 { 1140 response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", 1141 proc_info.GetProcessID(), 1142 proc_info.GetParentProcessID(), 1143 proc_info.GetUserID(), 1144 proc_info.GetGroupID(), 1145 proc_info.GetEffectiveUserID(), 1146 proc_info.GetEffectiveGroupID()); 1147 1148 const ArchSpec &proc_arch = proc_info.GetArchitecture(); 1149 if (proc_arch.IsValid()) 1150 { 1151 const llvm::Triple &proc_triple = proc_arch.GetTriple(); 1152 #if defined(__APPLE__) 1153 // We'll send cputype/cpusubtype. 1154 const uint32_t cpu_type = proc_arch.GetMachOCPUType(); 1155 if (cpu_type != 0) 1156 response.Printf ("cputype:%" PRIx32 ";", cpu_type); 1157 1158 const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); 1159 if (cpu_subtype != 0) 1160 response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype); 1161 1162 const std::string vendor = proc_triple.getVendorName (); 1163 if (!vendor.empty ()) 1164 response.Printf ("vendor:%s;", vendor.c_str ()); 1165 #else 1166 // We'll send the triple. 1167 response.PutCString("triple:"); 1168 response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); 1169 response.PutChar(';'); 1170 #endif 1171 std::string ostype = proc_triple.getOSName (); 1172 // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. 1173 if (proc_triple.getVendor () == llvm::Triple::Apple) 1174 { 1175 switch (proc_triple.getArch ()) 1176 { 1177 case llvm::Triple::arm: 1178 case llvm::Triple::aarch64: 1179 ostype = "ios"; 1180 break; 1181 default: 1182 // No change. 1183 break; 1184 } 1185 } 1186 response.Printf ("ostype:%s;", ostype.c_str ()); 1187 1188 1189 switch (proc_arch.GetByteOrder ()) 1190 { 1191 case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break; 1192 case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break; 1193 case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break; 1194 default: 1195 // Nothing. 1196 break; 1197 } 1198 1199 if (proc_triple.isArch64Bit ()) 1200 response.PutCString ("ptrsize:8;"); 1201 else if (proc_triple.isArch32Bit ()) 1202 response.PutCString ("ptrsize:4;"); 1203 else if (proc_triple.isArch16Bit ()) 1204 response.PutCString ("ptrsize:2;"); 1205 } 1206 } 1207