blob: ba18ba6d187f0c5084c090bf59868d340f8f214c [file] [log] [blame]
//===-- SBPlatform.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/API/SBPlatform.h"
#include "lldb/API/SBEnvironment.h"
#include "lldb/API/SBError.h"
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBLaunchInfo.h"
#include "lldb/API/SBPlatform.h"
#include "lldb/API/SBUnixSignals.h"
#include "lldb/Host/File.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/Instrumentation.h"
#include "lldb/Utility/Status.h"
#include "llvm/Support/FileSystem.h"
#include <functional>
using namespace lldb;
using namespace lldb_private;
// PlatformConnectOptions
struct PlatformConnectOptions {
PlatformConnectOptions(const char *url = nullptr) {
if (url && url[0])
m_url = url;
}
~PlatformConnectOptions() = default;
std::string m_url;
std::string m_rsync_options;
std::string m_rsync_remote_path_prefix;
bool m_rsync_enabled = false;
bool m_rsync_omit_hostname_from_remote_path = false;
ConstString m_local_cache_directory;
};
// PlatformShellCommand
struct PlatformShellCommand {
PlatformShellCommand(llvm::StringRef shell_interpreter,
llvm::StringRef shell_command) {
if (!shell_interpreter.empty())
m_shell = shell_interpreter.str();
if (!m_shell.empty() && !shell_command.empty())
m_command = shell_command.str();
}
PlatformShellCommand(llvm::StringRef shell_command = llvm::StringRef()) {
if (!shell_command.empty())
m_command = shell_command.str();
}
~PlatformShellCommand() = default;
std::string m_shell;
std::string m_command;
std::string m_working_dir;
std::string m_output;
int m_status = 0;
int m_signo = 0;
Timeout<std::ratio<1>> m_timeout = llvm::None;
};
// SBPlatformConnectOptions
SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url)
: m_opaque_ptr(new PlatformConnectOptions(url)) {
LLDB_INSTRUMENT_VA(this, url);
}
SBPlatformConnectOptions::SBPlatformConnectOptions(
const SBPlatformConnectOptions &rhs)
: m_opaque_ptr(new PlatformConnectOptions()) {
LLDB_INSTRUMENT_VA(this, rhs);
*m_opaque_ptr = *rhs.m_opaque_ptr;
}
SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; }
SBPlatformConnectOptions &
SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);
*m_opaque_ptr = *rhs.m_opaque_ptr;
return *this;
}
const char *SBPlatformConnectOptions::GetURL() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_ptr->m_url.empty())
return nullptr;
return m_opaque_ptr->m_url.c_str();
}
void SBPlatformConnectOptions::SetURL(const char *url) {
LLDB_INSTRUMENT_VA(this, url);
if (url && url[0])
m_opaque_ptr->m_url = url;
else
m_opaque_ptr->m_url.clear();
}
bool SBPlatformConnectOptions::GetRsyncEnabled() {
LLDB_INSTRUMENT_VA(this);
return m_opaque_ptr->m_rsync_enabled;
}
void SBPlatformConnectOptions::EnableRsync(
const char *options, const char *remote_path_prefix,
bool omit_hostname_from_remote_path) {
LLDB_INSTRUMENT_VA(this, options, remote_path_prefix,
omit_hostname_from_remote_path);
m_opaque_ptr->m_rsync_enabled = true;
m_opaque_ptr->m_rsync_omit_hostname_from_remote_path =
omit_hostname_from_remote_path;
if (remote_path_prefix && remote_path_prefix[0])
m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix;
else
m_opaque_ptr->m_rsync_remote_path_prefix.clear();
if (options && options[0])
m_opaque_ptr->m_rsync_options = options;
else
m_opaque_ptr->m_rsync_options.clear();
}
void SBPlatformConnectOptions::DisableRsync() {
LLDB_INSTRUMENT_VA(this);
m_opaque_ptr->m_rsync_enabled = false;
}
const char *SBPlatformConnectOptions::GetLocalCacheDirectory() {
LLDB_INSTRUMENT_VA(this);
return m_opaque_ptr->m_local_cache_directory.GetCString();
}
void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) {
LLDB_INSTRUMENT_VA(this, path);
if (path && path[0])
m_opaque_ptr->m_local_cache_directory.SetCString(path);
else
m_opaque_ptr->m_local_cache_directory = ConstString();
}
// SBPlatformShellCommand
SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_interpreter,
const char *shell_command)
: m_opaque_ptr(new PlatformShellCommand(shell_interpreter, shell_command)) {
LLDB_INSTRUMENT_VA(this, shell_interpreter, shell_command);
}
SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command)
: m_opaque_ptr(new PlatformShellCommand(shell_command)) {
LLDB_INSTRUMENT_VA(this, shell_command);
}
SBPlatformShellCommand::SBPlatformShellCommand(
const SBPlatformShellCommand &rhs)
: m_opaque_ptr(new PlatformShellCommand()) {
LLDB_INSTRUMENT_VA(this, rhs);
*m_opaque_ptr = *rhs.m_opaque_ptr;
}
SBPlatformShellCommand &
SBPlatformShellCommand::operator=(const SBPlatformShellCommand &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);
*m_opaque_ptr = *rhs.m_opaque_ptr;
return *this;
}
SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; }
void SBPlatformShellCommand::Clear() {
LLDB_INSTRUMENT_VA(this);
m_opaque_ptr->m_output = std::string();
m_opaque_ptr->m_status = 0;
m_opaque_ptr->m_signo = 0;
}
const char *SBPlatformShellCommand::GetShell() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_ptr->m_shell.empty())
return nullptr;
return m_opaque_ptr->m_shell.c_str();
}
void SBPlatformShellCommand::SetShell(const char *shell_interpreter) {
LLDB_INSTRUMENT_VA(this, shell_interpreter);
if (shell_interpreter && shell_interpreter[0])
m_opaque_ptr->m_shell = shell_interpreter;
else
m_opaque_ptr->m_shell.clear();
}
const char *SBPlatformShellCommand::GetCommand() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_ptr->m_command.empty())
return nullptr;
return m_opaque_ptr->m_command.c_str();
}
void SBPlatformShellCommand::SetCommand(const char *shell_command) {
LLDB_INSTRUMENT_VA(this, shell_command);
if (shell_command && shell_command[0])
m_opaque_ptr->m_command = shell_command;
else
m_opaque_ptr->m_command.clear();
}
const char *SBPlatformShellCommand::GetWorkingDirectory() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_ptr->m_working_dir.empty())
return nullptr;
return m_opaque_ptr->m_working_dir.c_str();
}
void SBPlatformShellCommand::SetWorkingDirectory(const char *path) {
LLDB_INSTRUMENT_VA(this, path);
if (path && path[0])
m_opaque_ptr->m_working_dir = path;
else
m_opaque_ptr->m_working_dir.clear();
}
uint32_t SBPlatformShellCommand::GetTimeoutSeconds() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_ptr->m_timeout)
return m_opaque_ptr->m_timeout->count();
return UINT32_MAX;
}
void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec) {
LLDB_INSTRUMENT_VA(this, sec);
if (sec == UINT32_MAX)
m_opaque_ptr->m_timeout = llvm::None;
else
m_opaque_ptr->m_timeout = std::chrono::seconds(sec);
}
int SBPlatformShellCommand::GetSignal() {
LLDB_INSTRUMENT_VA(this);
return m_opaque_ptr->m_signo;
}
int SBPlatformShellCommand::GetStatus() {
LLDB_INSTRUMENT_VA(this);
return m_opaque_ptr->m_status;
}
const char *SBPlatformShellCommand::GetOutput() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_ptr->m_output.empty())
return nullptr;
return m_opaque_ptr->m_output.c_str();
}
// SBPlatform
SBPlatform::SBPlatform() { LLDB_INSTRUMENT_VA(this); }
SBPlatform::SBPlatform(const char *platform_name) {
LLDB_INSTRUMENT_VA(this, platform_name);
m_opaque_sp = Platform::Create(platform_name);
}
SBPlatform::SBPlatform(const SBPlatform &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);
m_opaque_sp = rhs.m_opaque_sp;
}
SBPlatform &SBPlatform::operator=(const SBPlatform &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);
m_opaque_sp = rhs.m_opaque_sp;
return *this;
}
SBPlatform::~SBPlatform() = default;
SBPlatform SBPlatform::GetHostPlatform() {
LLDB_INSTRUMENT();
SBPlatform host_platform;
host_platform.m_opaque_sp = Platform::GetHostPlatform();
return host_platform;
}
bool SBPlatform::IsValid() const {
LLDB_INSTRUMENT_VA(this);
return this->operator bool();
}
SBPlatform::operator bool() const {
LLDB_INSTRUMENT_VA(this);
return m_opaque_sp.get() != nullptr;
}
void SBPlatform::Clear() {
LLDB_INSTRUMENT_VA(this);
m_opaque_sp.reset();
}
const char *SBPlatform::GetName() {
LLDB_INSTRUMENT_VA(this);
PlatformSP platform_sp(GetSP());
if (platform_sp)
return ConstString(platform_sp->GetName()).AsCString();
return nullptr;
}
lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; }
void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) {
m_opaque_sp = platform_sp;
}
const char *SBPlatform::GetWorkingDirectory() {
LLDB_INSTRUMENT_VA(this);
PlatformSP platform_sp(GetSP());
if (platform_sp)
return platform_sp->GetWorkingDirectory().GetCString();
return nullptr;
}
bool SBPlatform::SetWorkingDirectory(const char *path) {
LLDB_INSTRUMENT_VA(this, path);
PlatformSP platform_sp(GetSP());
if (platform_sp) {
if (path)
platform_sp->SetWorkingDirectory(FileSpec(path));
else
platform_sp->SetWorkingDirectory(FileSpec());
return true;
}
return false;
}
SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) {
LLDB_INSTRUMENT_VA(this, connect_options);
SBError sb_error;
PlatformSP platform_sp(GetSP());
if (platform_sp && connect_options.GetURL()) {
Args args;
args.AppendArgument(connect_options.GetURL());
sb_error.ref() = platform_sp->ConnectRemote(args);
} else {
sb_error.SetErrorString("invalid platform");
}
return sb_error;
}
void SBPlatform::DisconnectRemote() {
LLDB_INSTRUMENT_VA(this);
PlatformSP platform_sp(GetSP());
if (platform_sp)
platform_sp->DisconnectRemote();
}
bool SBPlatform::IsConnected() {
LLDB_INSTRUMENT_VA(this);
PlatformSP platform_sp(GetSP());
if (platform_sp)
return platform_sp->IsConnected();
return false;
}
const char *SBPlatform::GetTriple() {
LLDB_INSTRUMENT_VA(this);
PlatformSP platform_sp(GetSP());
if (platform_sp) {
ArchSpec arch(platform_sp->GetSystemArchitecture());
if (arch.IsValid()) {
// Const-ify the string so we don't need to worry about the lifetime of
// the string
return ConstString(arch.GetTriple().getTriple().c_str()).GetCString();
}
}
return nullptr;
}
const char *SBPlatform::GetOSBuild() {
LLDB_INSTRUMENT_VA(this);
PlatformSP platform_sp(GetSP());
if (platform_sp) {
std::string s = platform_sp->GetOSBuildString().value_or("");
if (!s.empty()) {
// Const-ify the string so we don't need to worry about the lifetime of
// the string
return ConstString(s).GetCString();
}
}
return nullptr;
}
const char *SBPlatform::GetOSDescription() {
LLDB_INSTRUMENT_VA(this);
PlatformSP platform_sp(GetSP());
if (platform_sp) {
std::string s = platform_sp->GetOSKernelDescription().value_or("");
if (!s.empty()) {
// Const-ify the string so we don't need to worry about the lifetime of
// the string
return ConstString(s.c_str()).GetCString();
}
}
return nullptr;
}
const char *SBPlatform::GetHostname() {
LLDB_INSTRUMENT_VA(this);
PlatformSP platform_sp(GetSP());
if (platform_sp)
return platform_sp->GetHostname();
return nullptr;
}
uint32_t SBPlatform::GetOSMajorVersion() {
LLDB_INSTRUMENT_VA(this);
llvm::VersionTuple version;
if (PlatformSP platform_sp = GetSP())
version = platform_sp->GetOSVersion();
return version.empty() ? UINT32_MAX : version.getMajor();
}
uint32_t SBPlatform::GetOSMinorVersion() {
LLDB_INSTRUMENT_VA(this);
llvm::VersionTuple version;
if (PlatformSP platform_sp = GetSP())
version = platform_sp->GetOSVersion();
return version.getMinor().value_or(UINT32_MAX);
}
uint32_t SBPlatform::GetOSUpdateVersion() {
LLDB_INSTRUMENT_VA(this);
llvm::VersionTuple version;
if (PlatformSP platform_sp = GetSP())
version = platform_sp->GetOSVersion();
return version.getSubminor().value_or(UINT32_MAX);
}
void SBPlatform::SetSDKRoot(const char *sysroot) {
LLDB_INSTRUMENT_VA(this, sysroot);
if (PlatformSP platform_sp = GetSP())
platform_sp->SetSDKRootDirectory(ConstString(sysroot));
}
SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) {
LLDB_INSTRUMENT_VA(this, src, dst);
SBError sb_error;
PlatformSP platform_sp(GetSP());
if (platform_sp) {
sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref());
} else {
sb_error.SetErrorString("invalid platform");
}
return sb_error;
}
SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) {
LLDB_INSTRUMENT_VA(this, src, dst);
return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
if (src.Exists()) {
uint32_t permissions = FileSystem::Instance().GetPermissions(src.ref());
if (permissions == 0) {
if (FileSystem::Instance().IsDirectory(src.ref()))
permissions = eFilePermissionsDirectoryDefault;
else
permissions = eFilePermissionsFileDefault;
}
return platform_sp->PutFile(src.ref(), dst.ref(), permissions);
}
Status error;
error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
src.ref().GetPath().c_str());
return error;
});
}
SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) {
LLDB_INSTRUMENT_VA(this, src, dst);
return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
if (src.Exists())
return platform_sp->Install(src.ref(), dst.ref());
Status error;
error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
src.ref().GetPath().c_str());
return error;
});
}
SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
LLDB_INSTRUMENT_VA(this, shell_command);
return ExecuteConnected(
[&](const lldb::PlatformSP &platform_sp) {
const char *command = shell_command.GetCommand();
if (!command)
return Status("invalid shell command (empty)");
const char *working_dir = shell_command.GetWorkingDirectory();
if (working_dir == nullptr) {
working_dir = platform_sp->GetWorkingDirectory().GetCString();
if (working_dir)
shell_command.SetWorkingDirectory(working_dir);
}
return platform_sp->RunShellCommand(
shell_command.m_opaque_ptr->m_shell, command, FileSpec(working_dir),
&shell_command.m_opaque_ptr->m_status,
&shell_command.m_opaque_ptr->m_signo,
&shell_command.m_opaque_ptr->m_output,
shell_command.m_opaque_ptr->m_timeout);
});
}
SBError SBPlatform::Launch(SBLaunchInfo &launch_info) {
LLDB_INSTRUMENT_VA(this, launch_info);
return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
ProcessLaunchInfo info = launch_info.ref();
Status error = platform_sp->LaunchProcess(info);
launch_info.set_ref(info);
return error;
});
}
SBError SBPlatform::Kill(const lldb::pid_t pid) {
LLDB_INSTRUMENT_VA(this, pid);
return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
return platform_sp->KillProcess(pid);
});
}
SBError SBPlatform::ExecuteConnected(
const std::function<Status(const lldb::PlatformSP &)> &func) {
SBError sb_error;
const auto platform_sp(GetSP());
if (platform_sp) {
if (platform_sp->IsConnected())
sb_error.ref() = func(platform_sp);
else
sb_error.SetErrorString("not connected");
} else
sb_error.SetErrorString("invalid platform");
return sb_error;
}
SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) {
LLDB_INSTRUMENT_VA(this, path, file_permissions);
SBError sb_error;
PlatformSP platform_sp(GetSP());
if (platform_sp) {
sb_error.ref() =
platform_sp->MakeDirectory(FileSpec(path), file_permissions);
} else {
sb_error.SetErrorString("invalid platform");
}
return sb_error;
}
uint32_t SBPlatform::GetFilePermissions(const char *path) {
LLDB_INSTRUMENT_VA(this, path);
PlatformSP platform_sp(GetSP());
if (platform_sp) {
uint32_t file_permissions = 0;
platform_sp->GetFilePermissions(FileSpec(path), file_permissions);
return file_permissions;
}
return 0;
}
SBError SBPlatform::SetFilePermissions(const char *path,
uint32_t file_permissions) {
LLDB_INSTRUMENT_VA(this, path, file_permissions);
SBError sb_error;
PlatformSP platform_sp(GetSP());
if (platform_sp) {
sb_error.ref() =
platform_sp->SetFilePermissions(FileSpec(path), file_permissions);
} else {
sb_error.SetErrorString("invalid platform");
}
return sb_error;
}
SBUnixSignals SBPlatform::GetUnixSignals() const {
LLDB_INSTRUMENT_VA(this);
if (auto platform_sp = GetSP())
return SBUnixSignals{platform_sp};
return SBUnixSignals();
}
SBEnvironment SBPlatform::GetEnvironment() {
LLDB_INSTRUMENT_VA(this);
PlatformSP platform_sp(GetSP());
if (platform_sp) {
return SBEnvironment(platform_sp->GetEnvironment());
}
return SBEnvironment();
}