1 //===-- SBPlatform.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 "lldb/API/SBPlatform.h"
10 #include "lldb/API/SBDebugger.h"
11 #include "lldb/API/SBEnvironment.h"
12 #include "lldb/API/SBError.h"
13 #include "lldb/API/SBFileSpec.h"
14 #include "lldb/API/SBLaunchInfo.h"
15 #include "lldb/API/SBModuleSpec.h"
16 #include "lldb/API/SBPlatform.h"
17 #include "lldb/API/SBProcessInfoList.h"
18 #include "lldb/API/SBTarget.h"
19 #include "lldb/API/SBUnixSignals.h"
20 #include "lldb/Host/File.h"
21 #include "lldb/Target/Platform.h"
22 #include "lldb/Target/Target.h"
23 #include "lldb/Utility/ArchSpec.h"
24 #include "lldb/Utility/Args.h"
25 #include "lldb/Utility/Instrumentation.h"
26 #include "lldb/Utility/Status.h"
27 
28 #include "llvm/Support/FileSystem.h"
29 
30 #include <functional>
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 
35 // PlatformConnectOptions
36 struct PlatformConnectOptions {
37   PlatformConnectOptions(const char *url = nullptr) {
38     if (url && url[0])
39       m_url = url;
40   }
41 
42   ~PlatformConnectOptions() = default;
43 
44   std::string m_url;
45   std::string m_rsync_options;
46   std::string m_rsync_remote_path_prefix;
47   bool m_rsync_enabled = false;
48   bool m_rsync_omit_hostname_from_remote_path = false;
49   ConstString m_local_cache_directory;
50 };
51 
52 // PlatformShellCommand
53 struct PlatformShellCommand {
54   PlatformShellCommand(llvm::StringRef shell_interpreter,
55                        llvm::StringRef shell_command) {
56     if (!shell_interpreter.empty())
57       m_shell = shell_interpreter.str();
58 
59     if (!m_shell.empty() && !shell_command.empty())
60       m_command = shell_command.str();
61   }
62 
63   PlatformShellCommand(llvm::StringRef shell_command = llvm::StringRef()) {
64     if (!shell_command.empty())
65       m_command = shell_command.str();
66   }
67 
68   ~PlatformShellCommand() = default;
69 
70   std::string m_shell;
71   std::string m_command;
72   std::string m_working_dir;
73   std::string m_output;
74   int m_status = 0;
75   int m_signo = 0;
76   Timeout<std::ratio<1>> m_timeout = std::nullopt;
77 };
78 // SBPlatformConnectOptions
79 SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url)
80     : m_opaque_ptr(new PlatformConnectOptions(url)) {
81   LLDB_INSTRUMENT_VA(this, url);
82 }
83 
84 SBPlatformConnectOptions::SBPlatformConnectOptions(
85     const SBPlatformConnectOptions &rhs)
86     : m_opaque_ptr(new PlatformConnectOptions()) {
87   LLDB_INSTRUMENT_VA(this, rhs);
88 
89   *m_opaque_ptr = *rhs.m_opaque_ptr;
90 }
91 
92 SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; }
93 
94 SBPlatformConnectOptions &
95 SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) {
96   LLDB_INSTRUMENT_VA(this, rhs);
97 
98   *m_opaque_ptr = *rhs.m_opaque_ptr;
99   return *this;
100 }
101 
102 const char *SBPlatformConnectOptions::GetURL() {
103   LLDB_INSTRUMENT_VA(this);
104 
105   if (m_opaque_ptr->m_url.empty())
106     return nullptr;
107   return ConstString(m_opaque_ptr->m_url.c_str()).GetCString();
108 }
109 
110 void SBPlatformConnectOptions::SetURL(const char *url) {
111   LLDB_INSTRUMENT_VA(this, url);
112 
113   if (url && url[0])
114     m_opaque_ptr->m_url = url;
115   else
116     m_opaque_ptr->m_url.clear();
117 }
118 
119 bool SBPlatformConnectOptions::GetRsyncEnabled() {
120   LLDB_INSTRUMENT_VA(this);
121 
122   return m_opaque_ptr->m_rsync_enabled;
123 }
124 
125 void SBPlatformConnectOptions::EnableRsync(
126     const char *options, const char *remote_path_prefix,
127     bool omit_hostname_from_remote_path) {
128   LLDB_INSTRUMENT_VA(this, options, remote_path_prefix,
129                      omit_hostname_from_remote_path);
130 
131   m_opaque_ptr->m_rsync_enabled = true;
132   m_opaque_ptr->m_rsync_omit_hostname_from_remote_path =
133       omit_hostname_from_remote_path;
134   if (remote_path_prefix && remote_path_prefix[0])
135     m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix;
136   else
137     m_opaque_ptr->m_rsync_remote_path_prefix.clear();
138 
139   if (options && options[0])
140     m_opaque_ptr->m_rsync_options = options;
141   else
142     m_opaque_ptr->m_rsync_options.clear();
143 }
144 
145 void SBPlatformConnectOptions::DisableRsync() {
146   LLDB_INSTRUMENT_VA(this);
147 
148   m_opaque_ptr->m_rsync_enabled = false;
149 }
150 
151 const char *SBPlatformConnectOptions::GetLocalCacheDirectory() {
152   LLDB_INSTRUMENT_VA(this);
153 
154   return m_opaque_ptr->m_local_cache_directory.GetCString();
155 }
156 
157 void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) {
158   LLDB_INSTRUMENT_VA(this, path);
159 
160   if (path && path[0])
161     m_opaque_ptr->m_local_cache_directory.SetCString(path);
162   else
163     m_opaque_ptr->m_local_cache_directory = ConstString();
164 }
165 
166 // SBPlatformShellCommand
167 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_interpreter,
168                                                const char *shell_command)
169     : m_opaque_ptr(new PlatformShellCommand(shell_interpreter, shell_command)) {
170   LLDB_INSTRUMENT_VA(this, shell_interpreter, shell_command);
171 }
172 
173 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command)
174     : m_opaque_ptr(new PlatformShellCommand(shell_command)) {
175   LLDB_INSTRUMENT_VA(this, shell_command);
176 }
177 
178 SBPlatformShellCommand::SBPlatformShellCommand(
179     const SBPlatformShellCommand &rhs)
180     : m_opaque_ptr(new PlatformShellCommand()) {
181   LLDB_INSTRUMENT_VA(this, rhs);
182 
183   *m_opaque_ptr = *rhs.m_opaque_ptr;
184 }
185 
186 SBPlatformShellCommand &
187 SBPlatformShellCommand::operator=(const SBPlatformShellCommand &rhs) {
188 
189   LLDB_INSTRUMENT_VA(this, rhs);
190 
191   *m_opaque_ptr = *rhs.m_opaque_ptr;
192   return *this;
193 }
194 
195 SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; }
196 
197 void SBPlatformShellCommand::Clear() {
198   LLDB_INSTRUMENT_VA(this);
199 
200   m_opaque_ptr->m_output = std::string();
201   m_opaque_ptr->m_status = 0;
202   m_opaque_ptr->m_signo = 0;
203 }
204 
205 const char *SBPlatformShellCommand::GetShell() {
206   LLDB_INSTRUMENT_VA(this);
207 
208   if (m_opaque_ptr->m_shell.empty())
209     return nullptr;
210   return ConstString(m_opaque_ptr->m_shell.c_str()).GetCString();
211 }
212 
213 void SBPlatformShellCommand::SetShell(const char *shell_interpreter) {
214   LLDB_INSTRUMENT_VA(this, shell_interpreter);
215 
216   if (shell_interpreter && shell_interpreter[0])
217     m_opaque_ptr->m_shell = shell_interpreter;
218   else
219     m_opaque_ptr->m_shell.clear();
220 }
221 
222 const char *SBPlatformShellCommand::GetCommand() {
223   LLDB_INSTRUMENT_VA(this);
224 
225   if (m_opaque_ptr->m_command.empty())
226     return nullptr;
227   return ConstString(m_opaque_ptr->m_command.c_str()).GetCString();
228 }
229 
230 void SBPlatformShellCommand::SetCommand(const char *shell_command) {
231   LLDB_INSTRUMENT_VA(this, shell_command);
232 
233   if (shell_command && shell_command[0])
234     m_opaque_ptr->m_command = shell_command;
235   else
236     m_opaque_ptr->m_command.clear();
237 }
238 
239 const char *SBPlatformShellCommand::GetWorkingDirectory() {
240   LLDB_INSTRUMENT_VA(this);
241 
242   if (m_opaque_ptr->m_working_dir.empty())
243     return nullptr;
244   return ConstString(m_opaque_ptr->m_working_dir.c_str()).GetCString();
245 }
246 
247 void SBPlatformShellCommand::SetWorkingDirectory(const char *path) {
248   LLDB_INSTRUMENT_VA(this, path);
249 
250   if (path && path[0])
251     m_opaque_ptr->m_working_dir = path;
252   else
253     m_opaque_ptr->m_working_dir.clear();
254 }
255 
256 uint32_t SBPlatformShellCommand::GetTimeoutSeconds() {
257   LLDB_INSTRUMENT_VA(this);
258 
259   if (m_opaque_ptr->m_timeout)
260     return m_opaque_ptr->m_timeout->count();
261   return UINT32_MAX;
262 }
263 
264 void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec) {
265   LLDB_INSTRUMENT_VA(this, sec);
266 
267   if (sec == UINT32_MAX)
268     m_opaque_ptr->m_timeout = std::nullopt;
269   else
270     m_opaque_ptr->m_timeout = std::chrono::seconds(sec);
271 }
272 
273 int SBPlatformShellCommand::GetSignal() {
274   LLDB_INSTRUMENT_VA(this);
275 
276   return m_opaque_ptr->m_signo;
277 }
278 
279 int SBPlatformShellCommand::GetStatus() {
280   LLDB_INSTRUMENT_VA(this);
281 
282   return m_opaque_ptr->m_status;
283 }
284 
285 const char *SBPlatformShellCommand::GetOutput() {
286   LLDB_INSTRUMENT_VA(this);
287 
288   if (m_opaque_ptr->m_output.empty())
289     return nullptr;
290   return ConstString(m_opaque_ptr->m_output.c_str()).GetCString();
291 }
292 
293 // SBPlatform
294 SBPlatform::SBPlatform() { LLDB_INSTRUMENT_VA(this); }
295 
296 SBPlatform::SBPlatform(const char *platform_name) {
297   LLDB_INSTRUMENT_VA(this, platform_name);
298 
299   m_opaque_sp = Platform::Create(platform_name);
300 }
301 
302 SBPlatform::SBPlatform(const SBPlatform &rhs) {
303   LLDB_INSTRUMENT_VA(this, rhs);
304 
305   m_opaque_sp = rhs.m_opaque_sp;
306 }
307 
308 SBPlatform &SBPlatform::operator=(const SBPlatform &rhs) {
309   LLDB_INSTRUMENT_VA(this, rhs);
310 
311   m_opaque_sp = rhs.m_opaque_sp;
312   return *this;
313 }
314 
315 SBPlatform::~SBPlatform() = default;
316 
317 SBPlatform SBPlatform::GetHostPlatform() {
318   LLDB_INSTRUMENT();
319 
320   SBPlatform host_platform;
321   host_platform.m_opaque_sp = Platform::GetHostPlatform();
322   return host_platform;
323 }
324 
325 bool SBPlatform::IsValid() const {
326   LLDB_INSTRUMENT_VA(this);
327   return this->operator bool();
328 }
329 SBPlatform::operator bool() const {
330   LLDB_INSTRUMENT_VA(this);
331 
332   return m_opaque_sp.get() != nullptr;
333 }
334 
335 void SBPlatform::Clear() {
336   LLDB_INSTRUMENT_VA(this);
337 
338   m_opaque_sp.reset();
339 }
340 
341 const char *SBPlatform::GetName() {
342   LLDB_INSTRUMENT_VA(this);
343 
344   PlatformSP platform_sp(GetSP());
345   if (platform_sp)
346     return ConstString(platform_sp->GetName()).AsCString();
347   return nullptr;
348 }
349 
350 lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; }
351 
352 void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) {
353   m_opaque_sp = platform_sp;
354 }
355 
356 const char *SBPlatform::GetWorkingDirectory() {
357   LLDB_INSTRUMENT_VA(this);
358 
359   PlatformSP platform_sp(GetSP());
360   if (platform_sp)
361     return platform_sp->GetWorkingDirectory().GetPathAsConstString().AsCString();
362   return nullptr;
363 }
364 
365 bool SBPlatform::SetWorkingDirectory(const char *path) {
366   LLDB_INSTRUMENT_VA(this, path);
367 
368   PlatformSP platform_sp(GetSP());
369   if (platform_sp) {
370     if (path)
371       platform_sp->SetWorkingDirectory(FileSpec(path));
372     else
373       platform_sp->SetWorkingDirectory(FileSpec());
374     return true;
375   }
376   return false;
377 }
378 
379 SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) {
380   LLDB_INSTRUMENT_VA(this, connect_options);
381 
382   SBError sb_error;
383   PlatformSP platform_sp(GetSP());
384   if (platform_sp && connect_options.GetURL()) {
385     Args args;
386     args.AppendArgument(connect_options.GetURL());
387     sb_error.ref() = platform_sp->ConnectRemote(args);
388   } else {
389     sb_error.SetErrorString("invalid platform");
390   }
391   return sb_error;
392 }
393 
394 void SBPlatform::DisconnectRemote() {
395   LLDB_INSTRUMENT_VA(this);
396 
397   PlatformSP platform_sp(GetSP());
398   if (platform_sp)
399     platform_sp->DisconnectRemote();
400 }
401 
402 bool SBPlatform::IsConnected() {
403   LLDB_INSTRUMENT_VA(this);
404 
405   PlatformSP platform_sp(GetSP());
406   if (platform_sp)
407     return platform_sp->IsConnected();
408   return false;
409 }
410 
411 const char *SBPlatform::GetTriple() {
412   LLDB_INSTRUMENT_VA(this);
413 
414   PlatformSP platform_sp(GetSP());
415   if (platform_sp) {
416     ArchSpec arch(platform_sp->GetSystemArchitecture());
417     if (arch.IsValid()) {
418       // Const-ify the string so we don't need to worry about the lifetime of
419       // the string
420       return ConstString(arch.GetTriple().getTriple().c_str()).GetCString();
421     }
422   }
423   return nullptr;
424 }
425 
426 const char *SBPlatform::GetOSBuild() {
427   LLDB_INSTRUMENT_VA(this);
428 
429   PlatformSP platform_sp(GetSP());
430   if (platform_sp) {
431     std::string s = platform_sp->GetOSBuildString().value_or("");
432     if (!s.empty()) {
433       // Const-ify the string so we don't need to worry about the lifetime of
434       // the string
435       return ConstString(s).GetCString();
436     }
437   }
438   return nullptr;
439 }
440 
441 const char *SBPlatform::GetOSDescription() {
442   LLDB_INSTRUMENT_VA(this);
443 
444   PlatformSP platform_sp(GetSP());
445   if (platform_sp) {
446     std::string s = platform_sp->GetOSKernelDescription().value_or("");
447     if (!s.empty()) {
448       // Const-ify the string so we don't need to worry about the lifetime of
449       // the string
450       return ConstString(s.c_str()).GetCString();
451     }
452   }
453   return nullptr;
454 }
455 
456 const char *SBPlatform::GetHostname() {
457   LLDB_INSTRUMENT_VA(this);
458 
459   PlatformSP platform_sp(GetSP());
460   if (platform_sp)
461     return ConstString(platform_sp->GetHostname()).GetCString();
462   return nullptr;
463 }
464 
465 uint32_t SBPlatform::GetOSMajorVersion() {
466   LLDB_INSTRUMENT_VA(this);
467 
468   llvm::VersionTuple version;
469   if (PlatformSP platform_sp = GetSP())
470     version = platform_sp->GetOSVersion();
471   return version.empty() ? UINT32_MAX : version.getMajor();
472 }
473 
474 uint32_t SBPlatform::GetOSMinorVersion() {
475   LLDB_INSTRUMENT_VA(this);
476 
477   llvm::VersionTuple version;
478   if (PlatformSP platform_sp = GetSP())
479     version = platform_sp->GetOSVersion();
480   return version.getMinor().value_or(UINT32_MAX);
481 }
482 
483 uint32_t SBPlatform::GetOSUpdateVersion() {
484   LLDB_INSTRUMENT_VA(this);
485 
486   llvm::VersionTuple version;
487   if (PlatformSP platform_sp = GetSP())
488     version = platform_sp->GetOSVersion();
489   return version.getSubminor().value_or(UINT32_MAX);
490 }
491 
492 void SBPlatform::SetSDKRoot(const char *sysroot) {
493   LLDB_INSTRUMENT_VA(this, sysroot);
494   if (PlatformSP platform_sp = GetSP())
495     platform_sp->SetSDKRootDirectory(llvm::StringRef(sysroot).str());
496 }
497 
498 SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) {
499   LLDB_INSTRUMENT_VA(this, src, dst);
500 
501   SBError sb_error;
502   PlatformSP platform_sp(GetSP());
503   if (platform_sp) {
504     sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref());
505   } else {
506     sb_error.SetErrorString("invalid platform");
507   }
508   return sb_error;
509 }
510 
511 SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) {
512   LLDB_INSTRUMENT_VA(this, src, dst);
513   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
514     if (src.Exists()) {
515       uint32_t permissions = FileSystem::Instance().GetPermissions(src.ref());
516       if (permissions == 0) {
517         if (FileSystem::Instance().IsDirectory(src.ref()))
518           permissions = eFilePermissionsDirectoryDefault;
519         else
520           permissions = eFilePermissionsFileDefault;
521       }
522 
523       return platform_sp->PutFile(src.ref(), dst.ref(), permissions);
524     }
525 
526     Status error;
527     error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
528                                    src.ref().GetPath().c_str());
529     return error;
530   });
531 }
532 
533 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) {
534   LLDB_INSTRUMENT_VA(this, src, dst);
535   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
536     if (src.Exists())
537       return platform_sp->Install(src.ref(), dst.ref());
538 
539     Status error;
540     error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
541                                    src.ref().GetPath().c_str());
542     return error;
543   });
544 }
545 
546 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
547   LLDB_INSTRUMENT_VA(this, shell_command);
548   return ExecuteConnected(
549       [&](const lldb::PlatformSP &platform_sp) {
550         const char *command = shell_command.GetCommand();
551         if (!command)
552           return Status("invalid shell command (empty)");
553 
554         if (shell_command.GetWorkingDirectory() == nullptr) {
555           std::string platform_working_dir =
556               platform_sp->GetWorkingDirectory().GetPath();
557           if (!platform_working_dir.empty())
558             shell_command.SetWorkingDirectory(platform_working_dir.c_str());
559         }
560         return platform_sp->RunShellCommand(
561             shell_command.m_opaque_ptr->m_shell, command,
562             FileSpec(shell_command.GetWorkingDirectory()),
563             &shell_command.m_opaque_ptr->m_status,
564             &shell_command.m_opaque_ptr->m_signo,
565             &shell_command.m_opaque_ptr->m_output,
566             shell_command.m_opaque_ptr->m_timeout);
567       });
568 }
569 
570 SBError SBPlatform::Launch(SBLaunchInfo &launch_info) {
571   LLDB_INSTRUMENT_VA(this, launch_info);
572   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
573     ProcessLaunchInfo info = launch_info.ref();
574     Status error = platform_sp->LaunchProcess(info);
575     launch_info.set_ref(info);
576     return error;
577   });
578 }
579 
580 SBProcess SBPlatform::Attach(SBAttachInfo &attach_info,
581                              const SBDebugger &debugger, SBTarget &target,
582                              SBError &error) {
583   LLDB_INSTRUMENT_VA(this, attach_info, debugger, target, error);
584 
585   if (PlatformSP platform_sp = GetSP()) {
586     if (platform_sp->IsConnected()) {
587       ProcessAttachInfo &info = attach_info.ref();
588       Status status;
589       ProcessSP process_sp = platform_sp->Attach(info, debugger.ref(),
590                                                  target.GetSP().get(), status);
591       error.SetError(status);
592       return SBProcess(process_sp);
593     }
594 
595     error.SetErrorString("not connected");
596     return {};
597   }
598 
599   error.SetErrorString("invalid platform");
600   return {};
601 }
602 
603 SBProcessInfoList SBPlatform::GetAllProcesses(SBError &error) {
604   if (PlatformSP platform_sp = GetSP()) {
605     if (platform_sp->IsConnected()) {
606       ProcessInstanceInfoList list = platform_sp->GetAllProcesses();
607       return SBProcessInfoList(list);
608     }
609     error.SetErrorString("not connected");
610     return {};
611   }
612 
613   error.SetErrorString("invalid platform");
614   return {};
615 }
616 
617 SBError SBPlatform::Kill(const lldb::pid_t pid) {
618   LLDB_INSTRUMENT_VA(this, pid);
619   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
620     return platform_sp->KillProcess(pid);
621   });
622 }
623 
624 SBError SBPlatform::ExecuteConnected(
625     const std::function<Status(const lldb::PlatformSP &)> &func) {
626   SBError sb_error;
627   const auto platform_sp(GetSP());
628   if (platform_sp) {
629     if (platform_sp->IsConnected())
630       sb_error.ref() = func(platform_sp);
631     else
632       sb_error.SetErrorString("not connected");
633   } else
634     sb_error.SetErrorString("invalid platform");
635 
636   return sb_error;
637 }
638 
639 SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) {
640   LLDB_INSTRUMENT_VA(this, path, file_permissions);
641 
642   SBError sb_error;
643   PlatformSP platform_sp(GetSP());
644   if (platform_sp) {
645     sb_error.ref() =
646         platform_sp->MakeDirectory(FileSpec(path), file_permissions);
647   } else {
648     sb_error.SetErrorString("invalid platform");
649   }
650   return sb_error;
651 }
652 
653 uint32_t SBPlatform::GetFilePermissions(const char *path) {
654   LLDB_INSTRUMENT_VA(this, path);
655 
656   PlatformSP platform_sp(GetSP());
657   if (platform_sp) {
658     uint32_t file_permissions = 0;
659     platform_sp->GetFilePermissions(FileSpec(path), file_permissions);
660     return file_permissions;
661   }
662   return 0;
663 }
664 
665 SBError SBPlatform::SetFilePermissions(const char *path,
666                                        uint32_t file_permissions) {
667   LLDB_INSTRUMENT_VA(this, path, file_permissions);
668 
669   SBError sb_error;
670   PlatformSP platform_sp(GetSP());
671   if (platform_sp) {
672     sb_error.ref() =
673         platform_sp->SetFilePermissions(FileSpec(path), file_permissions);
674   } else {
675     sb_error.SetErrorString("invalid platform");
676   }
677   return sb_error;
678 }
679 
680 SBUnixSignals SBPlatform::GetUnixSignals() const {
681   LLDB_INSTRUMENT_VA(this);
682 
683   if (auto platform_sp = GetSP())
684     return SBUnixSignals{platform_sp};
685 
686   return SBUnixSignals();
687 }
688 
689 SBEnvironment SBPlatform::GetEnvironment() {
690   LLDB_INSTRUMENT_VA(this);
691   PlatformSP platform_sp(GetSP());
692 
693   if (platform_sp) {
694     return SBEnvironment(platform_sp->GetEnvironment());
695   }
696 
697   return SBEnvironment();
698 }
699 
700 SBError SBPlatform::SetLocateModuleCallback(
701     lldb::SBPlatformLocateModuleCallback callback, void *callback_baton) {
702   LLDB_INSTRUMENT_VA(this, callback, callback_baton);
703   PlatformSP platform_sp(GetSP());
704   if (!platform_sp)
705     return SBError("invalid platform");
706 
707   if (!callback) {
708     // Clear the callback.
709     platform_sp->SetLocateModuleCallback(nullptr);
710     return SBError();
711   }
712 
713   // Platform.h does not accept lldb::SBPlatformLocateModuleCallback directly
714   // because of the SBModuleSpec and SBFileSpec dependencies. Use a lambda to
715   // convert ModuleSpec/FileSpec <--> SBModuleSpec/SBFileSpec for the callback
716   // arguments.
717   platform_sp->SetLocateModuleCallback(
718       [callback, callback_baton](const ModuleSpec &module_spec,
719                                  FileSpec &module_file_spec,
720                                  FileSpec &symbol_file_spec) {
721         SBModuleSpec module_spec_sb(module_spec);
722         SBFileSpec module_file_spec_sb;
723         SBFileSpec symbol_file_spec_sb;
724 
725         SBError error = callback(callback_baton, module_spec_sb,
726                                  module_file_spec_sb, symbol_file_spec_sb);
727 
728         if (error.Success()) {
729           module_file_spec = module_file_spec_sb.ref();
730           symbol_file_spec = symbol_file_spec_sb.ref();
731         }
732 
733         return error.ref();
734       });
735   return SBError();
736 }
737