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 
Initialize()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 
Terminate()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 
CreateInstance(bool force,const ArchSpec * arch)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 
GetDescriptionStatic()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 
GetDescription()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 
GetModuleSpec(const FileSpec & module_file_spec,const ArchSpec & arch,ModuleSpec & module_spec)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 
GetFileWithUUID(const FileSpec & platform_file,const UUID * uuid_ptr,FileSpec & local_file)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
PlatformRemoteGDBServer()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 
GetSoftwareBreakpointTrapOpcode(Target & target,BreakpointSite * bp_site)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 
GetRemoteOSVersion()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 
GetRemoteOSBuildString()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>
GetRemoteOSKernelDescription()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
GetRemoteSystemArchitecture()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 
GetRemoteWorkingDirectory()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 
SetRemoteWorkingDirectory(const FileSpec & working_dir)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 
IsConnected() const2080b57cec5SDimitry 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 
ConnectRemote(Args & args)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 
DisconnectRemote()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 
GetHostname()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>
DoGetUserName(UserIDResolver::id_t uid)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>
DoGetGroupName(UserIDResolver::id_t gid)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 
FindProcesses(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)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 
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)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 
LaunchProcess(ProcessLaunchInfo & launch_info)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 
KillProcess(const lldb::pid_t pid)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
DebugProcess(ProcessLaunchInfo & launch_info,Debugger & debugger,Target & target,Status & error)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 
LaunchGDBServer(lldb::pid_t & pid,std::string & connect_url)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 
KillSpawnedProcess(lldb::pid_t pid)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 
Attach(ProcessAttachInfo & attach_info,Debugger & debugger,Target * target,Status & error)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 
MakeDirectory(const FileSpec & file_spec,uint32_t mode)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 
GetFilePermissions(const FileSpec & file_spec,uint32_t & file_permissions)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 
SetFilePermissions(const FileSpec & file_spec,uint32_t file_permissions)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 
OpenFile(const FileSpec & file_spec,File::OpenOptions flags,uint32_t mode,Status & error)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 
CloseFile(lldb::user_id_t fd,Status & error)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
GetFileSize(const FileSpec & file_spec)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 
AutoCompleteDiskFileOrDirectory(CompletionRequest & request,bool only_dir)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 
ReadFile(lldb::user_id_t fd,uint64_t offset,void * dst,uint64_t dst_len,Status & error)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 
WriteFile(lldb::user_id_t fd,uint64_t offset,const void * src,uint64_t src_len,Status & error)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 
PutFile(const FileSpec & source,const FileSpec & destination,uint32_t uid,uint32_t gid)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 
CreateSymlink(const FileSpec & src,const FileSpec & dst)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 
Unlink(const FileSpec & file_spec)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 
GetFileExists(const FileSpec & file_spec)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 
RunShellCommand(llvm::StringRef shell,llvm::StringRef command,const FileSpec & working_dir,int * status_ptr,int * signo_ptr,std::string * command_output,const Timeout<std::micro> & timeout)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 
CalculateTrapHandlerSymbolNames()6870b57cec5SDimitry Andric void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() {
6880b57cec5SDimitry Andric   m_trap_handlers.push_back(ConstString("_sigtramp"));
6890b57cec5SDimitry Andric }
6900b57cec5SDimitry Andric 
GetRemoteUnixSignals()6910b57cec5SDimitry Andric const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() {
6920b57cec5SDimitry Andric   if (!IsConnected())
6930b57cec5SDimitry Andric     return Platform::GetRemoteUnixSignals();
6940b57cec5SDimitry Andric 
6950b57cec5SDimitry Andric   if (m_remote_signals_sp)
6960b57cec5SDimitry Andric     return m_remote_signals_sp;
6970b57cec5SDimitry Andric 
6980b57cec5SDimitry Andric   // If packet not implemented or JSON failed to parse, we'll guess the signal
6990b57cec5SDimitry Andric   // set based on the remote architecture.
7000b57cec5SDimitry Andric   m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture());
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric   StringExtractorGDBRemote response;
703fe6060f1SDimitry Andric   auto result =
70404eeddc0SDimitry Andric       m_gdb_client_up->SendPacketAndWaitForResponse("jSignalsInfo", response);
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric   if (result != decltype(result)::Success ||
7070b57cec5SDimitry Andric       response.GetResponseType() != response.eResponse)
7080b57cec5SDimitry Andric     return m_remote_signals_sp;
7090b57cec5SDimitry Andric 
71006c3fb27SDimitry Andric   auto object_sp = StructuredData::ParseJSON(response.GetStringRef());
7110b57cec5SDimitry Andric   if (!object_sp || !object_sp->IsValid())
7120b57cec5SDimitry Andric     return m_remote_signals_sp;
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric   auto array_sp = object_sp->GetAsArray();
7150b57cec5SDimitry Andric   if (!array_sp || !array_sp->IsValid())
7160b57cec5SDimitry Andric     return m_remote_signals_sp;
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric   auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>();
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric   bool done = array_sp->ForEach(
7210b57cec5SDimitry Andric       [&remote_signals_sp](StructuredData::Object *object) -> bool {
7220b57cec5SDimitry Andric         if (!object || !object->IsValid())
7230b57cec5SDimitry Andric           return false;
7240b57cec5SDimitry Andric 
7250b57cec5SDimitry Andric         auto dict = object->GetAsDictionary();
7260b57cec5SDimitry Andric         if (!dict || !dict->IsValid())
7270b57cec5SDimitry Andric           return false;
7280b57cec5SDimitry Andric 
7290b57cec5SDimitry Andric         // Signal number and signal name are required.
73006c3fb27SDimitry Andric         uint64_t signo;
7310b57cec5SDimitry Andric         if (!dict->GetValueForKeyAsInteger("signo", signo))
7320b57cec5SDimitry Andric           return false;
7330b57cec5SDimitry Andric 
7340b57cec5SDimitry Andric         llvm::StringRef name;
7350b57cec5SDimitry Andric         if (!dict->GetValueForKeyAsString("name", name))
7360b57cec5SDimitry Andric           return false;
7370b57cec5SDimitry Andric 
7380b57cec5SDimitry Andric         // We can live without short_name, description, etc.
7390b57cec5SDimitry Andric         bool suppress{false};
7400b57cec5SDimitry Andric         auto object_sp = dict->GetValueForKey("suppress");
7410b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7420b57cec5SDimitry Andric           suppress = object_sp->GetBooleanValue();
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric         bool stop{false};
7450b57cec5SDimitry Andric         object_sp = dict->GetValueForKey("stop");
7460b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7470b57cec5SDimitry Andric           stop = object_sp->GetBooleanValue();
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric         bool notify{false};
7500b57cec5SDimitry Andric         object_sp = dict->GetValueForKey("notify");
7510b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7520b57cec5SDimitry Andric           notify = object_sp->GetBooleanValue();
7530b57cec5SDimitry Andric 
75404eeddc0SDimitry Andric         std::string description;
7550b57cec5SDimitry Andric         object_sp = dict->GetValueForKey("description");
7560b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7575ffd83dbSDimitry Andric           description = std::string(object_sp->GetStringValue());
7580b57cec5SDimitry Andric 
7595f757f3fSDimitry Andric         llvm::StringRef name_backed, description_backed;
7605f757f3fSDimitry Andric         {
7615f757f3fSDimitry Andric           std::lock_guard<std::mutex> guard(g_signal_string_mutex);
7625f757f3fSDimitry Andric           name_backed =
7635f757f3fSDimitry Andric               g_signal_string_storage.insert(name).first->getKeyData();
7645f757f3fSDimitry Andric           if (!description.empty())
7655f757f3fSDimitry Andric             description_backed =
7665f757f3fSDimitry Andric                 g_signal_string_storage.insert(description).first->getKeyData();
7675f757f3fSDimitry Andric         }
7685f757f3fSDimitry Andric 
7695f757f3fSDimitry Andric         remote_signals_sp->AddSignal(signo, name_backed, suppress, stop, notify,
7705f757f3fSDimitry Andric                                      description_backed);
7710b57cec5SDimitry Andric         return true;
7720b57cec5SDimitry Andric       });
7730b57cec5SDimitry Andric 
7740b57cec5SDimitry Andric   if (done)
7750b57cec5SDimitry Andric     m_remote_signals_sp = std::move(remote_signals_sp);
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric   return m_remote_signals_sp;
7780b57cec5SDimitry Andric }
7790b57cec5SDimitry Andric 
MakeGdbServerUrl(const std::string & platform_scheme,const std::string & platform_hostname,uint16_t port,const char * socket_name)7800b57cec5SDimitry Andric std::string PlatformRemoteGDBServer::MakeGdbServerUrl(
7810b57cec5SDimitry Andric     const std::string &platform_scheme, const std::string &platform_hostname,
7820b57cec5SDimitry Andric     uint16_t port, const char *socket_name) {
7830b57cec5SDimitry Andric   const char *override_scheme =
7840b57cec5SDimitry Andric       getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME");
7850b57cec5SDimitry Andric   const char *override_hostname =
7860b57cec5SDimitry Andric       getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
7870b57cec5SDimitry Andric   const char *port_offset_c_str =
7880b57cec5SDimitry Andric       getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
7890b57cec5SDimitry Andric   int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
7900b57cec5SDimitry Andric 
7910b57cec5SDimitry Andric   return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(),
7920b57cec5SDimitry Andric                  override_hostname ? override_hostname
7930b57cec5SDimitry Andric                                    : platform_hostname.c_str(),
7940b57cec5SDimitry Andric                  port + port_offset, socket_name);
7950b57cec5SDimitry Andric }
7960b57cec5SDimitry Andric 
MakeUrl(const char * scheme,const char * hostname,uint16_t port,const char * path)7970b57cec5SDimitry Andric std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme,
7980b57cec5SDimitry Andric                                              const char *hostname,
7990b57cec5SDimitry Andric                                              uint16_t port, const char *path) {
8000b57cec5SDimitry Andric   StreamString result;
801e8d8bef9SDimitry Andric   result.Printf("%s://[%s]", scheme, hostname);
8020b57cec5SDimitry Andric   if (port != 0)
8030b57cec5SDimitry Andric     result.Printf(":%u", port);
8040b57cec5SDimitry Andric   if (path)
8050b57cec5SDimitry Andric     result.Write(path, strlen(path));
8065ffd83dbSDimitry Andric   return std::string(result.GetString());
8070b57cec5SDimitry Andric }
8080b57cec5SDimitry Andric 
ConnectToWaitingProcesses(Debugger & debugger,Status & error)8090b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger,
8100b57cec5SDimitry Andric                                                           Status &error) {
8110b57cec5SDimitry Andric   std::vector<std::string> connection_urls;
8120b57cec5SDimitry Andric   GetPendingGdbServerList(connection_urls);
8130b57cec5SDimitry Andric 
8140b57cec5SDimitry Andric   for (size_t i = 0; i < connection_urls.size(); ++i) {
815fe6060f1SDimitry Andric     ConnectProcess(connection_urls[i].c_str(), "gdb-remote", debugger, nullptr, error);
8160b57cec5SDimitry Andric     if (error.Fail())
817bdd1243dSDimitry Andric       return i; // We already connected to i process successfully
8180b57cec5SDimitry Andric   }
8190b57cec5SDimitry Andric   return connection_urls.size();
8200b57cec5SDimitry Andric }
8210b57cec5SDimitry Andric 
GetPendingGdbServerList(std::vector<std::string> & connection_urls)8220b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::GetPendingGdbServerList(
8230b57cec5SDimitry Andric     std::vector<std::string> &connection_urls) {
8240b57cec5SDimitry Andric   std::vector<std::pair<uint16_t, std::string>> remote_servers;
82504eeddc0SDimitry Andric   if (!IsConnected())
82604eeddc0SDimitry Andric     return 0;
82704eeddc0SDimitry Andric   m_gdb_client_up->QueryGDBServer(remote_servers);
8280b57cec5SDimitry Andric   for (const auto &gdbserver : remote_servers) {
8290b57cec5SDimitry Andric     const char *socket_name_cstr =
8300b57cec5SDimitry Andric         gdbserver.second.empty() ? nullptr : gdbserver.second.c_str();
8310b57cec5SDimitry Andric     connection_urls.emplace_back(
8320b57cec5SDimitry Andric         MakeGdbServerUrl(m_platform_scheme, m_platform_hostname,
8330b57cec5SDimitry Andric                          gdbserver.first, socket_name_cstr));
8340b57cec5SDimitry Andric   }
8350b57cec5SDimitry Andric   return connection_urls.size();
8360b57cec5SDimitry Andric }
837