1 //===-- SBPlatform.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
28 #include "llvm/Support/FileSystem.h"
33 using namespace lldb_private
;
35 // PlatformConnectOptions
36 struct PlatformConnectOptions
{
37 PlatformConnectOptions(const char *url
= nullptr) {
42 ~PlatformConnectOptions() = default;
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
;
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();
59 if (!m_shell
.empty() && !shell_command
.empty())
60 m_command
= shell_command
.str();
63 PlatformShellCommand(llvm::StringRef shell_command
= llvm::StringRef()) {
64 if (!shell_command
.empty())
65 m_command
= shell_command
.str();
68 ~PlatformShellCommand() = default;
71 std::string m_command
;
72 std::string m_working_dir
;
76 Timeout
<std::ratio
<1>> m_timeout
= std::nullopt
;
78 // SBPlatformConnectOptions
79 SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url
)
80 : m_opaque_ptr(new PlatformConnectOptions(url
)) {
81 LLDB_INSTRUMENT_VA(this, url
);
84 SBPlatformConnectOptions::SBPlatformConnectOptions(
85 const SBPlatformConnectOptions
&rhs
)
86 : m_opaque_ptr(new PlatformConnectOptions()) {
87 LLDB_INSTRUMENT_VA(this, rhs
);
89 *m_opaque_ptr
= *rhs
.m_opaque_ptr
;
92 SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr
; }
94 SBPlatformConnectOptions
&
95 SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions
&rhs
) {
96 LLDB_INSTRUMENT_VA(this, rhs
);
98 *m_opaque_ptr
= *rhs
.m_opaque_ptr
;
102 const char *SBPlatformConnectOptions::GetURL() {
103 LLDB_INSTRUMENT_VA(this);
105 if (m_opaque_ptr
->m_url
.empty())
107 return ConstString(m_opaque_ptr
->m_url
.c_str()).GetCString();
110 void SBPlatformConnectOptions::SetURL(const char *url
) {
111 LLDB_INSTRUMENT_VA(this, url
);
114 m_opaque_ptr
->m_url
= url
;
116 m_opaque_ptr
->m_url
.clear();
119 bool SBPlatformConnectOptions::GetRsyncEnabled() {
120 LLDB_INSTRUMENT_VA(this);
122 return m_opaque_ptr
->m_rsync_enabled
;
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
);
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
;
137 m_opaque_ptr
->m_rsync_remote_path_prefix
.clear();
139 if (options
&& options
[0])
140 m_opaque_ptr
->m_rsync_options
= options
;
142 m_opaque_ptr
->m_rsync_options
.clear();
145 void SBPlatformConnectOptions::DisableRsync() {
146 LLDB_INSTRUMENT_VA(this);
148 m_opaque_ptr
->m_rsync_enabled
= false;
151 const char *SBPlatformConnectOptions::GetLocalCacheDirectory() {
152 LLDB_INSTRUMENT_VA(this);
154 return m_opaque_ptr
->m_local_cache_directory
.GetCString();
157 void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path
) {
158 LLDB_INSTRUMENT_VA(this, path
);
161 m_opaque_ptr
->m_local_cache_directory
.SetCString(path
);
163 m_opaque_ptr
->m_local_cache_directory
= ConstString();
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
);
173 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command
)
174 : m_opaque_ptr(new PlatformShellCommand(shell_command
)) {
175 LLDB_INSTRUMENT_VA(this, shell_command
);
178 SBPlatformShellCommand::SBPlatformShellCommand(
179 const SBPlatformShellCommand
&rhs
)
180 : m_opaque_ptr(new PlatformShellCommand()) {
181 LLDB_INSTRUMENT_VA(this, rhs
);
183 *m_opaque_ptr
= *rhs
.m_opaque_ptr
;
186 SBPlatformShellCommand
&
187 SBPlatformShellCommand::operator=(const SBPlatformShellCommand
&rhs
) {
189 LLDB_INSTRUMENT_VA(this, rhs
);
191 *m_opaque_ptr
= *rhs
.m_opaque_ptr
;
195 SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr
; }
197 void SBPlatformShellCommand::Clear() {
198 LLDB_INSTRUMENT_VA(this);
200 m_opaque_ptr
->m_output
= std::string();
201 m_opaque_ptr
->m_status
= 0;
202 m_opaque_ptr
->m_signo
= 0;
205 const char *SBPlatformShellCommand::GetShell() {
206 LLDB_INSTRUMENT_VA(this);
208 if (m_opaque_ptr
->m_shell
.empty())
210 return ConstString(m_opaque_ptr
->m_shell
.c_str()).GetCString();
213 void SBPlatformShellCommand::SetShell(const char *shell_interpreter
) {
214 LLDB_INSTRUMENT_VA(this, shell_interpreter
);
216 if (shell_interpreter
&& shell_interpreter
[0])
217 m_opaque_ptr
->m_shell
= shell_interpreter
;
219 m_opaque_ptr
->m_shell
.clear();
222 const char *SBPlatformShellCommand::GetCommand() {
223 LLDB_INSTRUMENT_VA(this);
225 if (m_opaque_ptr
->m_command
.empty())
227 return ConstString(m_opaque_ptr
->m_command
.c_str()).GetCString();
230 void SBPlatformShellCommand::SetCommand(const char *shell_command
) {
231 LLDB_INSTRUMENT_VA(this, shell_command
);
233 if (shell_command
&& shell_command
[0])
234 m_opaque_ptr
->m_command
= shell_command
;
236 m_opaque_ptr
->m_command
.clear();
239 const char *SBPlatformShellCommand::GetWorkingDirectory() {
240 LLDB_INSTRUMENT_VA(this);
242 if (m_opaque_ptr
->m_working_dir
.empty())
244 return ConstString(m_opaque_ptr
->m_working_dir
.c_str()).GetCString();
247 void SBPlatformShellCommand::SetWorkingDirectory(const char *path
) {
248 LLDB_INSTRUMENT_VA(this, path
);
251 m_opaque_ptr
->m_working_dir
= path
;
253 m_opaque_ptr
->m_working_dir
.clear();
256 uint32_t SBPlatformShellCommand::GetTimeoutSeconds() {
257 LLDB_INSTRUMENT_VA(this);
259 if (m_opaque_ptr
->m_timeout
)
260 return m_opaque_ptr
->m_timeout
->count();
264 void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec
) {
265 LLDB_INSTRUMENT_VA(this, sec
);
267 if (sec
== UINT32_MAX
)
268 m_opaque_ptr
->m_timeout
= std::nullopt
;
270 m_opaque_ptr
->m_timeout
= std::chrono::seconds(sec
);
273 int SBPlatformShellCommand::GetSignal() {
274 LLDB_INSTRUMENT_VA(this);
276 return m_opaque_ptr
->m_signo
;
279 int SBPlatformShellCommand::GetStatus() {
280 LLDB_INSTRUMENT_VA(this);
282 return m_opaque_ptr
->m_status
;
285 const char *SBPlatformShellCommand::GetOutput() {
286 LLDB_INSTRUMENT_VA(this);
288 if (m_opaque_ptr
->m_output
.empty())
290 return ConstString(m_opaque_ptr
->m_output
.c_str()).GetCString();
294 SBPlatform::SBPlatform() { LLDB_INSTRUMENT_VA(this); }
296 SBPlatform::SBPlatform(const char *platform_name
) {
297 LLDB_INSTRUMENT_VA(this, platform_name
);
299 m_opaque_sp
= Platform::Create(platform_name
);
302 SBPlatform::SBPlatform(const SBPlatform
&rhs
) {
303 LLDB_INSTRUMENT_VA(this, rhs
);
305 m_opaque_sp
= rhs
.m_opaque_sp
;
308 SBPlatform
&SBPlatform::operator=(const SBPlatform
&rhs
) {
309 LLDB_INSTRUMENT_VA(this, rhs
);
311 m_opaque_sp
= rhs
.m_opaque_sp
;
315 SBPlatform::~SBPlatform() = default;
317 SBPlatform
SBPlatform::GetHostPlatform() {
320 SBPlatform host_platform
;
321 host_platform
.m_opaque_sp
= Platform::GetHostPlatform();
322 return host_platform
;
325 bool SBPlatform::IsValid() const {
326 LLDB_INSTRUMENT_VA(this);
327 return this->operator bool();
329 SBPlatform::operator bool() const {
330 LLDB_INSTRUMENT_VA(this);
332 return m_opaque_sp
.get() != nullptr;
335 void SBPlatform::Clear() {
336 LLDB_INSTRUMENT_VA(this);
341 const char *SBPlatform::GetName() {
342 LLDB_INSTRUMENT_VA(this);
344 PlatformSP
platform_sp(GetSP());
346 return ConstString(platform_sp
->GetName()).AsCString();
350 lldb::PlatformSP
SBPlatform::GetSP() const { return m_opaque_sp
; }
352 void SBPlatform::SetSP(const lldb::PlatformSP
&platform_sp
) {
353 m_opaque_sp
= platform_sp
;
356 const char *SBPlatform::GetWorkingDirectory() {
357 LLDB_INSTRUMENT_VA(this);
359 PlatformSP
platform_sp(GetSP());
361 return platform_sp
->GetWorkingDirectory().GetPathAsConstString().AsCString();
365 bool SBPlatform::SetWorkingDirectory(const char *path
) {
366 LLDB_INSTRUMENT_VA(this, path
);
368 PlatformSP
platform_sp(GetSP());
371 platform_sp
->SetWorkingDirectory(FileSpec(path
));
373 platform_sp
->SetWorkingDirectory(FileSpec());
379 SBError
SBPlatform::ConnectRemote(SBPlatformConnectOptions
&connect_options
) {
380 LLDB_INSTRUMENT_VA(this, connect_options
);
383 PlatformSP
platform_sp(GetSP());
384 if (platform_sp
&& connect_options
.GetURL()) {
386 args
.AppendArgument(connect_options
.GetURL());
387 sb_error
.ref() = platform_sp
->ConnectRemote(args
);
389 sb_error
= Status::FromErrorString("invalid platform");
394 void SBPlatform::DisconnectRemote() {
395 LLDB_INSTRUMENT_VA(this);
397 PlatformSP
platform_sp(GetSP());
399 platform_sp
->DisconnectRemote();
402 bool SBPlatform::IsConnected() {
403 LLDB_INSTRUMENT_VA(this);
405 PlatformSP
platform_sp(GetSP());
407 return platform_sp
->IsConnected();
411 const char *SBPlatform::GetTriple() {
412 LLDB_INSTRUMENT_VA(this);
414 PlatformSP
platform_sp(GetSP());
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
420 return ConstString(arch
.GetTriple().getTriple().c_str()).GetCString();
426 const char *SBPlatform::GetOSBuild() {
427 LLDB_INSTRUMENT_VA(this);
429 PlatformSP
platform_sp(GetSP());
431 std::string s
= platform_sp
->GetOSBuildString().value_or("");
433 // Const-ify the string so we don't need to worry about the lifetime of
435 return ConstString(s
).GetCString();
441 const char *SBPlatform::GetOSDescription() {
442 LLDB_INSTRUMENT_VA(this);
444 PlatformSP
platform_sp(GetSP());
446 std::string s
= platform_sp
->GetOSKernelDescription().value_or("");
448 // Const-ify the string so we don't need to worry about the lifetime of
450 return ConstString(s
.c_str()).GetCString();
456 const char *SBPlatform::GetHostname() {
457 LLDB_INSTRUMENT_VA(this);
459 PlatformSP
platform_sp(GetSP());
461 return ConstString(platform_sp
->GetHostname()).GetCString();
465 uint32_t SBPlatform::GetOSMajorVersion() {
466 LLDB_INSTRUMENT_VA(this);
468 llvm::VersionTuple version
;
469 if (PlatformSP platform_sp
= GetSP())
470 version
= platform_sp
->GetOSVersion();
471 return version
.empty() ? UINT32_MAX
: version
.getMajor();
474 uint32_t SBPlatform::GetOSMinorVersion() {
475 LLDB_INSTRUMENT_VA(this);
477 llvm::VersionTuple version
;
478 if (PlatformSP platform_sp
= GetSP())
479 version
= platform_sp
->GetOSVersion();
480 return version
.getMinor().value_or(UINT32_MAX
);
483 uint32_t SBPlatform::GetOSUpdateVersion() {
484 LLDB_INSTRUMENT_VA(this);
486 llvm::VersionTuple version
;
487 if (PlatformSP platform_sp
= GetSP())
488 version
= platform_sp
->GetOSVersion();
489 return version
.getSubminor().value_or(UINT32_MAX
);
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());
498 SBError
SBPlatform::Get(SBFileSpec
&src
, SBFileSpec
&dst
) {
499 LLDB_INSTRUMENT_VA(this, src
, dst
);
502 PlatformSP
platform_sp(GetSP());
504 sb_error
.ref() = platform_sp
->GetFile(src
.ref(), dst
.ref());
506 sb_error
= Status::FromErrorString("invalid platform");
511 SBError
SBPlatform::Put(SBFileSpec
&src
, SBFileSpec
&dst
) {
512 LLDB_INSTRUMENT_VA(this, src
, dst
);
513 return ExecuteConnected([&](const lldb::PlatformSP
&platform_sp
) {
515 uint32_t permissions
= FileSystem::Instance().GetPermissions(src
.ref());
516 if (permissions
== 0) {
517 if (FileSystem::Instance().IsDirectory(src
.ref()))
518 permissions
= eFilePermissionsDirectoryDefault
;
520 permissions
= eFilePermissionsFileDefault
;
523 return platform_sp
->PutFile(src
.ref(), dst
.ref(), permissions
);
526 return Status::FromErrorStringWithFormat(
527 "'src' argument doesn't exist: '%s'", src
.ref().GetPath().c_str());
531 SBError
SBPlatform::Install(SBFileSpec
&src
, SBFileSpec
&dst
) {
532 LLDB_INSTRUMENT_VA(this, src
, dst
);
533 return ExecuteConnected([&](const lldb::PlatformSP
&platform_sp
) {
535 return platform_sp
->Install(src
.ref(), dst
.ref());
538 error
= Status::FromErrorStringWithFormat(
539 "'src' argument doesn't exist: '%s'", src
.ref().GetPath().c_str());
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();
550 return Status::FromErrorString("invalid shell command (empty)");
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());
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
);
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
);
578 SBProcess
SBPlatform::Attach(SBAttachInfo
&attach_info
,
579 const SBDebugger
&debugger
, SBTarget
&target
,
581 LLDB_INSTRUMENT_VA(this, attach_info
, debugger
, target
, error
);
583 if (PlatformSP platform_sp
= GetSP()) {
584 if (platform_sp
->IsConnected()) {
585 ProcessAttachInfo
&info
= attach_info
.ref();
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
);
593 error
= Status::FromErrorString("not connected");
597 error
= Status::FromErrorString("invalid platform");
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
);
607 error
= Status::FromErrorString("not connected");
611 error
= Status::FromErrorString("invalid platform");
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
);
622 SBError
SBPlatform::ExecuteConnected(
623 const std::function
<Status(const lldb::PlatformSP
&)> &func
) {
625 const auto platform_sp(GetSP());
627 if (platform_sp
->IsConnected())
628 sb_error
.ref() = func(platform_sp
);
630 sb_error
= Status::FromErrorString("not connected");
632 sb_error
= Status::FromErrorString("invalid platform");
637 SBError
SBPlatform::MakeDirectory(const char *path
, uint32_t file_permissions
) {
638 LLDB_INSTRUMENT_VA(this, path
, file_permissions
);
641 PlatformSP
platform_sp(GetSP());
644 platform_sp
->MakeDirectory(FileSpec(path
), file_permissions
);
646 sb_error
= Status::FromErrorString("invalid platform");
651 uint32_t SBPlatform::GetFilePermissions(const char *path
) {
652 LLDB_INSTRUMENT_VA(this, path
);
654 PlatformSP
platform_sp(GetSP());
656 uint32_t file_permissions
= 0;
657 platform_sp
->GetFilePermissions(FileSpec(path
), file_permissions
);
658 return file_permissions
;
663 SBError
SBPlatform::SetFilePermissions(const char *path
,
664 uint32_t file_permissions
) {
665 LLDB_INSTRUMENT_VA(this, path
, file_permissions
);
668 PlatformSP
platform_sp(GetSP());
671 platform_sp
->SetFilePermissions(FileSpec(path
), file_permissions
);
673 sb_error
= Status::FromErrorString("invalid platform");
678 SBUnixSignals
SBPlatform::GetUnixSignals() const {
679 LLDB_INSTRUMENT_VA(this);
681 if (auto platform_sp
= GetSP())
682 return SBUnixSignals
{platform_sp
};
684 return SBUnixSignals();
687 SBEnvironment
SBPlatform::GetEnvironment() {
688 LLDB_INSTRUMENT_VA(this);
689 PlatformSP
platform_sp(GetSP());
692 return SBEnvironment(platform_sp
->GetEnvironment());
695 return SBEnvironment();
698 SBError
SBPlatform::SetLocateModuleCallback(
699 lldb::SBPlatformLocateModuleCallback callback
, void *callback_baton
) {
700 LLDB_INSTRUMENT_VA(this, callback
, callback_baton
);
701 PlatformSP
platform_sp(GetSP());
703 return SBError("invalid platform");
706 // Clear the callback.
707 platform_sp
->SetLocateModuleCallback(nullptr);
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
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
;
723 SBError error
= callback(callback_baton
, module_spec_sb
,
724 module_file_spec_sb
, symbol_file_spec_sb
);
726 if (error
.Success()) {
727 module_file_spec
= module_file_spec_sb
.ref();
728 symbol_file_spec
= symbol_file_spec_sb
.ref();
731 return error
.ref().Clone();