1//===-- PlatformRemoteGDBServer.cpp ---------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "PlatformRemoteGDBServer.h"
10#include "lldb/Host/Config.h"
11
12#include "lldb/Breakpoint/BreakpointLocation.h"
13#include "lldb/Core/Debugger.h"
14#include "lldb/Core/Module.h"
15#include "lldb/Core/ModuleList.h"
16#include "lldb/Core/ModuleSpec.h"
17#include "lldb/Core/PluginManager.h"
18#include "lldb/Host/ConnectionFileDescriptor.h"
19#include "lldb/Host/Host.h"
20#include "lldb/Host/HostInfo.h"
21#include "lldb/Host/PosixApi.h"
22#include "lldb/Target/Process.h"
23#include "lldb/Target/Target.h"
24#include "lldb/Utility/FileSpec.h"
25#include "lldb/Utility/LLDBLog.h"
26#include "lldb/Utility/Log.h"
27#include "lldb/Utility/ProcessInfo.h"
28#include "lldb/Utility/Status.h"
29#include "lldb/Utility/StreamString.h"
30#include "lldb/Utility/UriParser.h"
31#include "llvm/ADT/StringSet.h"
32#include "llvm/Support/FormatAdapters.h"
33
34#include "Plugins/Process/Utility/GDBRemoteSignals.h"
35#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
36#include <mutex>
37#include <optional>
38
39using namespace lldb;
40using namespace lldb_private;
41using namespace lldb_private::platform_gdb_server;
42
43LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteGDBServer, PlatformGDB)
44
45static bool g_initialized = false;
46// UnixSignals does not store the signal names or descriptions itself.
47// It holds onto StringRefs. Becaue we may get signal information dynamically
48// from the remote, these strings need persistent storage client-side.
49static std::mutex g_signal_string_mutex;
50static llvm::StringSet<> g_signal_string_storage;
51
52void PlatformRemoteGDBServer::Initialize() {
53  Platform::Initialize();
54
55  if (!g_initialized) {
56    g_initialized = true;
57    PluginManager::RegisterPlugin(
58        PlatformRemoteGDBServer::GetPluginNameStatic(),
59        PlatformRemoteGDBServer::GetDescriptionStatic(),
60        PlatformRemoteGDBServer::CreateInstance);
61  }
62}
63
64void PlatformRemoteGDBServer::Terminate() {
65  if (g_initialized) {
66    g_initialized = false;
67    PluginManager::UnregisterPlugin(PlatformRemoteGDBServer::CreateInstance);
68  }
69
70  Platform::Terminate();
71}
72
73PlatformSP PlatformRemoteGDBServer::CreateInstance(bool force,
74                                                   const ArchSpec *arch) {
75  bool create = force;
76  if (!create) {
77    create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified();
78  }
79  if (create)
80    return PlatformSP(new PlatformRemoteGDBServer());
81  return PlatformSP();
82}
83
84llvm::StringRef PlatformRemoteGDBServer::GetDescriptionStatic() {
85  return "A platform that uses the GDB remote protocol as the communication "
86         "transport.";
87}
88
89llvm::StringRef PlatformRemoteGDBServer::GetDescription() {
90  if (m_platform_description.empty()) {
91    if (IsConnected()) {
92      // Send the get description packet
93    }
94  }
95
96  if (!m_platform_description.empty())
97    return m_platform_description.c_str();
98  return GetDescriptionStatic();
99}
100
101bool PlatformRemoteGDBServer::GetModuleSpec(const FileSpec &module_file_spec,
102                                            const ArchSpec &arch,
103                                            ModuleSpec &module_spec) {
104  Log *log = GetLog(LLDBLog::Platform);
105
106  const auto module_path = module_file_spec.GetPath(false);
107
108  if (!m_gdb_client_up ||
109      !m_gdb_client_up->GetModuleInfo(module_file_spec, arch, module_spec)) {
110    LLDB_LOGF(
111        log,
112        "PlatformRemoteGDBServer::%s - failed to get module info for %s:%s",
113        __FUNCTION__, module_path.c_str(),
114        arch.GetTriple().getTriple().c_str());
115    return false;
116  }
117
118  if (log) {
119    StreamString stream;
120    module_spec.Dump(stream);
121    LLDB_LOGF(log,
122              "PlatformRemoteGDBServer::%s - got module info for (%s:%s) : %s",
123              __FUNCTION__, module_path.c_str(),
124              arch.GetTriple().getTriple().c_str(), stream.GetData());
125  }
126
127  return true;
128}
129
130Status PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file,
131                                                const UUID *uuid_ptr,
132                                                FileSpec &local_file) {
133  // Default to the local case
134  local_file = platform_file;
135  return Status();
136}
137
138/// Default Constructor
139PlatformRemoteGDBServer::PlatformRemoteGDBServer()
140    : Platform(/*is_host=*/false) {}
141
142/// Destructor.
143///
144/// The destructor is virtual since this class is designed to be
145/// inherited from by the plug-in instance.
146PlatformRemoteGDBServer::~PlatformRemoteGDBServer() = default;
147
148size_t PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode(
149    Target &target, BreakpointSite *bp_site) {
150  // This isn't needed if the z/Z packets are supported in the GDB remote
151  // server. But we might need a packet to detect this.
152  return 0;
153}
154
155bool PlatformRemoteGDBServer::GetRemoteOSVersion() {
156  if (m_gdb_client_up)
157    m_os_version = m_gdb_client_up->GetOSVersion();
158  return !m_os_version.empty();
159}
160
161std::optional<std::string> PlatformRemoteGDBServer::GetRemoteOSBuildString() {
162  if (!m_gdb_client_up)
163    return std::nullopt;
164  return m_gdb_client_up->GetOSBuildString();
165}
166
167std::optional<std::string>
168PlatformRemoteGDBServer::GetRemoteOSKernelDescription() {
169  if (!m_gdb_client_up)
170    return std::nullopt;
171  return m_gdb_client_up->GetOSKernelDescription();
172}
173
174// Remote Platform subclasses need to override this function
175ArchSpec PlatformRemoteGDBServer::GetRemoteSystemArchitecture() {
176  if (!m_gdb_client_up)
177    return ArchSpec();
178  return m_gdb_client_up->GetSystemArchitecture();
179}
180
181FileSpec PlatformRemoteGDBServer::GetRemoteWorkingDirectory() {
182  if (IsConnected()) {
183    Log *log = GetLog(LLDBLog::Platform);
184    FileSpec working_dir;
185    if (m_gdb_client_up->GetWorkingDir(working_dir) && log)
186      LLDB_LOGF(log,
187                "PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'",
188                working_dir.GetPath().c_str());
189    return working_dir;
190  } else {
191    return Platform::GetRemoteWorkingDirectory();
192  }
193}
194
195bool PlatformRemoteGDBServer::SetRemoteWorkingDirectory(
196    const FileSpec &working_dir) {
197  if (IsConnected()) {
198    // Clear the working directory it case it doesn't get set correctly. This
199    // will for use to re-read it
200    Log *log = GetLog(LLDBLog::Platform);
201    LLDB_LOGF(log, "PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')",
202              working_dir.GetPath().c_str());
203    return m_gdb_client_up->SetWorkingDir(working_dir) == 0;
204  } else
205    return Platform::SetRemoteWorkingDirectory(working_dir);
206}
207
208bool PlatformRemoteGDBServer::IsConnected() const {
209  if (m_gdb_client_up) {
210    assert(m_gdb_client_up->IsConnected());
211    return true;
212  }
213  return false;
214}
215
216Status PlatformRemoteGDBServer::ConnectRemote(Args &args) {
217  Status error;
218  if (IsConnected()) {
219    error.SetErrorStringWithFormat("the platform is already connected to '%s', "
220                                   "execute 'platform disconnect' to close the "
221                                   "current connection",
222                                   GetHostname());
223    return error;
224  }
225
226  if (args.GetArgumentCount() != 1) {
227    error.SetErrorString(
228        "\"platform connect\" takes a single argument: <connect-url>");
229    return error;
230  }
231
232  const char *url = args.GetArgumentAtIndex(0);
233  if (!url)
234    return Status("URL is null.");
235
236  std::optional<URI> parsed_url = URI::Parse(url);
237  if (!parsed_url)
238    return Status("Invalid URL: %s", url);
239
240  // We're going to reuse the hostname when we connect to the debugserver.
241  m_platform_scheme = parsed_url->scheme.str();
242  m_platform_hostname = parsed_url->hostname.str();
243
244  auto client_up =
245      std::make_unique<process_gdb_remote::GDBRemoteCommunicationClient>();
246  client_up->SetPacketTimeout(
247      process_gdb_remote::ProcessGDBRemote::GetPacketTimeout());
248  client_up->SetConnection(std::make_unique<ConnectionFileDescriptor>());
249  client_up->Connect(url, &error);
250
251  if (error.Fail())
252    return error;
253
254  if (client_up->HandshakeWithServer(&error)) {
255    m_gdb_client_up = std::move(client_up);
256    m_gdb_client_up->GetHostInfo();
257    // If a working directory was set prior to connecting, send it down
258    // now.
259    if (m_working_dir)
260      m_gdb_client_up->SetWorkingDir(m_working_dir);
261
262    m_supported_architectures.clear();
263    ArchSpec remote_arch = m_gdb_client_up->GetSystemArchitecture();
264    if (remote_arch) {
265      m_supported_architectures.push_back(remote_arch);
266      if (remote_arch.GetTriple().isArch64Bit())
267        m_supported_architectures.push_back(
268            ArchSpec(remote_arch.GetTriple().get32BitArchVariant()));
269    }
270  } else {
271    client_up->Disconnect();
272    if (error.Success())
273      error.SetErrorString("handshake failed");
274  }
275  return error;
276}
277
278Status PlatformRemoteGDBServer::DisconnectRemote() {
279  Status error;
280  m_gdb_client_up.reset();
281  m_remote_signals_sp.reset();
282  return error;
283}
284
285const char *PlatformRemoteGDBServer::GetHostname() {
286  if (m_gdb_client_up)
287    m_gdb_client_up->GetHostname(m_hostname);
288  if (m_hostname.empty())
289    return nullptr;
290  return m_hostname.c_str();
291}
292
293std::optional<std::string>
294PlatformRemoteGDBServer::DoGetUserName(UserIDResolver::id_t uid) {
295  std::string name;
296  if (m_gdb_client_up && m_gdb_client_up->GetUserName(uid, name))
297    return std::move(name);
298  return std::nullopt;
299}
300
301std::optional<std::string>
302PlatformRemoteGDBServer::DoGetGroupName(UserIDResolver::id_t gid) {
303  std::string name;
304  if (m_gdb_client_up && m_gdb_client_up->GetGroupName(gid, name))
305    return std::move(name);
306  return std::nullopt;
307}
308
309uint32_t PlatformRemoteGDBServer::FindProcesses(
310    const ProcessInstanceInfoMatch &match_info,
311    ProcessInstanceInfoList &process_infos) {
312  if (m_gdb_client_up)
313    return m_gdb_client_up->FindProcesses(match_info, process_infos);
314  return 0;
315}
316
317bool PlatformRemoteGDBServer::GetProcessInfo(
318    lldb::pid_t pid, ProcessInstanceInfo &process_info) {
319  if (m_gdb_client_up)
320    return m_gdb_client_up->GetProcessInfo(pid, process_info);
321  return false;
322}
323
324Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) {
325  Log *log = GetLog(LLDBLog::Platform);
326  Status error;
327
328  LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() called", __FUNCTION__);
329
330  if (!IsConnected())
331    return Status("Not connected.");
332  auto num_file_actions = launch_info.GetNumFileActions();
333  for (decltype(num_file_actions) i = 0; i < num_file_actions; ++i) {
334    const auto file_action = launch_info.GetFileActionAtIndex(i);
335    if (file_action->GetAction() != FileAction::eFileActionOpen)
336      continue;
337    switch (file_action->GetFD()) {
338    case STDIN_FILENO:
339      m_gdb_client_up->SetSTDIN(file_action->GetFileSpec());
340      break;
341    case STDOUT_FILENO:
342      m_gdb_client_up->SetSTDOUT(file_action->GetFileSpec());
343      break;
344    case STDERR_FILENO:
345      m_gdb_client_up->SetSTDERR(file_action->GetFileSpec());
346      break;
347    }
348  }
349
350  m_gdb_client_up->SetDisableASLR(
351      launch_info.GetFlags().Test(eLaunchFlagDisableASLR));
352  m_gdb_client_up->SetDetachOnError(
353      launch_info.GetFlags().Test(eLaunchFlagDetachOnError));
354
355  FileSpec working_dir = launch_info.GetWorkingDirectory();
356  if (working_dir) {
357    m_gdb_client_up->SetWorkingDir(working_dir);
358  }
359
360  // Send the environment and the program + arguments after we connect
361  m_gdb_client_up->SendEnvironment(launch_info.GetEnvironment());
362
363  ArchSpec arch_spec = launch_info.GetArchitecture();
364  const char *arch_triple = arch_spec.GetTriple().str().c_str();
365
366  m_gdb_client_up->SendLaunchArchPacket(arch_triple);
367  LLDB_LOGF(
368      log,
369      "PlatformRemoteGDBServer::%s() set launch architecture triple to '%s'",
370      __FUNCTION__, arch_triple ? arch_triple : "<NULL>");
371
372  {
373    // Scope for the scoped timeout object
374    process_gdb_remote::GDBRemoteCommunication::ScopedTimeout timeout(
375        *m_gdb_client_up, std::chrono::seconds(5));
376    // Since we can't send argv0 separate from the executable path, we need to
377    // make sure to use the actual executable path found in the launch_info...
378    Args args = launch_info.GetArguments();
379    if (FileSpec exe_file = launch_info.GetExecutableFile())
380      args.ReplaceArgumentAtIndex(0, exe_file.GetPath(false));
381    if (llvm::Error err = m_gdb_client_up->LaunchProcess(args)) {
382      error.SetErrorStringWithFormatv("Cannot launch '{0}': {1}",
383                                      args.GetArgumentAtIndex(0),
384                                      llvm::fmt_consume(std::move(err)));
385      return error;
386    }
387  }
388
389  const auto pid = m_gdb_client_up->GetCurrentProcessID(false);
390  if (pid != LLDB_INVALID_PROCESS_ID) {
391    launch_info.SetProcessID(pid);
392    LLDB_LOGF(log,
393              "PlatformRemoteGDBServer::%s() pid %" PRIu64
394              " launched successfully",
395              __FUNCTION__, pid);
396  } else {
397    LLDB_LOGF(log,
398              "PlatformRemoteGDBServer::%s() launch succeeded but we "
399              "didn't get a valid process id back!",
400              __FUNCTION__);
401    error.SetErrorString("failed to get PID");
402  }
403  return error;
404}
405
406Status PlatformRemoteGDBServer::KillProcess(const lldb::pid_t pid) {
407  if (!KillSpawnedProcess(pid))
408    return Status("failed to kill remote spawned process");
409  return Status();
410}
411
412lldb::ProcessSP
413PlatformRemoteGDBServer::DebugProcess(ProcessLaunchInfo &launch_info,
414                                      Debugger &debugger, Target &target,
415                                      Status &error) {
416  lldb::ProcessSP process_sp;
417  if (IsRemote()) {
418    if (IsConnected()) {
419      lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
420      std::string connect_url;
421      if (!LaunchGDBServer(debugserver_pid, connect_url)) {
422        error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
423                                       GetHostname());
424      } else {
425        // The darwin always currently uses the GDB remote debugger plug-in
426        // so even when debugging locally we are debugging remotely!
427        process_sp = target.CreateProcess(launch_info.GetListener(),
428                                          "gdb-remote", nullptr, true);
429
430        if (process_sp) {
431          process_sp->HijackProcessEvents(launch_info.GetHijackListener());
432          process_sp->SetShadowListener(launch_info.GetShadowListener());
433
434          error = process_sp->ConnectRemote(connect_url.c_str());
435          // Retry the connect remote one time...
436          if (error.Fail())
437            error = process_sp->ConnectRemote(connect_url.c_str());
438          if (error.Success())
439            error = process_sp->Launch(launch_info);
440          else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) {
441            printf("error: connect remote failed (%s)\n", error.AsCString());
442            KillSpawnedProcess(debugserver_pid);
443          }
444        }
445      }
446    } else {
447      error.SetErrorString("not connected to remote gdb server");
448    }
449  }
450  return process_sp;
451}
452
453bool PlatformRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid,
454                                              std::string &connect_url) {
455  assert(IsConnected());
456
457  ArchSpec remote_arch = GetRemoteSystemArchitecture();
458  llvm::Triple &remote_triple = remote_arch.GetTriple();
459
460  uint16_t port = 0;
461  std::string socket_name;
462  bool launch_result = false;
463  if (remote_triple.getVendor() == llvm::Triple::Apple &&
464      remote_triple.getOS() == llvm::Triple::IOS) {
465    // When remote debugging to iOS, we use a USB mux that always talks to
466    // localhost, so we will need the remote debugserver to accept connections
467    // only from localhost, no matter what our current hostname is
468    launch_result =
469        m_gdb_client_up->LaunchGDBServer("127.0.0.1", pid, port, socket_name);
470  } else {
471    // All other hosts should use their actual hostname
472    launch_result =
473        m_gdb_client_up->LaunchGDBServer(nullptr, pid, port, socket_name);
474  }
475
476  if (!launch_result)
477    return false;
478
479  connect_url =
480      MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port,
481                       (socket_name.empty()) ? nullptr : socket_name.c_str());
482  return true;
483}
484
485bool PlatformRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) {
486  assert(IsConnected());
487  return m_gdb_client_up->KillSpawnedProcess(pid);
488}
489
490lldb::ProcessSP PlatformRemoteGDBServer::Attach(
491    ProcessAttachInfo &attach_info, Debugger &debugger,
492    Target *target, // Can be NULL, if NULL create a new target, else use
493                    // existing one
494    Status &error) {
495  lldb::ProcessSP process_sp;
496  if (IsRemote()) {
497    if (IsConnected()) {
498      lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
499      std::string connect_url;
500      if (!LaunchGDBServer(debugserver_pid, connect_url)) {
501        error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
502                                       GetHostname());
503      } else {
504        if (target == nullptr) {
505          TargetSP new_target_sp;
506
507          error = debugger.GetTargetList().CreateTarget(
508              debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
509          target = new_target_sp.get();
510        } else
511          error.Clear();
512
513        if (target && error.Success()) {
514          // The darwin always currently uses the GDB remote debugger plug-in
515          // so even when debugging locally we are debugging remotely!
516          process_sp =
517              target->CreateProcess(attach_info.GetListenerForProcess(debugger),
518                                    "gdb-remote", nullptr, true);
519          if (process_sp) {
520            error = process_sp->ConnectRemote(connect_url.c_str());
521            if (error.Success()) {
522              ListenerSP listener_sp = attach_info.GetHijackListener();
523              if (listener_sp)
524                process_sp->HijackProcessEvents(listener_sp);
525              process_sp->SetShadowListener(attach_info.GetShadowListener());
526              error = process_sp->Attach(attach_info);
527            }
528
529            if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) {
530              KillSpawnedProcess(debugserver_pid);
531            }
532          }
533        }
534      }
535    } else {
536      error.SetErrorString("not connected to remote gdb server");
537    }
538  }
539  return process_sp;
540}
541
542Status PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec,
543                                              uint32_t mode) {
544  if (!IsConnected())
545    return Status("Not connected.");
546  Status error = m_gdb_client_up->MakeDirectory(file_spec, mode);
547  Log *log = GetLog(LLDBLog::Platform);
548  LLDB_LOGF(log,
549            "PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) "
550            "error = %u (%s)",
551            file_spec.GetPath().c_str(), mode, error.GetError(),
552            error.AsCString());
553  return error;
554}
555
556Status PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec,
557                                                   uint32_t &file_permissions) {
558  if (!IsConnected())
559    return Status("Not connected.");
560  Status error =
561      m_gdb_client_up->GetFilePermissions(file_spec, file_permissions);
562  Log *log = GetLog(LLDBLog::Platform);
563  LLDB_LOGF(log,
564            "PlatformRemoteGDBServer::GetFilePermissions(path='%s', "
565            "file_permissions=%o) error = %u (%s)",
566            file_spec.GetPath().c_str(), file_permissions, error.GetError(),
567            error.AsCString());
568  return error;
569}
570
571Status PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
572                                                   uint32_t file_permissions) {
573  if (!IsConnected())
574    return Status("Not connected.");
575  Status error =
576      m_gdb_client_up->SetFilePermissions(file_spec, file_permissions);
577  Log *log = GetLog(LLDBLog::Platform);
578  LLDB_LOGF(log,
579            "PlatformRemoteGDBServer::SetFilePermissions(path='%s', "
580            "file_permissions=%o) error = %u (%s)",
581            file_spec.GetPath().c_str(), file_permissions, error.GetError(),
582            error.AsCString());
583  return error;
584}
585
586lldb::user_id_t PlatformRemoteGDBServer::OpenFile(const FileSpec &file_spec,
587                                                  File::OpenOptions flags,
588                                                  uint32_t mode,
589                                                  Status &error) {
590  if (IsConnected())
591    return m_gdb_client_up->OpenFile(file_spec, flags, mode, error);
592  return LLDB_INVALID_UID;
593}
594
595bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Status &error) {
596  if (IsConnected())
597    return m_gdb_client_up->CloseFile(fd, error);
598  error = Status("Not connected.");
599  return false;
600}
601
602lldb::user_id_t
603PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) {
604  if (IsConnected())
605    return m_gdb_client_up->GetFileSize(file_spec);
606  return LLDB_INVALID_UID;
607}
608
609void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory(
610    CompletionRequest &request, bool only_dir) {
611  if (IsConnected())
612    m_gdb_client_up->AutoCompleteDiskFileOrDirectory(request, only_dir);
613}
614
615uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset,
616                                           void *dst, uint64_t dst_len,
617                                           Status &error) {
618  if (IsConnected())
619    return m_gdb_client_up->ReadFile(fd, offset, dst, dst_len, error);
620  error = Status("Not connected.");
621  return 0;
622}
623
624uint64_t PlatformRemoteGDBServer::WriteFile(lldb::user_id_t fd, uint64_t offset,
625                                            const void *src, uint64_t src_len,
626                                            Status &error) {
627  if (IsConnected())
628    return m_gdb_client_up->WriteFile(fd, offset, src, src_len, error);
629  error = Status("Not connected.");
630  return 0;
631}
632
633Status PlatformRemoteGDBServer::PutFile(const FileSpec &source,
634                                        const FileSpec &destination,
635                                        uint32_t uid, uint32_t gid) {
636  return Platform::PutFile(source, destination, uid, gid);
637}
638
639Status PlatformRemoteGDBServer::CreateSymlink(
640    const FileSpec &src, // The name of the link is in src
641    const FileSpec &dst) // The symlink points to dst
642{
643  if (!IsConnected())
644    return Status("Not connected.");
645  Status error = m_gdb_client_up->CreateSymlink(src, dst);
646  Log *log = GetLog(LLDBLog::Platform);
647  LLDB_LOGF(log,
648            "PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') "
649            "error = %u (%s)",
650            src.GetPath().c_str(), dst.GetPath().c_str(), error.GetError(),
651            error.AsCString());
652  return error;
653}
654
655Status PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) {
656  if (!IsConnected())
657    return Status("Not connected.");
658  Status error = m_gdb_client_up->Unlink(file_spec);
659  Log *log = GetLog(LLDBLog::Platform);
660  LLDB_LOGF(log, "PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)",
661            file_spec.GetPath().c_str(), error.GetError(), error.AsCString());
662  return error;
663}
664
665bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) {
666  if (IsConnected())
667    return m_gdb_client_up->GetFileExists(file_spec);
668  return false;
669}
670
671Status PlatformRemoteGDBServer::RunShellCommand(
672    llvm::StringRef shell, llvm::StringRef command,
673    const FileSpec &
674        working_dir, // Pass empty FileSpec to use the current working directory
675    int *status_ptr, // Pass NULL if you don't want the process exit status
676    int *signo_ptr,  // Pass NULL if you don't want the signal that caused the
677                     // process to exit
678    std::string
679        *command_output, // Pass NULL if you don't want the command output
680    const Timeout<std::micro> &timeout) {
681  if (!IsConnected())
682    return Status("Not connected.");
683  return m_gdb_client_up->RunShellCommand(command, working_dir, status_ptr,
684                                          signo_ptr, command_output, timeout);
685}
686
687void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() {
688  m_trap_handlers.push_back(ConstString("_sigtramp"));
689}
690
691const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() {
692  if (!IsConnected())
693    return Platform::GetRemoteUnixSignals();
694
695  if (m_remote_signals_sp)
696    return m_remote_signals_sp;
697
698  // If packet not implemented or JSON failed to parse, we'll guess the signal
699  // set based on the remote architecture.
700  m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture());
701
702  StringExtractorGDBRemote response;
703  auto result =
704      m_gdb_client_up->SendPacketAndWaitForResponse("jSignalsInfo", response);
705
706  if (result != decltype(result)::Success ||
707      response.GetResponseType() != response.eResponse)
708    return m_remote_signals_sp;
709
710  auto object_sp = StructuredData::ParseJSON(response.GetStringRef());
711  if (!object_sp || !object_sp->IsValid())
712    return m_remote_signals_sp;
713
714  auto array_sp = object_sp->GetAsArray();
715  if (!array_sp || !array_sp->IsValid())
716    return m_remote_signals_sp;
717
718  auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>();
719
720  bool done = array_sp->ForEach(
721      [&remote_signals_sp](StructuredData::Object *object) -> bool {
722        if (!object || !object->IsValid())
723          return false;
724
725        auto dict = object->GetAsDictionary();
726        if (!dict || !dict->IsValid())
727          return false;
728
729        // Signal number and signal name are required.
730        uint64_t signo;
731        if (!dict->GetValueForKeyAsInteger("signo", signo))
732          return false;
733
734        llvm::StringRef name;
735        if (!dict->GetValueForKeyAsString("name", name))
736          return false;
737
738        // We can live without short_name, description, etc.
739        bool suppress{false};
740        auto object_sp = dict->GetValueForKey("suppress");
741        if (object_sp && object_sp->IsValid())
742          suppress = object_sp->GetBooleanValue();
743
744        bool stop{false};
745        object_sp = dict->GetValueForKey("stop");
746        if (object_sp && object_sp->IsValid())
747          stop = object_sp->GetBooleanValue();
748
749        bool notify{false};
750        object_sp = dict->GetValueForKey("notify");
751        if (object_sp && object_sp->IsValid())
752          notify = object_sp->GetBooleanValue();
753
754        std::string description;
755        object_sp = dict->GetValueForKey("description");
756        if (object_sp && object_sp->IsValid())
757          description = std::string(object_sp->GetStringValue());
758
759        llvm::StringRef name_backed, description_backed;
760        {
761          std::lock_guard<std::mutex> guard(g_signal_string_mutex);
762          name_backed =
763              g_signal_string_storage.insert(name).first->getKeyData();
764          if (!description.empty())
765            description_backed =
766                g_signal_string_storage.insert(description).first->getKeyData();
767        }
768
769        remote_signals_sp->AddSignal(signo, name_backed, suppress, stop, notify,
770                                     description_backed);
771        return true;
772      });
773
774  if (done)
775    m_remote_signals_sp = std::move(remote_signals_sp);
776
777  return m_remote_signals_sp;
778}
779
780std::string PlatformRemoteGDBServer::MakeGdbServerUrl(
781    const std::string &platform_scheme, const std::string &platform_hostname,
782    uint16_t port, const char *socket_name) {
783  const char *override_scheme =
784      getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME");
785  const char *override_hostname =
786      getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
787  const char *port_offset_c_str =
788      getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
789  int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
790
791  return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(),
792                 override_hostname ? override_hostname
793                                   : platform_hostname.c_str(),
794                 port + port_offset, socket_name);
795}
796
797std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme,
798                                             const char *hostname,
799                                             uint16_t port, const char *path) {
800  StreamString result;
801  result.Printf("%s://[%s]", scheme, hostname);
802  if (port != 0)
803    result.Printf(":%u", port);
804  if (path)
805    result.Write(path, strlen(path));
806  return std::string(result.GetString());
807}
808
809size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger,
810                                                          Status &error) {
811  std::vector<std::string> connection_urls;
812  GetPendingGdbServerList(connection_urls);
813
814  for (size_t i = 0; i < connection_urls.size(); ++i) {
815    ConnectProcess(connection_urls[i].c_str(), "gdb-remote", debugger, nullptr, error);
816    if (error.Fail())
817      return i; // We already connected to i process successfully
818  }
819  return connection_urls.size();
820}
821
822size_t PlatformRemoteGDBServer::GetPendingGdbServerList(
823    std::vector<std::string> &connection_urls) {
824  std::vector<std::pair<uint16_t, std::string>> remote_servers;
825  if (!IsConnected())
826    return 0;
827  m_gdb_client_up->QueryGDBServer(remote_servers);
828  for (const auto &gdbserver : remote_servers) {
829    const char *socket_name_cstr =
830        gdbserver.second.empty() ? nullptr : gdbserver.second.c_str();
831    connection_urls.emplace_back(
832        MakeGdbServerUrl(m_platform_scheme, m_platform_hostname,
833                         gdbserver.first, socket_name_cstr));
834  }
835  return connection_urls.size();
836}
837