//===-- 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, *m_remote_platform_sp); } // 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; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( idx, resolved_module_spec.GetArchitecture()); ++idx) { 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(); } if (idx > 0) arch_names.PutCString(", "); arch_names.PutCString( resolved_module_spec.GetArchitecture().GetArchitectureName()); } if (error.Fail() || !exe_module_sp) { if (FileSystem::Instance().Readable( resolved_module_spec.GetFileSpec())) { error.SetErrorStringWithFormat( "'%s' doesn't contain any '%s' platform architectures: %s", resolved_module_spec.GetFileSpec().GetPath().c_str(), GetPluginName().GetCString(), 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 &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 &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; } bool RemoteAwarePlatform::GetRemoteOSBuildString(std::string &s) { if (m_remote_platform_sp) return m_remote_platform_sp->GetRemoteOSBuildString(s); s.clear(); return false; } bool RemoteAwarePlatform::GetRemoteOSKernelDescription(std::string &s) { if (m_remote_platform_sp) return m_remote_platform_sp->GetRemoteOSKernelDescription(s); s.clear(); return false; } 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"); }