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