llvm-project/lldb/source/Target/RemoteAwarePlatform.cpp

443 lines
17 KiB
C++

//===-- RemoteAwarePlatform.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/Target/RemoteAwarePlatform.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/FileCache.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
using namespace lldb;
bool RemoteAwarePlatform::GetModuleSpec(const FileSpec &module_file_spec,
const ArchSpec &arch,
ModuleSpec &module_spec) {
if (m_remote_platform_sp)
return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch,
module_spec);
return false;
}
Status RemoteAwarePlatform::ResolveExecutable(
const ModuleSpec &module_spec, ModuleSP &exe_module_sp,
const FileSpecList *module_search_paths_ptr) {
Status error;
// Nothing special to do here, just use the actual file and architecture
char exe_path[PATH_MAX];
ModuleSpec resolved_module_spec(module_spec);
if (IsHost()) {
// If we have "ls" as the exe_file, resolve the executable location based
// on the current path variables
if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) {
resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
resolved_module_spec.GetFileSpec().SetFile(exe_path,
FileSpec::Style::native);
FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec());
}
if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
FileSystem::Instance().ResolveExecutableLocation(
resolved_module_spec.GetFileSpec());
// Resolve any executable within a bundle on MacOSX
Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
error.Clear();
else {
const uint32_t permissions = FileSystem::Instance().GetPermissions(
resolved_module_spec.GetFileSpec());
if (permissions && (permissions & eFilePermissionsEveryoneR) == 0)
error.SetErrorStringWithFormat(
"executable '%s' is not readable",
resolved_module_spec.GetFileSpec().GetPath().c_str());
else
error.SetErrorStringWithFormat(
"unable to find executable for '%s'",
resolved_module_spec.GetFileSpec().GetPath().c_str());
}
} else {
if (m_remote_platform_sp) {
return GetCachedExecutable(resolved_module_spec, exe_module_sp,
module_search_paths_ptr);
}
// We may connect to a process and use the provided executable (Don't use
// local $PATH).
// Resolve any executable within a bundle on MacOSX
Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
error.Clear();
else
error.SetErrorStringWithFormat("the platform is not currently "
"connected, and '%s' doesn't exist in "
"the system root.",
exe_path);
}
if (error.Success()) {
if (resolved_module_spec.GetArchitecture().IsValid()) {
error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
module_search_paths_ptr, nullptr, nullptr);
if (error.Fail()) {
// If we failed, it may be because the vendor and os aren't known. If
// that is the case, try setting them to the host architecture and give
// it another try.
llvm::Triple &module_triple =
resolved_module_spec.GetArchitecture().GetTriple();
bool is_vendor_specified =
(module_triple.getVendor() != llvm::Triple::UnknownVendor);
bool is_os_specified =
(module_triple.getOS() != llvm::Triple::UnknownOS);
if (!is_vendor_specified || !is_os_specified) {
const llvm::Triple &host_triple =
HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple();
if (!is_vendor_specified)
module_triple.setVendorName(host_triple.getVendorName());
if (!is_os_specified)
module_triple.setOSName(host_triple.getOSName());
error = ModuleList::GetSharedModule(resolved_module_spec,
exe_module_sp, module_search_paths_ptr, nullptr, nullptr);
}
}
// TODO find out why exe_module_sp might be NULL
if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) {
exe_module_sp.reset();
error.SetErrorStringWithFormat(
"'%s' doesn't contain the architecture %s",
resolved_module_spec.GetFileSpec().GetPath().c_str(),
resolved_module_spec.GetArchitecture().GetArchitectureName());
}
} else {
// No valid architecture was specified, ask the platform for the
// architectures that we should be using (in the correct order) and see
// if we can find a match that way
StreamString arch_names;
llvm::ListSeparator LS;
ArchSpec process_host_arch;
for (const ArchSpec &arch :
GetSupportedArchitectures(process_host_arch)) {
resolved_module_spec.GetArchitecture() = arch;
error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
module_search_paths_ptr, nullptr, nullptr);
// Did we find an executable using one of the
if (error.Success()) {
if (exe_module_sp && exe_module_sp->GetObjectFile())
break;
else
error.SetErrorToGenericError();
}
arch_names << LS << arch.GetArchitectureName();
}
if (error.Fail() || !exe_module_sp) {
if (FileSystem::Instance().Readable(
resolved_module_spec.GetFileSpec())) {
error.SetErrorStringWithFormatv(
"'{0}' doesn't contain any '{1}' platform architectures: {2}",
resolved_module_spec.GetFileSpec(), GetPluginName(),
arch_names.GetData());
} else {
error.SetErrorStringWithFormat(
"'%s' is not readable",
resolved_module_spec.GetFileSpec().GetPath().c_str());
}
}
}
}
return error;
}
Status RemoteAwarePlatform::RunShellCommand(
llvm::StringRef command, const FileSpec &working_dir, int *status_ptr,
int *signo_ptr, std::string *command_output,
const Timeout<std::micro> &timeout) {
return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr,
signo_ptr, command_output, timeout);
}
Status RemoteAwarePlatform::RunShellCommand(
llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir,
int *status_ptr, int *signo_ptr, std::string *command_output,
const Timeout<std::micro> &timeout) {
if (IsHost())
return Host::RunShellCommand(shell, command, working_dir, status_ptr,
signo_ptr, command_output, timeout);
if (m_remote_platform_sp)
return m_remote_platform_sp->RunShellCommand(shell, command, working_dir,
status_ptr, signo_ptr,
command_output, timeout);
return Status("unable to run a remote command without a platform");
}
Status RemoteAwarePlatform::MakeDirectory(const FileSpec &file_spec,
uint32_t file_permissions) {
if (m_remote_platform_sp)
return m_remote_platform_sp->MakeDirectory(file_spec, file_permissions);
return Platform::MakeDirectory(file_spec, file_permissions);
}
Status RemoteAwarePlatform::GetFilePermissions(const FileSpec &file_spec,
uint32_t &file_permissions) {
if (m_remote_platform_sp)
return m_remote_platform_sp->GetFilePermissions(file_spec,
file_permissions);
return Platform::GetFilePermissions(file_spec, file_permissions);
}
Status RemoteAwarePlatform::SetFilePermissions(const FileSpec &file_spec,
uint32_t file_permissions) {
if (m_remote_platform_sp)
return m_remote_platform_sp->SetFilePermissions(file_spec,
file_permissions);
return Platform::SetFilePermissions(file_spec, file_permissions);
}
lldb::user_id_t RemoteAwarePlatform::OpenFile(const FileSpec &file_spec,
File::OpenOptions flags,
uint32_t mode, Status &error) {
if (IsHost())
return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error);
if (m_remote_platform_sp)
return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
return Platform::OpenFile(file_spec, flags, mode, error);
}
bool RemoteAwarePlatform::CloseFile(lldb::user_id_t fd, Status &error) {
if (IsHost())
return FileCache::GetInstance().CloseFile(fd, error);
if (m_remote_platform_sp)
return m_remote_platform_sp->CloseFile(fd, error);
return Platform::CloseFile(fd, error);
}
uint64_t RemoteAwarePlatform::ReadFile(lldb::user_id_t fd, uint64_t offset,
void *dst, uint64_t dst_len,
Status &error) {
if (IsHost())
return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error);
if (m_remote_platform_sp)
return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
return Platform::ReadFile(fd, offset, dst, dst_len, error);
}
uint64_t RemoteAwarePlatform::WriteFile(lldb::user_id_t fd, uint64_t offset,
const void *src, uint64_t src_len,
Status &error) {
if (IsHost())
return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error);
if (m_remote_platform_sp)
return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
return Platform::WriteFile(fd, offset, src, src_len, error);
}
lldb::user_id_t RemoteAwarePlatform::GetFileSize(const FileSpec &file_spec) {
if (IsHost()) {
uint64_t Size;
if (llvm::sys::fs::file_size(file_spec.GetPath(), Size))
return 0;
return Size;
}
if (m_remote_platform_sp)
return m_remote_platform_sp->GetFileSize(file_spec);
return Platform::GetFileSize(file_spec);
}
Status RemoteAwarePlatform::CreateSymlink(const FileSpec &src,
const FileSpec &dst) {
if (IsHost())
return FileSystem::Instance().Symlink(src, dst);
if (m_remote_platform_sp)
return m_remote_platform_sp->CreateSymlink(src, dst);
return Platform::CreateSymlink(src, dst);
}
bool RemoteAwarePlatform::GetFileExists(const FileSpec &file_spec) {
if (IsHost())
return FileSystem::Instance().Exists(file_spec);
if (m_remote_platform_sp)
return m_remote_platform_sp->GetFileExists(file_spec);
return Platform::GetFileExists(file_spec);
}
Status RemoteAwarePlatform::Unlink(const FileSpec &file_spec) {
if (IsHost())
return llvm::sys::fs::remove(file_spec.GetPath());
if (m_remote_platform_sp)
return m_remote_platform_sp->Unlink(file_spec);
return Platform::Unlink(file_spec);
}
bool RemoteAwarePlatform::CalculateMD5(const FileSpec &file_spec, uint64_t &low,
uint64_t &high) {
if (IsHost())
return Platform::CalculateMD5(file_spec, low, high);
if (m_remote_platform_sp)
return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
return false;
}
FileSpec RemoteAwarePlatform::GetRemoteWorkingDirectory() {
if (IsRemote() && m_remote_platform_sp)
return m_remote_platform_sp->GetRemoteWorkingDirectory();
return Platform::GetRemoteWorkingDirectory();
}
bool RemoteAwarePlatform::SetRemoteWorkingDirectory(
const FileSpec &working_dir) {
if (IsRemote() && m_remote_platform_sp)
return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir);
return Platform::SetRemoteWorkingDirectory(working_dir);
}
Status RemoteAwarePlatform::GetFileWithUUID(const FileSpec &platform_file,
const UUID *uuid_ptr,
FileSpec &local_file) {
if (IsRemote() && m_remote_platform_sp)
return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
local_file);
// Default to the local case
local_file = platform_file;
return Status();
}
bool RemoteAwarePlatform::GetRemoteOSVersion() {
if (m_remote_platform_sp) {
m_os_version = m_remote_platform_sp->GetOSVersion();
return !m_os_version.empty();
}
return false;
}
llvm::Optional<std::string> RemoteAwarePlatform::GetRemoteOSBuildString() {
if (m_remote_platform_sp)
return m_remote_platform_sp->GetRemoteOSBuildString();
return llvm::None;
}
llvm::Optional<std::string> RemoteAwarePlatform::GetRemoteOSKernelDescription() {
if (m_remote_platform_sp)
return m_remote_platform_sp->GetRemoteOSKernelDescription();
return llvm::None;
}
ArchSpec RemoteAwarePlatform::GetRemoteSystemArchitecture() {
if (m_remote_platform_sp)
return m_remote_platform_sp->GetRemoteSystemArchitecture();
return ArchSpec();
}
const char *RemoteAwarePlatform::GetHostname() {
if (IsHost())
return Platform::GetHostname();
if (m_remote_platform_sp)
return m_remote_platform_sp->GetHostname();
return nullptr;
}
UserIDResolver &RemoteAwarePlatform::GetUserIDResolver() {
if (IsHost())
return HostInfo::GetUserIDResolver();
if (m_remote_platform_sp)
return m_remote_platform_sp->GetUserIDResolver();
return UserIDResolver::GetNoopResolver();
}
Environment RemoteAwarePlatform::GetEnvironment() {
if (IsRemote()) {
if (m_remote_platform_sp)
return m_remote_platform_sp->GetEnvironment();
return Environment();
}
return Host::GetEnvironment();
}
bool RemoteAwarePlatform::IsConnected() const {
if (IsHost())
return true;
else if (m_remote_platform_sp)
return m_remote_platform_sp->IsConnected();
return false;
}
bool RemoteAwarePlatform::GetProcessInfo(lldb::pid_t pid,
ProcessInstanceInfo &process_info) {
if (IsHost())
return Platform::GetProcessInfo(pid, process_info);
if (m_remote_platform_sp)
return m_remote_platform_sp->GetProcessInfo(pid, process_info);
return false;
}
uint32_t
RemoteAwarePlatform::FindProcesses(const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &process_infos) {
if (IsHost())
return Platform::FindProcesses(match_info, process_infos);
if (m_remote_platform_sp)
return m_remote_platform_sp->FindProcesses(match_info, process_infos);
return 0;
}
lldb::ProcessSP RemoteAwarePlatform::ConnectProcess(llvm::StringRef connect_url,
llvm::StringRef plugin_name,
Debugger &debugger,
Target *target,
Status &error) {
if (m_remote_platform_sp)
return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name,
debugger, target, error);
return Platform::ConnectProcess(connect_url, plugin_name, debugger, target,
error);
}
Status RemoteAwarePlatform::LaunchProcess(ProcessLaunchInfo &launch_info) {
Status error;
if (IsHost()) {
error = Platform::LaunchProcess(launch_info);
} else {
if (m_remote_platform_sp)
error = m_remote_platform_sp->LaunchProcess(launch_info);
else
error.SetErrorString("the platform is not currently connected");
}
return error;
}
Status RemoteAwarePlatform::KillProcess(const lldb::pid_t pid) {
if (IsHost())
return Platform::KillProcess(pid);
if (m_remote_platform_sp)
return m_remote_platform_sp->KillProcess(pid);
return Status("the platform is not currently connected");
}
size_t RemoteAwarePlatform::ConnectToWaitingProcesses(Debugger &debugger,
Status &error) {
if (m_remote_platform_sp)
return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error);
return Platform::ConnectToWaitingProcesses(debugger, error);
}