Path: blob/main/contrib/llvm-project/lldb/source/Target/Platform.cpp
39587 views
//===-- Platform.cpp ------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <algorithm>9#include <csignal>10#include <fstream>11#include <memory>12#include <optional>13#include <vector>1415#include "lldb/Breakpoint/BreakpointIDList.h"16#include "lldb/Breakpoint/BreakpointLocation.h"17#include "lldb/Core/Debugger.h"18#include "lldb/Core/Module.h"19#include "lldb/Core/ModuleSpec.h"20#include "lldb/Core/PluginManager.h"21#include "lldb/Host/FileCache.h"22#include "lldb/Host/FileSystem.h"23#include "lldb/Host/Host.h"24#include "lldb/Host/HostInfo.h"25#include "lldb/Host/OptionParser.h"26#include "lldb/Interpreter/OptionValueFileSpec.h"27#include "lldb/Interpreter/OptionValueProperties.h"28#include "lldb/Interpreter/Property.h"29#include "lldb/Symbol/ObjectFile.h"30#include "lldb/Target/ModuleCache.h"31#include "lldb/Target/Platform.h"32#include "lldb/Target/Process.h"33#include "lldb/Target/Target.h"34#include "lldb/Target/UnixSignals.h"35#include "lldb/Utility/DataBufferHeap.h"36#include "lldb/Utility/FileSpec.h"37#include "lldb/Utility/LLDBLog.h"38#include "lldb/Utility/Log.h"39#include "lldb/Utility/Status.h"40#include "lldb/Utility/StructuredData.h"41#include "llvm/ADT/STLExtras.h"42#include "llvm/Support/FileSystem.h"43#include "llvm/Support/Path.h"4445// Define these constants from POSIX mman.h rather than include the file so46// that they will be correct even when compiled on Linux.47#define MAP_PRIVATE 248#define MAP_ANON 0x10004950using namespace lldb;51using namespace lldb_private;5253// Use a singleton function for g_local_platform_sp to avoid init constructors54// since LLDB is often part of a shared library55static PlatformSP &GetHostPlatformSP() {56static PlatformSP g_platform_sp;57return g_platform_sp;58}5960const char *Platform::GetHostPlatformName() { return "host"; }6162namespace {6364#define LLDB_PROPERTIES_platform65#include "TargetProperties.inc"6667enum {68#define LLDB_PROPERTIES_platform69#include "TargetPropertiesEnum.inc"70};7172} // namespace7374llvm::StringRef PlatformProperties::GetSettingName() {75static constexpr llvm::StringLiteral g_setting_name("platform");76return g_setting_name;77}7879PlatformProperties::PlatformProperties() {80m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());81m_collection_sp->Initialize(g_platform_properties);8283auto module_cache_dir = GetModuleCacheDirectory();84if (module_cache_dir)85return;8687llvm::SmallString<64> user_home_dir;88if (!FileSystem::Instance().GetHomeDirectory(user_home_dir))89return;9091module_cache_dir = FileSpec(user_home_dir.c_str());92module_cache_dir.AppendPathComponent(".lldb");93module_cache_dir.AppendPathComponent("module_cache");94SetDefaultModuleCacheDirectory(module_cache_dir);95SetModuleCacheDirectory(module_cache_dir);96}9798bool PlatformProperties::GetUseModuleCache() const {99const auto idx = ePropertyUseModuleCache;100return GetPropertyAtIndexAs<bool>(101idx, g_platform_properties[idx].default_uint_value != 0);102}103104bool PlatformProperties::SetUseModuleCache(bool use_module_cache) {105return SetPropertyAtIndex(ePropertyUseModuleCache, use_module_cache);106}107108FileSpec PlatformProperties::GetModuleCacheDirectory() const {109return GetPropertyAtIndexAs<FileSpec>(ePropertyModuleCacheDirectory, {});110}111112bool PlatformProperties::SetModuleCacheDirectory(const FileSpec &dir_spec) {113return m_collection_sp->SetPropertyAtIndex(ePropertyModuleCacheDirectory,114dir_spec);115}116117void PlatformProperties::SetDefaultModuleCacheDirectory(118const FileSpec &dir_spec) {119auto f_spec_opt = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec(120ePropertyModuleCacheDirectory);121assert(f_spec_opt);122f_spec_opt->SetDefaultValue(dir_spec);123}124125/// Get the native host platform plug-in.126///127/// There should only be one of these for each host that LLDB runs128/// upon that should be statically compiled in and registered using129/// preprocessor macros or other similar build mechanisms.130///131/// This platform will be used as the default platform when launching132/// or attaching to processes unless another platform is specified.133PlatformSP Platform::GetHostPlatform() { return GetHostPlatformSP(); }134135void Platform::Initialize() {}136137void Platform::Terminate() {}138139PlatformProperties &Platform::GetGlobalPlatformProperties() {140static PlatformProperties g_settings;141return g_settings;142}143144void Platform::SetHostPlatform(const lldb::PlatformSP &platform_sp) {145// The native platform should use its static void Platform::Initialize()146// function to register itself as the native platform.147GetHostPlatformSP() = platform_sp;148}149150Status Platform::GetFileWithUUID(const FileSpec &platform_file,151const UUID *uuid_ptr, FileSpec &local_file) {152// Default to the local case153local_file = platform_file;154return Status();155}156157FileSpecList158Platform::LocateExecutableScriptingResources(Target *target, Module &module,159Stream &feedback_stream) {160return FileSpecList();161}162163Status Platform::GetSharedModule(164const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,165const FileSpecList *module_search_paths_ptr,166llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {167if (IsHost())168return ModuleList::GetSharedModule(module_spec, module_sp,169module_search_paths_ptr, old_modules,170did_create_ptr, false);171172// Module resolver lambda.173auto resolver = [&](const ModuleSpec &spec) {174Status error(eErrorTypeGeneric);175ModuleSpec resolved_spec;176// Check if we have sysroot set.177if (!m_sdk_sysroot.empty()) {178// Prepend sysroot to module spec.179resolved_spec = spec;180resolved_spec.GetFileSpec().PrependPathComponent(m_sdk_sysroot);181// Try to get shared module with resolved spec.182error = ModuleList::GetSharedModule(resolved_spec, module_sp,183module_search_paths_ptr, old_modules,184did_create_ptr, false);185}186// If we don't have sysroot or it didn't work then187// try original module spec.188if (!error.Success()) {189resolved_spec = spec;190error = ModuleList::GetSharedModule(resolved_spec, module_sp,191module_search_paths_ptr, old_modules,192did_create_ptr, false);193}194if (error.Success() && module_sp)195module_sp->SetPlatformFileSpec(resolved_spec.GetFileSpec());196return error;197};198199return GetRemoteSharedModule(module_spec, process, module_sp, resolver,200did_create_ptr);201}202203bool Platform::GetModuleSpec(const FileSpec &module_file_spec,204const ArchSpec &arch, ModuleSpec &module_spec) {205ModuleSpecList module_specs;206if (ObjectFile::GetModuleSpecifications(module_file_spec, 0, 0,207module_specs) == 0)208return false;209210ModuleSpec matched_module_spec;211return module_specs.FindMatchingModuleSpec(ModuleSpec(module_file_spec, arch),212module_spec);213}214215PlatformSP Platform::Create(llvm::StringRef name) {216lldb::PlatformSP platform_sp;217if (name == GetHostPlatformName())218return GetHostPlatform();219220if (PlatformCreateInstance create_callback =221PluginManager::GetPlatformCreateCallbackForPluginName(name))222return create_callback(true, nullptr);223return nullptr;224}225226ArchSpec Platform::GetAugmentedArchSpec(Platform *platform, llvm::StringRef triple) {227if (platform)228return platform->GetAugmentedArchSpec(triple);229return HostInfo::GetAugmentedArchSpec(triple);230}231232/// Default Constructor233Platform::Platform(bool is_host)234: m_is_host(is_host), m_os_version_set_while_connected(false),235m_system_arch_set_while_connected(false), m_max_uid_name_len(0),236m_max_gid_name_len(0), m_supports_rsync(false), m_rsync_opts(),237m_rsync_prefix(), m_supports_ssh(false), m_ssh_opts(),238m_ignores_remote_hostname(false), m_trap_handlers(),239m_calculated_trap_handlers(false),240m_module_cache(std::make_unique<ModuleCache>()) {241Log *log = GetLog(LLDBLog::Object);242LLDB_LOGF(log, "%p Platform::Platform()", static_cast<void *>(this));243}244245Platform::~Platform() = default;246247void Platform::GetStatus(Stream &strm) {248strm.Format(" Platform: {0}\n", GetPluginName());249250ArchSpec arch(GetSystemArchitecture());251if (arch.IsValid()) {252if (!arch.GetTriple().str().empty()) {253strm.Printf(" Triple: ");254arch.DumpTriple(strm.AsRawOstream());255strm.EOL();256}257}258259llvm::VersionTuple os_version = GetOSVersion();260if (!os_version.empty()) {261strm.Format("OS Version: {0}", os_version.getAsString());262263if (std::optional<std::string> s = GetOSBuildString())264strm.Format(" ({0})", *s);265266strm.EOL();267}268269if (IsHost()) {270strm.Printf(" Hostname: %s\n", GetHostname());271} else {272const bool is_connected = IsConnected();273if (is_connected)274strm.Printf(" Hostname: %s\n", GetHostname());275strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no");276}277278if (const std::string &sdk_root = GetSDKRootDirectory(); !sdk_root.empty())279strm.Format(" Sysroot: {0}\n", sdk_root);280281if (GetWorkingDirectory()) {282strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetPath().c_str());283}284if (!IsConnected())285return;286287std::string specific_info(GetPlatformSpecificConnectionInformation());288289if (!specific_info.empty())290strm.Printf("Platform-specific connection: %s\n", specific_info.c_str());291292if (std::optional<std::string> s = GetOSKernelDescription())293strm.Format(" Kernel: {0}\n", *s);294}295296llvm::VersionTuple Platform::GetOSVersion(Process *process) {297std::lock_guard<std::mutex> guard(m_mutex);298299if (IsHost()) {300if (m_os_version.empty()) {301// We have a local host platform302m_os_version = HostInfo::GetOSVersion();303m_os_version_set_while_connected = !m_os_version.empty();304}305} else {306// We have a remote platform. We can only fetch the remote307// OS version if we are connected, and we don't want to do it308// more than once.309310const bool is_connected = IsConnected();311312bool fetch = false;313if (!m_os_version.empty()) {314// We have valid OS version info, check to make sure it wasn't manually315// set prior to connecting. If it was manually set prior to connecting,316// then lets fetch the actual OS version info if we are now connected.317if (is_connected && !m_os_version_set_while_connected)318fetch = true;319} else {320// We don't have valid OS version info, fetch it if we are connected321fetch = is_connected;322}323324if (fetch)325m_os_version_set_while_connected = GetRemoteOSVersion();326}327328if (!m_os_version.empty())329return m_os_version;330if (process) {331// Check with the process in case it can answer the question if a process332// was provided333return process->GetHostOSVersion();334}335return llvm::VersionTuple();336}337338std::optional<std::string> Platform::GetOSBuildString() {339if (IsHost())340return HostInfo::GetOSBuildString();341return GetRemoteOSBuildString();342}343344std::optional<std::string> Platform::GetOSKernelDescription() {345if (IsHost())346return HostInfo::GetOSKernelDescription();347return GetRemoteOSKernelDescription();348}349350void Platform::AddClangModuleCompilationOptions(351Target *target, std::vector<std::string> &options) {352std::vector<std::string> default_compilation_options = {353"-x", "c++", "-Xclang", "-nostdsysteminc", "-Xclang", "-nostdsysteminc"};354355options.insert(options.end(), default_compilation_options.begin(),356default_compilation_options.end());357}358359FileSpec Platform::GetWorkingDirectory() {360if (IsHost()) {361llvm::SmallString<64> cwd;362if (llvm::sys::fs::current_path(cwd))363return {};364else {365FileSpec file_spec(cwd);366FileSystem::Instance().Resolve(file_spec);367return file_spec;368}369} else {370if (!m_working_dir)371m_working_dir = GetRemoteWorkingDirectory();372return m_working_dir;373}374}375376struct RecurseCopyBaton {377const FileSpec &dst;378Platform *platform_ptr;379Status error;380};381382static FileSystem::EnumerateDirectoryResult383RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft,384llvm::StringRef path) {385RecurseCopyBaton *rc_baton = (RecurseCopyBaton *)baton;386FileSpec src(path);387namespace fs = llvm::sys::fs;388switch (ft) {389case fs::file_type::fifo_file:390case fs::file_type::socket_file:391// we have no way to copy pipes and sockets - ignore them and continue392return FileSystem::eEnumerateDirectoryResultNext;393break;394395case fs::file_type::directory_file: {396// make the new directory and get in there397FileSpec dst_dir = rc_baton->dst;398if (!dst_dir.GetFilename())399dst_dir.SetFilename(src.GetFilename());400Status error = rc_baton->platform_ptr->MakeDirectory(401dst_dir, lldb::eFilePermissionsDirectoryDefault);402if (error.Fail()) {403rc_baton->error.SetErrorStringWithFormat(404"unable to setup directory %s on remote end",405dst_dir.GetPath().c_str());406return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out407}408409// now recurse410std::string src_dir_path(src.GetPath());411412// Make a filespec that only fills in the directory of a FileSpec so when413// we enumerate we can quickly fill in the filename for dst copies414FileSpec recurse_dst;415recurse_dst.SetDirectory(dst_dir.GetPathAsConstString());416RecurseCopyBaton rc_baton2 = {recurse_dst, rc_baton->platform_ptr,417Status()};418FileSystem::Instance().EnumerateDirectory(src_dir_path, true, true, true,419RecurseCopy_Callback, &rc_baton2);420if (rc_baton2.error.Fail()) {421rc_baton->error.SetErrorString(rc_baton2.error.AsCString());422return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out423}424return FileSystem::eEnumerateDirectoryResultNext;425} break;426427case fs::file_type::symlink_file: {428// copy the file and keep going429FileSpec dst_file = rc_baton->dst;430if (!dst_file.GetFilename())431dst_file.SetFilename(src.GetFilename());432433FileSpec src_resolved;434435rc_baton->error = FileSystem::Instance().Readlink(src, src_resolved);436437if (rc_baton->error.Fail())438return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out439440rc_baton->error =441rc_baton->platform_ptr->CreateSymlink(dst_file, src_resolved);442443if (rc_baton->error.Fail())444return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out445446return FileSystem::eEnumerateDirectoryResultNext;447} break;448449case fs::file_type::regular_file: {450// copy the file and keep going451FileSpec dst_file = rc_baton->dst;452if (!dst_file.GetFilename())453dst_file.SetFilename(src.GetFilename());454Status err = rc_baton->platform_ptr->PutFile(src, dst_file);455if (err.Fail()) {456rc_baton->error.SetErrorString(err.AsCString());457return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out458}459return FileSystem::eEnumerateDirectoryResultNext;460} break;461462default:463rc_baton->error.SetErrorStringWithFormat(464"invalid file detected during copy: %s", src.GetPath().c_str());465return FileSystem::eEnumerateDirectoryResultQuit; // got an error, bail out466break;467}468llvm_unreachable("Unhandled file_type!");469}470471Status Platform::Install(const FileSpec &src, const FileSpec &dst) {472Status error;473474Log *log = GetLog(LLDBLog::Platform);475LLDB_LOGF(log, "Platform::Install (src='%s', dst='%s')",476src.GetPath().c_str(), dst.GetPath().c_str());477FileSpec fixed_dst(dst);478479if (!fixed_dst.GetFilename())480fixed_dst.SetFilename(src.GetFilename());481482FileSpec working_dir = GetWorkingDirectory();483484if (dst) {485if (dst.GetDirectory()) {486const char first_dst_dir_char = dst.GetDirectory().GetCString()[0];487if (first_dst_dir_char == '/' || first_dst_dir_char == '\\') {488fixed_dst.SetDirectory(dst.GetDirectory());489}490// If the fixed destination file doesn't have a directory yet, then we491// must have a relative path. We will resolve this relative path against492// the platform's working directory493if (!fixed_dst.GetDirectory()) {494FileSpec relative_spec;495std::string path;496if (working_dir) {497relative_spec = working_dir;498relative_spec.AppendPathComponent(dst.GetPath());499fixed_dst.SetDirectory(relative_spec.GetDirectory());500} else {501error.SetErrorStringWithFormat(502"platform working directory must be valid for relative path '%s'",503dst.GetPath().c_str());504return error;505}506}507} else {508if (working_dir) {509fixed_dst.SetDirectory(working_dir.GetPathAsConstString());510} else {511error.SetErrorStringWithFormat(512"platform working directory must be valid for relative path '%s'",513dst.GetPath().c_str());514return error;515}516}517} else {518if (working_dir) {519fixed_dst.SetDirectory(working_dir.GetPathAsConstString());520} else {521error.SetErrorStringWithFormat("platform working directory must be valid "522"when destination directory is empty");523return error;524}525}526527LLDB_LOGF(log, "Platform::Install (src='%s', dst='%s') fixed_dst='%s'",528src.GetPath().c_str(), dst.GetPath().c_str(),529fixed_dst.GetPath().c_str());530531if (GetSupportsRSync()) {532error = PutFile(src, dst);533} else {534namespace fs = llvm::sys::fs;535switch (fs::get_file_type(src.GetPath(), false)) {536case fs::file_type::directory_file: {537llvm::sys::fs::remove(fixed_dst.GetPath());538uint32_t permissions = FileSystem::Instance().GetPermissions(src);539if (permissions == 0)540permissions = eFilePermissionsDirectoryDefault;541error = MakeDirectory(fixed_dst, permissions);542if (error.Success()) {543// Make a filespec that only fills in the directory of a FileSpec so544// when we enumerate we can quickly fill in the filename for dst copies545FileSpec recurse_dst;546recurse_dst.SetDirectory(fixed_dst.GetPathAsConstString());547std::string src_dir_path(src.GetPath());548RecurseCopyBaton baton = {recurse_dst, this, Status()};549FileSystem::Instance().EnumerateDirectory(550src_dir_path, true, true, true, RecurseCopy_Callback, &baton);551return baton.error;552}553} break;554555case fs::file_type::regular_file:556llvm::sys::fs::remove(fixed_dst.GetPath());557error = PutFile(src, fixed_dst);558break;559560case fs::file_type::symlink_file: {561llvm::sys::fs::remove(fixed_dst.GetPath());562FileSpec src_resolved;563error = FileSystem::Instance().Readlink(src, src_resolved);564if (error.Success())565error = CreateSymlink(dst, src_resolved);566} break;567case fs::file_type::fifo_file:568error.SetErrorString("platform install doesn't handle pipes");569break;570case fs::file_type::socket_file:571error.SetErrorString("platform install doesn't handle sockets");572break;573default:574error.SetErrorString(575"platform install doesn't handle non file or directory items");576break;577}578}579return error;580}581582bool Platform::SetWorkingDirectory(const FileSpec &file_spec) {583if (IsHost()) {584Log *log = GetLog(LLDBLog::Platform);585LLDB_LOG(log, "{0}", file_spec);586if (std::error_code ec = llvm::sys::fs::set_current_path(file_spec.GetPath())) {587LLDB_LOG(log, "error: {0}", ec.message());588return false;589}590return true;591} else {592m_working_dir.Clear();593return SetRemoteWorkingDirectory(file_spec);594}595}596597Status Platform::MakeDirectory(const FileSpec &file_spec,598uint32_t permissions) {599if (IsHost())600return llvm::sys::fs::create_directory(file_spec.GetPath(), permissions);601else {602Status error;603error.SetErrorStringWithFormatv("remote platform {0} doesn't support {1}",604GetPluginName(), LLVM_PRETTY_FUNCTION);605return error;606}607}608609Status Platform::GetFilePermissions(const FileSpec &file_spec,610uint32_t &file_permissions) {611if (IsHost()) {612auto Value = llvm::sys::fs::getPermissions(file_spec.GetPath());613if (Value)614file_permissions = Value.get();615return Status(Value.getError());616} else {617Status error;618error.SetErrorStringWithFormatv("remote platform {0} doesn't support {1}",619GetPluginName(), LLVM_PRETTY_FUNCTION);620return error;621}622}623624Status Platform::SetFilePermissions(const FileSpec &file_spec,625uint32_t file_permissions) {626if (IsHost()) {627auto Perms = static_cast<llvm::sys::fs::perms>(file_permissions);628return llvm::sys::fs::setPermissions(file_spec.GetPath(), Perms);629} else {630Status error;631error.SetErrorStringWithFormatv("remote platform {0} doesn't support {1}",632GetPluginName(), LLVM_PRETTY_FUNCTION);633return error;634}635}636637user_id_t Platform::OpenFile(const FileSpec &file_spec,638File::OpenOptions flags, uint32_t mode,639Status &error) {640if (IsHost())641return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error);642return UINT64_MAX;643}644645bool Platform::CloseFile(user_id_t fd, Status &error) {646if (IsHost())647return FileCache::GetInstance().CloseFile(fd, error);648return false;649}650651user_id_t Platform::GetFileSize(const FileSpec &file_spec) {652if (!IsHost())653return UINT64_MAX;654655uint64_t Size;656if (llvm::sys::fs::file_size(file_spec.GetPath(), Size))657return 0;658return Size;659}660661uint64_t Platform::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,662uint64_t dst_len, Status &error) {663if (IsHost())664return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error);665error.SetErrorStringWithFormatv(666"Platform::ReadFile() is not supported in the {0} platform",667GetPluginName());668return -1;669}670671uint64_t Platform::WriteFile(lldb::user_id_t fd, uint64_t offset,672const void *src, uint64_t src_len, Status &error) {673if (IsHost())674return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error);675error.SetErrorStringWithFormatv(676"Platform::WriteFile() is not supported in the {0} platform",677GetPluginName());678return -1;679}680681UserIDResolver &Platform::GetUserIDResolver() {682if (IsHost())683return HostInfo::GetUserIDResolver();684return UserIDResolver::GetNoopResolver();685}686687const char *Platform::GetHostname() {688if (IsHost())689return "127.0.0.1";690691if (m_hostname.empty())692return nullptr;693return m_hostname.c_str();694}695696ConstString Platform::GetFullNameForDylib(ConstString basename) {697return basename;698}699700bool Platform::SetRemoteWorkingDirectory(const FileSpec &working_dir) {701Log *log = GetLog(LLDBLog::Platform);702LLDB_LOGF(log, "Platform::SetRemoteWorkingDirectory('%s')",703working_dir.GetPath().c_str());704m_working_dir = working_dir;705return true;706}707708bool Platform::SetOSVersion(llvm::VersionTuple version) {709if (IsHost()) {710// We don't need anyone setting the OS version for the host platform, we711// should be able to figure it out by calling HostInfo::GetOSVersion(...).712return false;713} else {714// We have a remote platform, allow setting the target OS version if we715// aren't connected, since if we are connected, we should be able to716// request the remote OS version from the connected platform.717if (IsConnected())718return false;719else {720// We aren't connected and we might want to set the OS version ahead of721// time before we connect so we can peruse files and use a local SDK or722// PDK cache of support files to disassemble or do other things.723m_os_version = version;724return true;725}726}727return false;728}729730Status731Platform::ResolveExecutable(const ModuleSpec &module_spec,732lldb::ModuleSP &exe_module_sp,733const FileSpecList *module_search_paths_ptr) {734735// We may connect to a process and use the provided executable (Don't use736// local $PATH).737ModuleSpec resolved_module_spec(module_spec);738739// Resolve any executable within a bundle on MacOSX740Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());741742if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()) &&743!module_spec.GetUUID().IsValid())744return Status::createWithFormat("'{0}' does not exist",745resolved_module_spec.GetFileSpec());746747if (resolved_module_spec.GetArchitecture().IsValid() ||748resolved_module_spec.GetUUID().IsValid()) {749Status error =750ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,751module_search_paths_ptr, nullptr, nullptr);752753if (exe_module_sp && exe_module_sp->GetObjectFile())754return error;755exe_module_sp.reset();756}757// No valid architecture was specified or the exact arch wasn't found.758// Ask the platform for the architectures that we should be using (in the759// correct order) and see if we can find a match that way.760StreamString arch_names;761llvm::ListSeparator LS;762ArchSpec process_host_arch;763Status error;764for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) {765resolved_module_spec.GetArchitecture() = arch;766error =767ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,768module_search_paths_ptr, nullptr, nullptr);769if (error.Success()) {770if (exe_module_sp && exe_module_sp->GetObjectFile())771break;772error.SetErrorToGenericError();773}774775arch_names << LS << arch.GetArchitectureName();776}777778if (exe_module_sp && error.Success())779return {};780781if (!FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec()))782return Status::createWithFormat("'{0}' is not readable",783resolved_module_spec.GetFileSpec());784785if (!ObjectFile::IsObjectFile(resolved_module_spec.GetFileSpec()))786return Status::createWithFormat("'{0}' is not a valid executable",787resolved_module_spec.GetFileSpec());788789return Status::createWithFormat(790"'{0}' doesn't contain any '{1}' platform architectures: {2}",791resolved_module_spec.GetFileSpec(), GetPluginName(),792arch_names.GetData());793}794795Status Platform::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec,796FileSpec &sym_file) {797Status error;798if (FileSystem::Instance().Exists(sym_spec.GetSymbolFileSpec()))799sym_file = sym_spec.GetSymbolFileSpec();800else801error.SetErrorString("unable to resolve symbol file");802return error;803}804805bool Platform::ResolveRemotePath(const FileSpec &platform_path,806FileSpec &resolved_platform_path) {807resolved_platform_path = platform_path;808FileSystem::Instance().Resolve(resolved_platform_path);809return true;810}811812const ArchSpec &Platform::GetSystemArchitecture() {813if (IsHost()) {814if (!m_system_arch.IsValid()) {815// We have a local host platform816m_system_arch = HostInfo::GetArchitecture();817m_system_arch_set_while_connected = m_system_arch.IsValid();818}819} else {820// We have a remote platform. We can only fetch the remote system821// architecture if we are connected, and we don't want to do it more than822// once.823824const bool is_connected = IsConnected();825826bool fetch = false;827if (m_system_arch.IsValid()) {828// We have valid OS version info, check to make sure it wasn't manually829// set prior to connecting. If it was manually set prior to connecting,830// then lets fetch the actual OS version info if we are now connected.831if (is_connected && !m_system_arch_set_while_connected)832fetch = true;833} else {834// We don't have valid OS version info, fetch it if we are connected835fetch = is_connected;836}837838if (fetch) {839m_system_arch = GetRemoteSystemArchitecture();840m_system_arch_set_while_connected = m_system_arch.IsValid();841}842}843return m_system_arch;844}845846ArchSpec Platform::GetAugmentedArchSpec(llvm::StringRef triple) {847if (triple.empty())848return ArchSpec();849llvm::Triple normalized_triple(llvm::Triple::normalize(triple));850if (!ArchSpec::ContainsOnlyArch(normalized_triple))851return ArchSpec(triple);852853if (auto kind = HostInfo::ParseArchitectureKind(triple))854return HostInfo::GetArchitecture(*kind);855856ArchSpec compatible_arch;857ArchSpec raw_arch(triple);858if (!IsCompatibleArchitecture(raw_arch, {}, ArchSpec::CompatibleMatch,859&compatible_arch))860return raw_arch;861862if (!compatible_arch.IsValid())863return ArchSpec(normalized_triple);864865const llvm::Triple &compatible_triple = compatible_arch.GetTriple();866if (normalized_triple.getVendorName().empty())867normalized_triple.setVendor(compatible_triple.getVendor());868if (normalized_triple.getOSName().empty())869normalized_triple.setOS(compatible_triple.getOS());870if (normalized_triple.getEnvironmentName().empty())871normalized_triple.setEnvironment(compatible_triple.getEnvironment());872return ArchSpec(normalized_triple);873}874875Status Platform::ConnectRemote(Args &args) {876Status error;877if (IsHost())878error.SetErrorStringWithFormatv(879"The currently selected platform ({0}) is "880"the host platform and is always connected.",881GetPluginName());882else883error.SetErrorStringWithFormatv(884"Platform::ConnectRemote() is not supported by {0}", GetPluginName());885return error;886}887888Status Platform::DisconnectRemote() {889Status error;890if (IsHost())891error.SetErrorStringWithFormatv(892"The currently selected platform ({0}) is "893"the host platform and is always connected.",894GetPluginName());895else896error.SetErrorStringWithFormatv(897"Platform::DisconnectRemote() is not supported by {0}",898GetPluginName());899return error;900}901902bool Platform::GetProcessInfo(lldb::pid_t pid,903ProcessInstanceInfo &process_info) {904// Take care of the host case so that each subclass can just call this905// function to get the host functionality.906if (IsHost())907return Host::GetProcessInfo(pid, process_info);908return false;909}910911uint32_t Platform::FindProcesses(const ProcessInstanceInfoMatch &match_info,912ProcessInstanceInfoList &process_infos) {913// Take care of the host case so that each subclass can just call this914// function to get the host functionality.915uint32_t match_count = 0;916if (IsHost())917match_count = Host::FindProcesses(match_info, process_infos);918return match_count;919}920921ProcessInstanceInfoList Platform::GetAllProcesses() {922ProcessInstanceInfoList processes;923ProcessInstanceInfoMatch match;924assert(match.MatchAllProcesses());925FindProcesses(match, processes);926return processes;927}928929Status Platform::LaunchProcess(ProcessLaunchInfo &launch_info) {930Status error;931Log *log = GetLog(LLDBLog::Platform);932LLDB_LOGF(log, "Platform::%s()", __FUNCTION__);933934// Take care of the host case so that each subclass can just call this935// function to get the host functionality.936if (IsHost()) {937if (::getenv("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY"))938launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY);939940if (launch_info.GetFlags().Test(eLaunchFlagLaunchInShell)) {941const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug);942const bool first_arg_is_full_shell_command = false;943uint32_t num_resumes = GetResumeCountForLaunchInfo(launch_info);944if (log) {945const FileSpec &shell = launch_info.GetShell();946std::string shell_str = (shell) ? shell.GetPath() : "<null>";947LLDB_LOGF(log,948"Platform::%s GetResumeCountForLaunchInfo() returned %" PRIu32949", shell is '%s'",950__FUNCTION__, num_resumes, shell_str.c_str());951}952953if (!launch_info.ConvertArgumentsForLaunchingInShell(954error, will_debug, first_arg_is_full_shell_command, num_resumes))955return error;956} else if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {957error = ShellExpandArguments(launch_info);958if (error.Fail()) {959error.SetErrorStringWithFormat("shell expansion failed (reason: %s). "960"consider launching with 'process "961"launch'.",962error.AsCString("unknown"));963return error;964}965}966967LLDB_LOGF(log, "Platform::%s final launch_info resume count: %" PRIu32,968__FUNCTION__, launch_info.GetResumeCount());969970error = Host::LaunchProcess(launch_info);971} else972error.SetErrorString(973"base lldb_private::Platform class can't launch remote processes");974return error;975}976977Status Platform::ShellExpandArguments(ProcessLaunchInfo &launch_info) {978if (IsHost())979return Host::ShellExpandArguments(launch_info);980return Status("base lldb_private::Platform class can't expand arguments");981}982983Status Platform::KillProcess(const lldb::pid_t pid) {984Log *log = GetLog(LLDBLog::Platform);985LLDB_LOGF(log, "Platform::%s, pid %" PRIu64, __FUNCTION__, pid);986987if (!IsHost()) {988return Status(989"base lldb_private::Platform class can't kill remote processes");990}991Host::Kill(pid, SIGKILL);992return Status();993}994995lldb::ProcessSP Platform::DebugProcess(ProcessLaunchInfo &launch_info,996Debugger &debugger, Target &target,997Status &error) {998Log *log = GetLog(LLDBLog::Platform);999LLDB_LOG(log, "target = {0}", &target);10001001ProcessSP process_sp;1002// Make sure we stop at the entry point1003launch_info.GetFlags().Set(eLaunchFlagDebug);1004// We always launch the process we are going to debug in a separate process1005// group, since then we can handle ^C interrupts ourselves w/o having to1006// worry about the target getting them as well.1007launch_info.SetLaunchInSeparateProcessGroup(true);10081009// Allow any StructuredData process-bound plugins to adjust the launch info1010// if needed1011size_t i = 0;1012bool iteration_complete = false;1013// Note iteration can't simply go until a nullptr callback is returned, as it1014// is valid for a plugin to not supply a filter.1015auto get_filter_func = PluginManager::GetStructuredDataFilterCallbackAtIndex;1016for (auto filter_callback = get_filter_func(i, iteration_complete);1017!iteration_complete;1018filter_callback = get_filter_func(++i, iteration_complete)) {1019if (filter_callback) {1020// Give this ProcessLaunchInfo filter a chance to adjust the launch info.1021error = (*filter_callback)(launch_info, &target);1022if (!error.Success()) {1023LLDB_LOGF(log,1024"Platform::%s() StructuredDataPlugin launch "1025"filter failed.",1026__FUNCTION__);1027return process_sp;1028}1029}1030}10311032error = LaunchProcess(launch_info);1033if (error.Success()) {1034LLDB_LOGF(log,1035"Platform::%s LaunchProcess() call succeeded (pid=%" PRIu64 ")",1036__FUNCTION__, launch_info.GetProcessID());1037if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {1038ProcessAttachInfo attach_info(launch_info);1039process_sp = Attach(attach_info, debugger, &target, error);1040if (process_sp) {1041LLDB_LOG(log, "Attach() succeeded, Process plugin: {0}",1042process_sp->GetPluginName());1043launch_info.SetHijackListener(attach_info.GetHijackListener());10441045// Since we attached to the process, it will think it needs to detach1046// if the process object just goes away without an explicit call to1047// Process::Kill() or Process::Detach(), so let it know to kill the1048// process if this happens.1049process_sp->SetShouldDetach(false);10501051// If we didn't have any file actions, the pseudo terminal might have1052// been used where the secondary side was given as the file to open for1053// stdin/out/err after we have already opened the primary so we can1054// read/write stdin/out/err.1055int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor();1056if (pty_fd != PseudoTerminal::invalid_fd) {1057process_sp->SetSTDIOFileDescriptor(pty_fd);1058}1059} else {1060LLDB_LOGF(log, "Platform::%s Attach() failed: %s", __FUNCTION__,1061error.AsCString());1062}1063} else {1064LLDB_LOGF(log,1065"Platform::%s LaunchProcess() returned launch_info with "1066"invalid process id",1067__FUNCTION__);1068}1069} else {1070LLDB_LOGF(log, "Platform::%s LaunchProcess() failed: %s", __FUNCTION__,1071error.AsCString());1072}10731074return process_sp;1075}10761077std::vector<ArchSpec>1078Platform::CreateArchList(llvm::ArrayRef<llvm::Triple::ArchType> archs,1079llvm::Triple::OSType os) {1080std::vector<ArchSpec> list;1081for(auto arch : archs) {1082llvm::Triple triple;1083triple.setArch(arch);1084triple.setOS(os);1085list.push_back(ArchSpec(triple));1086}1087return list;1088}10891090/// Lets a platform answer if it is compatible with a given1091/// architecture and the target triple contained within.1092bool Platform::IsCompatibleArchitecture(const ArchSpec &arch,1093const ArchSpec &process_host_arch,1094ArchSpec::MatchType match,1095ArchSpec *compatible_arch_ptr) {1096// If the architecture is invalid, we must answer true...1097if (arch.IsValid()) {1098ArchSpec platform_arch;1099for (const ArchSpec &platform_arch :1100GetSupportedArchitectures(process_host_arch)) {1101if (arch.IsMatch(platform_arch, match)) {1102if (compatible_arch_ptr)1103*compatible_arch_ptr = platform_arch;1104return true;1105}1106}1107}1108if (compatible_arch_ptr)1109compatible_arch_ptr->Clear();1110return false;1111}11121113Status Platform::PutFile(const FileSpec &source, const FileSpec &destination,1114uint32_t uid, uint32_t gid) {1115Log *log = GetLog(LLDBLog::Platform);1116LLDB_LOGF(log, "[PutFile] Using block by block transfer....\n");11171118auto source_open_options =1119File::eOpenOptionReadOnly | File::eOpenOptionCloseOnExec;1120namespace fs = llvm::sys::fs;1121if (fs::is_symlink_file(source.GetPath()))1122source_open_options |= File::eOpenOptionDontFollowSymlinks;11231124auto source_file = FileSystem::Instance().Open(source, source_open_options,1125lldb::eFilePermissionsUserRW);1126if (!source_file)1127return Status(source_file.takeError());1128Status error;11291130bool requires_upload = true;1131llvm::ErrorOr<llvm::MD5::MD5Result> remote_md5 = CalculateMD5(destination);1132if (std::error_code ec = remote_md5.getError()) {1133LLDB_LOG(log, "[PutFile] couldn't get md5 sum of destination: {0}",1134ec.message());1135} else {1136llvm::ErrorOr<llvm::MD5::MD5Result> local_md5 =1137llvm::sys::fs::md5_contents(source.GetPath());1138if (std::error_code ec = local_md5.getError()) {1139LLDB_LOG(log, "[PutFile] couldn't get md5 sum of source: {0}",1140ec.message());1141} else {1142LLDB_LOGF(log, "[PutFile] destination md5: %016" PRIx64 "%016" PRIx64,1143remote_md5->high(), remote_md5->low());1144LLDB_LOGF(log, "[PutFile] local md5: %016" PRIx64 "%016" PRIx64,1145local_md5->high(), local_md5->low());1146requires_upload = *remote_md5 != *local_md5;1147}1148}11491150if (!requires_upload) {1151LLDB_LOGF(log, "[PutFile] skipping PutFile because md5sums match");1152return error;1153}11541155uint32_t permissions = source_file.get()->GetPermissions(error);1156if (permissions == 0)1157permissions = lldb::eFilePermissionsUserRWX;11581159lldb::user_id_t dest_file = OpenFile(1160destination, File::eOpenOptionCanCreate | File::eOpenOptionWriteOnly |1161File::eOpenOptionTruncate | File::eOpenOptionCloseOnExec,1162permissions, error);1163LLDB_LOGF(log, "dest_file = %" PRIu64 "\n", dest_file);11641165if (error.Fail())1166return error;1167if (dest_file == UINT64_MAX)1168return Status("unable to open target file");1169lldb::WritableDataBufferSP buffer_sp(new DataBufferHeap(1024 * 16, 0));1170uint64_t offset = 0;1171for (;;) {1172size_t bytes_read = buffer_sp->GetByteSize();1173error = source_file.get()->Read(buffer_sp->GetBytes(), bytes_read);1174if (error.Fail() || bytes_read == 0)1175break;11761177const uint64_t bytes_written =1178WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error);1179if (error.Fail())1180break;11811182offset += bytes_written;1183if (bytes_written != bytes_read) {1184// We didn't write the correct number of bytes, so adjust the file1185// position in the source file we are reading from...1186source_file.get()->SeekFromStart(offset);1187}1188}1189CloseFile(dest_file, error);11901191if (uid == UINT32_MAX && gid == UINT32_MAX)1192return error;11931194// TODO: ChownFile?11951196return error;1197}11981199Status Platform::GetFile(const FileSpec &source, const FileSpec &destination) {1200Status error("unimplemented");1201return error;1202}12031204Status1205Platform::CreateSymlink(const FileSpec &src, // The name of the link is in src1206const FileSpec &dst) // The symlink points to dst1207{1208if (IsHost())1209return FileSystem::Instance().Symlink(src, dst);1210return Status("unimplemented");1211}12121213bool Platform::GetFileExists(const lldb_private::FileSpec &file_spec) {1214if (IsHost())1215return FileSystem::Instance().Exists(file_spec);1216return false;1217}12181219Status Platform::Unlink(const FileSpec &path) {1220if (IsHost())1221return llvm::sys::fs::remove(path.GetPath());1222return Status("unimplemented");1223}12241225MmapArgList Platform::GetMmapArgumentList(const ArchSpec &arch, addr_t addr,1226addr_t length, unsigned prot,1227unsigned flags, addr_t fd,1228addr_t offset) {1229uint64_t flags_platform = 0;1230if (flags & eMmapFlagsPrivate)1231flags_platform |= MAP_PRIVATE;1232if (flags & eMmapFlagsAnon)1233flags_platform |= MAP_ANON;12341235MmapArgList args({addr, length, prot, flags_platform, fd, offset});1236return args;1237}12381239lldb_private::Status Platform::RunShellCommand(1240llvm::StringRef command,1241const FileSpec &1242working_dir, // Pass empty FileSpec to use the current working directory1243int *status_ptr, // Pass nullptr if you don't want the process exit status1244int *signo_ptr, // Pass nullptr if you don't want the signal that caused the1245// process to exit1246std::string1247*command_output, // Pass nullptr if you don't want the command output1248const Timeout<std::micro> &timeout) {1249return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr,1250signo_ptr, command_output, timeout);1251}12521253lldb_private::Status Platform::RunShellCommand(1254llvm::StringRef shell, // Pass empty if you want to use the default1255// shell interpreter1256llvm::StringRef command, // Shouldn't be empty1257const FileSpec &1258working_dir, // Pass empty FileSpec to use the current working directory1259int *status_ptr, // Pass nullptr if you don't want the process exit status1260int *signo_ptr, // Pass nullptr if you don't want the signal that caused the1261// process to exit1262std::string1263*command_output, // Pass nullptr if you don't want the command output1264const Timeout<std::micro> &timeout) {1265if (IsHost())1266return Host::RunShellCommand(shell, command, working_dir, status_ptr,1267signo_ptr, command_output, timeout);1268return Status("unable to run a remote command without a platform");1269}12701271llvm::ErrorOr<llvm::MD5::MD5Result>1272Platform::CalculateMD5(const FileSpec &file_spec) {1273if (!IsHost())1274return std::make_error_code(std::errc::not_supported);1275return llvm::sys::fs::md5_contents(file_spec.GetPath());1276}12771278void Platform::SetLocalCacheDirectory(const char *local) {1279m_local_cache_directory.assign(local);1280}12811282const char *Platform::GetLocalCacheDirectory() {1283return m_local_cache_directory.c_str();1284}12851286static constexpr OptionDefinition g_rsync_option_table[] = {1287{LLDB_OPT_SET_ALL, false, "rsync", 'r', OptionParser::eNoArgument, nullptr,1288{}, 0, eArgTypeNone, "Enable rsync."},1289{LLDB_OPT_SET_ALL, false, "rsync-opts", 'R',1290OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName,1291"Platform-specific options required for rsync to work."},1292{LLDB_OPT_SET_ALL, false, "rsync-prefix", 'P',1293OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName,1294"Platform-specific rsync prefix put before the remote path."},1295{LLDB_OPT_SET_ALL, false, "ignore-remote-hostname", 'i',1296OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,1297"Do not automatically fill in the remote hostname when composing the "1298"rsync command."},1299};13001301static constexpr OptionDefinition g_ssh_option_table[] = {1302{LLDB_OPT_SET_ALL, false, "ssh", 's', OptionParser::eNoArgument, nullptr,1303{}, 0, eArgTypeNone, "Enable SSH."},1304{LLDB_OPT_SET_ALL, false, "ssh-opts", 'S', OptionParser::eRequiredArgument,1305nullptr, {}, 0, eArgTypeCommandName,1306"Platform-specific options required for SSH to work."},1307};13081309static constexpr OptionDefinition g_caching_option_table[] = {1310{LLDB_OPT_SET_ALL, false, "local-cache-dir", 'c',1311OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePath,1312"Path in which to store local copies of files."},1313};13141315llvm::ArrayRef<OptionDefinition> OptionGroupPlatformRSync::GetDefinitions() {1316return llvm::ArrayRef(g_rsync_option_table);1317}13181319void OptionGroupPlatformRSync::OptionParsingStarting(1320ExecutionContext *execution_context) {1321m_rsync = false;1322m_rsync_opts.clear();1323m_rsync_prefix.clear();1324m_ignores_remote_hostname = false;1325}13261327lldb_private::Status1328OptionGroupPlatformRSync::SetOptionValue(uint32_t option_idx,1329llvm::StringRef option_arg,1330ExecutionContext *execution_context) {1331Status error;1332char short_option = (char)GetDefinitions()[option_idx].short_option;1333switch (short_option) {1334case 'r':1335m_rsync = true;1336break;13371338case 'R':1339m_rsync_opts.assign(std::string(option_arg));1340break;13411342case 'P':1343m_rsync_prefix.assign(std::string(option_arg));1344break;13451346case 'i':1347m_ignores_remote_hostname = true;1348break;13491350default:1351error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);1352break;1353}13541355return error;1356}13571358lldb::BreakpointSP1359Platform::SetThreadCreationBreakpoint(lldb_private::Target &target) {1360return lldb::BreakpointSP();1361}13621363llvm::ArrayRef<OptionDefinition> OptionGroupPlatformSSH::GetDefinitions() {1364return llvm::ArrayRef(g_ssh_option_table);1365}13661367void OptionGroupPlatformSSH::OptionParsingStarting(1368ExecutionContext *execution_context) {1369m_ssh = false;1370m_ssh_opts.clear();1371}13721373lldb_private::Status1374OptionGroupPlatformSSH::SetOptionValue(uint32_t option_idx,1375llvm::StringRef option_arg,1376ExecutionContext *execution_context) {1377Status error;1378char short_option = (char)GetDefinitions()[option_idx].short_option;1379switch (short_option) {1380case 's':1381m_ssh = true;1382break;13831384case 'S':1385m_ssh_opts.assign(std::string(option_arg));1386break;13871388default:1389error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);1390break;1391}13921393return error;1394}13951396llvm::ArrayRef<OptionDefinition> OptionGroupPlatformCaching::GetDefinitions() {1397return llvm::ArrayRef(g_caching_option_table);1398}13991400void OptionGroupPlatformCaching::OptionParsingStarting(1401ExecutionContext *execution_context) {1402m_cache_dir.clear();1403}14041405lldb_private::Status OptionGroupPlatformCaching::SetOptionValue(1406uint32_t option_idx, llvm::StringRef option_arg,1407ExecutionContext *execution_context) {1408Status error;1409char short_option = (char)GetDefinitions()[option_idx].short_option;1410switch (short_option) {1411case 'c':1412m_cache_dir.assign(std::string(option_arg));1413break;14141415default:1416error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);1417break;1418}14191420return error;1421}14221423Environment Platform::GetEnvironment() {1424if (IsHost())1425return Host::GetEnvironment();1426return Environment();1427}14281429const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() {1430if (!m_calculated_trap_handlers) {1431std::lock_guard<std::mutex> guard(m_mutex);1432if (!m_calculated_trap_handlers) {1433CalculateTrapHandlerSymbolNames();1434m_calculated_trap_handlers = true;1435}1436}1437return m_trap_handlers;1438}14391440Status1441Platform::GetCachedExecutable(ModuleSpec &module_spec,1442lldb::ModuleSP &module_sp,1443const FileSpecList *module_search_paths_ptr) {1444FileSpec platform_spec = module_spec.GetFileSpec();1445Status error = GetRemoteSharedModule(1446module_spec, nullptr, module_sp,1447[&](const ModuleSpec &spec) {1448return Platform::ResolveExecutable(spec, module_sp,1449module_search_paths_ptr);1450},1451nullptr);1452if (error.Success()) {1453module_spec.GetFileSpec() = module_sp->GetFileSpec();1454module_spec.GetPlatformFileSpec() = platform_spec;1455}14561457return error;1458}14591460Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec,1461Process *process,1462lldb::ModuleSP &module_sp,1463const ModuleResolver &module_resolver,1464bool *did_create_ptr) {1465// Get module information from a target.1466ModuleSpec resolved_module_spec;1467ArchSpec process_host_arch;1468bool got_module_spec = false;1469if (process) {1470process_host_arch = process->GetSystemArchitecture();1471// Try to get module information from the process1472if (process->GetModuleSpec(module_spec.GetFileSpec(),1473module_spec.GetArchitecture(),1474resolved_module_spec)) {1475if (!module_spec.GetUUID().IsValid() ||1476module_spec.GetUUID() == resolved_module_spec.GetUUID()) {1477got_module_spec = true;1478}1479}1480}14811482if (!module_spec.GetArchitecture().IsValid()) {1483Status error;1484// No valid architecture was specified, ask the platform for the1485// architectures that we should be using (in the correct order) and see if1486// we can find a match that way1487ModuleSpec arch_module_spec(module_spec);1488for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) {1489arch_module_spec.GetArchitecture() = arch;1490error = ModuleList::GetSharedModule(arch_module_spec, module_sp, nullptr,1491nullptr, nullptr);1492// Did we find an executable using one of the1493if (error.Success() && module_sp)1494break;1495}1496if (module_sp) {1497resolved_module_spec = arch_module_spec;1498got_module_spec = true;1499}1500}15011502if (!got_module_spec) {1503// Get module information from a target.1504if (GetModuleSpec(module_spec.GetFileSpec(), module_spec.GetArchitecture(),1505resolved_module_spec)) {1506if (!module_spec.GetUUID().IsValid() ||1507module_spec.GetUUID() == resolved_module_spec.GetUUID()) {1508got_module_spec = true;1509}1510}1511}15121513if (!got_module_spec) {1514// Fall back to the given module resolver, which may have its own1515// search logic.1516return module_resolver(module_spec);1517}15181519// If we are looking for a specific UUID, make sure resolved_module_spec has1520// the same one before we search.1521if (module_spec.GetUUID().IsValid()) {1522resolved_module_spec.GetUUID() = module_spec.GetUUID();1523}15241525// Call locate module callback if set. This allows users to implement their1526// own module cache system. For example, to leverage build system artifacts,1527// to bypass pulling files from remote platform, or to search symbol files1528// from symbol servers.1529FileSpec symbol_file_spec;1530CallLocateModuleCallbackIfSet(resolved_module_spec, module_sp,1531symbol_file_spec, did_create_ptr);1532if (module_sp) {1533// The module is loaded.1534if (symbol_file_spec) {1535// 1. module_sp:loaded, symbol_file_spec:set1536// The callback found a module file and a symbol file for this1537// resolved_module_spec. Set the symbol file to the module.1538module_sp->SetSymbolFileFileSpec(symbol_file_spec);1539} else {1540// 2. module_sp:loaded, symbol_file_spec:empty1541// The callback only found a module file for this1542// resolved_module_spec.1543}1544return Status();1545}15461547// The module is not loaded by CallLocateModuleCallbackIfSet.1548// 3. module_sp:empty, symbol_file_spec:set1549// The callback only found a symbol file for the module. We continue to1550// find a module file for this resolved_module_spec. and we will call1551// module_sp->SetSymbolFileFileSpec with the symbol_file_spec later.1552// 4. module_sp:empty, symbol_file_spec:empty1553// The callback is not set. Or the callback did not find any module1554// files nor any symbol files. Or the callback failed, or something1555// went wrong. We continue to find a module file for this1556// resolved_module_spec.15571558// Trying to find a module by UUID on local file system.1559const Status error = module_resolver(resolved_module_spec);1560if (error.Success()) {1561if (module_sp && symbol_file_spec) {1562// Set the symbol file to the module if the locate modudle callback was1563// called and returned only a symbol file.1564module_sp->SetSymbolFileFileSpec(symbol_file_spec);1565}1566return error;1567}15681569// Fallback to call GetCachedSharedModule on failure.1570if (GetCachedSharedModule(resolved_module_spec, module_sp, did_create_ptr)) {1571if (module_sp && symbol_file_spec) {1572// Set the symbol file to the module if the locate modudle callback was1573// called and returned only a symbol file.1574module_sp->SetSymbolFileFileSpec(symbol_file_spec);1575}1576return Status();1577}15781579return Status("Failed to call GetCachedSharedModule");1580}15811582void Platform::CallLocateModuleCallbackIfSet(const ModuleSpec &module_spec,1583lldb::ModuleSP &module_sp,1584FileSpec &symbol_file_spec,1585bool *did_create_ptr) {1586if (!m_locate_module_callback) {1587// Locate module callback is not set.1588return;1589}15901591FileSpec module_file_spec;1592Status error =1593m_locate_module_callback(module_spec, module_file_spec, symbol_file_spec);15941595// Locate module callback is set and called. Check the error.1596Log *log = GetLog(LLDBLog::Platform);1597if (error.Fail()) {1598LLDB_LOGF(log, "%s: locate module callback failed: %s",1599LLVM_PRETTY_FUNCTION, error.AsCString());1600return;1601}16021603// The locate module callback was succeeded.1604// Check the module_file_spec and symbol_file_spec values.1605// 1. module:empty symbol:empty -> Failure1606// - The callback did not return any files.1607// 2. module:exists symbol:exists -> Success1608// - The callback returned a module file and a symbol file.1609// 3. module:exists symbol:empty -> Success1610// - The callback returned only a module file.1611// 4. module:empty symbol:exists -> Success1612// - The callback returned only a symbol file.1613// For example, a breakpad symbol text file.1614if (!module_file_spec && !symbol_file_spec) {1615// This is '1. module:empty symbol:empty -> Failure'1616// The callback did not return any files.1617LLDB_LOGF(log,1618"%s: locate module callback did not set both "1619"module_file_spec and symbol_file_spec",1620LLVM_PRETTY_FUNCTION);1621return;1622}16231624// If the callback returned a module file, it should exist.1625if (module_file_spec && !FileSystem::Instance().Exists(module_file_spec)) {1626LLDB_LOGF(log,1627"%s: locate module callback set a non-existent file to "1628"module_file_spec: %s",1629LLVM_PRETTY_FUNCTION, module_file_spec.GetPath().c_str());1630// Clear symbol_file_spec for the error.1631symbol_file_spec.Clear();1632return;1633}16341635// If the callback returned a symbol file, it should exist.1636if (symbol_file_spec && !FileSystem::Instance().Exists(symbol_file_spec)) {1637LLDB_LOGF(log,1638"%s: locate module callback set a non-existent file to "1639"symbol_file_spec: %s",1640LLVM_PRETTY_FUNCTION, symbol_file_spec.GetPath().c_str());1641// Clear symbol_file_spec for the error.1642symbol_file_spec.Clear();1643return;1644}16451646if (!module_file_spec && symbol_file_spec) {1647// This is '4. module:empty symbol:exists -> Success'1648// The locate module callback returned only a symbol file. For example,1649// a breakpad symbol text file. GetRemoteSharedModule will use this returned1650// symbol_file_spec.1651LLDB_LOGF(log, "%s: locate module callback succeeded: symbol=%s",1652LLVM_PRETTY_FUNCTION, symbol_file_spec.GetPath().c_str());1653return;1654}16551656// This is one of the following.1657// - 2. module:exists symbol:exists -> Success1658// - The callback returned a module file and a symbol file.1659// - 3. module:exists symbol:empty -> Success1660// - The callback returned Only a module file.1661// Load the module file.1662auto cached_module_spec(module_spec);1663cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md51664// content hash instead of real UUID.1665cached_module_spec.GetFileSpec() = module_file_spec;1666cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec();1667cached_module_spec.SetObjectOffset(0);16681669error = ModuleList::GetSharedModule(cached_module_spec, module_sp, nullptr,1670nullptr, did_create_ptr, false);1671if (error.Success() && module_sp) {1672// Succeeded to load the module file.1673LLDB_LOGF(log, "%s: locate module callback succeeded: module=%s symbol=%s",1674LLVM_PRETTY_FUNCTION, module_file_spec.GetPath().c_str(),1675symbol_file_spec.GetPath().c_str());1676} else {1677LLDB_LOGF(log,1678"%s: locate module callback succeeded but failed to load: "1679"module=%s symbol=%s",1680LLVM_PRETTY_FUNCTION, module_file_spec.GetPath().c_str(),1681symbol_file_spec.GetPath().c_str());1682// Clear module_sp and symbol_file_spec for the error.1683module_sp.reset();1684symbol_file_spec.Clear();1685}1686}16871688bool Platform::GetCachedSharedModule(const ModuleSpec &module_spec,1689lldb::ModuleSP &module_sp,1690bool *did_create_ptr) {1691if (IsHost() || !GetGlobalPlatformProperties().GetUseModuleCache() ||1692!GetGlobalPlatformProperties().GetModuleCacheDirectory())1693return false;16941695Log *log = GetLog(LLDBLog::Platform);16961697// Check local cache for a module.1698auto error = m_module_cache->GetAndPut(1699GetModuleCacheRoot(), GetCacheHostname(), module_spec,1700[this](const ModuleSpec &module_spec,1701const FileSpec &tmp_download_file_spec) {1702return DownloadModuleSlice(1703module_spec.GetFileSpec(), module_spec.GetObjectOffset(),1704module_spec.GetObjectSize(), tmp_download_file_spec);17051706},1707[this](const ModuleSP &module_sp,1708const FileSpec &tmp_download_file_spec) {1709return DownloadSymbolFile(module_sp, tmp_download_file_spec);1710},1711module_sp, did_create_ptr);1712if (error.Success())1713return true;17141715LLDB_LOGF(log, "Platform::%s - module %s not found in local cache: %s",1716__FUNCTION__, module_spec.GetUUID().GetAsString().c_str(),1717error.AsCString());1718return false;1719}17201721Status Platform::DownloadModuleSlice(const FileSpec &src_file_spec,1722const uint64_t src_offset,1723const uint64_t src_size,1724const FileSpec &dst_file_spec) {1725Status error;17261727std::error_code EC;1728llvm::raw_fd_ostream dst(dst_file_spec.GetPath(), EC, llvm::sys::fs::OF_None);1729if (EC) {1730error.SetErrorStringWithFormat("unable to open destination file: %s",1731dst_file_spec.GetPath().c_str());1732return error;1733}17341735auto src_fd = OpenFile(src_file_spec, File::eOpenOptionReadOnly,1736lldb::eFilePermissionsFileDefault, error);17371738if (error.Fail()) {1739error.SetErrorStringWithFormat("unable to open source file: %s",1740error.AsCString());1741return error;1742}17431744std::vector<char> buffer(512 * 1024);1745auto offset = src_offset;1746uint64_t total_bytes_read = 0;1747while (total_bytes_read < src_size) {1748const auto to_read = std::min(static_cast<uint64_t>(buffer.size()),1749src_size - total_bytes_read);1750const uint64_t n_read =1751ReadFile(src_fd, offset, &buffer[0], to_read, error);1752if (error.Fail())1753break;1754if (n_read == 0) {1755error.SetErrorString("read 0 bytes");1756break;1757}1758offset += n_read;1759total_bytes_read += n_read;1760dst.write(&buffer[0], n_read);1761}17621763Status close_error;1764CloseFile(src_fd, close_error); // Ignoring close error.17651766return error;1767}17681769Status Platform::DownloadSymbolFile(const lldb::ModuleSP &module_sp,1770const FileSpec &dst_file_spec) {1771return Status(1772"Symbol file downloading not supported by the default platform.");1773}17741775FileSpec Platform::GetModuleCacheRoot() {1776auto dir_spec = GetGlobalPlatformProperties().GetModuleCacheDirectory();1777dir_spec.AppendPathComponent(GetPluginName());1778return dir_spec;1779}17801781const char *Platform::GetCacheHostname() { return GetHostname(); }17821783const UnixSignalsSP &Platform::GetRemoteUnixSignals() {1784static const auto s_default_unix_signals_sp = std::make_shared<UnixSignals>();1785return s_default_unix_signals_sp;1786}17871788UnixSignalsSP Platform::GetUnixSignals() {1789if (IsHost())1790return UnixSignals::CreateForHost();1791return GetRemoteUnixSignals();1792}17931794uint32_t Platform::LoadImage(lldb_private::Process *process,1795const lldb_private::FileSpec &local_file,1796const lldb_private::FileSpec &remote_file,1797lldb_private::Status &error) {1798if (local_file && remote_file) {1799// Both local and remote file was specified. Install the local file to the1800// given location.1801if (IsRemote() || local_file != remote_file) {1802error = Install(local_file, remote_file);1803if (error.Fail())1804return LLDB_INVALID_IMAGE_TOKEN;1805}1806return DoLoadImage(process, remote_file, nullptr, error);1807}18081809if (local_file) {1810// Only local file was specified. Install it to the current working1811// directory.1812FileSpec target_file = GetWorkingDirectory();1813target_file.AppendPathComponent(local_file.GetFilename().AsCString());1814if (IsRemote() || local_file != target_file) {1815error = Install(local_file, target_file);1816if (error.Fail())1817return LLDB_INVALID_IMAGE_TOKEN;1818}1819return DoLoadImage(process, target_file, nullptr, error);1820}18211822if (remote_file) {1823// Only remote file was specified so we don't have to do any copying1824return DoLoadImage(process, remote_file, nullptr, error);1825}18261827error.SetErrorString("Neither local nor remote file was specified");1828return LLDB_INVALID_IMAGE_TOKEN;1829}18301831uint32_t Platform::DoLoadImage(lldb_private::Process *process,1832const lldb_private::FileSpec &remote_file,1833const std::vector<std::string> *paths,1834lldb_private::Status &error,1835lldb_private::FileSpec *loaded_image) {1836error.SetErrorString("LoadImage is not supported on the current platform");1837return LLDB_INVALID_IMAGE_TOKEN;1838}18391840uint32_t Platform::LoadImageUsingPaths(lldb_private::Process *process,1841const lldb_private::FileSpec &remote_filename,1842const std::vector<std::string> &paths,1843lldb_private::Status &error,1844lldb_private::FileSpec *loaded_path)1845{1846FileSpec file_to_use;1847if (remote_filename.IsAbsolute())1848file_to_use = FileSpec(remote_filename.GetFilename().GetStringRef(),18491850remote_filename.GetPathStyle());1851else1852file_to_use = remote_filename;18531854return DoLoadImage(process, file_to_use, &paths, error, loaded_path);1855}18561857Status Platform::UnloadImage(lldb_private::Process *process,1858uint32_t image_token) {1859return Status("UnloadImage is not supported on the current platform");1860}18611862lldb::ProcessSP Platform::ConnectProcess(llvm::StringRef connect_url,1863llvm::StringRef plugin_name,1864Debugger &debugger, Target *target,1865Status &error) {1866return DoConnectProcess(connect_url, plugin_name, debugger, nullptr, target,1867error);1868}18691870lldb::ProcessSP Platform::ConnectProcessSynchronous(1871llvm::StringRef connect_url, llvm::StringRef plugin_name,1872Debugger &debugger, Stream &stream, Target *target, Status &error) {1873return DoConnectProcess(connect_url, plugin_name, debugger, &stream, target,1874error);1875}18761877lldb::ProcessSP Platform::DoConnectProcess(llvm::StringRef connect_url,1878llvm::StringRef plugin_name,1879Debugger &debugger, Stream *stream,1880Target *target, Status &error) {1881error.Clear();18821883if (!target) {1884ArchSpec arch = Target::GetDefaultArchitecture();18851886const char *triple =1887arch.IsValid() ? arch.GetTriple().getTriple().c_str() : "";18881889TargetSP new_target_sp;1890error = debugger.GetTargetList().CreateTarget(1891debugger, "", triple, eLoadDependentsNo, nullptr, new_target_sp);18921893target = new_target_sp.get();1894if (!target || error.Fail()) {1895return nullptr;1896}1897}18981899lldb::ProcessSP process_sp =1900target->CreateProcess(debugger.GetListener(), plugin_name, nullptr, true);19011902if (!process_sp)1903return nullptr;19041905// If this private method is called with a stream we are synchronous.1906const bool synchronous = stream != nullptr;19071908ListenerSP listener_sp(1909Listener::MakeListener("lldb.Process.ConnectProcess.hijack"));1910if (synchronous)1911process_sp->HijackProcessEvents(listener_sp);19121913error = process_sp->ConnectRemote(connect_url);1914if (error.Fail()) {1915if (synchronous)1916process_sp->RestoreProcessEvents();1917return nullptr;1918}19191920if (synchronous) {1921EventSP event_sp;1922process_sp->WaitForProcessToStop(std::nullopt, &event_sp, true, listener_sp,1923nullptr);1924process_sp->RestoreProcessEvents();1925bool pop_process_io_handler = false;1926// This is a user-level stop, so we allow recognizers to select frames.1927Process::HandleProcessStateChangedEvent(1928event_sp, stream, SelectMostRelevantFrame, pop_process_io_handler);1929}19301931return process_sp;1932}19331934size_t Platform::ConnectToWaitingProcesses(lldb_private::Debugger &debugger,1935lldb_private::Status &error) {1936error.Clear();1937return 0;1938}19391940size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,1941BreakpointSite *bp_site) {1942ArchSpec arch = target.GetArchitecture();1943assert(arch.IsValid());1944const uint8_t *trap_opcode = nullptr;1945size_t trap_opcode_size = 0;19461947switch (arch.GetMachine()) {1948case llvm::Triple::aarch64_32:1949case llvm::Triple::aarch64: {1950static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4};1951trap_opcode = g_aarch64_opcode;1952trap_opcode_size = sizeof(g_aarch64_opcode);1953} break;19541955case llvm::Triple::arc: {1956static const uint8_t g_hex_opcode[] = { 0xff, 0x7f };1957trap_opcode = g_hex_opcode;1958trap_opcode_size = sizeof(g_hex_opcode);1959} break;19601961// TODO: support big-endian arm and thumb trap codes.1962case llvm::Triple::arm: {1963// The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the1964// linux kernel does otherwise.1965static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7};1966static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde};19671968lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetConstituentAtIndex(0));1969AddressClass addr_class = AddressClass::eUnknown;19701971if (bp_loc_sp) {1972addr_class = bp_loc_sp->GetAddress().GetAddressClass();1973if (addr_class == AddressClass::eUnknown &&1974(bp_loc_sp->GetAddress().GetFileAddress() & 1))1975addr_class = AddressClass::eCodeAlternateISA;1976}19771978if (addr_class == AddressClass::eCodeAlternateISA) {1979trap_opcode = g_thumb_breakpoint_opcode;1980trap_opcode_size = sizeof(g_thumb_breakpoint_opcode);1981} else {1982trap_opcode = g_arm_breakpoint_opcode;1983trap_opcode_size = sizeof(g_arm_breakpoint_opcode);1984}1985} break;19861987case llvm::Triple::avr: {1988static const uint8_t g_hex_opcode[] = {0x98, 0x95};1989trap_opcode = g_hex_opcode;1990trap_opcode_size = sizeof(g_hex_opcode);1991} break;19921993case llvm::Triple::mips:1994case llvm::Triple::mips64: {1995static const uint8_t g_hex_opcode[] = {0x00, 0x00, 0x00, 0x0d};1996trap_opcode = g_hex_opcode;1997trap_opcode_size = sizeof(g_hex_opcode);1998} break;19992000case llvm::Triple::mipsel:2001case llvm::Triple::mips64el: {2002static const uint8_t g_hex_opcode[] = {0x0d, 0x00, 0x00, 0x00};2003trap_opcode = g_hex_opcode;2004trap_opcode_size = sizeof(g_hex_opcode);2005} break;20062007case llvm::Triple::msp430: {2008static const uint8_t g_msp430_opcode[] = {0x43, 0x43};2009trap_opcode = g_msp430_opcode;2010trap_opcode_size = sizeof(g_msp430_opcode);2011} break;20122013case llvm::Triple::systemz: {2014static const uint8_t g_hex_opcode[] = {0x00, 0x01};2015trap_opcode = g_hex_opcode;2016trap_opcode_size = sizeof(g_hex_opcode);2017} break;20182019case llvm::Triple::hexagon: {2020static const uint8_t g_hex_opcode[] = {0x0c, 0xdb, 0x00, 0x54};2021trap_opcode = g_hex_opcode;2022trap_opcode_size = sizeof(g_hex_opcode);2023} break;20242025case llvm::Triple::ppc:2026case llvm::Triple::ppc64: {2027static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08};2028trap_opcode = g_ppc_opcode;2029trap_opcode_size = sizeof(g_ppc_opcode);2030} break;20312032case llvm::Triple::ppc64le: {2033static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap2034trap_opcode = g_ppc64le_opcode;2035trap_opcode_size = sizeof(g_ppc64le_opcode);2036} break;20372038case llvm::Triple::x86:2039case llvm::Triple::x86_64: {2040static const uint8_t g_i386_opcode[] = {0xCC};2041trap_opcode = g_i386_opcode;2042trap_opcode_size = sizeof(g_i386_opcode);2043} break;20442045case llvm::Triple::riscv32:2046case llvm::Triple::riscv64: {2047static const uint8_t g_riscv_opcode[] = {0x73, 0x00, 0x10, 0x00}; // ebreak2048static const uint8_t g_riscv_opcode_c[] = {0x02, 0x90}; // c.ebreak2049if (arch.GetFlags() & ArchSpec::eRISCV_rvc) {2050trap_opcode = g_riscv_opcode_c;2051trap_opcode_size = sizeof(g_riscv_opcode_c);2052} else {2053trap_opcode = g_riscv_opcode;2054trap_opcode_size = sizeof(g_riscv_opcode);2055}2056} break;20572058case llvm::Triple::loongarch32:2059case llvm::Triple::loongarch64: {2060static const uint8_t g_loongarch_opcode[] = {0x05, 0x00, 0x2a,20610x00}; // break 0x52062trap_opcode = g_loongarch_opcode;2063trap_opcode_size = sizeof(g_loongarch_opcode);2064} break;20652066default:2067return 0;2068}20692070assert(bp_site);2071if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))2072return trap_opcode_size;20732074return 0;2075}20762077CompilerType Platform::GetSiginfoType(const llvm::Triple& triple) {2078return CompilerType();2079}20802081Args Platform::GetExtraStartupCommands() {2082return {};2083}20842085void Platform::SetLocateModuleCallback(LocateModuleCallback callback) {2086m_locate_module_callback = callback;2087}20882089Platform::LocateModuleCallback Platform::GetLocateModuleCallback() const {2090return m_locate_module_callback;2091}20922093PlatformSP PlatformList::GetOrCreate(llvm::StringRef name) {2094std::lock_guard<std::recursive_mutex> guard(m_mutex);2095for (const PlatformSP &platform_sp : m_platforms) {2096if (platform_sp->GetName() == name)2097return platform_sp;2098}2099return Create(name);2100}21012102PlatformSP PlatformList::GetOrCreate(const ArchSpec &arch,2103const ArchSpec &process_host_arch,2104ArchSpec *platform_arch_ptr,2105Status &error) {2106std::lock_guard<std::recursive_mutex> guard(m_mutex);2107// First try exact arch matches across all platforms already created2108for (const auto &platform_sp : m_platforms) {2109if (platform_sp->IsCompatibleArchitecture(2110arch, process_host_arch, ArchSpec::ExactMatch, platform_arch_ptr))2111return platform_sp;2112}21132114// Next try compatible arch matches across all platforms already created2115for (const auto &platform_sp : m_platforms) {2116if (platform_sp->IsCompatibleArchitecture(arch, process_host_arch,2117ArchSpec::CompatibleMatch,2118platform_arch_ptr))2119return platform_sp;2120}21212122PlatformCreateInstance create_callback;2123// First try exact arch matches across all platform plug-ins2124uint32_t idx;2125for (idx = 0;2126(create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx));2127++idx) {2128PlatformSP platform_sp = create_callback(false, &arch);2129if (platform_sp &&2130platform_sp->IsCompatibleArchitecture(2131arch, process_host_arch, ArchSpec::ExactMatch, platform_arch_ptr)) {2132m_platforms.push_back(platform_sp);2133return platform_sp;2134}2135}2136// Next try compatible arch matches across all platform plug-ins2137for (idx = 0;2138(create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx));2139++idx) {2140PlatformSP platform_sp = create_callback(false, &arch);2141if (platform_sp && platform_sp->IsCompatibleArchitecture(2142arch, process_host_arch, ArchSpec::CompatibleMatch,2143platform_arch_ptr)) {2144m_platforms.push_back(platform_sp);2145return platform_sp;2146}2147}2148if (platform_arch_ptr)2149platform_arch_ptr->Clear();2150return nullptr;2151}21522153PlatformSP PlatformList::GetOrCreate(const ArchSpec &arch,2154const ArchSpec &process_host_arch,2155ArchSpec *platform_arch_ptr) {2156Status error;2157if (arch.IsValid())2158return GetOrCreate(arch, process_host_arch, platform_arch_ptr, error);2159return nullptr;2160}21612162PlatformSP PlatformList::GetOrCreate(llvm::ArrayRef<ArchSpec> archs,2163const ArchSpec &process_host_arch,2164std::vector<PlatformSP> &candidates) {2165candidates.clear();2166candidates.reserve(archs.size());21672168if (archs.empty())2169return nullptr;21702171PlatformSP host_platform_sp = Platform::GetHostPlatform();21722173// Prefer the selected platform if it matches at least one architecture.2174if (m_selected_platform_sp) {2175for (const ArchSpec &arch : archs) {2176if (m_selected_platform_sp->IsCompatibleArchitecture(2177arch, process_host_arch, ArchSpec::CompatibleMatch, nullptr))2178return m_selected_platform_sp;2179}2180}21812182// Prefer the host platform if it matches at least one architecture.2183if (host_platform_sp) {2184for (const ArchSpec &arch : archs) {2185if (host_platform_sp->IsCompatibleArchitecture(2186arch, process_host_arch, ArchSpec::CompatibleMatch, nullptr))2187return host_platform_sp;2188}2189}21902191// Collect a list of candidate platforms for the architectures.2192for (const ArchSpec &arch : archs) {2193if (PlatformSP platform = GetOrCreate(arch, process_host_arch, nullptr))2194candidates.push_back(platform);2195}21962197// The selected or host platform didn't match any of the architectures. If2198// the same platform supports all architectures then that's the obvious next2199// best thing.2200if (candidates.size() == archs.size()) {2201if (llvm::all_of(candidates, [&](const PlatformSP &p) -> bool {2202return p->GetName() == candidates.front()->GetName();2203})) {2204return candidates.front();2205}2206}22072208// At this point we either have no platforms that match the given2209// architectures or multiple platforms with no good way to disambiguate2210// between them.2211return nullptr;2212}22132214PlatformSP PlatformList::Create(llvm::StringRef name) {2215std::lock_guard<std::recursive_mutex> guard(m_mutex);2216PlatformSP platform_sp = Platform::Create(name);2217m_platforms.push_back(platform_sp);2218return platform_sp;2219}22202221bool PlatformList::LoadPlatformBinaryAndSetup(Process *process,2222lldb::addr_t addr, bool notify) {2223std::lock_guard<std::recursive_mutex> guard(m_mutex);22242225PlatformCreateInstance create_callback;2226for (int idx = 0;2227(create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx));2228++idx) {2229ArchSpec arch;2230PlatformSP platform_sp = create_callback(true, &arch);2231if (platform_sp) {2232if (platform_sp->LoadPlatformBinaryAndSetup(process, addr, notify))2233return true;2234}2235}2236return false;2237}223822392240