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 process_sp->HijackProcessEvents(launch_info.GetHijackListener()); 432 433 error = process_sp->ConnectRemote(connect_url.c_str()); 434 // Retry the connect remote one time... 435 if (error.Fail()) 436 error = process_sp->ConnectRemote(connect_url.c_str()); 437 if (error.Success()) 438 error = process_sp->Launch(launch_info); 439 else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { 440 printf("error: connect remote failed (%s)\n", error.AsCString()); 441 KillSpawnedProcess(debugserver_pid); 442 } 443 } 444 } 445 } else { 446 error.SetErrorString("not connected to remote gdb server"); 447 } 448 } 449 return process_sp; 450 } 451 452 bool PlatformRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid, 453 std::string &connect_url) { 454 assert(IsConnected()); 455 456 ArchSpec remote_arch = GetRemoteSystemArchitecture(); 457 llvm::Triple &remote_triple = remote_arch.GetTriple(); 458 459 uint16_t port = 0; 460 std::string socket_name; 461 bool launch_result = false; 462 if (remote_triple.getVendor() == llvm::Triple::Apple && 463 remote_triple.getOS() == llvm::Triple::IOS) { 464 // When remote debugging to iOS, we use a USB mux that always talks to 465 // localhost, so we will need the remote debugserver to accept connections 466 // only from localhost, no matter what our current hostname is 467 launch_result = 468 m_gdb_client_up->LaunchGDBServer("127.0.0.1", pid, port, socket_name); 469 } else { 470 // All other hosts should use their actual hostname 471 launch_result = 472 m_gdb_client_up->LaunchGDBServer(nullptr, pid, port, socket_name); 473 } 474 475 if (!launch_result) 476 return false; 477 478 connect_url = 479 MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port, 480 (socket_name.empty()) ? nullptr : socket_name.c_str()); 481 return true; 482 } 483 484 bool PlatformRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) { 485 assert(IsConnected()); 486 return m_gdb_client_up->KillSpawnedProcess(pid); 487 } 488 489 lldb::ProcessSP PlatformRemoteGDBServer::Attach( 490 ProcessAttachInfo &attach_info, Debugger &debugger, 491 Target *target, // Can be NULL, if NULL create a new target, else use 492 // existing one 493 Status &error) { 494 lldb::ProcessSP process_sp; 495 if (IsRemote()) { 496 if (IsConnected()) { 497 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; 498 std::string connect_url; 499 if (!LaunchGDBServer(debugserver_pid, connect_url)) { 500 error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'", 501 GetHostname()); 502 } else { 503 if (target == nullptr) { 504 TargetSP new_target_sp; 505 506 error = debugger.GetTargetList().CreateTarget( 507 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); 508 target = new_target_sp.get(); 509 } else 510 error.Clear(); 511 512 if (target && error.Success()) { 513 // The darwin always currently uses the GDB remote debugger plug-in 514 // so even when debugging locally we are debugging remotely! 515 process_sp = 516 target->CreateProcess(attach_info.GetListenerForProcess(debugger), 517 "gdb-remote", nullptr, true); 518 if (process_sp) { 519 error = process_sp->ConnectRemote(connect_url.c_str()); 520 if (error.Success()) { 521 ListenerSP listener_sp = attach_info.GetHijackListener(); 522 if (listener_sp) 523 process_sp->HijackProcessEvents(listener_sp); 524 error = process_sp->Attach(attach_info); 525 } 526 527 if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) { 528 KillSpawnedProcess(debugserver_pid); 529 } 530 } 531 } 532 } 533 } else { 534 error.SetErrorString("not connected to remote gdb server"); 535 } 536 } 537 return process_sp; 538 } 539 540 Status PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec, 541 uint32_t mode) { 542 if (!IsConnected()) 543 return Status("Not connected."); 544 Status error = m_gdb_client_up->MakeDirectory(file_spec, mode); 545 Log *log = GetLog(LLDBLog::Platform); 546 LLDB_LOGF(log, 547 "PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) " 548 "error = %u (%s)", 549 file_spec.GetCString(), mode, error.GetError(), error.AsCString()); 550 return error; 551 } 552 553 Status PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec, 554 uint32_t &file_permissions) { 555 if (!IsConnected()) 556 return Status("Not connected."); 557 Status error = 558 m_gdb_client_up->GetFilePermissions(file_spec, file_permissions); 559 Log *log = GetLog(LLDBLog::Platform); 560 LLDB_LOGF(log, 561 "PlatformRemoteGDBServer::GetFilePermissions(path='%s', " 562 "file_permissions=%o) error = %u (%s)", 563 file_spec.GetCString(), file_permissions, error.GetError(), 564 error.AsCString()); 565 return error; 566 } 567 568 Status PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec, 569 uint32_t file_permissions) { 570 if (!IsConnected()) 571 return Status("Not connected."); 572 Status error = 573 m_gdb_client_up->SetFilePermissions(file_spec, file_permissions); 574 Log *log = GetLog(LLDBLog::Platform); 575 LLDB_LOGF(log, 576 "PlatformRemoteGDBServer::SetFilePermissions(path='%s', " 577 "file_permissions=%o) error = %u (%s)", 578 file_spec.GetCString(), file_permissions, error.GetError(), 579 error.AsCString()); 580 return error; 581 } 582 583 lldb::user_id_t PlatformRemoteGDBServer::OpenFile(const FileSpec &file_spec, 584 File::OpenOptions flags, 585 uint32_t mode, 586 Status &error) { 587 if (IsConnected()) 588 return m_gdb_client_up->OpenFile(file_spec, flags, mode, error); 589 return LLDB_INVALID_UID; 590 } 591 592 bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Status &error) { 593 if (IsConnected()) 594 return m_gdb_client_up->CloseFile(fd, error); 595 error = Status("Not connected."); 596 return false; 597 } 598 599 lldb::user_id_t 600 PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) { 601 if (IsConnected()) 602 return m_gdb_client_up->GetFileSize(file_spec); 603 return LLDB_INVALID_UID; 604 } 605 606 void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory( 607 CompletionRequest &request, bool only_dir) { 608 if (IsConnected()) 609 m_gdb_client_up->AutoCompleteDiskFileOrDirectory(request, only_dir); 610 } 611 612 uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset, 613 void *dst, uint64_t dst_len, 614 Status &error) { 615 if (IsConnected()) 616 return m_gdb_client_up->ReadFile(fd, offset, dst, dst_len, error); 617 error = Status("Not connected."); 618 return 0; 619 } 620 621 uint64_t PlatformRemoteGDBServer::WriteFile(lldb::user_id_t fd, uint64_t offset, 622 const void *src, uint64_t src_len, 623 Status &error) { 624 if (IsConnected()) 625 return m_gdb_client_up->WriteFile(fd, offset, src, src_len, error); 626 error = Status("Not connected."); 627 return 0; 628 } 629 630 Status PlatformRemoteGDBServer::PutFile(const FileSpec &source, 631 const FileSpec &destination, 632 uint32_t uid, uint32_t gid) { 633 return Platform::PutFile(source, destination, uid, gid); 634 } 635 636 Status PlatformRemoteGDBServer::CreateSymlink( 637 const FileSpec &src, // The name of the link is in src 638 const FileSpec &dst) // The symlink points to dst 639 { 640 if (!IsConnected()) 641 return Status("Not connected."); 642 Status error = m_gdb_client_up->CreateSymlink(src, dst); 643 Log *log = GetLog(LLDBLog::Platform); 644 LLDB_LOGF(log, 645 "PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') " 646 "error = %u (%s)", 647 src.GetCString(), dst.GetCString(), error.GetError(), 648 error.AsCString()); 649 return error; 650 } 651 652 Status PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) { 653 if (!IsConnected()) 654 return Status("Not connected."); 655 Status error = m_gdb_client_up->Unlink(file_spec); 656 Log *log = GetLog(LLDBLog::Platform); 657 LLDB_LOGF(log, "PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)", 658 file_spec.GetCString(), error.GetError(), error.AsCString()); 659 return error; 660 } 661 662 bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) { 663 if (IsConnected()) 664 return m_gdb_client_up->GetFileExists(file_spec); 665 return false; 666 } 667 668 Status PlatformRemoteGDBServer::RunShellCommand( 669 llvm::StringRef shell, llvm::StringRef command, 670 const FileSpec & 671 working_dir, // Pass empty FileSpec to use the current working directory 672 int *status_ptr, // Pass NULL if you don't want the process exit status 673 int *signo_ptr, // Pass NULL if you don't want the signal that caused the 674 // process to exit 675 std::string 676 *command_output, // Pass NULL if you don't want the command output 677 const Timeout<std::micro> &timeout) { 678 if (!IsConnected()) 679 return Status("Not connected."); 680 return m_gdb_client_up->RunShellCommand(command, working_dir, status_ptr, 681 signo_ptr, command_output, timeout); 682 } 683 684 void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() { 685 m_trap_handlers.push_back(ConstString("_sigtramp")); 686 } 687 688 const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() { 689 if (!IsConnected()) 690 return Platform::GetRemoteUnixSignals(); 691 692 if (m_remote_signals_sp) 693 return m_remote_signals_sp; 694 695 // If packet not implemented or JSON failed to parse, we'll guess the signal 696 // set based on the remote architecture. 697 m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture()); 698 699 StringExtractorGDBRemote response; 700 auto result = 701 m_gdb_client_up->SendPacketAndWaitForResponse("jSignalsInfo", response); 702 703 if (result != decltype(result)::Success || 704 response.GetResponseType() != response.eResponse) 705 return m_remote_signals_sp; 706 707 auto object_sp = 708 StructuredData::ParseJSON(std::string(response.GetStringRef())); 709 if (!object_sp || !object_sp->IsValid()) 710 return m_remote_signals_sp; 711 712 auto array_sp = object_sp->GetAsArray(); 713 if (!array_sp || !array_sp->IsValid()) 714 return m_remote_signals_sp; 715 716 auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>(); 717 718 bool done = array_sp->ForEach( 719 [&remote_signals_sp](StructuredData::Object *object) -> bool { 720 if (!object || !object->IsValid()) 721 return false; 722 723 auto dict = object->GetAsDictionary(); 724 if (!dict || !dict->IsValid()) 725 return false; 726 727 // Signal number and signal name are required. 728 int signo; 729 if (!dict->GetValueForKeyAsInteger("signo", signo)) 730 return false; 731 732 llvm::StringRef name; 733 if (!dict->GetValueForKeyAsString("name", name)) 734 return false; 735 736 // We can live without short_name, description, etc. 737 bool suppress{false}; 738 auto object_sp = dict->GetValueForKey("suppress"); 739 if (object_sp && object_sp->IsValid()) 740 suppress = object_sp->GetBooleanValue(); 741 742 bool stop{false}; 743 object_sp = dict->GetValueForKey("stop"); 744 if (object_sp && object_sp->IsValid()) 745 stop = object_sp->GetBooleanValue(); 746 747 bool notify{false}; 748 object_sp = dict->GetValueForKey("notify"); 749 if (object_sp && object_sp->IsValid()) 750 notify = object_sp->GetBooleanValue(); 751 752 std::string description; 753 object_sp = dict->GetValueForKey("description"); 754 if (object_sp && object_sp->IsValid()) 755 description = std::string(object_sp->GetStringValue()); 756 757 remote_signals_sp->AddSignal(signo, name.str().c_str(), suppress, stop, 758 notify, description.c_str()); 759 return true; 760 }); 761 762 if (done) 763 m_remote_signals_sp = std::move(remote_signals_sp); 764 765 return m_remote_signals_sp; 766 } 767 768 std::string PlatformRemoteGDBServer::MakeGdbServerUrl( 769 const std::string &platform_scheme, const std::string &platform_hostname, 770 uint16_t port, const char *socket_name) { 771 const char *override_scheme = 772 getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME"); 773 const char *override_hostname = 774 getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); 775 const char *port_offset_c_str = 776 getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); 777 int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; 778 779 return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(), 780 override_hostname ? override_hostname 781 : platform_hostname.c_str(), 782 port + port_offset, socket_name); 783 } 784 785 std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme, 786 const char *hostname, 787 uint16_t port, const char *path) { 788 StreamString result; 789 result.Printf("%s://[%s]", scheme, hostname); 790 if (port != 0) 791 result.Printf(":%u", port); 792 if (path) 793 result.Write(path, strlen(path)); 794 return std::string(result.GetString()); 795 } 796 797 size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger, 798 Status &error) { 799 std::vector<std::string> connection_urls; 800 GetPendingGdbServerList(connection_urls); 801 802 for (size_t i = 0; i < connection_urls.size(); ++i) { 803 ConnectProcess(connection_urls[i].c_str(), "gdb-remote", debugger, nullptr, error); 804 if (error.Fail()) 805 return i; // We already connected to i process succsessfully 806 } 807 return connection_urls.size(); 808 } 809 810 size_t PlatformRemoteGDBServer::GetPendingGdbServerList( 811 std::vector<std::string> &connection_urls) { 812 std::vector<std::pair<uint16_t, std::string>> remote_servers; 813 if (!IsConnected()) 814 return 0; 815 m_gdb_client_up->QueryGDBServer(remote_servers); 816 for (const auto &gdbserver : remote_servers) { 817 const char *socket_name_cstr = 818 gdbserver.second.empty() ? nullptr : gdbserver.second.c_str(); 819 connection_urls.emplace_back( 820 MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, 821 gdbserver.first, socket_name_cstr)); 822 } 823 return connection_urls.size(); 824 } 825