diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 3b02f44a7fe21..8b8ca6268071f 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -94,79 +94,11 @@ class Platform : public PluginInterface { /// attaching to processes unless another platform is specified. static lldb::PlatformSP GetHostPlatform(); - /// Get the platform for the given architecture. See Platform::Create for how - /// a platform is chosen for a given architecture. - /// - /// \param[in] arch - /// The architecture for which we are getting a platform. - /// - /// \param[in] process_host_arch - /// The process host architecture if it's known. An invalid ArchSpec - /// represents that the process host architecture is unknown. - /// - /// \param[out] platform_arch_ptr - /// The architecture which was used to pick the returned platform. This - /// can be different from the input architecture if we're looking for a - /// compatible match instead of an exact match. - /// - /// \return - /// Return the platform that matches the input architecture or the - /// default (invalid) platform if none could be found. - static lldb::PlatformSP - GetPlatformForArchitecture(const ArchSpec &arch, - const ArchSpec &process_host_arch = {}, - ArchSpec *platform_arch_ptr = nullptr); - - /// Get the platform for the given list of architectures. - /// - /// The algorithm works a follows: - /// - /// 1. Returns the selected platform if it matches any of the architectures. - /// 2. Returns the host platform if it matches any of the architectures. - /// 3. Returns the platform that matches all the architectures. - /// - /// If none of the above apply, this function returns a default platform. The - /// candidates output argument differentiates between either no platforms - /// supporting the given architecture or multiple platforms supporting the - /// given architecture. - /// - /// \param[in] arch - /// The architecture for which we are getting a platform. - /// - /// \param[in] process_host_arch - /// The process host architecture if it's known. An invalid ArchSpec - /// represents that the process host architecture is unknown. - /// - /// \param[in] selected_platform_sp - /// The currently selected platform. - /// - /// \param[out] candidates - /// A list of candidate platforms in case multiple platforms could - /// support the given list of architectures. If no platforms match the - /// given architecture the list will be empty. - /// - /// \return - /// Return the platform that matches the input architectures or the - /// default (invalid) platform if no platforms support the given - /// architectures or multiple platforms support the given architecture. - static lldb::PlatformSP - GetPlatformForArchitectures(std::vector archs, - const ArchSpec &process_host_arch, - lldb::PlatformSP selected_platform_sp, - std::vector &candidates); - static const char *GetHostPlatformName(); static void SetHostPlatform(const lldb::PlatformSP &platform_sp); - // Find an existing platform plug-in by name - static lldb::PlatformSP Find(ConstString name); - - static lldb::PlatformSP Create(ConstString name, Status &error); - - static lldb::PlatformSP Create(const ArchSpec &arch, - const ArchSpec &process_host_arch, - ArchSpec *platform_arch_ptr, Status &error); + static lldb::PlatformSP Create(llvm::StringRef name); /// Augments the triple either with information from platform or the host /// system (if platform is null). @@ -917,9 +849,6 @@ class Platform : public PluginInterface { virtual CompilerType GetSiginfoType(const llvm::Triple &triple); protected: - /// For unit testing purposes only. - static void Clear(); - /// Create a list of ArchSpecs with the given OS and a architectures. The /// vendor field is left as an "unspecified unknown". static std::vector @@ -1069,6 +998,32 @@ class PlatformList { } } + lldb::PlatformSP GetOrCreate(llvm::StringRef name); + lldb::PlatformSP GetOrCreate(const ArchSpec &arch, + const ArchSpec &process_host_arch, + ArchSpec *platform_arch_ptr, Status &error); + lldb::PlatformSP GetOrCreate(const ArchSpec &arch, + const ArchSpec &process_host_arch, + ArchSpec *platform_arch_ptr); + + /// Get the platform for the given list of architectures. + /// + /// The algorithm works a follows: + /// + /// 1. Returns the selected platform if it matches any of the architectures. + /// 2. Returns the host platform if it matches any of the architectures. + /// 3. Returns the platform that matches all the architectures. + /// + /// If none of the above apply, this function returns a default platform. The + /// candidates output argument differentiates between either no platforms + /// supporting the given architecture or multiple platforms supporting the + /// given architecture. + lldb::PlatformSP GetOrCreate(llvm::ArrayRef archs, + const ArchSpec &process_host_arch, + std::vector &candidates); + + lldb::PlatformSP Create(llvm::StringRef name); + protected: typedef std::vector collection; mutable std::recursive_mutex m_mutex; diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py index 489e6ce7bd7a1..a9ca741cf3a72 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -902,6 +902,7 @@ def run_suite(): (configuration.lldb_platform_name)) lldb.remote_platform = lldb.SBPlatform( configuration.lldb_platform_name) + lldb.selected_platform = lldb.remote_platform if not lldb.remote_platform.IsValid(): print( "error: unable to create the LLDB platform named '%s'." % @@ -918,7 +919,6 @@ def run_suite(): err = lldb.remote_platform.ConnectRemote(platform_connect_options) if err.Success(): print("Connected.") - lldb.selected_platform = lldb.remote_platform else: print("error: failed to connect to remote platform using URL '%s': %s" % ( configuration.lldb_platform_url, err)) diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index c82ff0f1e878d..ea340e3a44792 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -1460,21 +1460,11 @@ SBError SBDebugger::SetCurrentPlatform(const char *platform_name_cstr) { SBError sb_error; if (m_opaque_sp) { if (platform_name_cstr && platform_name_cstr[0]) { - ConstString platform_name(platform_name_cstr); - PlatformSP platform_sp(Platform::Find(platform_name)); - - if (platform_sp) { - // Already have a platform with this name, just select it - m_opaque_sp->GetPlatformList().SetSelectedPlatform(platform_sp); - } else { - // We don't have a platform by this name yet, create one - platform_sp = Platform::Create(platform_name, sb_error.ref()); - if (platform_sp) { - // We created the platform, now append and select it - bool make_selected = true; - m_opaque_sp->GetPlatformList().Append(platform_sp, make_selected); - } - } + PlatformList &platforms = m_opaque_sp->GetPlatformList(); + if (PlatformSP platform_sp = platforms.GetOrCreate(platform_name_cstr)) + platforms.SetSelectedPlatform(platform_sp); + else + sb_error.ref().SetErrorString("platform not found"); } else { sb_error.ref().SetErrorString("invalid platform name"); } diff --git a/lldb/source/API/SBPlatform.cpp b/lldb/source/API/SBPlatform.cpp index 15a6966798454..ac767f740a305 100644 --- a/lldb/source/API/SBPlatform.cpp +++ b/lldb/source/API/SBPlatform.cpp @@ -292,9 +292,7 @@ SBPlatform::SBPlatform() { LLDB_INSTRUMENT_VA(this); } SBPlatform::SBPlatform(const char *platform_name) { LLDB_INSTRUMENT_VA(this, platform_name); - Status error; - if (platform_name && platform_name[0]) - m_opaque_sp = Platform::Create(ConstString(platform_name), error); + m_opaque_sp = Platform::Create(platform_name); } SBPlatform::SBPlatform(const SBPlatform &rhs) { diff --git a/lldb/source/Interpreter/OptionGroupPlatform.cpp b/lldb/source/Interpreter/OptionGroupPlatform.cpp index 9550edc2613e6..acdf3f293496f 100644 --- a/lldb/source/Interpreter/OptionGroupPlatform.cpp +++ b/lldb/source/Interpreter/OptionGroupPlatform.cpp @@ -18,10 +18,17 @@ using namespace lldb_private; PlatformSP OptionGroupPlatform::CreatePlatformWithOptions( CommandInterpreter &interpreter, const ArchSpec &arch, bool make_selected, Status &error, ArchSpec &platform_arch) const { + PlatformList &platforms = interpreter.GetDebugger().GetPlatformList(); + PlatformSP platform_sp; if (!m_platform_name.empty()) { - platform_sp = Platform::Create(ConstString(m_platform_name.c_str()), error); + platform_sp = platforms.Create(m_platform_name); + if (!platform_sp) { + error.SetErrorStringWithFormatv( + "unable to find a plug-in for the platform named \"{0}\"", + m_platform_name); + } if (platform_sp) { if (platform_arch.IsValid() && !platform_sp->IsCompatibleArchitecture( arch, {}, false, &platform_arch)) { @@ -33,12 +40,12 @@ PlatformSP OptionGroupPlatform::CreatePlatformWithOptions( } } } else if (arch.IsValid()) { - platform_sp = Platform::Create(arch, {}, &platform_arch, error); + platform_sp = platforms.GetOrCreate(arch, {}, &platform_arch, error); } if (platform_sp) { - interpreter.GetDebugger().GetPlatformList().Append(platform_sp, - make_selected); + if (make_selected) + platforms.SetSelectedPlatform(platform_sp); if (!m_os_version.empty()) platform_sp->SetOSVersion(m_os_version); diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 036450bf17d3b..1b699f293b37f 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -511,8 +511,9 @@ DynamicLoaderDarwinKernel::DynamicLoaderDarwinKernel(Process *process, m_kext_summary_header(), m_known_kexts(), m_mutex(), m_break_id(LLDB_INVALID_BREAK_ID) { Status error; - PlatformSP platform_sp(Platform::Create( - ConstString(PlatformDarwinKernel::GetPluginNameStatic()), error)); + PlatformSP platform_sp = + process->GetTarget().GetDebugger().GetPlatformList().Create( + PlatformDarwinKernel::GetPluginNameStatic()); if (platform_sp.get()) process->GetTarget().SetPlatform(platform_sp); } diff --git a/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt b/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt index 6f52deabc855d..78eb7bc60e0ea 100644 --- a/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt @@ -7,5 +7,6 @@ add_lldb_library(lldbPluginPlatformPOSIX lldbHost lldbInterpreter lldbTarget + lldbPluginPlatformGDB lldbPluginTypeSystemClang ) diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index a274065fded23..9a2f0972f9993 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -8,6 +8,7 @@ #include "PlatformPOSIX.h" +#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -307,7 +308,8 @@ Status PlatformPOSIX::ConnectRemote(Args &args) { } else { if (!m_remote_platform_sp) m_remote_platform_sp = - Platform::Create(ConstString("remote-gdb-server"), error); + platform_gdb_server::PlatformRemoteGDBServer::CreateInstance( + /*force=*/true, nullptr); if (m_remote_platform_sp && error.Success()) error = m_remote_platform_sp->ConnectRemote(args); diff --git a/lldb/source/Plugins/Platform/Windows/CMakeLists.txt b/lldb/source/Plugins/Platform/Windows/CMakeLists.txt index 28c174dc4d95e..2820ae77e7491 100644 --- a/lldb/source/Plugins/Platform/Windows/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/Windows/CMakeLists.txt @@ -6,6 +6,7 @@ add_lldb_library(lldbPluginPlatformWindows PLUGIN lldbCore lldbHost lldbTarget + lldbPluginPlatformGDB LINK_COMPONENTS Support diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp index 708268ff900bc..b0501af7df30b 100644 --- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp +++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp @@ -14,6 +14,8 @@ #include #endif +#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/BreakpointSite.h" #include "lldb/Core/Debugger.h" @@ -28,8 +30,6 @@ #include "lldb/Target/Process.h" #include "lldb/Utility/Status.h" -#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" - #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/ConvertUTF.h" @@ -140,7 +140,8 @@ Status PlatformWindows::ConnectRemote(Args &args) { } else { if (!m_remote_platform_sp) m_remote_platform_sp = - Platform::Create(ConstString("remote-gdb-server"), error); + platform_gdb_server::PlatformRemoteGDBServer::CreateInstance( + /*force=*/true, nullptr); if (m_remote_platform_sp) { if (error.Success()) { diff --git a/lldb/source/Plugins/Platform/gdb-server/CMakeLists.txt b/lldb/source/Plugins/Platform/gdb-server/CMakeLists.txt index 2e3302590b443..2fbe817acbdd2 100644 --- a/lldb/source/Plugins/Platform/gdb-server/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/gdb-server/CMakeLists.txt @@ -7,4 +7,5 @@ add_lldb_library(lldbPluginPlatformGDB PLUGIN lldbHost lldbTarget lldbPluginProcessUtility + lldbPluginProcessGDBRemote ) diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 2dff0dbfae9ee..1976aa636a046 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -51,8 +51,6 @@ using namespace lldb; using namespace lldb_private; -static uint32_t g_initialize_count = 0; - // Use a singleton function for g_local_platform_sp to avoid init constructors // since LLDB is often part of a shared library static PlatformSP &GetHostPlatformSP() { @@ -137,28 +135,9 @@ void PlatformProperties::SetDefaultModuleCacheDirectory( /// or attaching to processes unless another platform is specified. PlatformSP Platform::GetHostPlatform() { return GetHostPlatformSP(); } -static std::vector &GetPlatformList() { - static std::vector g_platform_list; - return g_platform_list; -} - -static std::recursive_mutex &GetPlatformListMutex() { - static std::recursive_mutex g_mutex; - return g_mutex; -} +void Platform::Initialize() {} -void Platform::Initialize() { g_initialize_count++; } - -void Platform::Terminate() { - if (g_initialize_count > 0) { - if (--g_initialize_count == 0) { - std::lock_guard guard(GetPlatformListMutex()); - GetPlatformList().clear(); - } - } -} - -void Platform::Clear() { GetPlatformList().clear(); } +void Platform::Terminate() {} PlatformProperties &Platform::GetGlobalPlatformProperties() { static PlatformProperties g_settings; @@ -169,11 +148,6 @@ void Platform::SetHostPlatform(const lldb::PlatformSP &platform_sp) { // The native platform should use its static void Platform::Initialize() // function to register itself as the native platform. GetHostPlatformSP() = platform_sp; - - if (platform_sp) { - std::lock_guard guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - } } Status Platform::GetFileWithUUID(const FileSpec &platform_file, @@ -276,109 +250,15 @@ bool Platform::GetModuleSpec(const FileSpec &module_file_spec, module_spec); } -PlatformSP Platform::Find(ConstString name) { - if (name) { - static ConstString g_host_platform_name("host"); - if (name == g_host_platform_name) - return GetHostPlatform(); - - std::lock_guard guard(GetPlatformListMutex()); - for (const auto &platform_sp : GetPlatformList()) { - if (platform_sp->GetName() == name.GetStringRef()) - return platform_sp; - } - } - return PlatformSP(); -} - -PlatformSP Platform::Create(ConstString name, Status &error) { - PlatformCreateInstance create_callback = nullptr; +PlatformSP Platform::Create(llvm::StringRef name) { lldb::PlatformSP platform_sp; - if (name) { - static ConstString g_host_platform_name("host"); - if (name == g_host_platform_name) - return GetHostPlatform(); - - create_callback = PluginManager::GetPlatformCreateCallbackForPluginName( - name.GetStringRef()); - if (create_callback) - platform_sp = create_callback(true, nullptr); - else - error.SetErrorStringWithFormat( - "unable to find a plug-in for the platform named \"%s\"", - name.GetCString()); - } else - error.SetErrorString("invalid platform name"); - - if (platform_sp) { - std::lock_guard guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - } + if (name == GetHostPlatformName()) + return GetHostPlatform(); - return platform_sp; -} - -PlatformSP Platform::Create(const ArchSpec &arch, - const ArchSpec &process_host_arch, - ArchSpec *platform_arch_ptr, Status &error) { - lldb::PlatformSP platform_sp; - if (arch.IsValid()) { - // Scope for locker - { - // First try exact arch matches across all platforms already created - std::lock_guard guard(GetPlatformListMutex()); - for (const auto &platform_sp : GetPlatformList()) { - if (platform_sp->IsCompatibleArchitecture(arch, process_host_arch, true, - platform_arch_ptr)) - return platform_sp; - } - - // Next try compatible arch matches across all platforms already created - for (const auto &platform_sp : GetPlatformList()) { - if (platform_sp->IsCompatibleArchitecture(arch, process_host_arch, - false, platform_arch_ptr)) - return platform_sp; - } - } - - PlatformCreateInstance create_callback; - // First try exact arch matches across all platform plug-ins - uint32_t idx; - for (idx = 0; (create_callback = - PluginManager::GetPlatformCreateCallbackAtIndex(idx)); - ++idx) { - if (create_callback) { - platform_sp = create_callback(false, &arch); - if (platform_sp && - platform_sp->IsCompatibleArchitecture(arch, process_host_arch, true, - platform_arch_ptr)) { - std::lock_guard guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - return platform_sp; - } - } - } - // Next try compatible arch matches across all platform plug-ins - for (idx = 0; (create_callback = - PluginManager::GetPlatformCreateCallbackAtIndex(idx)); - ++idx) { - if (create_callback) { - platform_sp = create_callback(false, &arch); - if (platform_sp && - platform_sp->IsCompatibleArchitecture(arch, process_host_arch, - false, platform_arch_ptr)) { - std::lock_guard guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - return platform_sp; - } - } - } - } else - error.SetErrorString("invalid platform name"); - if (platform_arch_ptr) - platform_arch_ptr->Clear(); - platform_sp.reset(); - return platform_sp; + if (PlatformCreateInstance create_callback = + PluginManager::GetPlatformCreateCallbackForPluginName(name)) + return create_callback(true, nullptr); + return nullptr; } ArchSpec Platform::GetAugmentedArchSpec(Platform *platform, llvm::StringRef triple) { @@ -1258,73 +1138,6 @@ lldb::ProcessSP Platform::DebugProcess(ProcessLaunchInfo &launch_info, return process_sp; } -lldb::PlatformSP -Platform::GetPlatformForArchitecture(const ArchSpec &arch, - const ArchSpec &process_host_arch, - ArchSpec *platform_arch_ptr) { - lldb::PlatformSP platform_sp; - Status error; - if (arch.IsValid()) - platform_sp = - Platform::Create(arch, process_host_arch, platform_arch_ptr, error); - return platform_sp; -} - -lldb::PlatformSP Platform::GetPlatformForArchitectures( - std::vector archs, const ArchSpec &process_host_arch, - lldb::PlatformSP selected_platform_sp, - std::vector &candidates) { - candidates.clear(); - candidates.reserve(archs.size()); - - if (archs.empty()) - return nullptr; - - PlatformSP host_platform_sp = Platform::GetHostPlatform(); - - // Prefer the selected platform if it matches at least one architecture. - if (selected_platform_sp) { - for (const ArchSpec &arch : archs) { - if (selected_platform_sp->IsCompatibleArchitecture( - arch, process_host_arch, false, nullptr)) - return selected_platform_sp; - } - } - - // Prefer the host platform if it matches at least one architecture. - if (host_platform_sp) { - for (const ArchSpec &arch : archs) { - if (host_platform_sp->IsCompatibleArchitecture(arch, process_host_arch, - false, nullptr)) - return host_platform_sp; - } - } - - // Collect a list of candidate platforms for the architectures. - for (const ArchSpec &arch : archs) { - if (PlatformSP platform = - Platform::GetPlatformForArchitecture(arch, process_host_arch)) - candidates.push_back(platform); - } - - // The selected or host platform didn't match any of the architectures. If - // the same platform supports all architectures then that's the obvious next - // best thing. - if (candidates.size() == archs.size()) { - if (std::all_of(candidates.begin(), candidates.end(), - [&](const PlatformSP &p) -> bool { - return p->GetName() == candidates.front()->GetName(); - })) { - return candidates.front(); - } - } - - // At this point we either have no platforms that match the given - // architectures or multiple platforms with no good way to disambiguate - // between them. - return nullptr; -} - std::vector Platform::CreateArchList(llvm::ArrayRef archs, llvm::Triple::OSType os) { @@ -2131,3 +1944,129 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, CompilerType Platform::GetSiginfoType(const llvm::Triple& triple) { return CompilerType(); } + +PlatformSP PlatformList::GetOrCreate(llvm::StringRef name) { + std::lock_guard guard(m_mutex); + for (const PlatformSP &platform_sp : m_platforms) { + if (platform_sp->GetName() == name) + return platform_sp; + } + return Create(name); +} + +PlatformSP PlatformList::GetOrCreate(const ArchSpec &arch, + const ArchSpec &process_host_arch, + ArchSpec *platform_arch_ptr, + Status &error) { + std::lock_guard guard(m_mutex); + // First try exact arch matches across all platforms already created + for (const auto &platform_sp : m_platforms) { + if (platform_sp->IsCompatibleArchitecture(arch, process_host_arch, true, + platform_arch_ptr)) + return platform_sp; + } + + // Next try compatible arch matches across all platforms already created + for (const auto &platform_sp : m_platforms) { + if (platform_sp->IsCompatibleArchitecture(arch, process_host_arch, false, + platform_arch_ptr)) + return platform_sp; + } + + PlatformCreateInstance create_callback; + // First try exact arch matches across all platform plug-ins + uint32_t idx; + for (idx = 0; + (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)); + ++idx) { + PlatformSP platform_sp = create_callback(false, &arch); + if (platform_sp && platform_sp->IsCompatibleArchitecture( + arch, process_host_arch, true, platform_arch_ptr)) { + m_platforms.push_back(platform_sp); + return platform_sp; + } + } + // Next try compatible arch matches across all platform plug-ins + for (idx = 0; + (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)); + ++idx) { + PlatformSP platform_sp = create_callback(false, &arch); + if (platform_sp && platform_sp->IsCompatibleArchitecture( + arch, process_host_arch, false, platform_arch_ptr)) { + m_platforms.push_back(platform_sp); + return platform_sp; + } + } + if (platform_arch_ptr) + platform_arch_ptr->Clear(); + return nullptr; +} + +PlatformSP PlatformList::GetOrCreate(const ArchSpec &arch, + const ArchSpec &process_host_arch, + ArchSpec *platform_arch_ptr) { + Status error; + if (arch.IsValid()) + return GetOrCreate(arch, process_host_arch, platform_arch_ptr, error); + return nullptr; +} + +PlatformSP PlatformList::GetOrCreate(llvm::ArrayRef archs, + const ArchSpec &process_host_arch, + std::vector &candidates) { + candidates.clear(); + candidates.reserve(archs.size()); + + if (archs.empty()) + return nullptr; + + PlatformSP host_platform_sp = Platform::GetHostPlatform(); + + // Prefer the selected platform if it matches at least one architecture. + if (m_selected_platform_sp) { + for (const ArchSpec &arch : archs) { + if (m_selected_platform_sp->IsCompatibleArchitecture( + arch, process_host_arch, false, nullptr)) + return m_selected_platform_sp; + } + } + + // Prefer the host platform if it matches at least one architecture. + if (host_platform_sp) { + for (const ArchSpec &arch : archs) { + if (host_platform_sp->IsCompatibleArchitecture(arch, process_host_arch, + false, nullptr)) + return host_platform_sp; + } + } + + // Collect a list of candidate platforms for the architectures. + for (const ArchSpec &arch : archs) { + if (PlatformSP platform = GetOrCreate(arch, process_host_arch, nullptr)) + candidates.push_back(platform); + } + + // The selected or host platform didn't match any of the architectures. If + // the same platform supports all architectures then that's the obvious next + // best thing. + if (candidates.size() == archs.size()) { + if (std::all_of(candidates.begin(), candidates.end(), + [&](const PlatformSP &p) -> bool { + return p->GetName() == candidates.front()->GetName(); + })) { + return candidates.front(); + } + } + + // At this point we either have no platforms that match the given + // architectures or multiple platforms with no good way to disambiguate + // between them. + return nullptr; +} + +PlatformSP PlatformList::Create(llvm::StringRef name) { + std::lock_guard guard(m_mutex); + PlatformSP platform_sp = Platform::Create(name); + m_platforms.push_back(platform_sp); + return platform_sp; +} diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 54a19833c8a65..0d19c2b11f42c 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2892,7 +2892,7 @@ void Process::CompleteAttach() { !platform_sp->IsCompatibleArchitecture(target_arch, process_host_arch, false, nullptr)) { ArchSpec platform_arch; - platform_sp = platform_sp->GetPlatformForArchitecture( + platform_sp = GetTarget().GetDebugger().GetPlatformList().GetOrCreate( target_arch, process_host_arch, &platform_arch); if (platform_sp) { GetTarget().SetPlatform(platform_sp); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 71991085145ab..8f0a8be50ff6d 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1485,9 +1485,9 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) { if (!platform_sp || !platform_sp->IsCompatibleArchitecture(other, {}, false, nullptr)) { ArchSpec platform_arch; - auto arch_platform_sp = - Platform::GetPlatformForArchitecture(other, {}, &platform_arch); - if (arch_platform_sp) { + if (PlatformSP arch_platform_sp = + GetDebugger().GetPlatformList().GetOrCreate(other, {}, + &platform_arch)) { SetPlatform(arch_platform_sp); if (platform_arch.IsValid()) other = platform_arch; diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp index 8d980d000253a..72b50811b8745 100644 --- a/lldb/source/Target/TargetList.cpp +++ b/lldb/source/Target/TargetList.cpp @@ -79,8 +79,9 @@ Status TargetList::CreateTargetInternal( const OptionGroupPlatform *platform_options, TargetSP &target_sp) { Status error; + PlatformList &platform_list = debugger.GetPlatformList(); // Let's start by looking at the selected platform. - PlatformSP platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); + PlatformSP platform_sp = platform_list.GetSelectedPlatform(); // This variable corresponds to the architecture specified by the triple // string. If that string was empty the currently selected platform will @@ -176,8 +177,7 @@ Status TargetList::CreateTargetInternal( for (const ModuleSpec &spec : module_specs.ModuleSpecs()) archs.push_back(spec.GetArchitecture()); if (PlatformSP platform_for_archs_sp = - Platform::GetPlatformForArchitectures(archs, {}, platform_sp, - candidates)) { + platform_list.GetOrCreate(archs, {}, candidates)) { platform_sp = platform_for_archs_sp; } else if (candidates.empty()) { error.SetErrorString("no matching platforms found for this file"); @@ -209,21 +209,19 @@ Status TargetList::CreateTargetInternal( // compatible with that architecture. if (!prefer_platform_arch && arch.IsValid()) { if (!platform_sp->IsCompatibleArchitecture(arch, {}, false, nullptr)) { - platform_sp = - Platform::GetPlatformForArchitecture(arch, {}, &platform_arch); + platform_sp = platform_list.GetOrCreate(arch, {}, &platform_arch); if (platform_sp) - debugger.GetPlatformList().SetSelectedPlatform(platform_sp); + platform_list.SetSelectedPlatform(platform_sp); } } else if (platform_arch.IsValid()) { // If "arch" isn't valid, yet "platform_arch" is, it means we have an // executable file with a single architecture which should be used. ArchSpec fixed_platform_arch; - if (!platform_sp->IsCompatibleArchitecture(platform_arch, {}, false, - nullptr)) { - platform_sp = Platform::GetPlatformForArchitecture(platform_arch, {}, - &fixed_platform_arch); + if (!platform_sp->IsCompatibleArchitecture(platform_arch, {}, false, nullptr)) { + platform_sp = + platform_list.GetOrCreate(platform_arch, {}, &fixed_platform_arch); if (platform_sp) - debugger.GetPlatformList().SetSelectedPlatform(platform_sp); + platform_list.SetSelectedPlatform(platform_sp); } } @@ -253,7 +251,7 @@ Status TargetList::CreateTargetInternal(Debugger &debugger, if (!platform_sp || !platform_sp->IsCompatibleArchitecture(arch, {}, false, nullptr)) platform_sp = - Platform::GetPlatformForArchitecture(specified_arch, {}, &arch); + debugger.GetPlatformList().GetOrCreate(specified_arch, {}, &arch); } if (!platform_sp) diff --git a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py index 0a19945af1097..f0ba1d1e20aae 100644 --- a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py +++ b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py @@ -92,3 +92,55 @@ def get_cache_line_size(): # Test the local property again, is it set to new_cache_line_size? self.assertEqual(get_cache_line_size(), new_cache_line_size) + + def test_CreateTarget_platform(self): + exe = self.getBuildArtifact("a.out") + self.yaml2obj("elf.yaml", exe) + error = lldb.SBError() + target1 = self.dbg.CreateTarget(exe, None, "remote-linux", + False, error) + self.assertSuccess(error) + platform1 = target1.GetPlatform() + platform1.SetWorkingDirectory("/foo/bar") + + # Reuse a platform if it matches the currently selected one... + target2 = self.dbg.CreateTarget(exe, None, "remote-linux", + False, error) + self.assertSuccess(error) + platform2 = target2.GetPlatform() + self.assertEqual(platform2.GetWorkingDirectory(), "/foo/bar") + + # ... but create a new one if it doesn't. + self.dbg.SetSelectedPlatform(lldb.SBPlatform("remote-windows")) + target3 = self.dbg.CreateTarget(exe, None, "remote-linux", + False, error) + self.assertSuccess(error) + platform3 = target3.GetPlatform() + self.assertIsNone(platform3.GetWorkingDirectory()) + + def test_CreateTarget_arch(self): + exe = self.getBuildArtifact("a.out") + if lldbplatformutil.getHostPlatform() == 'linux': + self.yaml2obj("macho.yaml", exe) + arch = "x86_64-apple-macosx" + else: + self.yaml2obj("elf.yaml", exe) + arch = "x86_64-pc-linux" + + fbsd = lldb.SBPlatform("remote-freebsd") + self.dbg.SetSelectedPlatform(fbsd) + + error = lldb.SBError() + target1 = self.dbg.CreateTarget(exe, arch, None, False, error) + self.assertSuccess(error) + platform1 = target1.GetPlatform() + self.assertEqual(platform1.GetName(), "remote-macosx") + platform1.SetWorkingDirectory("/foo/bar") + + # Reuse a platform even if it is not currently selected. + self.dbg.SetSelectedPlatform(fbsd) + target2 = self.dbg.CreateTarget(exe, arch, None, False, error) + self.assertSuccess(error) + platform2 = target2.GetPlatform() + self.assertEqual(platform2.GetName(), "remote-macosx") + self.assertEqual(platform2.GetWorkingDirectory(), "/foo/bar") diff --git a/lldb/test/API/python_api/debugger/elf.yaml b/lldb/test/API/python_api/debugger/elf.yaml new file mode 100644 index 0000000000000..d62ebaac847c6 --- /dev/null +++ b/lldb/test/API/python_api/debugger/elf.yaml @@ -0,0 +1,35 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x4 + Content: "c3c3c3c3" + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x2000 + AddressAlign: 0x4 + Content: "3232" +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + VAddr: 0x1000 + PAddr: 0x1000 + Align: 0x4 + FirstSec: .text + LastSec: .text + - Type: PT_LOAD + Flags: [ PF_R, PF_W ] + VAddr: 0x2000 + PAddr: 0x1004 + Align: 0x4 + FirstSec: .data + LastSec: .data + diff --git a/lldb/test/API/python_api/debugger/macho.yaml b/lldb/test/API/python_api/debugger/macho.yaml new file mode 100644 index 0000000000000..5fdef2901385a --- /dev/null +++ b/lldb/test/API/python_api/debugger/macho.yaml @@ -0,0 +1,42 @@ +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 1160 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 1032 + segname: '' + vmaddr: 0 + vmsize: 744 + fileoff: 1192 + filesize: 744 + maxprot: 7 + initprot: 7 + nsects: 12 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 22 + offset: 0x000004A8 + align: 4 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_BUILD_VERSION + cmdsize: 24 + platform: 1 + minos: 658944 + sdk: 658944 + ntools: 0 +... diff --git a/lldb/test/API/python_api/sbplatform/TestSBPlatform.py b/lldb/test/API/python_api/sbplatform/TestSBPlatform.py index 002d9a68490f6..dbb3f4ca5db1c 100644 --- a/lldb/test/API/python_api/sbplatform/TestSBPlatform.py +++ b/lldb/test/API/python_api/sbplatform/TestSBPlatform.py @@ -25,6 +25,29 @@ def test_SetSDKRoot(self): plat = lldb.SBPlatform("remote-linux") # arbitrary choice self.assertTrue(plat) plat.SetSDKRoot(self.getBuildDir()) - self.dbg.SetCurrentPlatform("remote-linux") + self.dbg.SetSelectedPlatform(plat) self.expect("platform status", substrs=["Sysroot:", self.getBuildDir()]) + + def test_SetCurrentPlatform_floating(self): + # floating platforms cannot be referenced by name until they are + # associated with a debugger + floating_platform = lldb.SBPlatform("remote-netbsd") + floating_platform.SetWorkingDirectory(self.getBuildDir()) + self.assertSuccess(self.dbg.SetCurrentPlatform("remote-netbsd")) + dbg_platform = self.dbg.GetSelectedPlatform() + self.assertEqual(dbg_platform.GetName(), "remote-netbsd") + self.assertIsNone(dbg_platform.GetWorkingDirectory()) + + def test_SetCurrentPlatform_associated(self): + # associated platforms are found by name-based lookup + floating_platform = lldb.SBPlatform("remote-netbsd") + floating_platform.SetWorkingDirectory(self.getBuildDir()) + orig_platform = self.dbg.GetSelectedPlatform() + + self.dbg.SetSelectedPlatform(floating_platform) + self.dbg.SetSelectedPlatform(orig_platform) + self.assertSuccess(self.dbg.SetCurrentPlatform("remote-netbsd")) + dbg_platform = self.dbg.GetSelectedPlatform() + self.assertEqual(dbg_platform.GetName(), "remote-netbsd") + self.assertEqual(dbg_platform.GetWorkingDirectory(), self.getBuildDir()) diff --git a/lldb/unittests/Platform/PlatformTest.cpp b/lldb/unittests/Platform/PlatformTest.cpp index e5e94e04ee072..8ab223ea2cd57 100644 --- a/lldb/unittests/Platform/PlatformTest.cpp +++ b/lldb/unittests/Platform/PlatformTest.cpp @@ -21,7 +21,6 @@ using namespace lldb_private; class TestPlatform : public PlatformPOSIX { public: TestPlatform() : PlatformPOSIX(false) {} - using Platform::Clear; }; class PlatformArm : public TestPlatform { @@ -75,67 +74,66 @@ class PlatformThumb : public TestPlatform { class PlatformTest : public ::testing::Test { SubsystemRAII subsystems; - void SetUp() override { TestPlatform::Clear(); } + +protected: + PlatformList list; + + void SetHostPlatform(const PlatformSP &platform_sp) { + Platform::SetHostPlatform(platform_sp); + ASSERT_EQ(Platform::GetHostPlatform(), platform_sp); + list.Append(platform_sp, /*set_selected=*/true); + } }; TEST_F(PlatformTest, GetPlatformForArchitecturesHost) { - const PlatformSP host_platform_sp = std::make_shared(); - Platform::SetHostPlatform(host_platform_sp); - ASSERT_EQ(Platform::GetHostPlatform(), host_platform_sp); + SetHostPlatform(std::make_shared()); const std::vector archs = {ArchSpec("arm64-apple-ps4"), ArchSpec("arm64e-apple-ps4")}; std::vector candidates; // The host platform matches all architectures. - PlatformSP platform_sp = - Platform::GetPlatformForArchitectures(archs, {}, {}, candidates); + PlatformSP platform_sp = list.GetOrCreate(archs, {}, candidates); ASSERT_TRUE(platform_sp); - EXPECT_EQ(platform_sp, host_platform_sp); + EXPECT_EQ(platform_sp, Platform::GetHostPlatform()); } TEST_F(PlatformTest, GetPlatformForArchitecturesSelected) { - const PlatformSP host_platform_sp = std::make_shared(); - Platform::SetHostPlatform(host_platform_sp); - ASSERT_EQ(Platform::GetHostPlatform(), host_platform_sp); + SetHostPlatform(std::make_shared()); const std::vector archs = {ArchSpec("arm64-apple-ps4"), ArchSpec("arm64e-apple-ps4")}; std::vector candidates; - // The host platform matches no architectures. No selected platform. - PlatformSP platform_sp = - Platform::GetPlatformForArchitectures(archs, {}, {}, candidates); + // The host platform matches no architectures. + PlatformSP platform_sp = list.GetOrCreate(archs, {}, candidates); ASSERT_FALSE(platform_sp); // The selected platform matches all architectures. const PlatformSP selected_platform_sp = std::make_shared(); - platform_sp = Platform::GetPlatformForArchitectures( - archs, {}, selected_platform_sp, candidates); + list.Append(selected_platform_sp, /*set_selected=*/true); + platform_sp = list.GetOrCreate(archs, {}, candidates); ASSERT_TRUE(platform_sp); EXPECT_EQ(platform_sp, selected_platform_sp); } TEST_F(PlatformTest, GetPlatformForArchitecturesSelectedOverHost) { - const PlatformSP host_platform_sp = std::make_shared(); - Platform::SetHostPlatform(host_platform_sp); - ASSERT_EQ(Platform::GetHostPlatform(), host_platform_sp); + SetHostPlatform(std::make_shared()); const std::vector archs = {ArchSpec("arm64-apple-ps4"), ArchSpec("x86_64-apple-ps4")}; std::vector candidates; - // The host platform matches one architecture. No selected platform. - PlatformSP platform_sp = - Platform::GetPlatformForArchitectures(archs, {}, {}, candidates); + // The host platform matches one architecture. + PlatformSP platform_sp = list.GetOrCreate(archs, {}, candidates); ASSERT_TRUE(platform_sp); - EXPECT_EQ(platform_sp, host_platform_sp); + EXPECT_EQ(platform_sp, Platform::GetHostPlatform()); // The selected and host platform each match one architecture. // The selected platform is preferred. const PlatformSP selected_platform_sp = std::make_shared(); - platform_sp = Platform::GetPlatformForArchitectures( - archs, {}, selected_platform_sp, candidates); + list.Append(selected_platform_sp, /*set_selected=*/true); + platform_sp = list.GetOrCreate(archs, {}, candidates); ASSERT_TRUE(platform_sp); EXPECT_EQ(platform_sp, selected_platform_sp); } @@ -143,18 +141,17 @@ TEST_F(PlatformTest, GetPlatformForArchitecturesSelectedOverHost) { TEST_F(PlatformTest, GetPlatformForArchitecturesCandidates) { PlatformThumb::Initialize(); - const PlatformSP host_platform_sp = std::make_shared(); - Platform::SetHostPlatform(host_platform_sp); - ASSERT_EQ(Platform::GetHostPlatform(), host_platform_sp); + SetHostPlatform(std::make_shared()); + const PlatformSP selected_platform_sp = std::make_shared(); + list.Append(selected_platform_sp, /*set_selected=*/true); const std::vector archs = {ArchSpec("thumbv7-apple-ps4"), ArchSpec("thumbv7f-apple-ps4")}; std::vector candidates; - // The host platform matches one architecture. No selected platform. - PlatformSP platform_sp = Platform::GetPlatformForArchitectures( - archs, {}, selected_platform_sp, candidates); + // The host platform matches one architecture. + PlatformSP platform_sp = list.GetOrCreate(archs, {}, candidates); ASSERT_TRUE(platform_sp); EXPECT_EQ(platform_sp->GetName(), "thumb");