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