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