Host::RunShellCommand takes a std::string *command_output argument and a bool hide_stderr=false defaulted argument. If the shell command returns stderr and stdout text, it is intermixed in the same command_output, unless hide_stderr=true. In SymbolLocatorDebugSymbols::DownloadObjectAndSymbolFile we call an external program to find a binary and dSYM by uuid, and the external program returns a plist (xml) output. In some cases, it printed a (harmless) warning message to stderr, and then a complete plist output to stdout. We attempt to parse the combination of these two streams, and the parse fails - we don't get the output. This patch removes hide_stderr and instead adds a `std::string *separated_error_output` argument. If `separated_error_output` is nullptr, output and error texts are returned combined in the `command_output` argument. If a std::string object address is provided for `separated_error_output`, then standard error output is separated into this string. A caller which wants the old `hide_stderr=true` behavior should pass a throwaway std::string object to `RunShellCommand` and ignore it. rdar://168621579
282 lines
11 KiB
C++
282 lines
11 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/FileSystem.h"
|
|
#include "lldb/Host/Host.h"
|
|
#include "lldb/Host/HostInfo.h"
|
|
#include "lldb/Utility/StreamString.h"
|
|
#include <optional>
|
|
|
|
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,
|
|
lldb::ModuleSP &exe_module_sp) {
|
|
ModuleSpec resolved_module_spec(module_spec);
|
|
|
|
// The host platform can resolve the path more aggressively.
|
|
if (IsHost()) {
|
|
FileSpec &resolved_file_spec = resolved_module_spec.GetFileSpec();
|
|
|
|
if (!FileSystem::Instance().Exists(resolved_file_spec)) {
|
|
resolved_module_spec.GetFileSpec().SetFile(resolved_file_spec.GetPath(),
|
|
FileSpec::Style::native);
|
|
FileSystem::Instance().Resolve(resolved_file_spec);
|
|
}
|
|
|
|
if (!FileSystem::Instance().Exists(resolved_file_spec))
|
|
FileSystem::Instance().ResolveExecutableLocation(resolved_file_spec);
|
|
} else if (m_remote_platform_sp) {
|
|
return GetCachedExecutable(resolved_module_spec, exe_module_sp);
|
|
}
|
|
|
|
return Platform::ResolveExecutable(resolved_module_spec, exe_module_sp);
|
|
}
|
|
|
|
Status RemoteAwarePlatform::RunShellCommand(
|
|
llvm::StringRef command, const FileSpec &working_dir, int *status_ptr,
|
|
int *signo_ptr, std::string *command_output,
|
|
std::string *separated_error_output, const Timeout<std::micro> &timeout) {
|
|
return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr,
|
|
signo_ptr, command_output, separated_error_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,
|
|
std::string *separated_error_output, const Timeout<std::micro> &timeout) {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->RunShellCommand(
|
|
shell, command, working_dir, status_ptr, signo_ptr, command_output,
|
|
separated_error_output, timeout);
|
|
return Platform::RunShellCommand(shell, command, working_dir, status_ptr,
|
|
signo_ptr, command_output,
|
|
separated_error_output, timeout);
|
|
}
|
|
|
|
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 (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 (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 (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 (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 (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 (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 (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 (m_remote_platform_sp)
|
|
return m_remote_platform_sp->Unlink(file_spec);
|
|
return Platform::Unlink(file_spec);
|
|
}
|
|
|
|
llvm::ErrorOr<llvm::MD5::MD5Result>
|
|
RemoteAwarePlatform::CalculateMD5(const FileSpec &file_spec) {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->CalculateMD5(file_spec);
|
|
return Platform::CalculateMD5(file_spec);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
std::optional<std::string> RemoteAwarePlatform::GetRemoteOSBuildString() {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->GetRemoteOSBuildString();
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<std::string> RemoteAwarePlatform::GetRemoteOSKernelDescription() {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->GetRemoteOSKernelDescription();
|
|
return std::nullopt;
|
|
}
|
|
|
|
ArchSpec RemoteAwarePlatform::GetRemoteSystemArchitecture() {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->GetRemoteSystemArchitecture();
|
|
return ArchSpec();
|
|
}
|
|
|
|
const char *RemoteAwarePlatform::GetHostname() {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->GetHostname();
|
|
return Platform::GetHostname();
|
|
}
|
|
|
|
UserIDResolver &RemoteAwarePlatform::GetUserIDResolver() {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->GetUserIDResolver();
|
|
return Platform::GetUserIDResolver();
|
|
}
|
|
|
|
Environment RemoteAwarePlatform::GetEnvironment() {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->GetEnvironment();
|
|
return Platform::GetEnvironment();
|
|
}
|
|
|
|
bool RemoteAwarePlatform::IsConnected() const {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->IsConnected();
|
|
return Platform::IsConnected();
|
|
}
|
|
|
|
bool RemoteAwarePlatform::GetProcessInfo(lldb::pid_t pid,
|
|
ProcessInstanceInfo &process_info) {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->GetProcessInfo(pid, process_info);
|
|
return Platform::GetProcessInfo(pid, process_info);
|
|
}
|
|
|
|
uint32_t
|
|
RemoteAwarePlatform::FindProcesses(const ProcessInstanceInfoMatch &match_info,
|
|
ProcessInstanceInfoList &process_infos) {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->FindProcesses(match_info, process_infos);
|
|
return Platform::FindProcesses(match_info, process_infos);
|
|
}
|
|
|
|
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) {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->LaunchProcess(launch_info);
|
|
return Platform::LaunchProcess(launch_info);
|
|
}
|
|
|
|
Status RemoteAwarePlatform::KillProcess(const lldb::pid_t pid) {
|
|
if (m_remote_platform_sp)
|
|
return m_remote_platform_sp->KillProcess(pid);
|
|
return Platform::KillProcess(pid);
|
|
}
|
|
|
|
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);
|
|
}
|