Index: lldb/source/Plugins/Platform/CMakeLists.txt =================================================================== --- lldb/source/Plugins/Platform/CMakeLists.txt +++ lldb/source/Plugins/Platform/CMakeLists.txt @@ -6,5 +6,6 @@ add_subdirectory(NetBSD) add_subdirectory(OpenBSD) add_subdirectory(POSIX) +add_subdirectory(Scripted) add_subdirectory(QemuUser) add_subdirectory(Windows) Index: lldb/source/Plugins/Platform/scripted/CMakeLists.txt =================================================================== --- /dev/null +++ lldb/source/Plugins/Platform/scripted/CMakeLists.txt @@ -0,0 +1,8 @@ +add_lldb_library(lldbPluginScriptedPlatform PLUGIN + ScriptedPlatform.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbUtility + ) Index: lldb/source/Plugins/Platform/scripted/ScriptedPlatform.h =================================================================== --- /dev/null +++ lldb/source/Plugins/Platform/scripted/ScriptedPlatform.h @@ -0,0 +1,86 @@ +//===-- ScriptedPlatform.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_PLATFORM_H +#define LLDB_SOURCE_PLUGINS_SCRIPTED_PLATFORM_H + +#include "lldb/Interpreter/ScriptedMetadata.h" +#include "lldb/Target/Platform.h" + +namespace lldb_private { + +class ScriptedPlatform : public Platform { +public: + ScriptedPlatform(Debugger *debugger, + const ScriptedMetadata *scripted_metadata, Status &error); + + ~ScriptedPlatform() override; + + static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch, + const Debugger *debugger, + const ScriptedMetadata *metadata); + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { return "scripted-platform"; } + + static llvm::StringRef GetDescriptionStatic() { + return "Scripted Platform plug-in."; + } + + llvm::StringRef GetDescription() override { return GetDescriptionStatic(); } + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + std::vector + GetSupportedArchitectures(const ArchSpec &process_host_arch) override; + + bool IsConnected() const override { return true; } + + lldb::ProcessSP Attach(lldb_private::ProcessAttachInfo &attach_info, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Status &error) override; + + uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos) override; + + bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info) override; + + Status LaunchProcess(ProcessLaunchInfo &launch_info) override; + + Status KillProcess(const lldb::pid_t pid) override; + + void CalculateTrapHandlerSymbolNames() override {} + +private: + inline void CheckInterpreterAndScriptObject() const { + assert(m_interpreter && "Invalid Script Interpreter."); + assert(m_script_object_sp && "Invalid Script Object."); + } + + ScriptedPlatform(const ScriptedPlatform &) = delete; + const ScriptedPlatform &operator=(const ScriptedPlatform &) = delete; + + ScriptedPlatformInterface &GetInterface() const; + + llvm::Expected + ParseProcessInfo(StructuredData::Dictionary &dict, lldb::pid_t pid) const; + + static bool IsScriptLanguageSupported(lldb::ScriptLanguage language); + + const ScriptedMetadata *m_scripted_metadata = nullptr; + lldb_private::ScriptInterpreter *m_interpreter = nullptr; + lldb_private::StructuredData::ObjectSP m_script_object_sp = nullptr; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_PLATFORM_H Index: lldb/source/Plugins/Platform/scripted/ScriptedPlatform.cpp =================================================================== --- /dev/null +++ lldb/source/Plugins/Platform/scripted/ScriptedPlatform.cpp @@ -0,0 +1,273 @@ +//===-- ScriptedPlatform.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ScriptedPlatform.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Utility/LLDBLog.h" + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ScriptedPlatform) + +static uint32_t g_initialize_count = 0; + +static constexpr lldb::ScriptLanguage g_supported_script_languages[] = { + ScriptLanguage::eScriptLanguagePython, +}; + +bool ScriptedPlatform::IsScriptLanguageSupported( + lldb::ScriptLanguage language) { + llvm::ArrayRef supported_languages = + llvm::makeArrayRef(g_supported_script_languages); + + return llvm::is_contained(supported_languages, language); +} + +ScriptedPlatformInterface &ScriptedPlatform::GetInterface() const { + return m_interpreter->GetScriptedPlatformInterface(); +} + +lldb::PlatformSP +ScriptedPlatform::CreateInstance(bool force, const ArchSpec *arch, + const Debugger *debugger, + const ScriptedMetadata *metadata) { + Log *log = GetLog(LLDBLog::Platform); + if (log) { + const char *arch_name; + if (arch && arch->GetArchitectureName()) + arch_name = arch->GetArchitectureName(); + else + arch_name = ""; + + const char *triple_cstr = + arch ? arch->GetTriple().getTriple().c_str() : ""; + + LLDB_LOGF(log, + "ScriptedPlatform::%s(force=%s, arch={%s,%s}, debugger=%" PRIxPTR + ")", + __PRETTY_FUNCTION__, force ? "true" : "false", arch_name, + triple_cstr, (uintptr_t)debugger); + } + + if (!debugger || !IsScriptLanguageSupported(debugger->GetScriptLanguage())) + return {}; + + if (!metadata) + return {}; + + Status error; + std::shared_ptr scripted_platform_sp = + std::make_shared(const_cast(debugger), + metadata, error); + + if (error.Success()) + return scripted_platform_sp; + + LLDB_LOGF(log, "ScriptedPlatform::%s() aborting creation of platform", + __PRETTY_FUNCTION__); + + return {}; +} + +ScriptedPlatform::ScriptedPlatform(Debugger *debugger, + const ScriptedMetadata *scripted_metadata, + Status &error) + : Platform(false), m_scripted_metadata(scripted_metadata) { + if (!debugger) { + error.SetErrorStringWithFormat("ScriptedPlatform::%s () - ERROR: %s", + __FUNCTION__, "Invalid debugger"); + return; + } + + m_interpreter = debugger->GetScriptInterpreter(); + + if (!m_interpreter) { + error.SetErrorStringWithFormat("ScriptedPlatform::%s () - ERROR: %s", + __FUNCTION__, + "Debugger has no Script Interpreter"); + return; + } + + ExecutionContext e; + + StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject( + m_scripted_metadata->GetClassName(), e, m_scripted_metadata->GetArgsSP()); + + if (!object_sp || !object_sp->IsValid()) { + error.SetErrorStringWithFormat("ScriptedPlatform::%s () - ERROR: %s", + __FUNCTION__, + "Failed to create valid script object"); + return; + } + + m_hostname = GetHostPlatform()->GetHostname(); + m_script_object_sp = object_sp; +} + +ScriptedPlatform::~ScriptedPlatform() {} + +void ScriptedPlatform::Initialize() { + if (g_initialize_count++ == 0) { + // NOTE: This should probably be using the driving process platform + PluginManager::RegisterPlugin(ScriptedPlatform::GetPluginNameStatic(), + ScriptedPlatform::GetDescriptionStatic(), + ScriptedPlatform::CreateInstance); + } +} + +void ScriptedPlatform::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(ScriptedPlatform::CreateInstance); + } + } +} + +std::vector +ScriptedPlatform::GetSupportedArchitectures(const ArchSpec &process_host_arch) { + std::vector result; + result.push_back(process_host_arch); + return result; +} + +lldb::ProcessSP +ScriptedPlatform::Attach(lldb_private::ProcessAttachInfo &attach_info, + lldb_private::Debugger &debugger, + lldb_private::Target *target, // Can be nullptr, if + // nullptr create a new + // target, else use + // existing one + lldb_private::Status &error) { + return nullptr; +} + +llvm::Expected +ScriptedPlatform::ParseProcessInfo(StructuredData::Dictionary &dict, + lldb::pid_t pid) const { + if (!dict.HasKey("name")) + return llvm::make_error( + "No 'arch' key in process info dictionary.", + llvm::inconvertibleErrorCode()); + if (!dict.HasKey("arch")) + return llvm::make_error( + "No 'arch' key in process info dictionary.", + llvm::inconvertibleErrorCode()); + + llvm::StringRef result; + if (!dict.GetValueForKeyAsString("name", result)) + return llvm::make_error( + "Couldn't extract 'name' key from process info dictionary.", + llvm::inconvertibleErrorCode()); + std::string name = result.str(); + + if (!dict.GetValueForKeyAsString("arch", result)) + return llvm::make_error( + "Couldn't extract 'arch' key from process info dictionary.", + llvm::inconvertibleErrorCode()); + const ArchSpec arch(result.data()); + if (!arch.IsValid()) + return llvm::make_error( + "Invalid 'arch' key in process info dictionary.", + llvm::inconvertibleErrorCode()); + + ProcessInstanceInfo proc_info = ProcessInstanceInfo(name.c_str(), arch, pid); + + lldb::pid_t parent = LLDB_INVALID_PROCESS_ID; + if (dict.GetValueForKeyAsInteger("parent", parent)) + proc_info.SetParentProcessID(parent); + + uint32_t uid = UINT32_MAX; + if (dict.GetValueForKeyAsInteger("uid", uid)) + proc_info.SetEffectiveUserID(uid); + + uint32_t gid = UINT32_MAX; + if (dict.GetValueForKeyAsInteger("gid", gid)) + proc_info.SetEffectiveGroupID(gid); + + return proc_info; +} + +uint32_t +ScriptedPlatform::FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos) { + CheckInterpreterAndScriptObject(); + StructuredData::DictionarySP dict_sp = GetInterface().ListProcesses(); + + Status error; + if (!dict_sp) + return ScriptedInterface::ErrorWithMessage( + LLVM_PRETTY_FUNCTION, "Failed to get scripted platform processes.", + error, LLDBLog::Platform); + + auto parse_process_info = [this, &proc_infos](ConstString key, + StructuredData::Object *val) { + if (!val) + return false; + + StructuredData::Dictionary *dict = val->GetAsDictionary(); + + if (!dict || !dict->IsValid()) + return false; + + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + if (!llvm::to_integer(key.GetStringRef(), pid)) + return false; + + auto proc_info_or_error = ParseProcessInfo(*dict, pid); + + if (llvm::Error e = proc_info_or_error.takeError()) { + LLDB_LOGF(GetLog(LLDBLog::Platform), "%s ERROR = %s", + LLVM_PRETTY_FUNCTION, llvm::toString(std::move(e)).c_str()); + return false; + } + + proc_infos.push_back(*proc_info_or_error); + return true; + }; + + dict_sp->ForEach(parse_process_info); + + // TODO: Use match_info to filter through processes + return proc_infos.size(); +} + +bool ScriptedPlatform::GetProcessInfo(lldb::pid_t pid, + ProcessInstanceInfo &proc_info) { + if (pid == LLDB_INVALID_PROCESS_ID) + return false; + + StructuredData::DictionarySP dict_sp = GetInterface().GetProcessInfo(pid); + + if (!dict_sp || !dict_sp->IsValid()) + return false; + + auto proc_info_or_error = ParseProcessInfo(*dict_sp.get(), pid); + + if (llvm::Error e = proc_info_or_error.takeError()) { + LLDB_LOGF(GetLog(LLDBLog::Platform), "%s ERROR = %s", LLVM_PRETTY_FUNCTION, + llvm::toString(std::move(e)).c_str()); + return false; + } + + proc_info = *proc_info_or_error; + return true; +} + +Status ScriptedPlatform::LaunchProcess(ProcessLaunchInfo &launch_info) { + return GetInterface().LaunchProcess(); +} + +Status ScriptedPlatform::KillProcess(const lldb::pid_t pid) { + return GetInterface().KillProcess(pid); +} Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.h =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedProcess.h +++ lldb/source/Plugins/Process/scripted/ScriptedProcess.h @@ -89,15 +89,18 @@ private: friend class ScriptedThread; - void CheckInterpreterAndScriptObject() const; + inline void CheckInterpreterAndScriptObject() const { + lldbassert(m_interpreter && "Invalid Script Interpreter."); + lldbassert(m_script_object_sp && "Invalid Script Object."); + } + ScriptedProcessInterface &GetInterface() const; + static bool IsScriptLanguageSupported(lldb::ScriptLanguage language); - // Member variables. const ScriptedMetadata m_scripted_metadata; lldb_private::ScriptInterpreter *m_interpreter = nullptr; lldb_private::StructuredData::ObjectSP m_script_object_sp = nullptr; - //@} }; } // namespace lldb_private Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -46,11 +46,6 @@ return llvm::is_contained(supported_languages, language); } -void ScriptedProcess::CheckInterpreterAndScriptObject() const { - lldbassert(m_interpreter && "Invalid Script Interpreter."); - lldbassert(m_script_object_sp && "Invalid Script Object."); -} - lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const FileSpec *file, Index: lldb/source/Plugins/Process/scripted/ScriptedThread.h =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedThread.h +++ lldb/source/Plugins/Process/scripted/ScriptedThread.h @@ -61,7 +61,11 @@ StructuredData::ObjectSP FetchThreadExtendedInfo() override; private: - void CheckInterpreterAndScriptObject() const; + inline void CheckInterpreterAndScriptObject() const { + assert(m_script_object_sp && "Invalid Script Object."); + assert(GetInterface() && "Invalid Scripted Thread Interface."); + } + lldb::ScriptedThreadInterfaceSP GetInterface() const; ScriptedThread(const ScriptedThread &) = delete; Index: lldb/source/Plugins/Process/scripted/ScriptedThread.cpp =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedThread.cpp +++ lldb/source/Plugins/Process/scripted/ScriptedThread.cpp @@ -23,11 +23,6 @@ using namespace lldb; using namespace lldb_private; -void ScriptedThread::CheckInterpreterAndScriptObject() const { - lldbassert(m_script_object_sp && "Invalid Script Object."); - lldbassert(GetInterface() && "Invalid Scripted Thread Interface."); -} - llvm::Expected> ScriptedThread::Create(ScriptedProcess &process, StructuredData::Generic *script_object) {