15ffd83dbSDimitry Andric //===-- PlatformRemoteGDBServer.cpp ---------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "PlatformRemoteGDBServer.h" 100b57cec5SDimitry Andric #include "lldb/Host/Config.h" 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h" 130b57cec5SDimitry Andric #include "lldb/Core/Debugger.h" 140b57cec5SDimitry Andric #include "lldb/Core/Module.h" 150b57cec5SDimitry Andric #include "lldb/Core/ModuleList.h" 160b57cec5SDimitry Andric #include "lldb/Core/ModuleSpec.h" 170b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h" 180b57cec5SDimitry Andric #include "lldb/Host/ConnectionFileDescriptor.h" 190b57cec5SDimitry Andric #include "lldb/Host/Host.h" 200b57cec5SDimitry Andric #include "lldb/Host/HostInfo.h" 210b57cec5SDimitry Andric #include "lldb/Host/PosixApi.h" 220b57cec5SDimitry Andric #include "lldb/Target/Process.h" 230b57cec5SDimitry Andric #include "lldb/Target/Target.h" 240b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h" 2581ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h" 260b57cec5SDimitry Andric #include "lldb/Utility/Log.h" 270b57cec5SDimitry Andric #include "lldb/Utility/ProcessInfo.h" 280b57cec5SDimitry Andric #include "lldb/Utility/Status.h" 290b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h" 300b57cec5SDimitry Andric #include "lldb/Utility/UriParser.h" 315f757f3fSDimitry Andric #include "llvm/ADT/StringSet.h" 32bdd1243dSDimitry Andric #include "llvm/Support/FormatAdapters.h" 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric #include "Plugins/Process/Utility/GDBRemoteSignals.h" 35fe6060f1SDimitry Andric #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" 365f757f3fSDimitry Andric #include <mutex> 37bdd1243dSDimitry Andric #include <optional> 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric using namespace lldb; 400b57cec5SDimitry Andric using namespace lldb_private; 410b57cec5SDimitry Andric using namespace lldb_private::platform_gdb_server; 420b57cec5SDimitry Andric 435ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteGDBServer, PlatformGDB) 445ffd83dbSDimitry Andric 450b57cec5SDimitry Andric static bool g_initialized = false; 465f757f3fSDimitry Andric // UnixSignals does not store the signal names or descriptions itself. 475f757f3fSDimitry Andric // It holds onto StringRefs. Becaue we may get signal information dynamically 485f757f3fSDimitry Andric // from the remote, these strings need persistent storage client-side. 495f757f3fSDimitry Andric static std::mutex g_signal_string_mutex; 505f757f3fSDimitry Andric static llvm::StringSet<> g_signal_string_storage; 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric void PlatformRemoteGDBServer::Initialize() { 530b57cec5SDimitry Andric Platform::Initialize(); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric if (!g_initialized) { 560b57cec5SDimitry Andric g_initialized = true; 570b57cec5SDimitry Andric PluginManager::RegisterPlugin( 580b57cec5SDimitry Andric PlatformRemoteGDBServer::GetPluginNameStatic(), 590b57cec5SDimitry Andric PlatformRemoteGDBServer::GetDescriptionStatic(), 600b57cec5SDimitry Andric PlatformRemoteGDBServer::CreateInstance); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric void PlatformRemoteGDBServer::Terminate() { 650b57cec5SDimitry Andric if (g_initialized) { 660b57cec5SDimitry Andric g_initialized = false; 670b57cec5SDimitry Andric PluginManager::UnregisterPlugin(PlatformRemoteGDBServer::CreateInstance); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric Platform::Terminate(); 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric PlatformSP PlatformRemoteGDBServer::CreateInstance(bool force, 740b57cec5SDimitry Andric const ArchSpec *arch) { 750b57cec5SDimitry Andric bool create = force; 760b57cec5SDimitry Andric if (!create) { 770b57cec5SDimitry Andric create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified(); 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric if (create) 800b57cec5SDimitry Andric return PlatformSP(new PlatformRemoteGDBServer()); 810b57cec5SDimitry Andric return PlatformSP(); 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 84349cc55cSDimitry Andric llvm::StringRef PlatformRemoteGDBServer::GetDescriptionStatic() { 850b57cec5SDimitry Andric return "A platform that uses the GDB remote protocol as the communication " 860b57cec5SDimitry Andric "transport."; 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 89349cc55cSDimitry Andric llvm::StringRef PlatformRemoteGDBServer::GetDescription() { 900b57cec5SDimitry Andric if (m_platform_description.empty()) { 910b57cec5SDimitry Andric if (IsConnected()) { 920b57cec5SDimitry Andric // Send the get description packet 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric if (!m_platform_description.empty()) 970b57cec5SDimitry Andric return m_platform_description.c_str(); 980b57cec5SDimitry Andric return GetDescriptionStatic(); 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetModuleSpec(const FileSpec &module_file_spec, 1020b57cec5SDimitry Andric const ArchSpec &arch, 1030b57cec5SDimitry Andric ModuleSpec &module_spec) { 10481ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Platform); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric const auto module_path = module_file_spec.GetPath(false); 1070b57cec5SDimitry Andric 10804eeddc0SDimitry Andric if (!m_gdb_client_up || 10904eeddc0SDimitry Andric !m_gdb_client_up->GetModuleInfo(module_file_spec, arch, module_spec)) { 1109dba64beSDimitry Andric LLDB_LOGF( 1119dba64beSDimitry Andric log, 1120b57cec5SDimitry Andric "PlatformRemoteGDBServer::%s - failed to get module info for %s:%s", 1130b57cec5SDimitry Andric __FUNCTION__, module_path.c_str(), 1140b57cec5SDimitry Andric arch.GetTriple().getTriple().c_str()); 1150b57cec5SDimitry Andric return false; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric if (log) { 1190b57cec5SDimitry Andric StreamString stream; 1200b57cec5SDimitry Andric module_spec.Dump(stream); 1219dba64beSDimitry Andric LLDB_LOGF(log, 1220b57cec5SDimitry Andric "PlatformRemoteGDBServer::%s - got module info for (%s:%s) : %s", 1239dba64beSDimitry Andric __FUNCTION__, module_path.c_str(), 1249dba64beSDimitry Andric arch.GetTriple().getTriple().c_str(), stream.GetData()); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric return true; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric Status PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file, 1310b57cec5SDimitry Andric const UUID *uuid_ptr, 1320b57cec5SDimitry Andric FileSpec &local_file) { 1330b57cec5SDimitry Andric // Default to the local case 1340b57cec5SDimitry Andric local_file = platform_file; 1350b57cec5SDimitry Andric return Status(); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric /// Default Constructor 1390b57cec5SDimitry Andric PlatformRemoteGDBServer::PlatformRemoteGDBServer() 14004eeddc0SDimitry Andric : Platform(/*is_host=*/false) {} 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric /// Destructor. 1430b57cec5SDimitry Andric /// 1440b57cec5SDimitry Andric /// The destructor is virtual since this class is designed to be 1450b57cec5SDimitry Andric /// inherited from by the plug-in instance. 146fe6060f1SDimitry Andric PlatformRemoteGDBServer::~PlatformRemoteGDBServer() = default; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode( 1490b57cec5SDimitry Andric Target &target, BreakpointSite *bp_site) { 1500b57cec5SDimitry Andric // This isn't needed if the z/Z packets are supported in the GDB remote 1510b57cec5SDimitry Andric // server. But we might need a packet to detect this. 1520b57cec5SDimitry Andric return 0; 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetRemoteOSVersion() { 15604eeddc0SDimitry Andric if (m_gdb_client_up) 15704eeddc0SDimitry Andric m_os_version = m_gdb_client_up->GetOSVersion(); 1580b57cec5SDimitry Andric return !m_os_version.empty(); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 161bdd1243dSDimitry Andric std::optional<std::string> PlatformRemoteGDBServer::GetRemoteOSBuildString() { 16204eeddc0SDimitry Andric if (!m_gdb_client_up) 163bdd1243dSDimitry Andric return std::nullopt; 16404eeddc0SDimitry Andric return m_gdb_client_up->GetOSBuildString(); 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 167bdd1243dSDimitry Andric std::optional<std::string> 168349cc55cSDimitry Andric PlatformRemoteGDBServer::GetRemoteOSKernelDescription() { 16904eeddc0SDimitry Andric if (!m_gdb_client_up) 170bdd1243dSDimitry Andric return std::nullopt; 17104eeddc0SDimitry Andric return m_gdb_client_up->GetOSKernelDescription(); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric // Remote Platform subclasses need to override this function 1750b57cec5SDimitry Andric ArchSpec PlatformRemoteGDBServer::GetRemoteSystemArchitecture() { 17604eeddc0SDimitry Andric if (!m_gdb_client_up) 17704eeddc0SDimitry Andric return ArchSpec(); 17804eeddc0SDimitry Andric return m_gdb_client_up->GetSystemArchitecture(); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric FileSpec PlatformRemoteGDBServer::GetRemoteWorkingDirectory() { 1820b57cec5SDimitry Andric if (IsConnected()) { 18381ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Platform); 1840b57cec5SDimitry Andric FileSpec working_dir; 18504eeddc0SDimitry Andric if (m_gdb_client_up->GetWorkingDir(working_dir) && log) 1869dba64beSDimitry Andric LLDB_LOGF(log, 1870b57cec5SDimitry Andric "PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'", 188bdd1243dSDimitry Andric working_dir.GetPath().c_str()); 1890b57cec5SDimitry Andric return working_dir; 1900b57cec5SDimitry Andric } else { 1910b57cec5SDimitry Andric return Platform::GetRemoteWorkingDirectory(); 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric } 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric bool PlatformRemoteGDBServer::SetRemoteWorkingDirectory( 1960b57cec5SDimitry Andric const FileSpec &working_dir) { 1970b57cec5SDimitry Andric if (IsConnected()) { 1980b57cec5SDimitry Andric // Clear the working directory it case it doesn't get set correctly. This 1990b57cec5SDimitry Andric // will for use to re-read it 20081ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Platform); 2019dba64beSDimitry Andric LLDB_LOGF(log, "PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')", 202bdd1243dSDimitry Andric working_dir.GetPath().c_str()); 20304eeddc0SDimitry Andric return m_gdb_client_up->SetWorkingDir(working_dir) == 0; 2040b57cec5SDimitry Andric } else 2050b57cec5SDimitry Andric return Platform::SetRemoteWorkingDirectory(working_dir); 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric bool PlatformRemoteGDBServer::IsConnected() const { 20904eeddc0SDimitry Andric if (m_gdb_client_up) { 21004eeddc0SDimitry Andric assert(m_gdb_client_up->IsConnected()); 21104eeddc0SDimitry Andric return true; 21204eeddc0SDimitry Andric } 21304eeddc0SDimitry Andric return false; 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric Status PlatformRemoteGDBServer::ConnectRemote(Args &args) { 2170b57cec5SDimitry Andric Status error; 2180b57cec5SDimitry Andric if (IsConnected()) { 2190b57cec5SDimitry Andric error.SetErrorStringWithFormat("the platform is already connected to '%s', " 2200b57cec5SDimitry Andric "execute 'platform disconnect' to close the " 2210b57cec5SDimitry Andric "current connection", 2220b57cec5SDimitry Andric GetHostname()); 2235ffd83dbSDimitry Andric return error; 2245ffd83dbSDimitry Andric } 2255ffd83dbSDimitry Andric 2265ffd83dbSDimitry Andric if (args.GetArgumentCount() != 1) { 2275ffd83dbSDimitry Andric error.SetErrorString( 2285ffd83dbSDimitry Andric "\"platform connect\" takes a single argument: <connect-url>"); 2295ffd83dbSDimitry Andric return error; 2305ffd83dbSDimitry Andric } 2315ffd83dbSDimitry Andric 2320b57cec5SDimitry Andric const char *url = args.GetArgumentAtIndex(0); 2330b57cec5SDimitry Andric if (!url) 2340b57cec5SDimitry Andric return Status("URL is null."); 2355ffd83dbSDimitry Andric 236bdd1243dSDimitry Andric std::optional<URI> parsed_url = URI::Parse(url); 237349cc55cSDimitry Andric if (!parsed_url) 2380b57cec5SDimitry Andric return Status("Invalid URL: %s", url); 2390b57cec5SDimitry Andric 2405ffd83dbSDimitry Andric // We're going to reuse the hostname when we connect to the debugserver. 241349cc55cSDimitry Andric m_platform_scheme = parsed_url->scheme.str(); 242349cc55cSDimitry Andric m_platform_hostname = parsed_url->hostname.str(); 2435ffd83dbSDimitry Andric 24404eeddc0SDimitry Andric auto client_up = 24504eeddc0SDimitry Andric std::make_unique<process_gdb_remote::GDBRemoteCommunicationClient>(); 24604eeddc0SDimitry Andric client_up->SetPacketTimeout( 24704eeddc0SDimitry Andric process_gdb_remote::ProcessGDBRemote::GetPacketTimeout()); 24804eeddc0SDimitry Andric client_up->SetConnection(std::make_unique<ConnectionFileDescriptor>()); 24904eeddc0SDimitry Andric client_up->Connect(url, &error); 2505ffd83dbSDimitry Andric 2515ffd83dbSDimitry Andric if (error.Fail()) 2525ffd83dbSDimitry Andric return error; 2535ffd83dbSDimitry Andric 25404eeddc0SDimitry Andric if (client_up->HandshakeWithServer(&error)) { 25504eeddc0SDimitry Andric m_gdb_client_up = std::move(client_up); 25604eeddc0SDimitry Andric m_gdb_client_up->GetHostInfo(); 2570b57cec5SDimitry Andric // If a working directory was set prior to connecting, send it down 2585ffd83dbSDimitry Andric // now. 2590b57cec5SDimitry Andric if (m_working_dir) 26004eeddc0SDimitry Andric m_gdb_client_up->SetWorkingDir(m_working_dir); 261349cc55cSDimitry Andric 262349cc55cSDimitry Andric m_supported_architectures.clear(); 26304eeddc0SDimitry Andric ArchSpec remote_arch = m_gdb_client_up->GetSystemArchitecture(); 264349cc55cSDimitry Andric if (remote_arch) { 265349cc55cSDimitry Andric m_supported_architectures.push_back(remote_arch); 266349cc55cSDimitry Andric if (remote_arch.GetTriple().isArch64Bit()) 267349cc55cSDimitry Andric m_supported_architectures.push_back( 268349cc55cSDimitry Andric ArchSpec(remote_arch.GetTriple().get32BitArchVariant())); 269349cc55cSDimitry Andric } 2700b57cec5SDimitry Andric } else { 27104eeddc0SDimitry Andric client_up->Disconnect(); 2720b57cec5SDimitry Andric if (error.Success()) 2730b57cec5SDimitry Andric error.SetErrorString("handshake failed"); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric return error; 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric Status PlatformRemoteGDBServer::DisconnectRemote() { 2790b57cec5SDimitry Andric Status error; 28004eeddc0SDimitry Andric m_gdb_client_up.reset(); 2810b57cec5SDimitry Andric m_remote_signals_sp.reset(); 2820b57cec5SDimitry Andric return error; 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric const char *PlatformRemoteGDBServer::GetHostname() { 28604eeddc0SDimitry Andric if (m_gdb_client_up) 28781ad6265SDimitry Andric m_gdb_client_up->GetHostname(m_hostname); 28881ad6265SDimitry Andric if (m_hostname.empty()) 2890b57cec5SDimitry Andric return nullptr; 29081ad6265SDimitry Andric return m_hostname.c_str(); 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric 293bdd1243dSDimitry Andric std::optional<std::string> 2940b57cec5SDimitry Andric PlatformRemoteGDBServer::DoGetUserName(UserIDResolver::id_t uid) { 2950b57cec5SDimitry Andric std::string name; 29604eeddc0SDimitry Andric if (m_gdb_client_up && m_gdb_client_up->GetUserName(uid, name)) 2970b57cec5SDimitry Andric return std::move(name); 298bdd1243dSDimitry Andric return std::nullopt; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 301bdd1243dSDimitry Andric std::optional<std::string> 3020b57cec5SDimitry Andric PlatformRemoteGDBServer::DoGetGroupName(UserIDResolver::id_t gid) { 3030b57cec5SDimitry Andric std::string name; 30404eeddc0SDimitry Andric if (m_gdb_client_up && m_gdb_client_up->GetGroupName(gid, name)) 3050b57cec5SDimitry Andric return std::move(name); 306bdd1243dSDimitry Andric return std::nullopt; 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric uint32_t PlatformRemoteGDBServer::FindProcesses( 3100b57cec5SDimitry Andric const ProcessInstanceInfoMatch &match_info, 3110b57cec5SDimitry Andric ProcessInstanceInfoList &process_infos) { 31204eeddc0SDimitry Andric if (m_gdb_client_up) 31304eeddc0SDimitry Andric return m_gdb_client_up->FindProcesses(match_info, process_infos); 31404eeddc0SDimitry Andric return 0; 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetProcessInfo( 3180b57cec5SDimitry Andric lldb::pid_t pid, ProcessInstanceInfo &process_info) { 31904eeddc0SDimitry Andric if (m_gdb_client_up) 32004eeddc0SDimitry Andric return m_gdb_client_up->GetProcessInfo(pid, process_info); 32104eeddc0SDimitry Andric return false; 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) { 32581ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Platform); 3260b57cec5SDimitry Andric Status error; 3270b57cec5SDimitry Andric 3289dba64beSDimitry Andric LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() called", __FUNCTION__); 3290b57cec5SDimitry Andric 33004eeddc0SDimitry Andric if (!IsConnected()) 33104eeddc0SDimitry Andric return Status("Not connected."); 3320b57cec5SDimitry Andric auto num_file_actions = launch_info.GetNumFileActions(); 3330b57cec5SDimitry Andric for (decltype(num_file_actions) i = 0; i < num_file_actions; ++i) { 3340b57cec5SDimitry Andric const auto file_action = launch_info.GetFileActionAtIndex(i); 3350b57cec5SDimitry Andric if (file_action->GetAction() != FileAction::eFileActionOpen) 3360b57cec5SDimitry Andric continue; 3370b57cec5SDimitry Andric switch (file_action->GetFD()) { 3380b57cec5SDimitry Andric case STDIN_FILENO: 33904eeddc0SDimitry Andric m_gdb_client_up->SetSTDIN(file_action->GetFileSpec()); 3400b57cec5SDimitry Andric break; 3410b57cec5SDimitry Andric case STDOUT_FILENO: 34204eeddc0SDimitry Andric m_gdb_client_up->SetSTDOUT(file_action->GetFileSpec()); 3430b57cec5SDimitry Andric break; 3440b57cec5SDimitry Andric case STDERR_FILENO: 34504eeddc0SDimitry Andric m_gdb_client_up->SetSTDERR(file_action->GetFileSpec()); 3460b57cec5SDimitry Andric break; 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric 35004eeddc0SDimitry Andric m_gdb_client_up->SetDisableASLR( 3510b57cec5SDimitry Andric launch_info.GetFlags().Test(eLaunchFlagDisableASLR)); 35204eeddc0SDimitry Andric m_gdb_client_up->SetDetachOnError( 3530b57cec5SDimitry Andric launch_info.GetFlags().Test(eLaunchFlagDetachOnError)); 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric FileSpec working_dir = launch_info.GetWorkingDirectory(); 3560b57cec5SDimitry Andric if (working_dir) { 35704eeddc0SDimitry Andric m_gdb_client_up->SetWorkingDir(working_dir); 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric // Send the environment and the program + arguments after we connect 36104eeddc0SDimitry Andric m_gdb_client_up->SendEnvironment(launch_info.GetEnvironment()); 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric ArchSpec arch_spec = launch_info.GetArchitecture(); 3640b57cec5SDimitry Andric const char *arch_triple = arch_spec.GetTriple().str().c_str(); 3650b57cec5SDimitry Andric 36604eeddc0SDimitry Andric m_gdb_client_up->SendLaunchArchPacket(arch_triple); 3679dba64beSDimitry Andric LLDB_LOGF( 3689dba64beSDimitry Andric log, 3690b57cec5SDimitry Andric "PlatformRemoteGDBServer::%s() set launch architecture triple to '%s'", 3700b57cec5SDimitry Andric __FUNCTION__, arch_triple ? arch_triple : "<NULL>"); 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric { 3730b57cec5SDimitry Andric // Scope for the scoped timeout object 3740b57cec5SDimitry Andric process_gdb_remote::GDBRemoteCommunication::ScopedTimeout timeout( 37504eeddc0SDimitry Andric *m_gdb_client_up, std::chrono::seconds(5)); 376bdd1243dSDimitry Andric // Since we can't send argv0 separate from the executable path, we need to 377bdd1243dSDimitry Andric // make sure to use the actual executable path found in the launch_info... 378bdd1243dSDimitry Andric Args args = launch_info.GetArguments(); 379bdd1243dSDimitry Andric if (FileSpec exe_file = launch_info.GetExecutableFile()) 380bdd1243dSDimitry Andric args.ReplaceArgumentAtIndex(0, exe_file.GetPath(false)); 381bdd1243dSDimitry Andric if (llvm::Error err = m_gdb_client_up->LaunchProcess(args)) { 382bdd1243dSDimitry Andric error.SetErrorStringWithFormatv("Cannot launch '{0}': {1}", 383bdd1243dSDimitry Andric args.GetArgumentAtIndex(0), 384bdd1243dSDimitry Andric llvm::fmt_consume(std::move(err))); 385bdd1243dSDimitry Andric return error; 386bdd1243dSDimitry Andric } 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric 38904eeddc0SDimitry Andric const auto pid = m_gdb_client_up->GetCurrentProcessID(false); 3900b57cec5SDimitry Andric if (pid != LLDB_INVALID_PROCESS_ID) { 3910b57cec5SDimitry Andric launch_info.SetProcessID(pid); 3929dba64beSDimitry Andric LLDB_LOGF(log, 3939dba64beSDimitry Andric "PlatformRemoteGDBServer::%s() pid %" PRIu64 3940b57cec5SDimitry Andric " launched successfully", 3950b57cec5SDimitry Andric __FUNCTION__, pid); 3960b57cec5SDimitry Andric } else { 3979dba64beSDimitry Andric LLDB_LOGF(log, 3989dba64beSDimitry Andric "PlatformRemoteGDBServer::%s() launch succeeded but we " 3990b57cec5SDimitry Andric "didn't get a valid process id back!", 4000b57cec5SDimitry Andric __FUNCTION__); 4010b57cec5SDimitry Andric error.SetErrorString("failed to get PID"); 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric return error; 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric Status PlatformRemoteGDBServer::KillProcess(const lldb::pid_t pid) { 4070b57cec5SDimitry Andric if (!KillSpawnedProcess(pid)) 4080b57cec5SDimitry Andric return Status("failed to kill remote spawned process"); 4090b57cec5SDimitry Andric return Status(); 4100b57cec5SDimitry Andric } 4110b57cec5SDimitry Andric 412349cc55cSDimitry Andric lldb::ProcessSP 413349cc55cSDimitry Andric PlatformRemoteGDBServer::DebugProcess(ProcessLaunchInfo &launch_info, 414349cc55cSDimitry Andric Debugger &debugger, Target &target, 4150b57cec5SDimitry Andric Status &error) { 4160b57cec5SDimitry Andric lldb::ProcessSP process_sp; 4170b57cec5SDimitry Andric if (IsRemote()) { 4180b57cec5SDimitry Andric if (IsConnected()) { 4190b57cec5SDimitry Andric lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; 4200b57cec5SDimitry Andric std::string connect_url; 4210b57cec5SDimitry Andric if (!LaunchGDBServer(debugserver_pid, connect_url)) { 4220b57cec5SDimitry Andric error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'", 4230b57cec5SDimitry Andric GetHostname()); 4240b57cec5SDimitry Andric } else { 4250b57cec5SDimitry Andric // The darwin always currently uses the GDB remote debugger plug-in 4260b57cec5SDimitry Andric // so even when debugging locally we are debugging remotely! 427349cc55cSDimitry Andric process_sp = target.CreateProcess(launch_info.GetListener(), 428e8d8bef9SDimitry Andric "gdb-remote", nullptr, true); 4290b57cec5SDimitry Andric 4300b57cec5SDimitry Andric if (process_sp) { 43181ad6265SDimitry Andric process_sp->HijackProcessEvents(launch_info.GetHijackListener()); 43206c3fb27SDimitry Andric process_sp->SetShadowListener(launch_info.GetShadowListener()); 43381ad6265SDimitry Andric 4345ffd83dbSDimitry Andric error = process_sp->ConnectRemote(connect_url.c_str()); 4350b57cec5SDimitry Andric // Retry the connect remote one time... 4360b57cec5SDimitry Andric if (error.Fail()) 4375ffd83dbSDimitry Andric error = process_sp->ConnectRemote(connect_url.c_str()); 4380b57cec5SDimitry Andric if (error.Success()) 4390b57cec5SDimitry Andric error = process_sp->Launch(launch_info); 4400b57cec5SDimitry Andric else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { 4410b57cec5SDimitry Andric printf("error: connect remote failed (%s)\n", error.AsCString()); 4420b57cec5SDimitry Andric KillSpawnedProcess(debugserver_pid); 4430b57cec5SDimitry Andric } 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric } else { 4470b57cec5SDimitry Andric error.SetErrorString("not connected to remote gdb server"); 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric } 4500b57cec5SDimitry Andric return process_sp; 4510b57cec5SDimitry Andric } 4520b57cec5SDimitry Andric 4530b57cec5SDimitry Andric bool PlatformRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid, 4540b57cec5SDimitry Andric std::string &connect_url) { 45504eeddc0SDimitry Andric assert(IsConnected()); 45604eeddc0SDimitry Andric 4570b57cec5SDimitry Andric ArchSpec remote_arch = GetRemoteSystemArchitecture(); 4580b57cec5SDimitry Andric llvm::Triple &remote_triple = remote_arch.GetTriple(); 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric uint16_t port = 0; 4610b57cec5SDimitry Andric std::string socket_name; 4620b57cec5SDimitry Andric bool launch_result = false; 4630b57cec5SDimitry Andric if (remote_triple.getVendor() == llvm::Triple::Apple && 4640b57cec5SDimitry Andric remote_triple.getOS() == llvm::Triple::IOS) { 4650b57cec5SDimitry Andric // When remote debugging to iOS, we use a USB mux that always talks to 4660b57cec5SDimitry Andric // localhost, so we will need the remote debugserver to accept connections 4670b57cec5SDimitry Andric // only from localhost, no matter what our current hostname is 4680b57cec5SDimitry Andric launch_result = 46904eeddc0SDimitry Andric m_gdb_client_up->LaunchGDBServer("127.0.0.1", pid, port, socket_name); 4700b57cec5SDimitry Andric } else { 4710b57cec5SDimitry Andric // All other hosts should use their actual hostname 4720b57cec5SDimitry Andric launch_result = 47304eeddc0SDimitry Andric m_gdb_client_up->LaunchGDBServer(nullptr, pid, port, socket_name); 4740b57cec5SDimitry Andric } 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric if (!launch_result) 4770b57cec5SDimitry Andric return false; 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric connect_url = 4800b57cec5SDimitry Andric MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port, 4810b57cec5SDimitry Andric (socket_name.empty()) ? nullptr : socket_name.c_str()); 4820b57cec5SDimitry Andric return true; 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric bool PlatformRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) { 48604eeddc0SDimitry Andric assert(IsConnected()); 48704eeddc0SDimitry Andric return m_gdb_client_up->KillSpawnedProcess(pid); 4880b57cec5SDimitry Andric } 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric lldb::ProcessSP PlatformRemoteGDBServer::Attach( 4910b57cec5SDimitry Andric ProcessAttachInfo &attach_info, Debugger &debugger, 4920b57cec5SDimitry Andric Target *target, // Can be NULL, if NULL create a new target, else use 4930b57cec5SDimitry Andric // existing one 4940b57cec5SDimitry Andric Status &error) { 4950b57cec5SDimitry Andric lldb::ProcessSP process_sp; 4960b57cec5SDimitry Andric if (IsRemote()) { 4970b57cec5SDimitry Andric if (IsConnected()) { 4980b57cec5SDimitry Andric lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; 4990b57cec5SDimitry Andric std::string connect_url; 5000b57cec5SDimitry Andric if (!LaunchGDBServer(debugserver_pid, connect_url)) { 5010b57cec5SDimitry Andric error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'", 5020b57cec5SDimitry Andric GetHostname()); 5030b57cec5SDimitry Andric } else { 5040b57cec5SDimitry Andric if (target == nullptr) { 5050b57cec5SDimitry Andric TargetSP new_target_sp; 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric error = debugger.GetTargetList().CreateTarget( 5080b57cec5SDimitry Andric debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); 5090b57cec5SDimitry Andric target = new_target_sp.get(); 5100b57cec5SDimitry Andric } else 5110b57cec5SDimitry Andric error.Clear(); 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric if (target && error.Success()) { 5140b57cec5SDimitry Andric // The darwin always currently uses the GDB remote debugger plug-in 5150b57cec5SDimitry Andric // so even when debugging locally we are debugging remotely! 5160b57cec5SDimitry Andric process_sp = 5170b57cec5SDimitry Andric target->CreateProcess(attach_info.GetListenerForProcess(debugger), 518e8d8bef9SDimitry Andric "gdb-remote", nullptr, true); 5190b57cec5SDimitry Andric if (process_sp) { 5205ffd83dbSDimitry Andric error = process_sp->ConnectRemote(connect_url.c_str()); 5210b57cec5SDimitry Andric if (error.Success()) { 5220b57cec5SDimitry Andric ListenerSP listener_sp = attach_info.GetHijackListener(); 5230b57cec5SDimitry Andric if (listener_sp) 5240b57cec5SDimitry Andric process_sp->HijackProcessEvents(listener_sp); 52506c3fb27SDimitry Andric process_sp->SetShadowListener(attach_info.GetShadowListener()); 5260b57cec5SDimitry Andric error = process_sp->Attach(attach_info); 5270b57cec5SDimitry Andric } 5280b57cec5SDimitry Andric 5290b57cec5SDimitry Andric if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) { 5300b57cec5SDimitry Andric KillSpawnedProcess(debugserver_pid); 5310b57cec5SDimitry Andric } 5320b57cec5SDimitry Andric } 5330b57cec5SDimitry Andric } 5340b57cec5SDimitry Andric } 5350b57cec5SDimitry Andric } else { 5360b57cec5SDimitry Andric error.SetErrorString("not connected to remote gdb server"); 5370b57cec5SDimitry Andric } 5380b57cec5SDimitry Andric } 5390b57cec5SDimitry Andric return process_sp; 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric Status PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec, 5430b57cec5SDimitry Andric uint32_t mode) { 54404eeddc0SDimitry Andric if (!IsConnected()) 54504eeddc0SDimitry Andric return Status("Not connected."); 54604eeddc0SDimitry Andric Status error = m_gdb_client_up->MakeDirectory(file_spec, mode); 54781ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Platform); 5489dba64beSDimitry Andric LLDB_LOGF(log, 5499dba64beSDimitry Andric "PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) " 5500b57cec5SDimitry Andric "error = %u (%s)", 551bdd1243dSDimitry Andric file_spec.GetPath().c_str(), mode, error.GetError(), 552bdd1243dSDimitry Andric error.AsCString()); 5530b57cec5SDimitry Andric return error; 5540b57cec5SDimitry Andric } 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric Status PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec, 5570b57cec5SDimitry Andric uint32_t &file_permissions) { 55804eeddc0SDimitry Andric if (!IsConnected()) 55904eeddc0SDimitry Andric return Status("Not connected."); 56004eeddc0SDimitry Andric Status error = 56104eeddc0SDimitry Andric m_gdb_client_up->GetFilePermissions(file_spec, file_permissions); 56281ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Platform); 5639dba64beSDimitry Andric LLDB_LOGF(log, 5649dba64beSDimitry Andric "PlatformRemoteGDBServer::GetFilePermissions(path='%s', " 5650b57cec5SDimitry Andric "file_permissions=%o) error = %u (%s)", 566bdd1243dSDimitry Andric file_spec.GetPath().c_str(), file_permissions, error.GetError(), 5670b57cec5SDimitry Andric error.AsCString()); 5680b57cec5SDimitry Andric return error; 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric Status PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec, 5720b57cec5SDimitry Andric uint32_t file_permissions) { 57304eeddc0SDimitry Andric if (!IsConnected()) 57404eeddc0SDimitry Andric return Status("Not connected."); 57504eeddc0SDimitry Andric Status error = 57604eeddc0SDimitry Andric m_gdb_client_up->SetFilePermissions(file_spec, file_permissions); 57781ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Platform); 5789dba64beSDimitry Andric LLDB_LOGF(log, 5799dba64beSDimitry Andric "PlatformRemoteGDBServer::SetFilePermissions(path='%s', " 5800b57cec5SDimitry Andric "file_permissions=%o) error = %u (%s)", 581bdd1243dSDimitry Andric file_spec.GetPath().c_str(), file_permissions, error.GetError(), 5820b57cec5SDimitry Andric error.AsCString()); 5830b57cec5SDimitry Andric return error; 5840b57cec5SDimitry Andric } 5850b57cec5SDimitry Andric 5860b57cec5SDimitry Andric lldb::user_id_t PlatformRemoteGDBServer::OpenFile(const FileSpec &file_spec, 5879dba64beSDimitry Andric File::OpenOptions flags, 5889dba64beSDimitry Andric uint32_t mode, 5890b57cec5SDimitry Andric Status &error) { 59004eeddc0SDimitry Andric if (IsConnected()) 59104eeddc0SDimitry Andric return m_gdb_client_up->OpenFile(file_spec, flags, mode, error); 59204eeddc0SDimitry Andric return LLDB_INVALID_UID; 5930b57cec5SDimitry Andric } 5940b57cec5SDimitry Andric 5950b57cec5SDimitry Andric bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Status &error) { 59604eeddc0SDimitry Andric if (IsConnected()) 59704eeddc0SDimitry Andric return m_gdb_client_up->CloseFile(fd, error); 59804eeddc0SDimitry Andric error = Status("Not connected."); 59904eeddc0SDimitry Andric return false; 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric 6020b57cec5SDimitry Andric lldb::user_id_t 6030b57cec5SDimitry Andric PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) { 60404eeddc0SDimitry Andric if (IsConnected()) 60504eeddc0SDimitry Andric return m_gdb_client_up->GetFileSize(file_spec); 60604eeddc0SDimitry Andric return LLDB_INVALID_UID; 6070b57cec5SDimitry Andric } 6080b57cec5SDimitry Andric 609e8d8bef9SDimitry Andric void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory( 610e8d8bef9SDimitry Andric CompletionRequest &request, bool only_dir) { 61104eeddc0SDimitry Andric if (IsConnected()) 61204eeddc0SDimitry Andric m_gdb_client_up->AutoCompleteDiskFileOrDirectory(request, only_dir); 613e8d8bef9SDimitry Andric } 614e8d8bef9SDimitry Andric 6150b57cec5SDimitry Andric uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset, 6160b57cec5SDimitry Andric void *dst, uint64_t dst_len, 6170b57cec5SDimitry Andric Status &error) { 61804eeddc0SDimitry Andric if (IsConnected()) 61904eeddc0SDimitry Andric return m_gdb_client_up->ReadFile(fd, offset, dst, dst_len, error); 62004eeddc0SDimitry Andric error = Status("Not connected."); 62104eeddc0SDimitry Andric return 0; 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric uint64_t PlatformRemoteGDBServer::WriteFile(lldb::user_id_t fd, uint64_t offset, 6250b57cec5SDimitry Andric const void *src, uint64_t src_len, 6260b57cec5SDimitry Andric Status &error) { 62704eeddc0SDimitry Andric if (IsConnected()) 62804eeddc0SDimitry Andric return m_gdb_client_up->WriteFile(fd, offset, src, src_len, error); 62904eeddc0SDimitry Andric error = Status("Not connected."); 63004eeddc0SDimitry Andric return 0; 6310b57cec5SDimitry Andric } 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric Status PlatformRemoteGDBServer::PutFile(const FileSpec &source, 6340b57cec5SDimitry Andric const FileSpec &destination, 6350b57cec5SDimitry Andric uint32_t uid, uint32_t gid) { 6360b57cec5SDimitry Andric return Platform::PutFile(source, destination, uid, gid); 6370b57cec5SDimitry Andric } 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric Status PlatformRemoteGDBServer::CreateSymlink( 6400b57cec5SDimitry Andric const FileSpec &src, // The name of the link is in src 6410b57cec5SDimitry Andric const FileSpec &dst) // The symlink points to dst 6420b57cec5SDimitry Andric { 64304eeddc0SDimitry Andric if (!IsConnected()) 64404eeddc0SDimitry Andric return Status("Not connected."); 64504eeddc0SDimitry Andric Status error = m_gdb_client_up->CreateSymlink(src, dst); 64681ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Platform); 6479dba64beSDimitry Andric LLDB_LOGF(log, 6489dba64beSDimitry Andric "PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') " 6490b57cec5SDimitry Andric "error = %u (%s)", 650bdd1243dSDimitry Andric src.GetPath().c_str(), dst.GetPath().c_str(), error.GetError(), 6510b57cec5SDimitry Andric error.AsCString()); 6520b57cec5SDimitry Andric return error; 6530b57cec5SDimitry Andric } 6540b57cec5SDimitry Andric 6550b57cec5SDimitry Andric Status PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) { 65604eeddc0SDimitry Andric if (!IsConnected()) 65704eeddc0SDimitry Andric return Status("Not connected."); 65804eeddc0SDimitry Andric Status error = m_gdb_client_up->Unlink(file_spec); 65981ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Platform); 6609dba64beSDimitry Andric LLDB_LOGF(log, "PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)", 661bdd1243dSDimitry Andric file_spec.GetPath().c_str(), error.GetError(), error.AsCString()); 6620b57cec5SDimitry Andric return error; 6630b57cec5SDimitry Andric } 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) { 66604eeddc0SDimitry Andric if (IsConnected()) 66704eeddc0SDimitry Andric return m_gdb_client_up->GetFileExists(file_spec); 66804eeddc0SDimitry Andric return false; 6690b57cec5SDimitry Andric } 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric Status PlatformRemoteGDBServer::RunShellCommand( 672e8d8bef9SDimitry Andric llvm::StringRef shell, llvm::StringRef command, 6730b57cec5SDimitry Andric const FileSpec & 6740b57cec5SDimitry Andric working_dir, // Pass empty FileSpec to use the current working directory 6750b57cec5SDimitry Andric int *status_ptr, // Pass NULL if you don't want the process exit status 6760b57cec5SDimitry Andric int *signo_ptr, // Pass NULL if you don't want the signal that caused the 6770b57cec5SDimitry Andric // process to exit 6780b57cec5SDimitry Andric std::string 6790b57cec5SDimitry Andric *command_output, // Pass NULL if you don't want the command output 6800b57cec5SDimitry Andric const Timeout<std::micro> &timeout) { 68104eeddc0SDimitry Andric if (!IsConnected()) 68204eeddc0SDimitry Andric return Status("Not connected."); 68304eeddc0SDimitry Andric return m_gdb_client_up->RunShellCommand(command, working_dir, status_ptr, 6840b57cec5SDimitry Andric signo_ptr, command_output, timeout); 6850b57cec5SDimitry Andric } 6860b57cec5SDimitry Andric 687*0fca6ea1SDimitry Andric llvm::ErrorOr<llvm::MD5::MD5Result> 688*0fca6ea1SDimitry Andric PlatformRemoteGDBServer::CalculateMD5(const FileSpec &file_spec) { 689*0fca6ea1SDimitry Andric if (!IsConnected()) 690*0fca6ea1SDimitry Andric return std::make_error_code(std::errc::not_connected); 691*0fca6ea1SDimitry Andric 692*0fca6ea1SDimitry Andric return m_gdb_client_up->CalculateMD5(file_spec); 693*0fca6ea1SDimitry Andric } 694*0fca6ea1SDimitry Andric 6950b57cec5SDimitry Andric void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() { 6960b57cec5SDimitry Andric m_trap_handlers.push_back(ConstString("_sigtramp")); 6970b57cec5SDimitry Andric } 6980b57cec5SDimitry Andric 6990b57cec5SDimitry Andric const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() { 7000b57cec5SDimitry Andric if (!IsConnected()) 7010b57cec5SDimitry Andric return Platform::GetRemoteUnixSignals(); 7020b57cec5SDimitry Andric 7030b57cec5SDimitry Andric if (m_remote_signals_sp) 7040b57cec5SDimitry Andric return m_remote_signals_sp; 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric // If packet not implemented or JSON failed to parse, we'll guess the signal 7070b57cec5SDimitry Andric // set based on the remote architecture. 7080b57cec5SDimitry Andric m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture()); 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric StringExtractorGDBRemote response; 711fe6060f1SDimitry Andric auto result = 71204eeddc0SDimitry Andric m_gdb_client_up->SendPacketAndWaitForResponse("jSignalsInfo", response); 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric if (result != decltype(result)::Success || 7150b57cec5SDimitry Andric response.GetResponseType() != response.eResponse) 7160b57cec5SDimitry Andric return m_remote_signals_sp; 7170b57cec5SDimitry Andric 71806c3fb27SDimitry Andric auto object_sp = StructuredData::ParseJSON(response.GetStringRef()); 7190b57cec5SDimitry Andric if (!object_sp || !object_sp->IsValid()) 7200b57cec5SDimitry Andric return m_remote_signals_sp; 7210b57cec5SDimitry Andric 7220b57cec5SDimitry Andric auto array_sp = object_sp->GetAsArray(); 7230b57cec5SDimitry Andric if (!array_sp || !array_sp->IsValid()) 7240b57cec5SDimitry Andric return m_remote_signals_sp; 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>(); 7270b57cec5SDimitry Andric 7280b57cec5SDimitry Andric bool done = array_sp->ForEach( 7290b57cec5SDimitry Andric [&remote_signals_sp](StructuredData::Object *object) -> bool { 7300b57cec5SDimitry Andric if (!object || !object->IsValid()) 7310b57cec5SDimitry Andric return false; 7320b57cec5SDimitry Andric 7330b57cec5SDimitry Andric auto dict = object->GetAsDictionary(); 7340b57cec5SDimitry Andric if (!dict || !dict->IsValid()) 7350b57cec5SDimitry Andric return false; 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric // Signal number and signal name are required. 73806c3fb27SDimitry Andric uint64_t signo; 7390b57cec5SDimitry Andric if (!dict->GetValueForKeyAsInteger("signo", signo)) 7400b57cec5SDimitry Andric return false; 7410b57cec5SDimitry Andric 7420b57cec5SDimitry Andric llvm::StringRef name; 7430b57cec5SDimitry Andric if (!dict->GetValueForKeyAsString("name", name)) 7440b57cec5SDimitry Andric return false; 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric // We can live without short_name, description, etc. 7470b57cec5SDimitry Andric bool suppress{false}; 7480b57cec5SDimitry Andric auto object_sp = dict->GetValueForKey("suppress"); 7490b57cec5SDimitry Andric if (object_sp && object_sp->IsValid()) 7500b57cec5SDimitry Andric suppress = object_sp->GetBooleanValue(); 7510b57cec5SDimitry Andric 7520b57cec5SDimitry Andric bool stop{false}; 7530b57cec5SDimitry Andric object_sp = dict->GetValueForKey("stop"); 7540b57cec5SDimitry Andric if (object_sp && object_sp->IsValid()) 7550b57cec5SDimitry Andric stop = object_sp->GetBooleanValue(); 7560b57cec5SDimitry Andric 7570b57cec5SDimitry Andric bool notify{false}; 7580b57cec5SDimitry Andric object_sp = dict->GetValueForKey("notify"); 7590b57cec5SDimitry Andric if (object_sp && object_sp->IsValid()) 7600b57cec5SDimitry Andric notify = object_sp->GetBooleanValue(); 7610b57cec5SDimitry Andric 76204eeddc0SDimitry Andric std::string description; 7630b57cec5SDimitry Andric object_sp = dict->GetValueForKey("description"); 7640b57cec5SDimitry Andric if (object_sp && object_sp->IsValid()) 7655ffd83dbSDimitry Andric description = std::string(object_sp->GetStringValue()); 7660b57cec5SDimitry Andric 7675f757f3fSDimitry Andric llvm::StringRef name_backed, description_backed; 7685f757f3fSDimitry Andric { 7695f757f3fSDimitry Andric std::lock_guard<std::mutex> guard(g_signal_string_mutex); 7705f757f3fSDimitry Andric name_backed = 7715f757f3fSDimitry Andric g_signal_string_storage.insert(name).first->getKeyData(); 7725f757f3fSDimitry Andric if (!description.empty()) 7735f757f3fSDimitry Andric description_backed = 7745f757f3fSDimitry Andric g_signal_string_storage.insert(description).first->getKeyData(); 7755f757f3fSDimitry Andric } 7765f757f3fSDimitry Andric 7775f757f3fSDimitry Andric remote_signals_sp->AddSignal(signo, name_backed, suppress, stop, notify, 7785f757f3fSDimitry Andric description_backed); 7790b57cec5SDimitry Andric return true; 7800b57cec5SDimitry Andric }); 7810b57cec5SDimitry Andric 7820b57cec5SDimitry Andric if (done) 7830b57cec5SDimitry Andric m_remote_signals_sp = std::move(remote_signals_sp); 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric return m_remote_signals_sp; 7860b57cec5SDimitry Andric } 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric std::string PlatformRemoteGDBServer::MakeGdbServerUrl( 7890b57cec5SDimitry Andric const std::string &platform_scheme, const std::string &platform_hostname, 7900b57cec5SDimitry Andric uint16_t port, const char *socket_name) { 7910b57cec5SDimitry Andric const char *override_scheme = 7920b57cec5SDimitry Andric getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME"); 7930b57cec5SDimitry Andric const char *override_hostname = 7940b57cec5SDimitry Andric getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); 7950b57cec5SDimitry Andric const char *port_offset_c_str = 7960b57cec5SDimitry Andric getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); 7970b57cec5SDimitry Andric int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; 7980b57cec5SDimitry Andric 7990b57cec5SDimitry Andric return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(), 8000b57cec5SDimitry Andric override_hostname ? override_hostname 8010b57cec5SDimitry Andric : platform_hostname.c_str(), 8020b57cec5SDimitry Andric port + port_offset, socket_name); 8030b57cec5SDimitry Andric } 8040b57cec5SDimitry Andric 8050b57cec5SDimitry Andric std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme, 8060b57cec5SDimitry Andric const char *hostname, 8070b57cec5SDimitry Andric uint16_t port, const char *path) { 8080b57cec5SDimitry Andric StreamString result; 809e8d8bef9SDimitry Andric result.Printf("%s://[%s]", scheme, hostname); 8100b57cec5SDimitry Andric if (port != 0) 8110b57cec5SDimitry Andric result.Printf(":%u", port); 8120b57cec5SDimitry Andric if (path) 8130b57cec5SDimitry Andric result.Write(path, strlen(path)); 8145ffd83dbSDimitry Andric return std::string(result.GetString()); 8150b57cec5SDimitry Andric } 8160b57cec5SDimitry Andric 8170b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger, 8180b57cec5SDimitry Andric Status &error) { 8190b57cec5SDimitry Andric std::vector<std::string> connection_urls; 8200b57cec5SDimitry Andric GetPendingGdbServerList(connection_urls); 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric for (size_t i = 0; i < connection_urls.size(); ++i) { 823fe6060f1SDimitry Andric ConnectProcess(connection_urls[i].c_str(), "gdb-remote", debugger, nullptr, error); 8240b57cec5SDimitry Andric if (error.Fail()) 825bdd1243dSDimitry Andric return i; // We already connected to i process successfully 8260b57cec5SDimitry Andric } 8270b57cec5SDimitry Andric return connection_urls.size(); 8280b57cec5SDimitry Andric } 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::GetPendingGdbServerList( 8310b57cec5SDimitry Andric std::vector<std::string> &connection_urls) { 8320b57cec5SDimitry Andric std::vector<std::pair<uint16_t, std::string>> remote_servers; 83304eeddc0SDimitry Andric if (!IsConnected()) 83404eeddc0SDimitry Andric return 0; 83504eeddc0SDimitry Andric m_gdb_client_up->QueryGDBServer(remote_servers); 8360b57cec5SDimitry Andric for (const auto &gdbserver : remote_servers) { 8370b57cec5SDimitry Andric const char *socket_name_cstr = 8380b57cec5SDimitry Andric gdbserver.second.empty() ? nullptr : gdbserver.second.c_str(); 8390b57cec5SDimitry Andric connection_urls.emplace_back( 8400b57cec5SDimitry Andric MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, 8410b57cec5SDimitry Andric gdbserver.first, socket_name_cstr)); 8420b57cec5SDimitry Andric } 8430b57cec5SDimitry Andric return connection_urls.size(); 8440b57cec5SDimitry Andric } 845