1 //===-- PlatformRemoteGDBServer.cpp ---------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "PlatformRemoteGDBServer.h" 10 #include "lldb/Host/Config.h" 11 12 #include "lldb/Breakpoint/BreakpointLocation.h" 13 #include "lldb/Core/Debugger.h" 14 #include "lldb/Core/Module.h" 15 #include "lldb/Core/ModuleList.h" 16 #include "lldb/Core/ModuleSpec.h" 17 #include "lldb/Core/PluginManager.h" 18 #include "lldb/Core/StreamFile.h" 19 #include "lldb/Host/ConnectionFileDescriptor.h" 20 #include "lldb/Host/Host.h" 21 #include "lldb/Host/HostInfo.h" 22 #include "lldb/Host/PosixApi.h" 23 #include "lldb/Target/Process.h" 24 #include "lldb/Target/Target.h" 25 #include "lldb/Utility/FileSpec.h" 26 #include "lldb/Utility/LLDBLog.h" 27 #include "lldb/Utility/Log.h" 28 #include "lldb/Utility/ProcessInfo.h" 29 #include "lldb/Utility/Status.h" 30 #include "lldb/Utility/StreamString.h" 31 #include "lldb/Utility/UriParser.h" 32 33 #include "Plugins/Process/Utility/GDBRemoteSignals.h" 34 #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" 35 36 using namespace lldb; 37 using namespace lldb_private; 38 using namespace lldb_private::platform_gdb_server; 39 40 LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteGDBServer, PlatformGDB) 41 42 static bool g_initialized = false; 43 44 void PlatformRemoteGDBServer::Initialize() { 45 Platform::Initialize(); 46 47 if (!g_initialized) { 48 g_initialized = true; 49 PluginManager::RegisterPlugin( 50 PlatformRemoteGDBServer::GetPluginNameStatic(), 51 PlatformRemoteGDBServer::GetDescriptionStatic(), 52 PlatformRemoteGDBServer::CreateInstance); 53 } 54 } 55 56 void PlatformRemoteGDBServer::Terminate() { 57 if (g_initialized) { 58 g_initialized = false; 59 PluginManager::UnregisterPlugin(PlatformRemoteGDBServer::CreateInstance); 60 } 61 62 Platform::Terminate(); 63 } 64 65 PlatformSP PlatformRemoteGDBServer::CreateInstance(bool force, 66 const ArchSpec *arch) { 67 bool create = force; 68 if (!create) { 69 create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified(); 70 } 71 if (create) 72 return PlatformSP(new PlatformRemoteGDBServer()); 73 return PlatformSP(); 74 } 75 76 llvm::StringRef PlatformRemoteGDBServer::GetDescriptionStatic() { 77 return "A platform that uses the GDB remote protocol as the communication " 78 "transport."; 79 } 80 81 llvm::StringRef PlatformRemoteGDBServer::GetDescription() { 82 if (m_platform_description.empty()) { 83 if (IsConnected()) { 84 // Send the get description packet 85 } 86 } 87 88 if (!m_platform_description.empty()) 89 return m_platform_description.c_str(); 90 return GetDescriptionStatic(); 91 } 92 93 bool PlatformRemoteGDBServer::GetModuleSpec(const FileSpec &module_file_spec, 94 const ArchSpec &arch, 95 ModuleSpec &module_spec) { 96 Log *log = GetLog(LLDBLog::Platform); 97 98 const auto module_path = module_file_spec.GetPath(false); 99 100 if (!m_gdb_client_up || 101 !m_gdb_client_up->GetModuleInfo(module_file_spec, arch, module_spec)) { 102 LLDB_LOGF( 103 log, 104 "PlatformRemoteGDBServer::%s - failed to get module info for %s:%s", 105 __FUNCTION__, module_path.c_str(), 106 arch.GetTriple().getTriple().c_str()); 107 return false; 108 } 109 110 if (log) { 111 StreamString stream; 112 module_spec.Dump(stream); 113 LLDB_LOGF(log, 114 "PlatformRemoteGDBServer::%s - got module info for (%s:%s) : %s", 115 __FUNCTION__, module_path.c_str(), 116 arch.GetTriple().getTriple().c_str(), stream.GetData()); 117 } 118 119 return true; 120 } 121 122 Status PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file, 123 const UUID *uuid_ptr, 124 FileSpec &local_file) { 125 // Default to the local case 126 local_file = platform_file; 127 return Status(); 128 } 129 130 /// Default Constructor 131 PlatformRemoteGDBServer::PlatformRemoteGDBServer() 132 : Platform(/*is_host=*/false) {} 133 134 /// Destructor. 135 /// 136 /// The destructor is virtual since this class is designed to be 137 /// inherited from by the plug-in instance. 138 PlatformRemoteGDBServer::~PlatformRemoteGDBServer() = default; 139 140 size_t PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode( 141 Target &target, BreakpointSite *bp_site) { 142 // This isn't needed if the z/Z packets are supported in the GDB remote 143 // server. But we might need a packet to detect this. 144 return 0; 145 } 146 147 bool PlatformRemoteGDBServer::GetRemoteOSVersion() { 148 if (m_gdb_client_up) 149 m_os_version = m_gdb_client_up->GetOSVersion(); 150 return !m_os_version.empty(); 151 } 152 153 llvm::Optional<std::string> PlatformRemoteGDBServer::GetRemoteOSBuildString() { 154 if (!m_gdb_client_up) 155 return llvm::None; 156 return m_gdb_client_up->GetOSBuildString(); 157 } 158 159 llvm::Optional<std::string> 160 PlatformRemoteGDBServer::GetRemoteOSKernelDescription() { 161 if (!m_gdb_client_up) 162 return llvm::None; 163 return m_gdb_client_up->GetOSKernelDescription(); 164 } 165 166 // Remote Platform subclasses need to override this function 167 ArchSpec PlatformRemoteGDBServer::GetRemoteSystemArchitecture() { 168 if (!m_gdb_client_up) 169 return ArchSpec(); 170 return m_gdb_client_up->GetSystemArchitecture(); 171 } 172 173 FileSpec PlatformRemoteGDBServer::GetRemoteWorkingDirectory() { 174 if (IsConnected()) { 175 Log *log = GetLog(LLDBLog::Platform); 176 FileSpec working_dir; 177 if (m_gdb_client_up->GetWorkingDir(working_dir) && log) 178 LLDB_LOGF(log, 179 "PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'", 180 working_dir.GetCString()); 181 return working_dir; 182 } else { 183 return Platform::GetRemoteWorkingDirectory(); 184 } 185 } 186 187 bool PlatformRemoteGDBServer::SetRemoteWorkingDirectory( 188 const FileSpec &working_dir) { 189 if (IsConnected()) { 190 // Clear the working directory it case it doesn't get set correctly. This 191 // will for use to re-read it 192 Log *log = GetLog(LLDBLog::Platform); 193 LLDB_LOGF(log, "PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')", 194 working_dir.GetCString()); 195 return m_gdb_client_up->SetWorkingDir(working_dir) == 0; 196 } else 197 return Platform::SetRemoteWorkingDirectory(working_dir); 198 } 199 200 bool PlatformRemoteGDBServer::IsConnected() const { 201 if (m_gdb_client_up) { 202 assert(m_gdb_client_up->IsConnected()); 203 return true; 204 } 205 return false; 206 } 207 208 Status PlatformRemoteGDBServer::ConnectRemote(Args &args) { 209 Status error; 210 if (IsConnected()) { 211 error.SetErrorStringWithFormat("the platform is already connected to '%s', " 212 "execute 'platform disconnect' to close the " 213 "current connection", 214 GetHostname()); 215 return error; 216 } 217 218 if (args.GetArgumentCount() != 1) { 219 error.SetErrorString( 220 "\"platform connect\" takes a single argument: <connect-url>"); 221 return error; 222 } 223 224 const char *url = args.GetArgumentAtIndex(0); 225 if (!url) 226 return Status("URL is null."); 227 228 llvm::Optional<URI> parsed_url = URI::Parse(url); 229 if (!parsed_url) 230 return Status("Invalid URL: %s", url); 231 232 // We're going to reuse the hostname when we connect to the debugserver. 233 m_platform_scheme = parsed_url->scheme.str(); 234 m_platform_hostname = parsed_url->hostname.str(); 235 236 auto client_up = 237 std::make_unique<process_gdb_remote::GDBRemoteCommunicationClient>(); 238 client_up->SetPacketTimeout( 239 process_gdb_remote::ProcessGDBRemote::GetPacketTimeout()); 240 client_up->SetConnection(std::make_unique<ConnectionFileDescriptor>()); 241 if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { 242 repro::GDBRemoteProvider &provider = 243 g->GetOrCreate<repro::GDBRemoteProvider>(); 244 client_up->SetPacketRecorder(provider.GetNewPacketRecorder()); 245 } 246 client_up->Connect(url, &error); 247 248 if (error.Fail()) 249 return error; 250 251 if (client_up->HandshakeWithServer(&error)) { 252 m_gdb_client_up = std::move(client_up); 253 m_gdb_client_up->GetHostInfo(); 254 // If a working directory was set prior to connecting, send it down 255 // now. 256 if (m_working_dir) 257 m_gdb_client_up->SetWorkingDir(m_working_dir); 258 259 m_supported_architectures.clear(); 260 ArchSpec remote_arch = m_gdb_client_up->GetSystemArchitecture(); 261 if (remote_arch) { 262 m_supported_architectures.push_back(remote_arch); 263 if (remote_arch.GetTriple().isArch64Bit()) 264 m_supported_architectures.push_back( 265 ArchSpec(remote_arch.GetTriple().get32BitArchVariant())); 266 } 267 } else { 268 client_up->Disconnect(); 269 if (error.Success()) 270 error.SetErrorString("handshake failed"); 271 } 272 return error; 273 } 274 275 Status PlatformRemoteGDBServer::DisconnectRemote() { 276 Status error; 277 m_gdb_client_up.reset(); 278 m_remote_signals_sp.reset(); 279 return error; 280 } 281 282 const char *PlatformRemoteGDBServer::GetHostname() { 283 if (m_gdb_client_up) 284 m_gdb_client_up->GetHostname(m_hostname); 285 if (m_hostname.empty()) 286 return nullptr; 287 return m_hostname.c_str(); 288 } 289 290 llvm::Optional<std::string> 291 PlatformRemoteGDBServer::DoGetUserName(UserIDResolver::id_t uid) { 292 std::string name; 293 if (m_gdb_client_up && m_gdb_client_up->GetUserName(uid, name)) 294 return std::move(name); 295 return llvm::None; 296 } 297 298 llvm::Optional<std::string> 299 PlatformRemoteGDBServer::DoGetGroupName(UserIDResolver::id_t gid) { 300 std::string name; 301 if (m_gdb_client_up && m_gdb_client_up->GetGroupName(gid, name)) 302 return std::move(name); 303 return llvm::None; 304 } 305 306 uint32_t PlatformRemoteGDBServer::FindProcesses( 307 const ProcessInstanceInfoMatch &match_info, 308 ProcessInstanceInfoList &process_infos) { 309 if (m_gdb_client_up) 310 return m_gdb_client_up->FindProcesses(match_info, process_infos); 311 return 0; 312 } 313 314 bool PlatformRemoteGDBServer::GetProcessInfo( 315 lldb::pid_t pid, ProcessInstanceInfo &process_info) { 316 if (m_gdb_client_up) 317 return m_gdb_client_up->GetProcessInfo(pid, process_info); 318 return false; 319 } 320 321 Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) { 322 Log *log = GetLog(LLDBLog::Platform); 323 Status error; 324 325 LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() called", __FUNCTION__); 326 327 if (!IsConnected()) 328 return Status("Not connected."); 329 auto num_file_actions = launch_info.GetNumFileActions(); 330 for (decltype(num_file_actions) i = 0; i < num_file_actions; ++i) { 331 const auto file_action = launch_info.GetFileActionAtIndex(i); 332 if (file_action->GetAction() != FileAction::eFileActionOpen) 333 continue; 334 switch (file_action->GetFD()) { 335 case STDIN_FILENO: 336 m_gdb_client_up->SetSTDIN(file_action->GetFileSpec()); 337 break; 338 case STDOUT_FILENO: 339 m_gdb_client_up->SetSTDOUT(file_action->GetFileSpec()); 340 break; 341 case STDERR_FILENO: 342 m_gdb_client_up->SetSTDERR(file_action->GetFileSpec()); 343 break; 344 } 345 } 346 347 m_gdb_client_up->SetDisableASLR( 348 launch_info.GetFlags().Test(eLaunchFlagDisableASLR)); 349 m_gdb_client_up->SetDetachOnError( 350 launch_info.GetFlags().Test(eLaunchFlagDetachOnError)); 351 352 FileSpec working_dir = launch_info.GetWorkingDirectory(); 353 if (working_dir) { 354 m_gdb_client_up->SetWorkingDir(working_dir); 355 } 356 357 // Send the environment and the program + arguments after we connect 358 m_gdb_client_up->SendEnvironment(launch_info.GetEnvironment()); 359 360 ArchSpec arch_spec = launch_info.GetArchitecture(); 361 const char *arch_triple = arch_spec.GetTriple().str().c_str(); 362 363 m_gdb_client_up->SendLaunchArchPacket(arch_triple); 364 LLDB_LOGF( 365 log, 366 "PlatformRemoteGDBServer::%s() set launch architecture triple to '%s'", 367 __FUNCTION__, arch_triple ? arch_triple : "<NULL>"); 368 369 int arg_packet_err; 370 { 371 // Scope for the scoped timeout object 372 process_gdb_remote::GDBRemoteCommunication::ScopedTimeout timeout( 373 *m_gdb_client_up, std::chrono::seconds(5)); 374 arg_packet_err = m_gdb_client_up->SendArgumentsPacket(launch_info); 375 } 376 377 if (arg_packet_err == 0) { 378 std::string error_str; 379 if (m_gdb_client_up->GetLaunchSuccess(error_str)) { 380 const auto pid = m_gdb_client_up->GetCurrentProcessID(false); 381 if (pid != LLDB_INVALID_PROCESS_ID) { 382 launch_info.SetProcessID(pid); 383 LLDB_LOGF(log, 384 "PlatformRemoteGDBServer::%s() pid %" PRIu64 385 " launched successfully", 386 __FUNCTION__, pid); 387 } else { 388 LLDB_LOGF(log, 389 "PlatformRemoteGDBServer::%s() launch succeeded but we " 390 "didn't get a valid process id back!", 391 __FUNCTION__); 392 error.SetErrorString("failed to get PID"); 393 } 394 } else { 395 error.SetErrorString(error_str.c_str()); 396 LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() launch failed: %s", 397 __FUNCTION__, error.AsCString()); 398 } 399 } else { 400 error.SetErrorStringWithFormat("'A' packet returned an error: %i", 401 arg_packet_err); 402 } 403 return error; 404 } 405 406 Status PlatformRemoteGDBServer::KillProcess(const lldb::pid_t pid) { 407 if (!KillSpawnedProcess(pid)) 408 return Status("failed to kill remote spawned process"); 409 return Status(); 410 } 411 412 lldb::ProcessSP 413 PlatformRemoteGDBServer::DebugProcess(ProcessLaunchInfo &launch_info, 414 Debugger &debugger, Target &target, 415 Status &error) { 416 lldb::ProcessSP process_sp; 417 if (IsRemote()) { 418 if (IsConnected()) { 419 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; 420 std::string connect_url; 421 if (!LaunchGDBServer(debugserver_pid, connect_url)) { 422 error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'", 423 GetHostname()); 424 } else { 425 // The darwin always currently uses the GDB remote debugger plug-in 426 // so even when debugging locally we are debugging remotely! 427 process_sp = target.CreateProcess(launch_info.GetListener(), 428 "gdb-remote", nullptr, true); 429 430 if (process_sp) { 431 error = process_sp->ConnectRemote(connect_url.c_str()); 432 // Retry the connect remote one time... 433 if (error.Fail()) 434 error = process_sp->ConnectRemote(connect_url.c_str()); 435 if (error.Success()) 436 error = process_sp->Launch(launch_info); 437 else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { 438 printf("error: connect remote failed (%s)\n", error.AsCString()); 439 KillSpawnedProcess(debugserver_pid); 440 } 441 } 442 } 443 } else { 444 error.SetErrorString("not connected to remote gdb server"); 445 } 446 } 447 return process_sp; 448 } 449 450 bool PlatformRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid, 451 std::string &connect_url) { 452 assert(IsConnected()); 453 454 ArchSpec remote_arch = GetRemoteSystemArchitecture(); 455 llvm::Triple &remote_triple = remote_arch.GetTriple(); 456 457 uint16_t port = 0; 458 std::string socket_name; 459 bool launch_result = false; 460 if (remote_triple.getVendor() == llvm::Triple::Apple && 461 remote_triple.getOS() == llvm::Triple::IOS) { 462 // When remote debugging to iOS, we use a USB mux that always talks to 463 // localhost, so we will need the remote debugserver to accept connections 464 // only from localhost, no matter what our current hostname is 465 launch_result = 466 m_gdb_client_up->LaunchGDBServer("127.0.0.1", pid, port, socket_name); 467 } else { 468 // All other hosts should use their actual hostname 469 launch_result = 470 m_gdb_client_up->LaunchGDBServer(nullptr, pid, port, socket_name); 471 } 472 473 if (!launch_result) 474 return false; 475 476 connect_url = 477 MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port, 478 (socket_name.empty()) ? nullptr : socket_name.c_str()); 479 return true; 480 } 481 482 bool PlatformRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) { 483 assert(IsConnected()); 484 return m_gdb_client_up->KillSpawnedProcess(pid); 485 } 486 487 lldb::ProcessSP PlatformRemoteGDBServer::Attach( 488 ProcessAttachInfo &attach_info, Debugger &debugger, 489 Target *target, // Can be NULL, if NULL create a new target, else use 490 // existing one 491 Status &error) { 492 lldb::ProcessSP process_sp; 493 if (IsRemote()) { 494 if (IsConnected()) { 495 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; 496 std::string connect_url; 497 if (!LaunchGDBServer(debugserver_pid, connect_url)) { 498 error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'", 499 GetHostname()); 500 } else { 501 if (target == nullptr) { 502 TargetSP new_target_sp; 503 504 error = debugger.GetTargetList().CreateTarget( 505 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); 506 target = new_target_sp.get(); 507 } else 508 error.Clear(); 509 510 if (target && error.Success()) { 511 // The darwin always currently uses the GDB remote debugger plug-in 512 // so even when debugging locally we are debugging remotely! 513 process_sp = 514 target->CreateProcess(attach_info.GetListenerForProcess(debugger), 515 "gdb-remote", nullptr, true); 516 if (process_sp) { 517 error = process_sp->ConnectRemote(connect_url.c_str()); 518 if (error.Success()) { 519 ListenerSP listener_sp = attach_info.GetHijackListener(); 520 if (listener_sp) 521 process_sp->HijackProcessEvents(listener_sp); 522 error = process_sp->Attach(attach_info); 523 } 524 525 if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) { 526 KillSpawnedProcess(debugserver_pid); 527 } 528 } 529 } 530 } 531 } else { 532 error.SetErrorString("not connected to remote gdb server"); 533 } 534 } 535 return process_sp; 536 } 537 538 Status PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec, 539 uint32_t mode) { 540 if (!IsConnected()) 541 return Status("Not connected."); 542 Status error = m_gdb_client_up->MakeDirectory(file_spec, mode); 543 Log *log = GetLog(LLDBLog::Platform); 544 LLDB_LOGF(log, 545 "PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) " 546 "error = %u (%s)", 547 file_spec.GetCString(), mode, error.GetError(), error.AsCString()); 548 return error; 549 } 550 551 Status PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec, 552 uint32_t &file_permissions) { 553 if (!IsConnected()) 554 return Status("Not connected."); 555 Status error = 556 m_gdb_client_up->GetFilePermissions(file_spec, file_permissions); 557 Log *log = GetLog(LLDBLog::Platform); 558 LLDB_LOGF(log, 559 "PlatformRemoteGDBServer::GetFilePermissions(path='%s', " 560 "file_permissions=%o) error = %u (%s)", 561 file_spec.GetCString(), file_permissions, error.GetError(), 562 error.AsCString()); 563 return error; 564 } 565 566 Status PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec, 567 uint32_t file_permissions) { 568 if (!IsConnected()) 569 return Status("Not connected."); 570 Status error = 571 m_gdb_client_up->SetFilePermissions(file_spec, file_permissions); 572 Log *log = GetLog(LLDBLog::Platform); 573 LLDB_LOGF(log, 574 "PlatformRemoteGDBServer::SetFilePermissions(path='%s', " 575 "file_permissions=%o) error = %u (%s)", 576 file_spec.GetCString(), file_permissions, error.GetError(), 577 error.AsCString()); 578 return error; 579 } 580 581 lldb::user_id_t PlatformRemoteGDBServer::OpenFile(const FileSpec &file_spec, 582 File::OpenOptions flags, 583 uint32_t mode, 584 Status &error) { 585 if (IsConnected()) 586 return m_gdb_client_up->OpenFile(file_spec, flags, mode, error); 587 return LLDB_INVALID_UID; 588 } 589 590 bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Status &error) { 591 if (IsConnected()) 592 return m_gdb_client_up->CloseFile(fd, error); 593 error = Status("Not connected."); 594 return false; 595 } 596 597 lldb::user_id_t 598 PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) { 599 if (IsConnected()) 600 return m_gdb_client_up->GetFileSize(file_spec); 601 return LLDB_INVALID_UID; 602 } 603 604 void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory( 605 CompletionRequest &request, bool only_dir) { 606 if (IsConnected()) 607 m_gdb_client_up->AutoCompleteDiskFileOrDirectory(request, only_dir); 608 } 609 610 uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset, 611 void *dst, uint64_t dst_len, 612 Status &error) { 613 if (IsConnected()) 614 return m_gdb_client_up->ReadFile(fd, offset, dst, dst_len, error); 615 error = Status("Not connected."); 616 return 0; 617 } 618 619 uint64_t PlatformRemoteGDBServer::WriteFile(lldb::user_id_t fd, uint64_t offset, 620 const void *src, uint64_t src_len, 621 Status &error) { 622 if (IsConnected()) 623 return m_gdb_client_up->WriteFile(fd, offset, src, src_len, error); 624 error = Status("Not connected."); 625 return 0; 626 } 627 628 Status PlatformRemoteGDBServer::PutFile(const FileSpec &source, 629 const FileSpec &destination, 630 uint32_t uid, uint32_t gid) { 631 return Platform::PutFile(source, destination, uid, gid); 632 } 633 634 Status PlatformRemoteGDBServer::CreateSymlink( 635 const FileSpec &src, // The name of the link is in src 636 const FileSpec &dst) // The symlink points to dst 637 { 638 if (!IsConnected()) 639 return Status("Not connected."); 640 Status error = m_gdb_client_up->CreateSymlink(src, dst); 641 Log *log = GetLog(LLDBLog::Platform); 642 LLDB_LOGF(log, 643 "PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') " 644 "error = %u (%s)", 645 src.GetCString(), dst.GetCString(), error.GetError(), 646 error.AsCString()); 647 return error; 648 } 649 650 Status PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) { 651 if (!IsConnected()) 652 return Status("Not connected."); 653 Status error = m_gdb_client_up->Unlink(file_spec); 654 Log *log = GetLog(LLDBLog::Platform); 655 LLDB_LOGF(log, "PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)", 656 file_spec.GetCString(), error.GetError(), error.AsCString()); 657 return error; 658 } 659 660 bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) { 661 if (IsConnected()) 662 return m_gdb_client_up->GetFileExists(file_spec); 663 return false; 664 } 665 666 Status PlatformRemoteGDBServer::RunShellCommand( 667 llvm::StringRef shell, llvm::StringRef command, 668 const FileSpec & 669 working_dir, // Pass empty FileSpec to use the current working directory 670 int *status_ptr, // Pass NULL if you don't want the process exit status 671 int *signo_ptr, // Pass NULL if you don't want the signal that caused the 672 // process to exit 673 std::string 674 *command_output, // Pass NULL if you don't want the command output 675 const Timeout<std::micro> &timeout) { 676 if (!IsConnected()) 677 return Status("Not connected."); 678 return m_gdb_client_up->RunShellCommand(command, working_dir, status_ptr, 679 signo_ptr, command_output, timeout); 680 } 681 682 void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() { 683 m_trap_handlers.push_back(ConstString("_sigtramp")); 684 } 685 686 const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() { 687 if (!IsConnected()) 688 return Platform::GetRemoteUnixSignals(); 689 690 if (m_remote_signals_sp) 691 return m_remote_signals_sp; 692 693 // If packet not implemented or JSON failed to parse, we'll guess the signal 694 // set based on the remote architecture. 695 m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture()); 696 697 StringExtractorGDBRemote response; 698 auto result = 699 m_gdb_client_up->SendPacketAndWaitForResponse("jSignalsInfo", response); 700 701 if (result != decltype(result)::Success || 702 response.GetResponseType() != response.eResponse) 703 return m_remote_signals_sp; 704 705 auto object_sp = 706 StructuredData::ParseJSON(std::string(response.GetStringRef())); 707 if (!object_sp || !object_sp->IsValid()) 708 return m_remote_signals_sp; 709 710 auto array_sp = object_sp->GetAsArray(); 711 if (!array_sp || !array_sp->IsValid()) 712 return m_remote_signals_sp; 713 714 auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>(); 715 716 bool done = array_sp->ForEach( 717 [&remote_signals_sp](StructuredData::Object *object) -> bool { 718 if (!object || !object->IsValid()) 719 return false; 720 721 auto dict = object->GetAsDictionary(); 722 if (!dict || !dict->IsValid()) 723 return false; 724 725 // Signal number and signal name are required. 726 int signo; 727 if (!dict->GetValueForKeyAsInteger("signo", signo)) 728 return false; 729 730 llvm::StringRef name; 731 if (!dict->GetValueForKeyAsString("name", name)) 732 return false; 733 734 // We can live without short_name, description, etc. 735 bool suppress{false}; 736 auto object_sp = dict->GetValueForKey("suppress"); 737 if (object_sp && object_sp->IsValid()) 738 suppress = object_sp->GetBooleanValue(); 739 740 bool stop{false}; 741 object_sp = dict->GetValueForKey("stop"); 742 if (object_sp && object_sp->IsValid()) 743 stop = object_sp->GetBooleanValue(); 744 745 bool notify{false}; 746 object_sp = dict->GetValueForKey("notify"); 747 if (object_sp && object_sp->IsValid()) 748 notify = object_sp->GetBooleanValue(); 749 750 std::string description; 751 object_sp = dict->GetValueForKey("description"); 752 if (object_sp && object_sp->IsValid()) 753 description = std::string(object_sp->GetStringValue()); 754 755 remote_signals_sp->AddSignal(signo, name.str().c_str(), suppress, stop, 756 notify, description.c_str()); 757 return true; 758 }); 759 760 if (done) 761 m_remote_signals_sp = std::move(remote_signals_sp); 762 763 return m_remote_signals_sp; 764 } 765 766 std::string PlatformRemoteGDBServer::MakeGdbServerUrl( 767 const std::string &platform_scheme, const std::string &platform_hostname, 768 uint16_t port, const char *socket_name) { 769 const char *override_scheme = 770 getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME"); 771 const char *override_hostname = 772 getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); 773 const char *port_offset_c_str = 774 getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); 775 int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; 776 777 return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(), 778 override_hostname ? override_hostname 779 : platform_hostname.c_str(), 780 port + port_offset, socket_name); 781 } 782 783 std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme, 784 const char *hostname, 785 uint16_t port, const char *path) { 786 StreamString result; 787 result.Printf("%s://[%s]", scheme, hostname); 788 if (port != 0) 789 result.Printf(":%u", port); 790 if (path) 791 result.Write(path, strlen(path)); 792 return std::string(result.GetString()); 793 } 794 795 size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger, 796 Status &error) { 797 std::vector<std::string> connection_urls; 798 GetPendingGdbServerList(connection_urls); 799 800 for (size_t i = 0; i < connection_urls.size(); ++i) { 801 ConnectProcess(connection_urls[i].c_str(), "gdb-remote", debugger, nullptr, error); 802 if (error.Fail()) 803 return i; // We already connected to i process succsessfully 804 } 805 return connection_urls.size(); 806 } 807 808 size_t PlatformRemoteGDBServer::GetPendingGdbServerList( 809 std::vector<std::string> &connection_urls) { 810 std::vector<std::pair<uint16_t, std::string>> remote_servers; 811 if (!IsConnected()) 812 return 0; 813 m_gdb_client_up->QueryGDBServer(remote_servers); 814 for (const auto &gdbserver : remote_servers) { 815 const char *socket_name_cstr = 816 gdbserver.second.empty() ? nullptr : gdbserver.second.c_str(); 817 connection_urls.emplace_back( 818 MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, 819 gdbserver.first, socket_name_cstr)); 820 } 821 return connection_urls.size(); 822 } 823