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"
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric using namespace lldb;
350b57cec5SDimitry Andric using namespace lldb_private;
360b57cec5SDimitry Andric using namespace lldb_private::platform_gdb_server;
370b57cec5SDimitry Andric 
385ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteGDBServer, PlatformGDB)
395ffd83dbSDimitry Andric 
400b57cec5SDimitry Andric static bool g_initialized = false;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric void PlatformRemoteGDBServer::Initialize() {
430b57cec5SDimitry Andric   Platform::Initialize();
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   if (!g_initialized) {
460b57cec5SDimitry Andric     g_initialized = true;
470b57cec5SDimitry Andric     PluginManager::RegisterPlugin(
480b57cec5SDimitry Andric         PlatformRemoteGDBServer::GetPluginNameStatic(),
490b57cec5SDimitry Andric         PlatformRemoteGDBServer::GetDescriptionStatic(),
500b57cec5SDimitry Andric         PlatformRemoteGDBServer::CreateInstance);
510b57cec5SDimitry Andric   }
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric void PlatformRemoteGDBServer::Terminate() {
550b57cec5SDimitry Andric   if (g_initialized) {
560b57cec5SDimitry Andric     g_initialized = false;
570b57cec5SDimitry Andric     PluginManager::UnregisterPlugin(PlatformRemoteGDBServer::CreateInstance);
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   Platform::Terminate();
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric PlatformSP PlatformRemoteGDBServer::CreateInstance(bool force,
640b57cec5SDimitry Andric                                                    const ArchSpec *arch) {
650b57cec5SDimitry Andric   bool create = force;
660b57cec5SDimitry Andric   if (!create) {
670b57cec5SDimitry Andric     create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified();
680b57cec5SDimitry Andric   }
690b57cec5SDimitry Andric   if (create)
700b57cec5SDimitry Andric     return PlatformSP(new PlatformRemoteGDBServer());
710b57cec5SDimitry Andric   return PlatformSP();
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric ConstString PlatformRemoteGDBServer::GetPluginNameStatic() {
750b57cec5SDimitry Andric   static ConstString g_name("remote-gdb-server");
760b57cec5SDimitry Andric   return g_name;
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric const char *PlatformRemoteGDBServer::GetDescriptionStatic() {
800b57cec5SDimitry Andric   return "A platform that uses the GDB remote protocol as the communication "
810b57cec5SDimitry Andric          "transport.";
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric const char *PlatformRemoteGDBServer::GetDescription() {
850b57cec5SDimitry Andric   if (m_platform_description.empty()) {
860b57cec5SDimitry Andric     if (IsConnected()) {
870b57cec5SDimitry Andric       // Send the get description packet
880b57cec5SDimitry Andric     }
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   if (!m_platform_description.empty())
920b57cec5SDimitry Andric     return m_platform_description.c_str();
930b57cec5SDimitry Andric   return GetDescriptionStatic();
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric Status PlatformRemoteGDBServer::ResolveExecutable(
970b57cec5SDimitry Andric     const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp,
980b57cec5SDimitry Andric     const FileSpecList *module_search_paths_ptr) {
990b57cec5SDimitry Andric   // copied from PlatformRemoteiOS
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   Status error;
1020b57cec5SDimitry Andric   // Nothing special to do here, just use the actual file and architecture
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   ModuleSpec resolved_module_spec(module_spec);
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   // Resolve any executable within an apk on Android?
1070b57cec5SDimitry Andric   // Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()) ||
1100b57cec5SDimitry Andric       module_spec.GetUUID().IsValid()) {
1110b57cec5SDimitry Andric     if (resolved_module_spec.GetArchitecture().IsValid() ||
1120b57cec5SDimitry Andric         resolved_module_spec.GetUUID().IsValid()) {
1130b57cec5SDimitry Andric       error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
1140b57cec5SDimitry Andric                                           module_search_paths_ptr, nullptr,
1150b57cec5SDimitry Andric                                           nullptr);
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric       if (exe_module_sp && exe_module_sp->GetObjectFile())
1180b57cec5SDimitry Andric         return error;
1190b57cec5SDimitry Andric       exe_module_sp.reset();
1200b57cec5SDimitry Andric     }
1210b57cec5SDimitry Andric     // No valid architecture was specified or the exact arch wasn't found so
1220b57cec5SDimitry Andric     // ask the platform for the architectures that we should be using (in the
1230b57cec5SDimitry Andric     // correct order) and see if we can find a match that way
1240b57cec5SDimitry Andric     StreamString arch_names;
1250b57cec5SDimitry Andric     for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
1260b57cec5SDimitry Andric              idx, resolved_module_spec.GetArchitecture());
1270b57cec5SDimitry Andric          ++idx) {
1280b57cec5SDimitry Andric       error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
1290b57cec5SDimitry Andric                                           module_search_paths_ptr, nullptr,
1300b57cec5SDimitry Andric                                           nullptr);
1310b57cec5SDimitry Andric       // Did we find an executable using one of the
1320b57cec5SDimitry Andric       if (error.Success()) {
1330b57cec5SDimitry Andric         if (exe_module_sp && exe_module_sp->GetObjectFile())
1340b57cec5SDimitry Andric           break;
1350b57cec5SDimitry Andric         else
1360b57cec5SDimitry Andric           error.SetErrorToGenericError();
1370b57cec5SDimitry Andric       }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric       if (idx > 0)
1400b57cec5SDimitry Andric         arch_names.PutCString(", ");
1410b57cec5SDimitry Andric       arch_names.PutCString(
1420b57cec5SDimitry Andric           resolved_module_spec.GetArchitecture().GetArchitectureName());
1430b57cec5SDimitry Andric     }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric     if (error.Fail() || !exe_module_sp) {
1460b57cec5SDimitry Andric       if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) {
1470b57cec5SDimitry Andric         error.SetErrorStringWithFormat(
1480b57cec5SDimitry Andric             "'%s' doesn't contain any '%s' platform architectures: %s",
1490b57cec5SDimitry Andric             resolved_module_spec.GetFileSpec().GetPath().c_str(),
1500b57cec5SDimitry Andric             GetPluginName().GetCString(), arch_names.GetData());
1510b57cec5SDimitry Andric       } else {
1520b57cec5SDimitry Andric         error.SetErrorStringWithFormat(
1530b57cec5SDimitry Andric             "'%s' is not readable",
1540b57cec5SDimitry Andric             resolved_module_spec.GetFileSpec().GetPath().c_str());
1550b57cec5SDimitry Andric       }
1560b57cec5SDimitry Andric     }
1570b57cec5SDimitry Andric   } else {
1580b57cec5SDimitry Andric     error.SetErrorStringWithFormat(
1590b57cec5SDimitry Andric         "'%s' does not exist",
1600b57cec5SDimitry Andric         resolved_module_spec.GetFileSpec().GetPath().c_str());
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   return error;
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetModuleSpec(const FileSpec &module_file_spec,
1670b57cec5SDimitry Andric                                             const ArchSpec &arch,
1680b57cec5SDimitry Andric                                             ModuleSpec &module_spec) {
1690b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   const auto module_path = module_file_spec.GetPath(false);
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   if (!m_gdb_client.GetModuleInfo(module_file_spec, arch, module_spec)) {
1749dba64beSDimitry Andric     LLDB_LOGF(
1759dba64beSDimitry Andric         log,
1760b57cec5SDimitry Andric         "PlatformRemoteGDBServer::%s - failed to get module info for %s:%s",
1770b57cec5SDimitry Andric         __FUNCTION__, module_path.c_str(),
1780b57cec5SDimitry Andric         arch.GetTriple().getTriple().c_str());
1790b57cec5SDimitry Andric     return false;
1800b57cec5SDimitry Andric   }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric   if (log) {
1830b57cec5SDimitry Andric     StreamString stream;
1840b57cec5SDimitry Andric     module_spec.Dump(stream);
1859dba64beSDimitry Andric     LLDB_LOGF(log,
1860b57cec5SDimitry Andric               "PlatformRemoteGDBServer::%s - got module info for (%s:%s) : %s",
1879dba64beSDimitry Andric               __FUNCTION__, module_path.c_str(),
1889dba64beSDimitry Andric               arch.GetTriple().getTriple().c_str(), stream.GetData());
1890b57cec5SDimitry Andric   }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric   return true;
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric Status PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file,
1950b57cec5SDimitry Andric                                                 const UUID *uuid_ptr,
1960b57cec5SDimitry Andric                                                 FileSpec &local_file) {
1970b57cec5SDimitry Andric   // Default to the local case
1980b57cec5SDimitry Andric   local_file = platform_file;
1990b57cec5SDimitry Andric   return Status();
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric /// Default Constructor
2030b57cec5SDimitry Andric PlatformRemoteGDBServer::PlatformRemoteGDBServer()
2040b57cec5SDimitry Andric     : Platform(false), // This is a remote platform
2050b57cec5SDimitry Andric       m_gdb_client() {}
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric /// Destructor.
2080b57cec5SDimitry Andric ///
2090b57cec5SDimitry Andric /// The destructor is virtual since this class is designed to be
2100b57cec5SDimitry Andric /// inherited from by the plug-in instance.
2110b57cec5SDimitry Andric PlatformRemoteGDBServer::~PlatformRemoteGDBServer() {}
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetSupportedArchitectureAtIndex(uint32_t idx,
2140b57cec5SDimitry Andric                                                               ArchSpec &arch) {
2150b57cec5SDimitry Andric   ArchSpec remote_arch = m_gdb_client.GetSystemArchitecture();
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric   if (idx == 0) {
2180b57cec5SDimitry Andric     arch = remote_arch;
2190b57cec5SDimitry Andric     return arch.IsValid();
2200b57cec5SDimitry Andric   } else if (idx == 1 && remote_arch.IsValid() &&
2210b57cec5SDimitry Andric              remote_arch.GetTriple().isArch64Bit()) {
2220b57cec5SDimitry Andric     arch.SetTriple(remote_arch.GetTriple().get32BitArchVariant());
2230b57cec5SDimitry Andric     return arch.IsValid();
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric   return false;
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode(
2290b57cec5SDimitry Andric     Target &target, BreakpointSite *bp_site) {
2300b57cec5SDimitry Andric   // This isn't needed if the z/Z packets are supported in the GDB remote
2310b57cec5SDimitry Andric   // server. But we might need a packet to detect this.
2320b57cec5SDimitry Andric   return 0;
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetRemoteOSVersion() {
2360b57cec5SDimitry Andric   m_os_version = m_gdb_client.GetOSVersion();
2370b57cec5SDimitry Andric   return !m_os_version.empty();
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetRemoteOSBuildString(std::string &s) {
2410b57cec5SDimitry Andric   return m_gdb_client.GetOSBuildString(s);
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetRemoteOSKernelDescription(std::string &s) {
2450b57cec5SDimitry Andric   return m_gdb_client.GetOSKernelDescription(s);
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric // Remote Platform subclasses need to override this function
2490b57cec5SDimitry Andric ArchSpec PlatformRemoteGDBServer::GetRemoteSystemArchitecture() {
2500b57cec5SDimitry Andric   return m_gdb_client.GetSystemArchitecture();
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric FileSpec PlatformRemoteGDBServer::GetRemoteWorkingDirectory() {
2540b57cec5SDimitry Andric   if (IsConnected()) {
2550b57cec5SDimitry Andric     Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
2560b57cec5SDimitry Andric     FileSpec working_dir;
2570b57cec5SDimitry Andric     if (m_gdb_client.GetWorkingDir(working_dir) && log)
2589dba64beSDimitry Andric       LLDB_LOGF(log,
2590b57cec5SDimitry Andric                 "PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'",
2600b57cec5SDimitry Andric                 working_dir.GetCString());
2610b57cec5SDimitry Andric     return working_dir;
2620b57cec5SDimitry Andric   } else {
2630b57cec5SDimitry Andric     return Platform::GetRemoteWorkingDirectory();
2640b57cec5SDimitry Andric   }
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric bool PlatformRemoteGDBServer::SetRemoteWorkingDirectory(
2680b57cec5SDimitry Andric     const FileSpec &working_dir) {
2690b57cec5SDimitry Andric   if (IsConnected()) {
2700b57cec5SDimitry Andric     // Clear the working directory it case it doesn't get set correctly. This
2710b57cec5SDimitry Andric     // will for use to re-read it
2720b57cec5SDimitry Andric     Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
2739dba64beSDimitry Andric     LLDB_LOGF(log, "PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')",
2740b57cec5SDimitry Andric               working_dir.GetCString());
2750b57cec5SDimitry Andric     return m_gdb_client.SetWorkingDir(working_dir) == 0;
2760b57cec5SDimitry Andric   } else
2770b57cec5SDimitry Andric     return Platform::SetRemoteWorkingDirectory(working_dir);
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric bool PlatformRemoteGDBServer::IsConnected() const {
2810b57cec5SDimitry Andric   return m_gdb_client.IsConnected();
2820b57cec5SDimitry Andric }
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric Status PlatformRemoteGDBServer::ConnectRemote(Args &args) {
2850b57cec5SDimitry Andric   Status error;
2860b57cec5SDimitry Andric   if (IsConnected()) {
2870b57cec5SDimitry Andric     error.SetErrorStringWithFormat("the platform is already connected to '%s', "
2880b57cec5SDimitry Andric                                    "execute 'platform disconnect' to close the "
2890b57cec5SDimitry Andric                                    "current connection",
2900b57cec5SDimitry Andric                                    GetHostname());
2915ffd83dbSDimitry Andric     return error;
2925ffd83dbSDimitry Andric   }
2935ffd83dbSDimitry Andric 
2945ffd83dbSDimitry Andric   if (args.GetArgumentCount() != 1) {
2955ffd83dbSDimitry Andric     error.SetErrorString(
2965ffd83dbSDimitry Andric         "\"platform connect\" takes a single argument: <connect-url>");
2975ffd83dbSDimitry Andric     return error;
2985ffd83dbSDimitry Andric   }
2995ffd83dbSDimitry Andric 
3000b57cec5SDimitry Andric   const char *url = args.GetArgumentAtIndex(0);
3010b57cec5SDimitry Andric   if (!url)
3020b57cec5SDimitry Andric     return Status("URL is null.");
3035ffd83dbSDimitry Andric 
3045ffd83dbSDimitry Andric   int port;
3050b57cec5SDimitry Andric   llvm::StringRef scheme, hostname, pathname;
3060b57cec5SDimitry Andric   if (!UriParser::Parse(url, scheme, hostname, port, pathname))
3070b57cec5SDimitry Andric     return Status("Invalid URL: %s", url);
3080b57cec5SDimitry Andric 
3095ffd83dbSDimitry Andric   // We're going to reuse the hostname when we connect to the debugserver.
3105ffd83dbSDimitry Andric   m_platform_scheme = std::string(scheme);
3115ffd83dbSDimitry Andric   m_platform_hostname = std::string(hostname);
3125ffd83dbSDimitry Andric 
3135ffd83dbSDimitry Andric   m_gdb_client.SetConnection(std::make_unique<ConnectionFileDescriptor>());
3145ffd83dbSDimitry Andric   if (repro::Reproducer::Instance().IsReplaying()) {
3155ffd83dbSDimitry Andric     error = m_gdb_replay_server.Connect(m_gdb_client);
3165ffd83dbSDimitry Andric     if (error.Success())
3175ffd83dbSDimitry Andric       m_gdb_replay_server.StartAsyncThread();
3185ffd83dbSDimitry Andric   } else {
3195ffd83dbSDimitry Andric     if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
3205ffd83dbSDimitry Andric       repro::GDBRemoteProvider &provider =
3215ffd83dbSDimitry Andric           g->GetOrCreate<repro::GDBRemoteProvider>();
3225ffd83dbSDimitry Andric       m_gdb_client.SetPacketRecorder(provider.GetNewPacketRecorder());
3235ffd83dbSDimitry Andric     }
3245ffd83dbSDimitry Andric     m_gdb_client.Connect(url, &error);
3255ffd83dbSDimitry Andric   }
3265ffd83dbSDimitry Andric 
3275ffd83dbSDimitry Andric   if (error.Fail())
3285ffd83dbSDimitry Andric     return error;
3295ffd83dbSDimitry Andric 
3300b57cec5SDimitry Andric   if (m_gdb_client.HandshakeWithServer(&error)) {
3310b57cec5SDimitry Andric     m_gdb_client.GetHostInfo();
3320b57cec5SDimitry Andric     // If a working directory was set prior to connecting, send it down
3335ffd83dbSDimitry Andric     // now.
3340b57cec5SDimitry Andric     if (m_working_dir)
3350b57cec5SDimitry Andric       m_gdb_client.SetWorkingDir(m_working_dir);
3360b57cec5SDimitry Andric   } else {
3370b57cec5SDimitry Andric     m_gdb_client.Disconnect();
3380b57cec5SDimitry Andric     if (error.Success())
3390b57cec5SDimitry Andric       error.SetErrorString("handshake failed");
3400b57cec5SDimitry Andric   }
3410b57cec5SDimitry Andric   return error;
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric Status PlatformRemoteGDBServer::DisconnectRemote() {
3450b57cec5SDimitry Andric   Status error;
3460b57cec5SDimitry Andric   m_gdb_client.Disconnect(&error);
3470b57cec5SDimitry Andric   m_remote_signals_sp.reset();
3480b57cec5SDimitry Andric   return error;
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric const char *PlatformRemoteGDBServer::GetHostname() {
3520b57cec5SDimitry Andric   m_gdb_client.GetHostname(m_name);
3530b57cec5SDimitry Andric   if (m_name.empty())
3540b57cec5SDimitry Andric     return nullptr;
3550b57cec5SDimitry Andric   return m_name.c_str();
3560b57cec5SDimitry Andric }
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric llvm::Optional<std::string>
3590b57cec5SDimitry Andric PlatformRemoteGDBServer::DoGetUserName(UserIDResolver::id_t uid) {
3600b57cec5SDimitry Andric   std::string name;
3610b57cec5SDimitry Andric   if (m_gdb_client.GetUserName(uid, name))
3620b57cec5SDimitry Andric     return std::move(name);
3630b57cec5SDimitry Andric   return llvm::None;
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric llvm::Optional<std::string>
3670b57cec5SDimitry Andric PlatformRemoteGDBServer::DoGetGroupName(UserIDResolver::id_t gid) {
3680b57cec5SDimitry Andric   std::string name;
3690b57cec5SDimitry Andric   if (m_gdb_client.GetGroupName(gid, name))
3700b57cec5SDimitry Andric     return std::move(name);
3710b57cec5SDimitry Andric   return llvm::None;
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric uint32_t PlatformRemoteGDBServer::FindProcesses(
3750b57cec5SDimitry Andric     const ProcessInstanceInfoMatch &match_info,
3760b57cec5SDimitry Andric     ProcessInstanceInfoList &process_infos) {
3770b57cec5SDimitry Andric   return m_gdb_client.FindProcesses(match_info, process_infos);
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetProcessInfo(
3810b57cec5SDimitry Andric     lldb::pid_t pid, ProcessInstanceInfo &process_info) {
3820b57cec5SDimitry Andric   return m_gdb_client.GetProcessInfo(pid, process_info);
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) {
3860b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
3870b57cec5SDimitry Andric   Status error;
3880b57cec5SDimitry Andric 
3899dba64beSDimitry Andric   LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() called", __FUNCTION__);
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric   auto num_file_actions = launch_info.GetNumFileActions();
3920b57cec5SDimitry Andric   for (decltype(num_file_actions) i = 0; i < num_file_actions; ++i) {
3930b57cec5SDimitry Andric     const auto file_action = launch_info.GetFileActionAtIndex(i);
3940b57cec5SDimitry Andric     if (file_action->GetAction() != FileAction::eFileActionOpen)
3950b57cec5SDimitry Andric       continue;
3960b57cec5SDimitry Andric     switch (file_action->GetFD()) {
3970b57cec5SDimitry Andric     case STDIN_FILENO:
3980b57cec5SDimitry Andric       m_gdb_client.SetSTDIN(file_action->GetFileSpec());
3990b57cec5SDimitry Andric       break;
4000b57cec5SDimitry Andric     case STDOUT_FILENO:
4010b57cec5SDimitry Andric       m_gdb_client.SetSTDOUT(file_action->GetFileSpec());
4020b57cec5SDimitry Andric       break;
4030b57cec5SDimitry Andric     case STDERR_FILENO:
4040b57cec5SDimitry Andric       m_gdb_client.SetSTDERR(file_action->GetFileSpec());
4050b57cec5SDimitry Andric       break;
4060b57cec5SDimitry Andric     }
4070b57cec5SDimitry Andric   }
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   m_gdb_client.SetDisableASLR(
4100b57cec5SDimitry Andric       launch_info.GetFlags().Test(eLaunchFlagDisableASLR));
4110b57cec5SDimitry Andric   m_gdb_client.SetDetachOnError(
4120b57cec5SDimitry Andric       launch_info.GetFlags().Test(eLaunchFlagDetachOnError));
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   FileSpec working_dir = launch_info.GetWorkingDirectory();
4150b57cec5SDimitry Andric   if (working_dir) {
4160b57cec5SDimitry Andric     m_gdb_client.SetWorkingDir(working_dir);
4170b57cec5SDimitry Andric   }
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric   // Send the environment and the program + arguments after we connect
4200b57cec5SDimitry Andric   m_gdb_client.SendEnvironment(launch_info.GetEnvironment());
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric   ArchSpec arch_spec = launch_info.GetArchitecture();
4230b57cec5SDimitry Andric   const char *arch_triple = arch_spec.GetTriple().str().c_str();
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric   m_gdb_client.SendLaunchArchPacket(arch_triple);
4269dba64beSDimitry Andric   LLDB_LOGF(
4279dba64beSDimitry Andric       log,
4280b57cec5SDimitry Andric       "PlatformRemoteGDBServer::%s() set launch architecture triple to '%s'",
4290b57cec5SDimitry Andric       __FUNCTION__, arch_triple ? arch_triple : "<NULL>");
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric   int arg_packet_err;
4320b57cec5SDimitry Andric   {
4330b57cec5SDimitry Andric     // Scope for the scoped timeout object
4340b57cec5SDimitry Andric     process_gdb_remote::GDBRemoteCommunication::ScopedTimeout timeout(
4350b57cec5SDimitry Andric         m_gdb_client, std::chrono::seconds(5));
4360b57cec5SDimitry Andric     arg_packet_err = m_gdb_client.SendArgumentsPacket(launch_info);
4370b57cec5SDimitry Andric   }
4380b57cec5SDimitry Andric 
4390b57cec5SDimitry Andric   if (arg_packet_err == 0) {
4400b57cec5SDimitry Andric     std::string error_str;
4410b57cec5SDimitry Andric     if (m_gdb_client.GetLaunchSuccess(error_str)) {
4420b57cec5SDimitry Andric       const auto pid = m_gdb_client.GetCurrentProcessID(false);
4430b57cec5SDimitry Andric       if (pid != LLDB_INVALID_PROCESS_ID) {
4440b57cec5SDimitry Andric         launch_info.SetProcessID(pid);
4459dba64beSDimitry Andric         LLDB_LOGF(log,
4469dba64beSDimitry Andric                   "PlatformRemoteGDBServer::%s() pid %" PRIu64
4470b57cec5SDimitry Andric                   " launched successfully",
4480b57cec5SDimitry Andric                   __FUNCTION__, pid);
4490b57cec5SDimitry Andric       } else {
4509dba64beSDimitry Andric         LLDB_LOGF(log,
4519dba64beSDimitry Andric                   "PlatformRemoteGDBServer::%s() launch succeeded but we "
4520b57cec5SDimitry Andric                   "didn't get a valid process id back!",
4530b57cec5SDimitry Andric                   __FUNCTION__);
4540b57cec5SDimitry Andric         error.SetErrorString("failed to get PID");
4550b57cec5SDimitry Andric       }
4560b57cec5SDimitry Andric     } else {
4570b57cec5SDimitry Andric       error.SetErrorString(error_str.c_str());
4589dba64beSDimitry Andric       LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() launch failed: %s",
4590b57cec5SDimitry Andric                 __FUNCTION__, error.AsCString());
4600b57cec5SDimitry Andric     }
4610b57cec5SDimitry Andric   } else {
4620b57cec5SDimitry Andric     error.SetErrorStringWithFormat("'A' packet returned an error: %i",
4630b57cec5SDimitry Andric                                    arg_packet_err);
4640b57cec5SDimitry Andric   }
4650b57cec5SDimitry Andric   return error;
4660b57cec5SDimitry Andric }
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric Status PlatformRemoteGDBServer::KillProcess(const lldb::pid_t pid) {
4690b57cec5SDimitry Andric   if (!KillSpawnedProcess(pid))
4700b57cec5SDimitry Andric     return Status("failed to kill remote spawned process");
4710b57cec5SDimitry Andric   return Status();
4720b57cec5SDimitry Andric }
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric lldb::ProcessSP PlatformRemoteGDBServer::DebugProcess(
4750b57cec5SDimitry Andric     ProcessLaunchInfo &launch_info, Debugger &debugger,
4760b57cec5SDimitry Andric     Target *target, // Can be NULL, if NULL create a new target, else use
4770b57cec5SDimitry Andric                     // existing one
4780b57cec5SDimitry Andric     Status &error) {
4790b57cec5SDimitry Andric   lldb::ProcessSP process_sp;
4800b57cec5SDimitry Andric   if (IsRemote()) {
4810b57cec5SDimitry Andric     if (IsConnected()) {
4820b57cec5SDimitry Andric       lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
4830b57cec5SDimitry Andric       std::string connect_url;
4840b57cec5SDimitry Andric       if (!LaunchGDBServer(debugserver_pid, connect_url)) {
4850b57cec5SDimitry Andric         error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
4860b57cec5SDimitry Andric                                        GetHostname());
4870b57cec5SDimitry Andric       } else {
4880b57cec5SDimitry Andric         if (target == nullptr) {
4890b57cec5SDimitry Andric           TargetSP new_target_sp;
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric           error = debugger.GetTargetList().CreateTarget(
4920b57cec5SDimitry Andric               debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
4930b57cec5SDimitry Andric           target = new_target_sp.get();
4940b57cec5SDimitry Andric         } else
4950b57cec5SDimitry Andric           error.Clear();
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric         if (target && error.Success()) {
4980b57cec5SDimitry Andric           debugger.GetTargetList().SetSelectedTarget(target);
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric           // The darwin always currently uses the GDB remote debugger plug-in
5010b57cec5SDimitry Andric           // so even when debugging locally we are debugging remotely!
5020b57cec5SDimitry Andric           process_sp = target->CreateProcess(launch_info.GetListener(),
5030b57cec5SDimitry Andric                                              "gdb-remote", nullptr);
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric           if (process_sp) {
5065ffd83dbSDimitry Andric             error = process_sp->ConnectRemote(connect_url.c_str());
5070b57cec5SDimitry Andric             // Retry the connect remote one time...
5080b57cec5SDimitry Andric             if (error.Fail())
5095ffd83dbSDimitry Andric               error = process_sp->ConnectRemote(connect_url.c_str());
5100b57cec5SDimitry Andric             if (error.Success())
5110b57cec5SDimitry Andric               error = process_sp->Launch(launch_info);
5120b57cec5SDimitry Andric             else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) {
5130b57cec5SDimitry Andric               printf("error: connect remote failed (%s)\n", error.AsCString());
5140b57cec5SDimitry Andric               KillSpawnedProcess(debugserver_pid);
5150b57cec5SDimitry Andric             }
5160b57cec5SDimitry Andric           }
5170b57cec5SDimitry Andric         }
5180b57cec5SDimitry Andric       }
5190b57cec5SDimitry Andric     } else {
5200b57cec5SDimitry Andric       error.SetErrorString("not connected to remote gdb server");
5210b57cec5SDimitry Andric     }
5220b57cec5SDimitry Andric   }
5230b57cec5SDimitry Andric   return process_sp;
5240b57cec5SDimitry Andric }
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric bool PlatformRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid,
5270b57cec5SDimitry Andric                                               std::string &connect_url) {
5280b57cec5SDimitry Andric   ArchSpec remote_arch = GetRemoteSystemArchitecture();
5290b57cec5SDimitry Andric   llvm::Triple &remote_triple = remote_arch.GetTriple();
5300b57cec5SDimitry Andric 
5310b57cec5SDimitry Andric   uint16_t port = 0;
5320b57cec5SDimitry Andric   std::string socket_name;
5330b57cec5SDimitry Andric   bool launch_result = false;
5340b57cec5SDimitry Andric   if (remote_triple.getVendor() == llvm::Triple::Apple &&
5350b57cec5SDimitry Andric       remote_triple.getOS() == llvm::Triple::IOS) {
5360b57cec5SDimitry Andric     // When remote debugging to iOS, we use a USB mux that always talks to
5370b57cec5SDimitry Andric     // localhost, so we will need the remote debugserver to accept connections
5380b57cec5SDimitry Andric     // only from localhost, no matter what our current hostname is
5390b57cec5SDimitry Andric     launch_result =
5400b57cec5SDimitry Andric         m_gdb_client.LaunchGDBServer("127.0.0.1", pid, port, socket_name);
5410b57cec5SDimitry Andric   } else {
5420b57cec5SDimitry Andric     // All other hosts should use their actual hostname
5430b57cec5SDimitry Andric     launch_result =
5440b57cec5SDimitry Andric         m_gdb_client.LaunchGDBServer(nullptr, pid, port, socket_name);
5450b57cec5SDimitry Andric   }
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric   if (!launch_result)
5480b57cec5SDimitry Andric     return false;
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric   connect_url =
5510b57cec5SDimitry Andric       MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port,
5520b57cec5SDimitry Andric                        (socket_name.empty()) ? nullptr : socket_name.c_str());
5530b57cec5SDimitry Andric   return true;
5540b57cec5SDimitry Andric }
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric bool PlatformRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) {
5570b57cec5SDimitry Andric   return m_gdb_client.KillSpawnedProcess(pid);
5580b57cec5SDimitry Andric }
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric lldb::ProcessSP PlatformRemoteGDBServer::Attach(
5610b57cec5SDimitry Andric     ProcessAttachInfo &attach_info, Debugger &debugger,
5620b57cec5SDimitry Andric     Target *target, // Can be NULL, if NULL create a new target, else use
5630b57cec5SDimitry Andric                     // existing one
5640b57cec5SDimitry Andric     Status &error) {
5650b57cec5SDimitry Andric   lldb::ProcessSP process_sp;
5660b57cec5SDimitry Andric   if (IsRemote()) {
5670b57cec5SDimitry Andric     if (IsConnected()) {
5680b57cec5SDimitry Andric       lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
5690b57cec5SDimitry Andric       std::string connect_url;
5700b57cec5SDimitry Andric       if (!LaunchGDBServer(debugserver_pid, connect_url)) {
5710b57cec5SDimitry Andric         error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
5720b57cec5SDimitry Andric                                        GetHostname());
5730b57cec5SDimitry Andric       } else {
5740b57cec5SDimitry Andric         if (target == nullptr) {
5750b57cec5SDimitry Andric           TargetSP new_target_sp;
5760b57cec5SDimitry Andric 
5770b57cec5SDimitry Andric           error = debugger.GetTargetList().CreateTarget(
5780b57cec5SDimitry Andric               debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
5790b57cec5SDimitry Andric           target = new_target_sp.get();
5800b57cec5SDimitry Andric         } else
5810b57cec5SDimitry Andric           error.Clear();
5820b57cec5SDimitry Andric 
5830b57cec5SDimitry Andric         if (target && error.Success()) {
5840b57cec5SDimitry Andric           debugger.GetTargetList().SetSelectedTarget(target);
5850b57cec5SDimitry Andric 
5860b57cec5SDimitry Andric           // The darwin always currently uses the GDB remote debugger plug-in
5870b57cec5SDimitry Andric           // so even when debugging locally we are debugging remotely!
5880b57cec5SDimitry Andric           process_sp =
5890b57cec5SDimitry Andric               target->CreateProcess(attach_info.GetListenerForProcess(debugger),
5900b57cec5SDimitry Andric                                     "gdb-remote", nullptr);
5910b57cec5SDimitry Andric           if (process_sp) {
5925ffd83dbSDimitry Andric             error = process_sp->ConnectRemote(connect_url.c_str());
5930b57cec5SDimitry Andric             if (error.Success()) {
5940b57cec5SDimitry Andric               ListenerSP listener_sp = attach_info.GetHijackListener();
5950b57cec5SDimitry Andric               if (listener_sp)
5960b57cec5SDimitry Andric                 process_sp->HijackProcessEvents(listener_sp);
5970b57cec5SDimitry Andric               error = process_sp->Attach(attach_info);
5980b57cec5SDimitry Andric             }
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric             if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) {
6010b57cec5SDimitry Andric               KillSpawnedProcess(debugserver_pid);
6020b57cec5SDimitry Andric             }
6030b57cec5SDimitry Andric           }
6040b57cec5SDimitry Andric         }
6050b57cec5SDimitry Andric       }
6060b57cec5SDimitry Andric     } else {
6070b57cec5SDimitry Andric       error.SetErrorString("not connected to remote gdb server");
6080b57cec5SDimitry Andric     }
6090b57cec5SDimitry Andric   }
6100b57cec5SDimitry Andric   return process_sp;
6110b57cec5SDimitry Andric }
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric Status PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec,
6140b57cec5SDimitry Andric                                               uint32_t mode) {
6150b57cec5SDimitry Andric   Status error = m_gdb_client.MakeDirectory(file_spec, mode);
6160b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
6179dba64beSDimitry Andric   LLDB_LOGF(log,
6189dba64beSDimitry Andric             "PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) "
6190b57cec5SDimitry Andric             "error = %u (%s)",
6209dba64beSDimitry Andric             file_spec.GetCString(), mode, error.GetError(), error.AsCString());
6210b57cec5SDimitry Andric   return error;
6220b57cec5SDimitry Andric }
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric Status PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec,
6250b57cec5SDimitry Andric                                                    uint32_t &file_permissions) {
6260b57cec5SDimitry Andric   Status error = m_gdb_client.GetFilePermissions(file_spec, file_permissions);
6270b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
6289dba64beSDimitry Andric   LLDB_LOGF(log,
6299dba64beSDimitry Andric             "PlatformRemoteGDBServer::GetFilePermissions(path='%s', "
6300b57cec5SDimitry Andric             "file_permissions=%o) error = %u (%s)",
6310b57cec5SDimitry Andric             file_spec.GetCString(), file_permissions, error.GetError(),
6320b57cec5SDimitry Andric             error.AsCString());
6330b57cec5SDimitry Andric   return error;
6340b57cec5SDimitry Andric }
6350b57cec5SDimitry Andric 
6360b57cec5SDimitry Andric Status PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
6370b57cec5SDimitry Andric                                                    uint32_t file_permissions) {
6380b57cec5SDimitry Andric   Status error = m_gdb_client.SetFilePermissions(file_spec, file_permissions);
6390b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
6409dba64beSDimitry Andric   LLDB_LOGF(log,
6419dba64beSDimitry Andric             "PlatformRemoteGDBServer::SetFilePermissions(path='%s', "
6420b57cec5SDimitry Andric             "file_permissions=%o) error = %u (%s)",
6430b57cec5SDimitry Andric             file_spec.GetCString(), file_permissions, error.GetError(),
6440b57cec5SDimitry Andric             error.AsCString());
6450b57cec5SDimitry Andric   return error;
6460b57cec5SDimitry Andric }
6470b57cec5SDimitry Andric 
6480b57cec5SDimitry Andric lldb::user_id_t PlatformRemoteGDBServer::OpenFile(const FileSpec &file_spec,
6499dba64beSDimitry Andric                                                   File::OpenOptions flags,
6509dba64beSDimitry Andric                                                   uint32_t mode,
6510b57cec5SDimitry Andric                                                   Status &error) {
6520b57cec5SDimitry Andric   return m_gdb_client.OpenFile(file_spec, flags, mode, error);
6530b57cec5SDimitry Andric }
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Status &error) {
6560b57cec5SDimitry Andric   return m_gdb_client.CloseFile(fd, error);
6570b57cec5SDimitry Andric }
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric lldb::user_id_t
6600b57cec5SDimitry Andric PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) {
6610b57cec5SDimitry Andric   return m_gdb_client.GetFileSize(file_spec);
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset,
6650b57cec5SDimitry Andric                                            void *dst, uint64_t dst_len,
6660b57cec5SDimitry Andric                                            Status &error) {
6670b57cec5SDimitry Andric   return m_gdb_client.ReadFile(fd, offset, dst, dst_len, error);
6680b57cec5SDimitry Andric }
6690b57cec5SDimitry Andric 
6700b57cec5SDimitry Andric uint64_t PlatformRemoteGDBServer::WriteFile(lldb::user_id_t fd, uint64_t offset,
6710b57cec5SDimitry Andric                                             const void *src, uint64_t src_len,
6720b57cec5SDimitry Andric                                             Status &error) {
6730b57cec5SDimitry Andric   return m_gdb_client.WriteFile(fd, offset, src, src_len, error);
6740b57cec5SDimitry Andric }
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric Status PlatformRemoteGDBServer::PutFile(const FileSpec &source,
6770b57cec5SDimitry Andric                                         const FileSpec &destination,
6780b57cec5SDimitry Andric                                         uint32_t uid, uint32_t gid) {
6790b57cec5SDimitry Andric   return Platform::PutFile(source, destination, uid, gid);
6800b57cec5SDimitry Andric }
6810b57cec5SDimitry Andric 
6820b57cec5SDimitry Andric Status PlatformRemoteGDBServer::CreateSymlink(
6830b57cec5SDimitry Andric     const FileSpec &src, // The name of the link is in src
6840b57cec5SDimitry Andric     const FileSpec &dst) // The symlink points to dst
6850b57cec5SDimitry Andric {
6860b57cec5SDimitry Andric   Status error = m_gdb_client.CreateSymlink(src, dst);
6870b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
6889dba64beSDimitry Andric   LLDB_LOGF(log,
6899dba64beSDimitry Andric             "PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') "
6900b57cec5SDimitry Andric             "error = %u (%s)",
6910b57cec5SDimitry Andric             src.GetCString(), dst.GetCString(), error.GetError(),
6920b57cec5SDimitry Andric             error.AsCString());
6930b57cec5SDimitry Andric   return error;
6940b57cec5SDimitry Andric }
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric Status PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) {
6970b57cec5SDimitry Andric   Status error = m_gdb_client.Unlink(file_spec);
6980b57cec5SDimitry Andric   Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
6999dba64beSDimitry Andric   LLDB_LOGF(log, "PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)",
7000b57cec5SDimitry Andric             file_spec.GetCString(), error.GetError(), error.AsCString());
7010b57cec5SDimitry Andric   return error;
7020b57cec5SDimitry Andric }
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) {
7050b57cec5SDimitry Andric   return m_gdb_client.GetFileExists(file_spec);
7060b57cec5SDimitry Andric }
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric Status PlatformRemoteGDBServer::RunShellCommand(
7090b57cec5SDimitry Andric     const char *command, // Shouldn't be NULL
7100b57cec5SDimitry Andric     const FileSpec &
7110b57cec5SDimitry Andric         working_dir, // Pass empty FileSpec to use the current working directory
7120b57cec5SDimitry Andric     int *status_ptr, // Pass NULL if you don't want the process exit status
7130b57cec5SDimitry Andric     int *signo_ptr,  // Pass NULL if you don't want the signal that caused the
7140b57cec5SDimitry Andric                      // process to exit
7150b57cec5SDimitry Andric     std::string
7160b57cec5SDimitry Andric         *command_output, // Pass NULL if you don't want the command output
7170b57cec5SDimitry Andric     const Timeout<std::micro> &timeout) {
7180b57cec5SDimitry Andric   return m_gdb_client.RunShellCommand(command, working_dir, status_ptr,
7190b57cec5SDimitry Andric                                       signo_ptr, command_output, timeout);
7200b57cec5SDimitry Andric }
7210b57cec5SDimitry Andric 
7220b57cec5SDimitry Andric void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() {
7230b57cec5SDimitry Andric   m_trap_handlers.push_back(ConstString("_sigtramp"));
7240b57cec5SDimitry Andric }
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() {
7270b57cec5SDimitry Andric   if (!IsConnected())
7280b57cec5SDimitry Andric     return Platform::GetRemoteUnixSignals();
7290b57cec5SDimitry Andric 
7300b57cec5SDimitry Andric   if (m_remote_signals_sp)
7310b57cec5SDimitry Andric     return m_remote_signals_sp;
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric   // If packet not implemented or JSON failed to parse, we'll guess the signal
7340b57cec5SDimitry Andric   // set based on the remote architecture.
7350b57cec5SDimitry Andric   m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture());
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   StringExtractorGDBRemote response;
7380b57cec5SDimitry Andric   auto result = m_gdb_client.SendPacketAndWaitForResponse("jSignalsInfo",
7390b57cec5SDimitry Andric                                                           response, false);
7400b57cec5SDimitry Andric 
7410b57cec5SDimitry Andric   if (result != decltype(result)::Success ||
7420b57cec5SDimitry Andric       response.GetResponseType() != response.eResponse)
7430b57cec5SDimitry Andric     return m_remote_signals_sp;
7440b57cec5SDimitry Andric 
7455ffd83dbSDimitry Andric   auto object_sp =
7465ffd83dbSDimitry Andric       StructuredData::ParseJSON(std::string(response.GetStringRef()));
7470b57cec5SDimitry Andric   if (!object_sp || !object_sp->IsValid())
7480b57cec5SDimitry Andric     return m_remote_signals_sp;
7490b57cec5SDimitry Andric 
7500b57cec5SDimitry Andric   auto array_sp = object_sp->GetAsArray();
7510b57cec5SDimitry Andric   if (!array_sp || !array_sp->IsValid())
7520b57cec5SDimitry Andric     return m_remote_signals_sp;
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric   auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>();
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric   bool done = array_sp->ForEach(
7570b57cec5SDimitry Andric       [&remote_signals_sp](StructuredData::Object *object) -> bool {
7580b57cec5SDimitry Andric         if (!object || !object->IsValid())
7590b57cec5SDimitry Andric           return false;
7600b57cec5SDimitry Andric 
7610b57cec5SDimitry Andric         auto dict = object->GetAsDictionary();
7620b57cec5SDimitry Andric         if (!dict || !dict->IsValid())
7630b57cec5SDimitry Andric           return false;
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric         // Signal number and signal name are required.
7660b57cec5SDimitry Andric         int signo;
7670b57cec5SDimitry Andric         if (!dict->GetValueForKeyAsInteger("signo", signo))
7680b57cec5SDimitry Andric           return false;
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric         llvm::StringRef name;
7710b57cec5SDimitry Andric         if (!dict->GetValueForKeyAsString("name", name))
7720b57cec5SDimitry Andric           return false;
7730b57cec5SDimitry Andric 
7740b57cec5SDimitry Andric         // We can live without short_name, description, etc.
7750b57cec5SDimitry Andric         bool suppress{false};
7760b57cec5SDimitry Andric         auto object_sp = dict->GetValueForKey("suppress");
7770b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7780b57cec5SDimitry Andric           suppress = object_sp->GetBooleanValue();
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric         bool stop{false};
7810b57cec5SDimitry Andric         object_sp = dict->GetValueForKey("stop");
7820b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7830b57cec5SDimitry Andric           stop = object_sp->GetBooleanValue();
7840b57cec5SDimitry Andric 
7850b57cec5SDimitry Andric         bool notify{false};
7860b57cec5SDimitry Andric         object_sp = dict->GetValueForKey("notify");
7870b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7880b57cec5SDimitry Andric           notify = object_sp->GetBooleanValue();
7890b57cec5SDimitry Andric 
7900b57cec5SDimitry Andric         std::string description{""};
7910b57cec5SDimitry Andric         object_sp = dict->GetValueForKey("description");
7920b57cec5SDimitry Andric         if (object_sp && object_sp->IsValid())
7935ffd83dbSDimitry Andric           description = std::string(object_sp->GetStringValue());
7940b57cec5SDimitry Andric 
7950b57cec5SDimitry Andric         remote_signals_sp->AddSignal(signo, name.str().c_str(), suppress, stop,
7960b57cec5SDimitry Andric                                      notify, description.c_str());
7970b57cec5SDimitry Andric         return true;
7980b57cec5SDimitry Andric       });
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric   if (done)
8010b57cec5SDimitry Andric     m_remote_signals_sp = std::move(remote_signals_sp);
8020b57cec5SDimitry Andric 
8030b57cec5SDimitry Andric   return m_remote_signals_sp;
8040b57cec5SDimitry Andric }
8050b57cec5SDimitry Andric 
8060b57cec5SDimitry Andric std::string PlatformRemoteGDBServer::MakeGdbServerUrl(
8070b57cec5SDimitry Andric     const std::string &platform_scheme, const std::string &platform_hostname,
8080b57cec5SDimitry Andric     uint16_t port, const char *socket_name) {
8090b57cec5SDimitry Andric   const char *override_scheme =
8100b57cec5SDimitry Andric       getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME");
8110b57cec5SDimitry Andric   const char *override_hostname =
8120b57cec5SDimitry Andric       getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
8130b57cec5SDimitry Andric   const char *port_offset_c_str =
8140b57cec5SDimitry Andric       getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
8150b57cec5SDimitry Andric   int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
8160b57cec5SDimitry Andric 
8170b57cec5SDimitry Andric   return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(),
8180b57cec5SDimitry Andric                  override_hostname ? override_hostname
8190b57cec5SDimitry Andric                                    : platform_hostname.c_str(),
8200b57cec5SDimitry Andric                  port + port_offset, socket_name);
8210b57cec5SDimitry Andric }
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme,
8240b57cec5SDimitry Andric                                              const char *hostname,
8250b57cec5SDimitry Andric                                              uint16_t port, const char *path) {
8260b57cec5SDimitry Andric   StreamString result;
8270b57cec5SDimitry Andric   result.Printf("%s://%s", scheme, hostname);
8280b57cec5SDimitry Andric   if (port != 0)
8290b57cec5SDimitry Andric     result.Printf(":%u", port);
8300b57cec5SDimitry Andric   if (path)
8310b57cec5SDimitry Andric     result.Write(path, strlen(path));
8325ffd83dbSDimitry Andric   return std::string(result.GetString());
8330b57cec5SDimitry Andric }
8340b57cec5SDimitry Andric 
8350b57cec5SDimitry Andric lldb::ProcessSP PlatformRemoteGDBServer::ConnectProcess(
8360b57cec5SDimitry Andric     llvm::StringRef connect_url, llvm::StringRef plugin_name,
8370b57cec5SDimitry Andric     lldb_private::Debugger &debugger, lldb_private::Target *target,
8380b57cec5SDimitry Andric     lldb_private::Status &error) {
8390b57cec5SDimitry Andric   if (!IsRemote() || !IsConnected()) {
8400b57cec5SDimitry Andric     error.SetErrorString("Not connected to remote gdb server");
8410b57cec5SDimitry Andric     return nullptr;
8420b57cec5SDimitry Andric   }
8430b57cec5SDimitry Andric   return Platform::ConnectProcess(connect_url, plugin_name, debugger, target,
8440b57cec5SDimitry Andric                                   error);
8450b57cec5SDimitry Andric }
8460b57cec5SDimitry Andric 
8470b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger,
8480b57cec5SDimitry Andric                                                           Status &error) {
8490b57cec5SDimitry Andric   std::vector<std::string> connection_urls;
8500b57cec5SDimitry Andric   GetPendingGdbServerList(connection_urls);
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric   for (size_t i = 0; i < connection_urls.size(); ++i) {
8530b57cec5SDimitry Andric     ConnectProcess(connection_urls[i].c_str(), "", debugger, nullptr, error);
8540b57cec5SDimitry Andric     if (error.Fail())
8550b57cec5SDimitry Andric       return i; // We already connected to i process succsessfully
8560b57cec5SDimitry Andric   }
8570b57cec5SDimitry Andric   return connection_urls.size();
8580b57cec5SDimitry Andric }
8590b57cec5SDimitry Andric 
8600b57cec5SDimitry Andric size_t PlatformRemoteGDBServer::GetPendingGdbServerList(
8610b57cec5SDimitry Andric     std::vector<std::string> &connection_urls) {
8620b57cec5SDimitry Andric   std::vector<std::pair<uint16_t, std::string>> remote_servers;
8630b57cec5SDimitry Andric   m_gdb_client.QueryGDBServer(remote_servers);
8640b57cec5SDimitry Andric   for (const auto &gdbserver : remote_servers) {
8650b57cec5SDimitry Andric     const char *socket_name_cstr =
8660b57cec5SDimitry Andric         gdbserver.second.empty() ? nullptr : gdbserver.second.c_str();
8670b57cec5SDimitry Andric     connection_urls.emplace_back(
8680b57cec5SDimitry Andric         MakeGdbServerUrl(m_platform_scheme, m_platform_hostname,
8690b57cec5SDimitry Andric                          gdbserver.first, socket_name_cstr));
8700b57cec5SDimitry Andric   }
8710b57cec5SDimitry Andric   return connection_urls.size();
8720b57cec5SDimitry Andric }
873