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/Core/StreamFile.h"
190b57cec5SDimitry Andric #include "lldb/Host/ConnectionFileDescriptor.h"
200b57cec5SDimitry Andric #include "lldb/Host/Host.h"
210b57cec5SDimitry Andric #include "lldb/Host/HostInfo.h"
220b57cec5SDimitry Andric #include "lldb/Host/PosixApi.h"
230b57cec5SDimitry Andric #include "lldb/Target/Process.h"
240b57cec5SDimitry Andric #include "lldb/Target/Target.h"
250b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.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"
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric #include "Plugins/Process/Utility/GDBRemoteSignals.h"
33fe6060f1SDimitry Andric #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric using namespace lldb;
360b57cec5SDimitry Andric using namespace lldb_private;
370b57cec5SDimitry Andric using namespace lldb_private::platform_gdb_server;
380b57cec5SDimitry Andric 
395ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteGDBServer, PlatformGDB)
405ffd83dbSDimitry Andric 
410b57cec5SDimitry Andric static bool g_initialized = false;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric void PlatformRemoteGDBServer::Initialize() {
440b57cec5SDimitry Andric   Platform::Initialize();
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   if (!g_initialized) {
470b57cec5SDimitry Andric     g_initialized = true;
480b57cec5SDimitry Andric     PluginManager::RegisterPlugin(
490b57cec5SDimitry Andric         PlatformRemoteGDBServer::GetPluginNameStatic(),
500b57cec5SDimitry Andric         PlatformRemoteGDBServer::GetDescriptionStatic(),
510b57cec5SDimitry Andric         PlatformRemoteGDBServer::CreateInstance);
520b57cec5SDimitry Andric   }
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric void PlatformRemoteGDBServer::Terminate() {
560b57cec5SDimitry Andric   if (g_initialized) {
570b57cec5SDimitry Andric     g_initialized = false;
580b57cec5SDimitry Andric     PluginManager::UnregisterPlugin(PlatformRemoteGDBServer::CreateInstance);
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   Platform::Terminate();
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric PlatformSP PlatformRemoteGDBServer::CreateInstance(bool force,
650b57cec5SDimitry Andric                                                    const ArchSpec *arch) {
660b57cec5SDimitry Andric   bool create = force;
670b57cec5SDimitry Andric   if (!create) {
680b57cec5SDimitry Andric     create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified();
690b57cec5SDimitry Andric   }
700b57cec5SDimitry Andric   if (create)
710b57cec5SDimitry Andric     return PlatformSP(new PlatformRemoteGDBServer());
720b57cec5SDimitry Andric   return PlatformSP();
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric 
75349cc55cSDimitry Andric llvm::StringRef PlatformRemoteGDBServer::GetDescriptionStatic() {
760b57cec5SDimitry Andric   return "A platform that uses the GDB remote protocol as the communication "
770b57cec5SDimitry Andric          "transport.";
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
80349cc55cSDimitry Andric llvm::StringRef PlatformRemoteGDBServer::GetDescription() {
810b57cec5SDimitry Andric   if (m_platform_description.empty()) {
820b57cec5SDimitry Andric     if (IsConnected()) {
830b57cec5SDimitry Andric       // Send the get description packet
840b57cec5SDimitry Andric     }
850b57cec5SDimitry Andric   }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   if (!m_platform_description.empty())
880b57cec5SDimitry Andric     return m_platform_description.c_str();
890b57cec5SDimitry Andric   return GetDescriptionStatic();
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetModuleSpec(const FileSpec &module_file_spec,
930b57cec5SDimitry Andric                                             const ArchSpec &arch,
940b57cec5SDimitry Andric                                             ModuleSpec &module_spec) {
950b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   const auto module_path = module_file_spec.GetPath(false);
980b57cec5SDimitry Andric 
9904eeddc0SDimitry Andric   if (!m_gdb_client_up ||
10004eeddc0SDimitry Andric       !m_gdb_client_up->GetModuleInfo(module_file_spec, arch, module_spec)) {
1019dba64beSDimitry Andric     LLDB_LOGF(
1029dba64beSDimitry Andric         log,
1030b57cec5SDimitry Andric         "PlatformRemoteGDBServer::%s - failed to get module info for %s:%s",
1040b57cec5SDimitry Andric         __FUNCTION__, module_path.c_str(),
1050b57cec5SDimitry Andric         arch.GetTriple().getTriple().c_str());
1060b57cec5SDimitry Andric     return false;
1070b57cec5SDimitry Andric   }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   if (log) {
1100b57cec5SDimitry Andric     StreamString stream;
1110b57cec5SDimitry Andric     module_spec.Dump(stream);
1129dba64beSDimitry Andric     LLDB_LOGF(log,
1130b57cec5SDimitry Andric               "PlatformRemoteGDBServer::%s - got module info for (%s:%s) : %s",
1149dba64beSDimitry Andric               __FUNCTION__, module_path.c_str(),
1159dba64beSDimitry Andric               arch.GetTriple().getTriple().c_str(), stream.GetData());
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   return true;
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric Status PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file,
1220b57cec5SDimitry Andric                                                 const UUID *uuid_ptr,
1230b57cec5SDimitry Andric                                                 FileSpec &local_file) {
1240b57cec5SDimitry Andric   // Default to the local case
1250b57cec5SDimitry Andric   local_file = platform_file;
1260b57cec5SDimitry Andric   return Status();
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric /// Default Constructor
1300b57cec5SDimitry Andric PlatformRemoteGDBServer::PlatformRemoteGDBServer()
13104eeddc0SDimitry Andric     : Platform(/*is_host=*/false) {}
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric /// Destructor.
1340b57cec5SDimitry Andric ///
1350b57cec5SDimitry Andric /// The destructor is virtual since this class is designed to be
1360b57cec5SDimitry Andric /// inherited from by the plug-in instance.
137fe6060f1SDimitry Andric PlatformRemoteGDBServer::~PlatformRemoteGDBServer() = default;
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode(
1400b57cec5SDimitry Andric     Target &target, BreakpointSite *bp_site) {
1410b57cec5SDimitry Andric   // This isn't needed if the z/Z packets are supported in the GDB remote
1420b57cec5SDimitry Andric   // server. But we might need a packet to detect this.
1430b57cec5SDimitry Andric   return 0;
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetRemoteOSVersion() {
14704eeddc0SDimitry Andric   if (m_gdb_client_up)
14804eeddc0SDimitry Andric     m_os_version = m_gdb_client_up->GetOSVersion();
1490b57cec5SDimitry Andric   return !m_os_version.empty();
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
152349cc55cSDimitry Andric llvm::Optional<std::string> PlatformRemoteGDBServer::GetRemoteOSBuildString() {
15304eeddc0SDimitry Andric   if (!m_gdb_client_up)
15404eeddc0SDimitry Andric     return llvm::None;
15504eeddc0SDimitry Andric   return m_gdb_client_up->GetOSBuildString();
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
158349cc55cSDimitry Andric llvm::Optional<std::string>
159349cc55cSDimitry Andric PlatformRemoteGDBServer::GetRemoteOSKernelDescription() {
16004eeddc0SDimitry Andric   if (!m_gdb_client_up)
16104eeddc0SDimitry Andric     return llvm::None;
16204eeddc0SDimitry Andric   return m_gdb_client_up->GetOSKernelDescription();
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric // Remote Platform subclasses need to override this function
1660b57cec5SDimitry Andric ArchSpec PlatformRemoteGDBServer::GetRemoteSystemArchitecture() {
16704eeddc0SDimitry Andric   if (!m_gdb_client_up)
16804eeddc0SDimitry Andric     return ArchSpec();
16904eeddc0SDimitry Andric   return m_gdb_client_up->GetSystemArchitecture();
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric FileSpec PlatformRemoteGDBServer::GetRemoteWorkingDirectory() {
1730b57cec5SDimitry Andric   if (IsConnected()) {
1740b57cec5SDimitry Andric     Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
1750b57cec5SDimitry Andric     FileSpec working_dir;
17604eeddc0SDimitry Andric     if (m_gdb_client_up->GetWorkingDir(working_dir) && log)
1779dba64beSDimitry Andric       LLDB_LOGF(log,
1780b57cec5SDimitry Andric                 "PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'",
1790b57cec5SDimitry Andric                 working_dir.GetCString());
1800b57cec5SDimitry Andric     return working_dir;
1810b57cec5SDimitry Andric   } else {
1820b57cec5SDimitry Andric     return Platform::GetRemoteWorkingDirectory();
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric bool PlatformRemoteGDBServer::SetRemoteWorkingDirectory(
1870b57cec5SDimitry Andric     const FileSpec &working_dir) {
1880b57cec5SDimitry Andric   if (IsConnected()) {
1890b57cec5SDimitry Andric     // Clear the working directory it case it doesn't get set correctly. This
1900b57cec5SDimitry Andric     // will for use to re-read it
1910b57cec5SDimitry Andric     Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
1929dba64beSDimitry Andric     LLDB_LOGF(log, "PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')",
1930b57cec5SDimitry Andric               working_dir.GetCString());
19404eeddc0SDimitry Andric     return m_gdb_client_up->SetWorkingDir(working_dir) == 0;
1950b57cec5SDimitry Andric   } else
1960b57cec5SDimitry Andric     return Platform::SetRemoteWorkingDirectory(working_dir);
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric bool PlatformRemoteGDBServer::IsConnected() const {
20004eeddc0SDimitry Andric   if (m_gdb_client_up) {
20104eeddc0SDimitry Andric     assert(m_gdb_client_up->IsConnected());
20204eeddc0SDimitry Andric     return true;
20304eeddc0SDimitry Andric   }
20404eeddc0SDimitry Andric   return false;
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric Status PlatformRemoteGDBServer::ConnectRemote(Args &args) {
2080b57cec5SDimitry Andric   Status error;
2090b57cec5SDimitry Andric   if (IsConnected()) {
2100b57cec5SDimitry Andric     error.SetErrorStringWithFormat("the platform is already connected to '%s', "
2110b57cec5SDimitry Andric                                    "execute 'platform disconnect' to close the "
2120b57cec5SDimitry Andric                                    "current connection",
2130b57cec5SDimitry Andric                                    GetHostname());
2145ffd83dbSDimitry Andric     return error;
2155ffd83dbSDimitry Andric   }
2165ffd83dbSDimitry Andric 
2175ffd83dbSDimitry Andric   if (args.GetArgumentCount() != 1) {
2185ffd83dbSDimitry Andric     error.SetErrorString(
2195ffd83dbSDimitry Andric         "\"platform connect\" takes a single argument: <connect-url>");
2205ffd83dbSDimitry Andric     return error;
2215ffd83dbSDimitry Andric   }
2225ffd83dbSDimitry Andric 
2230b57cec5SDimitry Andric   const char *url = args.GetArgumentAtIndex(0);
2240b57cec5SDimitry Andric   if (!url)
2250b57cec5SDimitry Andric     return Status("URL is null.");
2265ffd83dbSDimitry Andric 
227349cc55cSDimitry Andric   llvm::Optional<URI> parsed_url = URI::Parse(url);
228349cc55cSDimitry Andric   if (!parsed_url)
2290b57cec5SDimitry Andric     return Status("Invalid URL: %s", url);
2300b57cec5SDimitry Andric 
2315ffd83dbSDimitry Andric   // We're going to reuse the hostname when we connect to the debugserver.
232349cc55cSDimitry Andric   m_platform_scheme = parsed_url->scheme.str();
233349cc55cSDimitry Andric   m_platform_hostname = parsed_url->hostname.str();
2345ffd83dbSDimitry Andric 
23504eeddc0SDimitry Andric   auto client_up =
23604eeddc0SDimitry Andric       std::make_unique<process_gdb_remote::GDBRemoteCommunicationClient>();
23704eeddc0SDimitry Andric   client_up->SetPacketTimeout(
23804eeddc0SDimitry Andric       process_gdb_remote::ProcessGDBRemote::GetPacketTimeout());
23904eeddc0SDimitry Andric   client_up->SetConnection(std::make_unique<ConnectionFileDescriptor>());
2405ffd83dbSDimitry Andric   if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
2415ffd83dbSDimitry Andric     repro::GDBRemoteProvider &provider =
2425ffd83dbSDimitry Andric         g->GetOrCreate<repro::GDBRemoteProvider>();
24304eeddc0SDimitry Andric     client_up->SetPacketRecorder(provider.GetNewPacketRecorder());
2445ffd83dbSDimitry Andric   }
24504eeddc0SDimitry Andric   client_up->Connect(url, &error);
2465ffd83dbSDimitry Andric 
2475ffd83dbSDimitry Andric   if (error.Fail())
2485ffd83dbSDimitry Andric     return error;
2495ffd83dbSDimitry Andric 
25004eeddc0SDimitry Andric   if (client_up->HandshakeWithServer(&error)) {
25104eeddc0SDimitry Andric     m_gdb_client_up = std::move(client_up);
25204eeddc0SDimitry Andric     m_gdb_client_up->GetHostInfo();
2530b57cec5SDimitry Andric     // If a working directory was set prior to connecting, send it down
2545ffd83dbSDimitry Andric     // now.
2550b57cec5SDimitry Andric     if (m_working_dir)
25604eeddc0SDimitry Andric       m_gdb_client_up->SetWorkingDir(m_working_dir);
257349cc55cSDimitry Andric 
258349cc55cSDimitry Andric     m_supported_architectures.clear();
25904eeddc0SDimitry Andric     ArchSpec remote_arch = m_gdb_client_up->GetSystemArchitecture();
260349cc55cSDimitry Andric     if (remote_arch) {
261349cc55cSDimitry Andric       m_supported_architectures.push_back(remote_arch);
262349cc55cSDimitry Andric       if (remote_arch.GetTriple().isArch64Bit())
263349cc55cSDimitry Andric         m_supported_architectures.push_back(
264349cc55cSDimitry Andric             ArchSpec(remote_arch.GetTriple().get32BitArchVariant()));
265349cc55cSDimitry Andric     }
2660b57cec5SDimitry Andric   } else {
26704eeddc0SDimitry Andric     client_up->Disconnect();
2680b57cec5SDimitry Andric     if (error.Success())
2690b57cec5SDimitry Andric       error.SetErrorString("handshake failed");
2700b57cec5SDimitry Andric   }
2710b57cec5SDimitry Andric   return error;
2720b57cec5SDimitry Andric }
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric Status PlatformRemoteGDBServer::DisconnectRemote() {
2750b57cec5SDimitry Andric   Status error;
27604eeddc0SDimitry Andric   m_gdb_client_up.reset();
2770b57cec5SDimitry Andric   m_remote_signals_sp.reset();
2780b57cec5SDimitry Andric   return error;
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric const char *PlatformRemoteGDBServer::GetHostname() {
28204eeddc0SDimitry Andric   if (m_gdb_client_up)
28304eeddc0SDimitry Andric     m_gdb_client_up->GetHostname(m_name);
2840b57cec5SDimitry Andric   if (m_name.empty())
2850b57cec5SDimitry Andric     return nullptr;
2860b57cec5SDimitry Andric   return m_name.c_str();
2870b57cec5SDimitry Andric }
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric llvm::Optional<std::string>
2900b57cec5SDimitry Andric PlatformRemoteGDBServer::DoGetUserName(UserIDResolver::id_t uid) {
2910b57cec5SDimitry Andric   std::string name;
29204eeddc0SDimitry Andric   if (m_gdb_client_up && m_gdb_client_up->GetUserName(uid, name))
2930b57cec5SDimitry Andric     return std::move(name);
2940b57cec5SDimitry Andric   return llvm::None;
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric llvm::Optional<std::string>
2980b57cec5SDimitry Andric PlatformRemoteGDBServer::DoGetGroupName(UserIDResolver::id_t gid) {
2990b57cec5SDimitry Andric   std::string name;
30004eeddc0SDimitry Andric   if (m_gdb_client_up && m_gdb_client_up->GetGroupName(gid, name))
3010b57cec5SDimitry Andric     return std::move(name);
3020b57cec5SDimitry Andric   return llvm::None;
3030b57cec5SDimitry Andric }
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric uint32_t PlatformRemoteGDBServer::FindProcesses(
3060b57cec5SDimitry Andric     const ProcessInstanceInfoMatch &match_info,
3070b57cec5SDimitry Andric     ProcessInstanceInfoList &process_infos) {
30804eeddc0SDimitry Andric   if (m_gdb_client_up)
30904eeddc0SDimitry Andric     return m_gdb_client_up->FindProcesses(match_info, process_infos);
31004eeddc0SDimitry Andric   return 0;
3110b57cec5SDimitry Andric }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetProcessInfo(
3140b57cec5SDimitry Andric     lldb::pid_t pid, ProcessInstanceInfo &process_info) {
31504eeddc0SDimitry Andric   if (m_gdb_client_up)
31604eeddc0SDimitry Andric     return m_gdb_client_up->GetProcessInfo(pid, process_info);
31704eeddc0SDimitry Andric   return false;
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) {
3210b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
3220b57cec5SDimitry Andric   Status error;
3230b57cec5SDimitry Andric 
3249dba64beSDimitry Andric   LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() called", __FUNCTION__);
3250b57cec5SDimitry Andric 
32604eeddc0SDimitry Andric   if (!IsConnected())
32704eeddc0SDimitry Andric     return Status("Not connected.");
3280b57cec5SDimitry Andric   auto num_file_actions = launch_info.GetNumFileActions();
3290b57cec5SDimitry Andric   for (decltype(num_file_actions) i = 0; i < num_file_actions; ++i) {
3300b57cec5SDimitry Andric     const auto file_action = launch_info.GetFileActionAtIndex(i);
3310b57cec5SDimitry Andric     if (file_action->GetAction() != FileAction::eFileActionOpen)
3320b57cec5SDimitry Andric       continue;
3330b57cec5SDimitry Andric     switch (file_action->GetFD()) {
3340b57cec5SDimitry Andric     case STDIN_FILENO:
33504eeddc0SDimitry Andric       m_gdb_client_up->SetSTDIN(file_action->GetFileSpec());
3360b57cec5SDimitry Andric       break;
3370b57cec5SDimitry Andric     case STDOUT_FILENO:
33804eeddc0SDimitry Andric       m_gdb_client_up->SetSTDOUT(file_action->GetFileSpec());
3390b57cec5SDimitry Andric       break;
3400b57cec5SDimitry Andric     case STDERR_FILENO:
34104eeddc0SDimitry Andric       m_gdb_client_up->SetSTDERR(file_action->GetFileSpec());
3420b57cec5SDimitry Andric       break;
3430b57cec5SDimitry Andric     }
3440b57cec5SDimitry Andric   }
3450b57cec5SDimitry Andric 
34604eeddc0SDimitry Andric   m_gdb_client_up->SetDisableASLR(
3470b57cec5SDimitry Andric       launch_info.GetFlags().Test(eLaunchFlagDisableASLR));
34804eeddc0SDimitry Andric   m_gdb_client_up->SetDetachOnError(
3490b57cec5SDimitry Andric       launch_info.GetFlags().Test(eLaunchFlagDetachOnError));
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric   FileSpec working_dir = launch_info.GetWorkingDirectory();
3520b57cec5SDimitry Andric   if (working_dir) {
35304eeddc0SDimitry Andric     m_gdb_client_up->SetWorkingDir(working_dir);
3540b57cec5SDimitry Andric   }
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric   // Send the environment and the program + arguments after we connect
35704eeddc0SDimitry Andric   m_gdb_client_up->SendEnvironment(launch_info.GetEnvironment());
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   ArchSpec arch_spec = launch_info.GetArchitecture();
3600b57cec5SDimitry Andric   const char *arch_triple = arch_spec.GetTriple().str().c_str();
3610b57cec5SDimitry Andric 
36204eeddc0SDimitry Andric   m_gdb_client_up->SendLaunchArchPacket(arch_triple);
3639dba64beSDimitry Andric   LLDB_LOGF(
3649dba64beSDimitry Andric       log,
3650b57cec5SDimitry Andric       "PlatformRemoteGDBServer::%s() set launch architecture triple to '%s'",
3660b57cec5SDimitry Andric       __FUNCTION__, arch_triple ? arch_triple : "<NULL>");
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   int arg_packet_err;
3690b57cec5SDimitry Andric   {
3700b57cec5SDimitry Andric     // Scope for the scoped timeout object
3710b57cec5SDimitry Andric     process_gdb_remote::GDBRemoteCommunication::ScopedTimeout timeout(
37204eeddc0SDimitry Andric         *m_gdb_client_up, std::chrono::seconds(5));
37304eeddc0SDimitry Andric     arg_packet_err = m_gdb_client_up->SendArgumentsPacket(launch_info);
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric   if (arg_packet_err == 0) {
3770b57cec5SDimitry Andric     std::string error_str;
37804eeddc0SDimitry Andric     if (m_gdb_client_up->GetLaunchSuccess(error_str)) {
37904eeddc0SDimitry Andric       const auto pid = m_gdb_client_up->GetCurrentProcessID(false);
3800b57cec5SDimitry Andric       if (pid != LLDB_INVALID_PROCESS_ID) {
3810b57cec5SDimitry Andric         launch_info.SetProcessID(pid);
3829dba64beSDimitry Andric         LLDB_LOGF(log,
3839dba64beSDimitry Andric                   "PlatformRemoteGDBServer::%s() pid %" PRIu64
3840b57cec5SDimitry Andric                   " launched successfully",
3850b57cec5SDimitry Andric                   __FUNCTION__, pid);
3860b57cec5SDimitry Andric       } else {
3879dba64beSDimitry Andric         LLDB_LOGF(log,
3889dba64beSDimitry Andric                   "PlatformRemoteGDBServer::%s() launch succeeded but we "
3890b57cec5SDimitry Andric                   "didn't get a valid process id back!",
3900b57cec5SDimitry Andric                   __FUNCTION__);
3910b57cec5SDimitry Andric         error.SetErrorString("failed to get PID");
3920b57cec5SDimitry Andric       }
3930b57cec5SDimitry Andric     } else {
3940b57cec5SDimitry Andric       error.SetErrorString(error_str.c_str());
3959dba64beSDimitry Andric       LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() launch failed: %s",
3960b57cec5SDimitry Andric                 __FUNCTION__, error.AsCString());
3970b57cec5SDimitry Andric     }
3980b57cec5SDimitry Andric   } else {
3990b57cec5SDimitry Andric     error.SetErrorStringWithFormat("'A' packet returned an error: %i",
4000b57cec5SDimitry Andric                                    arg_packet_err);
4010b57cec5SDimitry Andric   }
4020b57cec5SDimitry Andric   return error;
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric Status PlatformRemoteGDBServer::KillProcess(const lldb::pid_t pid) {
4060b57cec5SDimitry Andric   if (!KillSpawnedProcess(pid))
4070b57cec5SDimitry Andric     return Status("failed to kill remote spawned process");
4080b57cec5SDimitry Andric   return Status();
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric 
411349cc55cSDimitry Andric lldb::ProcessSP
412349cc55cSDimitry Andric PlatformRemoteGDBServer::DebugProcess(ProcessLaunchInfo &launch_info,
413349cc55cSDimitry Andric                                       Debugger &debugger, Target &target,
4140b57cec5SDimitry Andric                                       Status &error) {
4150b57cec5SDimitry Andric   lldb::ProcessSP process_sp;
4160b57cec5SDimitry Andric   if (IsRemote()) {
4170b57cec5SDimitry Andric     if (IsConnected()) {
4180b57cec5SDimitry Andric       lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
4190b57cec5SDimitry Andric       std::string connect_url;
4200b57cec5SDimitry Andric       if (!LaunchGDBServer(debugserver_pid, connect_url)) {
4210b57cec5SDimitry Andric         error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
4220b57cec5SDimitry Andric                                        GetHostname());
4230b57cec5SDimitry Andric       } else {
4240b57cec5SDimitry Andric         // The darwin always currently uses the GDB remote debugger plug-in
4250b57cec5SDimitry Andric         // so even when debugging locally we are debugging remotely!
426349cc55cSDimitry Andric         process_sp = target.CreateProcess(launch_info.GetListener(),
427e8d8bef9SDimitry Andric                                           "gdb-remote", nullptr, true);
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric         if (process_sp) {
4305ffd83dbSDimitry Andric           error = process_sp->ConnectRemote(connect_url.c_str());
4310b57cec5SDimitry Andric           // Retry the connect remote one time...
4320b57cec5SDimitry Andric           if (error.Fail())
4335ffd83dbSDimitry Andric             error = process_sp->ConnectRemote(connect_url.c_str());
4340b57cec5SDimitry Andric           if (error.Success())
4350b57cec5SDimitry Andric             error = process_sp->Launch(launch_info);
4360b57cec5SDimitry Andric           else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) {
4370b57cec5SDimitry Andric             printf("error: connect remote failed (%s)\n", error.AsCString());
4380b57cec5SDimitry Andric             KillSpawnedProcess(debugserver_pid);
4390b57cec5SDimitry Andric           }
4400b57cec5SDimitry Andric         }
4410b57cec5SDimitry Andric       }
4420b57cec5SDimitry Andric     } else {
4430b57cec5SDimitry Andric       error.SetErrorString("not connected to remote gdb server");
4440b57cec5SDimitry Andric     }
4450b57cec5SDimitry Andric   }
4460b57cec5SDimitry Andric   return process_sp;
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric bool PlatformRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid,
4500b57cec5SDimitry Andric                                               std::string &connect_url) {
45104eeddc0SDimitry Andric   assert(IsConnected());
45204eeddc0SDimitry Andric 
4530b57cec5SDimitry Andric   ArchSpec remote_arch = GetRemoteSystemArchitecture();
4540b57cec5SDimitry Andric   llvm::Triple &remote_triple = remote_arch.GetTriple();
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric   uint16_t port = 0;
4570b57cec5SDimitry Andric   std::string socket_name;
4580b57cec5SDimitry Andric   bool launch_result = false;
4590b57cec5SDimitry Andric   if (remote_triple.getVendor() == llvm::Triple::Apple &&
4600b57cec5SDimitry Andric       remote_triple.getOS() == llvm::Triple::IOS) {
4610b57cec5SDimitry Andric     // When remote debugging to iOS, we use a USB mux that always talks to
4620b57cec5SDimitry Andric     // localhost, so we will need the remote debugserver to accept connections
4630b57cec5SDimitry Andric     // only from localhost, no matter what our current hostname is
4640b57cec5SDimitry Andric     launch_result =
46504eeddc0SDimitry Andric         m_gdb_client_up->LaunchGDBServer("127.0.0.1", pid, port, socket_name);
4660b57cec5SDimitry Andric   } else {
4670b57cec5SDimitry Andric     // All other hosts should use their actual hostname
4680b57cec5SDimitry Andric     launch_result =
46904eeddc0SDimitry Andric         m_gdb_client_up->LaunchGDBServer(nullptr, pid, port, socket_name);
4700b57cec5SDimitry Andric   }
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   if (!launch_result)
4730b57cec5SDimitry Andric     return false;
4740b57cec5SDimitry Andric 
4750b57cec5SDimitry Andric   connect_url =
4760b57cec5SDimitry Andric       MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port,
4770b57cec5SDimitry Andric                        (socket_name.empty()) ? nullptr : socket_name.c_str());
4780b57cec5SDimitry Andric   return true;
4790b57cec5SDimitry Andric }
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric bool PlatformRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) {
48204eeddc0SDimitry Andric   assert(IsConnected());
48304eeddc0SDimitry Andric   return m_gdb_client_up->KillSpawnedProcess(pid);
4840b57cec5SDimitry Andric }
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric lldb::ProcessSP PlatformRemoteGDBServer::Attach(
4870b57cec5SDimitry Andric     ProcessAttachInfo &attach_info, Debugger &debugger,
4880b57cec5SDimitry Andric     Target *target, // Can be NULL, if NULL create a new target, else use
4890b57cec5SDimitry Andric                     // existing one
4900b57cec5SDimitry Andric     Status &error) {
4910b57cec5SDimitry Andric   lldb::ProcessSP process_sp;
4920b57cec5SDimitry Andric   if (IsRemote()) {
4930b57cec5SDimitry Andric     if (IsConnected()) {
4940b57cec5SDimitry Andric       lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
4950b57cec5SDimitry Andric       std::string connect_url;
4960b57cec5SDimitry Andric       if (!LaunchGDBServer(debugserver_pid, connect_url)) {
4970b57cec5SDimitry Andric         error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
4980b57cec5SDimitry Andric                                        GetHostname());
4990b57cec5SDimitry Andric       } else {
5000b57cec5SDimitry Andric         if (target == nullptr) {
5010b57cec5SDimitry Andric           TargetSP new_target_sp;
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric           error = debugger.GetTargetList().CreateTarget(
5040b57cec5SDimitry Andric               debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
5050b57cec5SDimitry Andric           target = new_target_sp.get();
5060b57cec5SDimitry Andric         } else
5070b57cec5SDimitry Andric           error.Clear();
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric         if (target && error.Success()) {
5100b57cec5SDimitry Andric           // The darwin always currently uses the GDB remote debugger plug-in
5110b57cec5SDimitry Andric           // so even when debugging locally we are debugging remotely!
5120b57cec5SDimitry Andric           process_sp =
5130b57cec5SDimitry Andric               target->CreateProcess(attach_info.GetListenerForProcess(debugger),
514e8d8bef9SDimitry Andric                                     "gdb-remote", nullptr, true);
5150b57cec5SDimitry Andric           if (process_sp) {
5165ffd83dbSDimitry Andric             error = process_sp->ConnectRemote(connect_url.c_str());
5170b57cec5SDimitry Andric             if (error.Success()) {
5180b57cec5SDimitry Andric               ListenerSP listener_sp = attach_info.GetHijackListener();
5190b57cec5SDimitry Andric               if (listener_sp)
5200b57cec5SDimitry Andric                 process_sp->HijackProcessEvents(listener_sp);
5210b57cec5SDimitry Andric               error = process_sp->Attach(attach_info);
5220b57cec5SDimitry Andric             }
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric             if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) {
5250b57cec5SDimitry Andric               KillSpawnedProcess(debugserver_pid);
5260b57cec5SDimitry Andric             }
5270b57cec5SDimitry Andric           }
5280b57cec5SDimitry Andric         }
5290b57cec5SDimitry Andric       }
5300b57cec5SDimitry Andric     } else {
5310b57cec5SDimitry Andric       error.SetErrorString("not connected to remote gdb server");
5320b57cec5SDimitry Andric     }
5330b57cec5SDimitry Andric   }
5340b57cec5SDimitry Andric   return process_sp;
5350b57cec5SDimitry Andric }
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric Status PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec,
5380b57cec5SDimitry Andric                                               uint32_t mode) {
53904eeddc0SDimitry Andric   if (!IsConnected())
54004eeddc0SDimitry Andric     return Status("Not connected.");
54104eeddc0SDimitry Andric   Status error = m_gdb_client_up->MakeDirectory(file_spec, mode);
5420b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
5439dba64beSDimitry Andric   LLDB_LOGF(log,
5449dba64beSDimitry Andric             "PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) "
5450b57cec5SDimitry Andric             "error = %u (%s)",
5469dba64beSDimitry Andric             file_spec.GetCString(), mode, error.GetError(), error.AsCString());
5470b57cec5SDimitry Andric   return error;
5480b57cec5SDimitry Andric }
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric Status PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec,
5510b57cec5SDimitry Andric                                                    uint32_t &file_permissions) {
55204eeddc0SDimitry Andric   if (!IsConnected())
55304eeddc0SDimitry Andric     return Status("Not connected.");
55404eeddc0SDimitry Andric   Status error =
55504eeddc0SDimitry Andric       m_gdb_client_up->GetFilePermissions(file_spec, file_permissions);
5560b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
5579dba64beSDimitry Andric   LLDB_LOGF(log,
5589dba64beSDimitry Andric             "PlatformRemoteGDBServer::GetFilePermissions(path='%s', "
5590b57cec5SDimitry Andric             "file_permissions=%o) error = %u (%s)",
5600b57cec5SDimitry Andric             file_spec.GetCString(), file_permissions, error.GetError(),
5610b57cec5SDimitry Andric             error.AsCString());
5620b57cec5SDimitry Andric   return error;
5630b57cec5SDimitry Andric }
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric Status PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
5660b57cec5SDimitry Andric                                                    uint32_t file_permissions) {
56704eeddc0SDimitry Andric   if (!IsConnected())
56804eeddc0SDimitry Andric     return Status("Not connected.");
56904eeddc0SDimitry Andric   Status error =
57004eeddc0SDimitry Andric       m_gdb_client_up->SetFilePermissions(file_spec, file_permissions);
5710b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
5729dba64beSDimitry Andric   LLDB_LOGF(log,
5739dba64beSDimitry Andric             "PlatformRemoteGDBServer::SetFilePermissions(path='%s', "
5740b57cec5SDimitry Andric             "file_permissions=%o) error = %u (%s)",
5750b57cec5SDimitry Andric             file_spec.GetCString(), file_permissions, error.GetError(),
5760b57cec5SDimitry Andric             error.AsCString());
5770b57cec5SDimitry Andric   return error;
5780b57cec5SDimitry Andric }
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric lldb::user_id_t PlatformRemoteGDBServer::OpenFile(const FileSpec &file_spec,
5819dba64beSDimitry Andric                                                   File::OpenOptions flags,
5829dba64beSDimitry Andric                                                   uint32_t mode,
5830b57cec5SDimitry Andric                                                   Status &error) {
58404eeddc0SDimitry Andric   if (IsConnected())
58504eeddc0SDimitry Andric     return m_gdb_client_up->OpenFile(file_spec, flags, mode, error);
58604eeddc0SDimitry Andric   return LLDB_INVALID_UID;
5870b57cec5SDimitry Andric }
5880b57cec5SDimitry Andric 
5890b57cec5SDimitry Andric bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Status &error) {
59004eeddc0SDimitry Andric   if (IsConnected())
59104eeddc0SDimitry Andric     return m_gdb_client_up->CloseFile(fd, error);
59204eeddc0SDimitry Andric   error = Status("Not connected.");
59304eeddc0SDimitry Andric   return false;
5940b57cec5SDimitry Andric }
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric lldb::user_id_t
5970b57cec5SDimitry Andric PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) {
59804eeddc0SDimitry Andric   if (IsConnected())
59904eeddc0SDimitry Andric     return m_gdb_client_up->GetFileSize(file_spec);
60004eeddc0SDimitry Andric   return LLDB_INVALID_UID;
6010b57cec5SDimitry Andric }
6020b57cec5SDimitry Andric 
603e8d8bef9SDimitry Andric void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory(
604e8d8bef9SDimitry Andric     CompletionRequest &request, bool only_dir) {
60504eeddc0SDimitry Andric   if (IsConnected())
60604eeddc0SDimitry Andric     m_gdb_client_up->AutoCompleteDiskFileOrDirectory(request, only_dir);
607e8d8bef9SDimitry Andric }
608e8d8bef9SDimitry Andric 
6090b57cec5SDimitry Andric uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset,
6100b57cec5SDimitry Andric                                            void *dst, uint64_t dst_len,
6110b57cec5SDimitry Andric                                            Status &error) {
61204eeddc0SDimitry Andric   if (IsConnected())
61304eeddc0SDimitry Andric     return m_gdb_client_up->ReadFile(fd, offset, dst, dst_len, error);
61404eeddc0SDimitry Andric   error = Status("Not connected.");
61504eeddc0SDimitry Andric   return 0;
6160b57cec5SDimitry Andric }
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric uint64_t PlatformRemoteGDBServer::WriteFile(lldb::user_id_t fd, uint64_t offset,
6190b57cec5SDimitry Andric                                             const void *src, uint64_t src_len,
6200b57cec5SDimitry Andric                                             Status &error) {
62104eeddc0SDimitry Andric   if (IsConnected())
62204eeddc0SDimitry Andric     return m_gdb_client_up->WriteFile(fd, offset, src, src_len, error);
62304eeddc0SDimitry Andric   error = Status("Not connected.");
62404eeddc0SDimitry Andric   return 0;
6250b57cec5SDimitry Andric }
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric Status PlatformRemoteGDBServer::PutFile(const FileSpec &source,
6280b57cec5SDimitry Andric                                         const FileSpec &destination,
6290b57cec5SDimitry Andric                                         uint32_t uid, uint32_t gid) {
6300b57cec5SDimitry Andric   return Platform::PutFile(source, destination, uid, gid);
6310b57cec5SDimitry Andric }
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric Status PlatformRemoteGDBServer::CreateSymlink(
6340b57cec5SDimitry Andric     const FileSpec &src, // The name of the link is in src
6350b57cec5SDimitry Andric     const FileSpec &dst) // The symlink points to dst
6360b57cec5SDimitry Andric {
63704eeddc0SDimitry Andric   if (!IsConnected())
63804eeddc0SDimitry Andric     return Status("Not connected.");
63904eeddc0SDimitry Andric   Status error = m_gdb_client_up->CreateSymlink(src, dst);
6400b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
6419dba64beSDimitry Andric   LLDB_LOGF(log,
6429dba64beSDimitry Andric             "PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') "
6430b57cec5SDimitry Andric             "error = %u (%s)",
6440b57cec5SDimitry Andric             src.GetCString(), dst.GetCString(), error.GetError(),
6450b57cec5SDimitry Andric             error.AsCString());
6460b57cec5SDimitry Andric   return error;
6470b57cec5SDimitry Andric }
6480b57cec5SDimitry Andric 
6490b57cec5SDimitry Andric Status PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) {
65004eeddc0SDimitry Andric   if (!IsConnected())
65104eeddc0SDimitry Andric     return Status("Not connected.");
65204eeddc0SDimitry Andric   Status error = m_gdb_client_up->Unlink(file_spec);
6530b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
6549dba64beSDimitry Andric   LLDB_LOGF(log, "PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)",
6550b57cec5SDimitry Andric             file_spec.GetCString(), error.GetError(), error.AsCString());
6560b57cec5SDimitry Andric   return error;
6570b57cec5SDimitry Andric }
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) {
66004eeddc0SDimitry Andric   if (IsConnected())
66104eeddc0SDimitry Andric     return m_gdb_client_up->GetFileExists(file_spec);
66204eeddc0SDimitry Andric   return false;
6630b57cec5SDimitry Andric }
6640b57cec5SDimitry Andric 
6650b57cec5SDimitry Andric Status PlatformRemoteGDBServer::RunShellCommand(
666e8d8bef9SDimitry Andric     llvm::StringRef shell, llvm::StringRef command,
6670b57cec5SDimitry Andric     const FileSpec &
6680b57cec5SDimitry Andric         working_dir, // Pass empty FileSpec to use the current working directory
6690b57cec5SDimitry Andric     int *status_ptr, // Pass NULL if you don't want the process exit status
6700b57cec5SDimitry Andric     int *signo_ptr,  // Pass NULL if you don't want the signal that caused the
6710b57cec5SDimitry Andric                      // process to exit
6720b57cec5SDimitry Andric     std::string
6730b57cec5SDimitry Andric         *command_output, // Pass NULL if you don't want the command output
6740b57cec5SDimitry Andric     const Timeout<std::micro> &timeout) {
67504eeddc0SDimitry Andric   if (!IsConnected())
67604eeddc0SDimitry Andric     return Status("Not connected.");
67704eeddc0SDimitry Andric   return m_gdb_client_up->RunShellCommand(command, working_dir, status_ptr,
6780b57cec5SDimitry Andric                                           signo_ptr, command_output, timeout);
6790b57cec5SDimitry Andric }
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() {
6820b57cec5SDimitry Andric   m_trap_handlers.push_back(ConstString("_sigtramp"));
6830b57cec5SDimitry Andric }
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() {
6860b57cec5SDimitry Andric   if (!IsConnected())
6870b57cec5SDimitry Andric     return Platform::GetRemoteUnixSignals();
6880b57cec5SDimitry Andric 
6890b57cec5SDimitry Andric   if (m_remote_signals_sp)
6900b57cec5SDimitry Andric     return m_remote_signals_sp;
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric   // If packet not implemented or JSON failed to parse, we'll guess the signal
6930b57cec5SDimitry Andric   // set based on the remote architecture.
6940b57cec5SDimitry Andric   m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture());
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric   StringExtractorGDBRemote response;
697fe6060f1SDimitry Andric   auto result =
69804eeddc0SDimitry Andric       m_gdb_client_up->SendPacketAndWaitForResponse("jSignalsInfo", response);
6990b57cec5SDimitry Andric 
7000b57cec5SDimitry Andric   if (result != decltype(result)::Success ||
7010b57cec5SDimitry Andric       response.GetResponseType() != response.eResponse)
7020b57cec5SDimitry Andric     return m_remote_signals_sp;
7030b57cec5SDimitry Andric 
7045ffd83dbSDimitry Andric   auto object_sp =
7055ffd83dbSDimitry Andric       StructuredData::ParseJSON(std::string(response.GetStringRef()));
7060b57cec5SDimitry Andric   if (!object_sp || !object_sp->IsValid())
7070b57cec5SDimitry Andric     return m_remote_signals_sp;
7080b57cec5SDimitry Andric 
7090b57cec5SDimitry Andric   auto array_sp = object_sp->GetAsArray();
7100b57cec5SDimitry Andric   if (!array_sp || !array_sp->IsValid())
7110b57cec5SDimitry Andric     return m_remote_signals_sp;
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric   auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>();
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric   bool done = array_sp->ForEach(
7160b57cec5SDimitry Andric       [&remote_signals_sp](StructuredData::Object *object) -> bool {
7170b57cec5SDimitry Andric         if (!object || !object->IsValid())
7180b57cec5SDimitry Andric           return false;
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric         auto dict = object->GetAsDictionary();
7210b57cec5SDimitry Andric         if (!dict || !dict->IsValid())
7220b57cec5SDimitry Andric           return false;
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric         // Signal number and signal name are required.
7250b57cec5SDimitry Andric         int signo;
7260b57cec5SDimitry Andric         if (!dict->GetValueForKeyAsInteger("signo", signo))
7270b57cec5SDimitry Andric           return false;
7280b57cec5SDimitry Andric 
7290b57cec5SDimitry Andric         llvm::StringRef name;
7300b57cec5SDimitry Andric         if (!dict->GetValueForKeyAsString("name", name))
7310b57cec5SDimitry Andric           return false;
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric         // We can live without short_name, description, etc.
7340b57cec5SDimitry Andric         bool suppress{false};
7350b57cec5SDimitry Andric         auto object_sp = dict->GetValueForKey("suppress");
7360b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7370b57cec5SDimitry Andric           suppress = object_sp->GetBooleanValue();
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric         bool stop{false};
7400b57cec5SDimitry Andric         object_sp = dict->GetValueForKey("stop");
7410b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7420b57cec5SDimitry Andric           stop = object_sp->GetBooleanValue();
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric         bool notify{false};
7450b57cec5SDimitry Andric         object_sp = dict->GetValueForKey("notify");
7460b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7470b57cec5SDimitry Andric           notify = object_sp->GetBooleanValue();
7480b57cec5SDimitry Andric 
74904eeddc0SDimitry Andric         std::string description;
7500b57cec5SDimitry Andric         object_sp = dict->GetValueForKey("description");
7510b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7525ffd83dbSDimitry Andric           description = std::string(object_sp->GetStringValue());
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric         remote_signals_sp->AddSignal(signo, name.str().c_str(), suppress, stop,
7550b57cec5SDimitry Andric                                      notify, description.c_str());
7560b57cec5SDimitry Andric         return true;
7570b57cec5SDimitry Andric       });
7580b57cec5SDimitry Andric 
7590b57cec5SDimitry Andric   if (done)
7600b57cec5SDimitry Andric     m_remote_signals_sp = std::move(remote_signals_sp);
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric   return m_remote_signals_sp;
7630b57cec5SDimitry Andric }
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric std::string PlatformRemoteGDBServer::MakeGdbServerUrl(
7660b57cec5SDimitry Andric     const std::string &platform_scheme, const std::string &platform_hostname,
7670b57cec5SDimitry Andric     uint16_t port, const char *socket_name) {
7680b57cec5SDimitry Andric   const char *override_scheme =
7690b57cec5SDimitry Andric       getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME");
7700b57cec5SDimitry Andric   const char *override_hostname =
7710b57cec5SDimitry Andric       getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
7720b57cec5SDimitry Andric   const char *port_offset_c_str =
7730b57cec5SDimitry Andric       getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
7740b57cec5SDimitry Andric   int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric   return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(),
7770b57cec5SDimitry Andric                  override_hostname ? override_hostname
7780b57cec5SDimitry Andric                                    : platform_hostname.c_str(),
7790b57cec5SDimitry Andric                  port + port_offset, socket_name);
7800b57cec5SDimitry Andric }
7810b57cec5SDimitry Andric 
7820b57cec5SDimitry Andric std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme,
7830b57cec5SDimitry Andric                                              const char *hostname,
7840b57cec5SDimitry Andric                                              uint16_t port, const char *path) {
7850b57cec5SDimitry Andric   StreamString result;
786e8d8bef9SDimitry Andric   result.Printf("%s://[%s]", scheme, hostname);
7870b57cec5SDimitry Andric   if (port != 0)
7880b57cec5SDimitry Andric     result.Printf(":%u", port);
7890b57cec5SDimitry Andric   if (path)
7900b57cec5SDimitry Andric     result.Write(path, strlen(path));
7915ffd83dbSDimitry Andric   return std::string(result.GetString());
7920b57cec5SDimitry Andric }
7930b57cec5SDimitry Andric 
7940b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger,
7950b57cec5SDimitry Andric                                                           Status &error) {
7960b57cec5SDimitry Andric   std::vector<std::string> connection_urls;
7970b57cec5SDimitry Andric   GetPendingGdbServerList(connection_urls);
7980b57cec5SDimitry Andric 
7990b57cec5SDimitry Andric   for (size_t i = 0; i < connection_urls.size(); ++i) {
800fe6060f1SDimitry Andric     ConnectProcess(connection_urls[i].c_str(), "gdb-remote", debugger, nullptr, error);
8010b57cec5SDimitry Andric     if (error.Fail())
8020b57cec5SDimitry Andric       return i; // We already connected to i process succsessfully
8030b57cec5SDimitry Andric   }
8040b57cec5SDimitry Andric   return connection_urls.size();
8050b57cec5SDimitry Andric }
8060b57cec5SDimitry Andric 
8070b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::GetPendingGdbServerList(
8080b57cec5SDimitry Andric     std::vector<std::string> &connection_urls) {
8090b57cec5SDimitry Andric   std::vector<std::pair<uint16_t, std::string>> remote_servers;
81004eeddc0SDimitry Andric   if (!IsConnected())
81104eeddc0SDimitry Andric     return 0;
81204eeddc0SDimitry Andric   m_gdb_client_up->QueryGDBServer(remote_servers);
8130b57cec5SDimitry Andric   for (const auto &gdbserver : remote_servers) {
8140b57cec5SDimitry Andric     const char *socket_name_cstr =
8150b57cec5SDimitry Andric         gdbserver.second.empty() ? nullptr : gdbserver.second.c_str();
8160b57cec5SDimitry Andric     connection_urls.emplace_back(
8170b57cec5SDimitry Andric         MakeGdbServerUrl(m_platform_scheme, m_platform_hostname,
8180b57cec5SDimitry Andric                          gdbserver.first, socket_name_cstr));
8190b57cec5SDimitry Andric   }
8200b57cec5SDimitry Andric   return connection_urls.size();
8210b57cec5SDimitry Andric }
822