xref: /llvm-project/lldb/source/API/SBPlatform.cpp (revision b798f4bd50bbf0f5eb46804afad10629797c73aa)
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 = Status::FromErrorString("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 = Status::FromErrorString("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     return Status::FromErrorStringWithFormat(
527         "'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str());
528   });
529 }
530 
531 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) {
532   LLDB_INSTRUMENT_VA(this, src, dst);
533   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
534     if (src.Exists())
535       return platform_sp->Install(src.ref(), dst.ref());
536 
537     Status error;
538     error = Status::FromErrorStringWithFormat(
539         "'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str());
540     return error;
541   });
542 }
543 
544 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
545   LLDB_INSTRUMENT_VA(this, shell_command);
546   return ExecuteConnected(
547       [&](const lldb::PlatformSP &platform_sp) {
548         const char *command = shell_command.GetCommand();
549         if (!command)
550           return Status::FromErrorString("invalid shell command (empty)");
551 
552         if (shell_command.GetWorkingDirectory() == nullptr) {
553           std::string platform_working_dir =
554               platform_sp->GetWorkingDirectory().GetPath();
555           if (!platform_working_dir.empty())
556             shell_command.SetWorkingDirectory(platform_working_dir.c_str());
557         }
558         return platform_sp->RunShellCommand(
559             shell_command.m_opaque_ptr->m_shell, command,
560             FileSpec(shell_command.GetWorkingDirectory()),
561             &shell_command.m_opaque_ptr->m_status,
562             &shell_command.m_opaque_ptr->m_signo,
563             &shell_command.m_opaque_ptr->m_output,
564             shell_command.m_opaque_ptr->m_timeout);
565       });
566 }
567 
568 SBError SBPlatform::Launch(SBLaunchInfo &launch_info) {
569   LLDB_INSTRUMENT_VA(this, launch_info);
570   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
571     ProcessLaunchInfo info = launch_info.ref();
572     Status error = platform_sp->LaunchProcess(info);
573     launch_info.set_ref(info);
574     return error;
575   });
576 }
577 
578 SBProcess SBPlatform::Attach(SBAttachInfo &attach_info,
579                              const SBDebugger &debugger, SBTarget &target,
580                              SBError &error) {
581   LLDB_INSTRUMENT_VA(this, attach_info, debugger, target, error);
582 
583   if (PlatformSP platform_sp = GetSP()) {
584     if (platform_sp->IsConnected()) {
585       ProcessAttachInfo &info = attach_info.ref();
586       Status status;
587       ProcessSP process_sp = platform_sp->Attach(info, debugger.ref(),
588                                                  target.GetSP().get(), status);
589       error.SetError(std::move(status));
590       return SBProcess(process_sp);
591     }
592 
593     error = Status::FromErrorString("not connected");
594     return {};
595   }
596 
597   error = Status::FromErrorString("invalid platform");
598   return {};
599 }
600 
601 SBProcessInfoList SBPlatform::GetAllProcesses(SBError &error) {
602   if (PlatformSP platform_sp = GetSP()) {
603     if (platform_sp->IsConnected()) {
604       ProcessInstanceInfoList list = platform_sp->GetAllProcesses();
605       return SBProcessInfoList(list);
606     }
607     error = Status::FromErrorString("not connected");
608     return {};
609   }
610 
611   error = Status::FromErrorString("invalid platform");
612   return {};
613 }
614 
615 SBError SBPlatform::Kill(const lldb::pid_t pid) {
616   LLDB_INSTRUMENT_VA(this, pid);
617   return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
618     return platform_sp->KillProcess(pid);
619   });
620 }
621 
622 SBError SBPlatform::ExecuteConnected(
623     const std::function<Status(const lldb::PlatformSP &)> &func) {
624   SBError sb_error;
625   const auto platform_sp(GetSP());
626   if (platform_sp) {
627     if (platform_sp->IsConnected())
628       sb_error.ref() = func(platform_sp);
629     else
630       sb_error = Status::FromErrorString("not connected");
631   } else
632     sb_error = Status::FromErrorString("invalid platform");
633 
634   return sb_error;
635 }
636 
637 SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) {
638   LLDB_INSTRUMENT_VA(this, path, file_permissions);
639 
640   SBError sb_error;
641   PlatformSP platform_sp(GetSP());
642   if (platform_sp) {
643     sb_error.ref() =
644         platform_sp->MakeDirectory(FileSpec(path), file_permissions);
645   } else {
646     sb_error = Status::FromErrorString("invalid platform");
647   }
648   return sb_error;
649 }
650 
651 uint32_t SBPlatform::GetFilePermissions(const char *path) {
652   LLDB_INSTRUMENT_VA(this, path);
653 
654   PlatformSP platform_sp(GetSP());
655   if (platform_sp) {
656     uint32_t file_permissions = 0;
657     platform_sp->GetFilePermissions(FileSpec(path), file_permissions);
658     return file_permissions;
659   }
660   return 0;
661 }
662 
663 SBError SBPlatform::SetFilePermissions(const char *path,
664                                        uint32_t file_permissions) {
665   LLDB_INSTRUMENT_VA(this, path, file_permissions);
666 
667   SBError sb_error;
668   PlatformSP platform_sp(GetSP());
669   if (platform_sp) {
670     sb_error.ref() =
671         platform_sp->SetFilePermissions(FileSpec(path), file_permissions);
672   } else {
673     sb_error = Status::FromErrorString("invalid platform");
674   }
675   return sb_error;
676 }
677 
678 SBUnixSignals SBPlatform::GetUnixSignals() const {
679   LLDB_INSTRUMENT_VA(this);
680 
681   if (auto platform_sp = GetSP())
682     return SBUnixSignals{platform_sp};
683 
684   return SBUnixSignals();
685 }
686 
687 SBEnvironment SBPlatform::GetEnvironment() {
688   LLDB_INSTRUMENT_VA(this);
689   PlatformSP platform_sp(GetSP());
690 
691   if (platform_sp) {
692     return SBEnvironment(platform_sp->GetEnvironment());
693   }
694 
695   return SBEnvironment();
696 }
697 
698 SBError SBPlatform::SetLocateModuleCallback(
699     lldb::SBPlatformLocateModuleCallback callback, void *callback_baton) {
700   LLDB_INSTRUMENT_VA(this, callback, callback_baton);
701   PlatformSP platform_sp(GetSP());
702   if (!platform_sp)
703     return SBError("invalid platform");
704 
705   if (!callback) {
706     // Clear the callback.
707     platform_sp->SetLocateModuleCallback(nullptr);
708     return SBError();
709   }
710 
711   // Platform.h does not accept lldb::SBPlatformLocateModuleCallback directly
712   // because of the SBModuleSpec and SBFileSpec dependencies. Use a lambda to
713   // convert ModuleSpec/FileSpec <--> SBModuleSpec/SBFileSpec for the callback
714   // arguments.
715   platform_sp->SetLocateModuleCallback(
716       [callback, callback_baton](const ModuleSpec &module_spec,
717                                  FileSpec &module_file_spec,
718                                  FileSpec &symbol_file_spec) {
719         SBModuleSpec module_spec_sb(module_spec);
720         SBFileSpec module_file_spec_sb;
721         SBFileSpec symbol_file_spec_sb;
722 
723         SBError error = callback(callback_baton, module_spec_sb,
724                                  module_file_spec_sb, symbol_file_spec_sb);
725 
726         if (error.Success()) {
727           module_file_spec = module_file_spec_sb.ref();
728           symbol_file_spec = symbol_file_spec_sb.ref();
729         }
730 
731         return error.ref().Clone();
732       });
733   return SBError();
734 }
735