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