diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -13,6 +13,7 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_subdirectory(MacOSX-Kernel) endif() +add_subdirectory(Scripted) add_subdirectory(gdb-remote) add_subdirectory(Utility) add_subdirectory(elf-core) diff --git a/lldb/source/Plugins/Process/Scripted/CMakeLists.txt b/lldb/source/Plugins/Process/Scripted/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/Scripted/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginScriptedProcess PLUGIN + ScriptedProcess.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbUtility + lldbPluginProcessUtility + LINK_COMPONENTS + BinaryFormat + Object + Support + ) \ No newline at end of file diff --git a/lldb/source/Plugins/Process/Scripted/ScriptedProcess.h b/lldb/source/Plugins/Process/Scripted/ScriptedProcess.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/Scripted/ScriptedProcess.h @@ -0,0 +1,107 @@ +//===-- ScriptedProcess.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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_PROCESS_H +#define LLDB_SOURCE_PLUGINS_SCRIPTED_PROCESS_H + +#include "lldb/Target/Process.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Status.h" + +namespace lldb_private { + +class ScriptedProcess : public Process { +protected: + class LaunchInfo { + public: + LaunchInfo(const ProcessLaunchInfo &launch_info) { + m_class_name = launch_info.GetScriptedProcessClassName(); + m_dictionary_sp = launch_info.GetScriptedProcessDictionarySP(); + } + + llvm::StringRef GetClassName() const { return m_class_name; } + StructuredData::DictionarySP GetDictionarySP() const { + return m_dictionary_sp; + } + + private: + llvm::StringRef m_class_name; + StructuredData::DictionarySP m_dictionary_sp; + }; + +public: + static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file_path, + bool can_connect); + + static void Initialize(); + + static void Terminate(); + + static ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + ScriptedProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const ScriptedProcess::LaunchInfo &launch_info); + + ~ScriptedProcess() override; + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + DynamicLoader *GetDynamicLoader() override { return nullptr; } + + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + SystemRuntime *GetSystemRuntime() override { return nullptr; } + + Status DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override; + + Status DoResume() override; + + Status DoDestroy() override; + + void RefreshStateAfterStop() override {}; + + bool IsAlive() override; + + size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) override; + + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) override; + + ArchSpec GetArchitecture(); + + Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Status + GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) override; + + bool GetProcessInfo(ProcessInstanceInfo &info) override; + +protected: + void Clear(); + + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; + +private: + const LaunchInfo &m_launch_info; + lldb_private::ScriptInterpreter *m_interpreter; + lldb_private::StructuredData::ObjectSP m_python_object_sp; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_PROCESS_H diff --git a/lldb/source/Plugins/Process/Scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/Scripted/ScriptedProcess.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/Scripted/ScriptedProcess.cpp @@ -0,0 +1,189 @@ +//===-- ScriptedProcess.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 "ScriptedProcess.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" + +#include "lldb/Host/OptionParser.h" + +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionGroupBoolean.h" +#include "lldb/Interpreter/ScriptInterpreter.h" + +#include "lldb/Target/MemoryRegionInfo.h" + +LLDB_PLUGIN_DEFINE(ScriptedProcess) + +using namespace lldb; +using namespace lldb_private; + +ConstString ScriptedProcess::GetPluginNameStatic() { + static ConstString g_name("ScriptedProcess"); + return g_name; +} + +const char *ScriptedProcess::GetPluginDescriptionStatic() { + return "Scripted Process plug-in."; +} + +lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *file, + bool can_connect) { + LaunchInfo launch_info(target_sp->GetProcessLaunchInfo()); + + return std::make_shared(target_sp, listener_sp, launch_info); +} + +bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + return true; +} + +ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const ScriptedProcess::LaunchInfo &launch_info) + : Process(target_sp, listener_sp), m_launch_info(launch_info), + m_interpreter(nullptr), m_python_object_sp(nullptr) { + if (!target_sp) + return; + + m_interpreter = target_sp->GetDebugger().GetScriptInterpreter(); + + if (!m_interpreter) + return; + + StructuredData::ObjectSP object_sp = + m_interpreter->ScriptedProcess_CreatePluginObject( + m_launch_info.GetClassName().str().c_str(), target_sp, + m_launch_info.GetDictionarySP()); + + if (object_sp && object_sp->IsValid()) + m_python_object_sp = object_sp; +} + +ScriptedProcess::~ScriptedProcess() { + Clear(); + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. + Finalize(); +} + +void ScriptedProcess::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); +} + +void ScriptedProcess::Terminate() { + PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance); +} + +ConstString ScriptedProcess::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t ScriptedProcess::GetPluginVersion() { return 1; } + +Status ScriptedProcess::DoLaunch(Module *exe_module, + ProcessLaunchInfo &launch_info) { + if (!m_interpreter) + return Status("No interpreter."); + + if (!m_python_object_sp) + return Status("No python object."); + + Status status = m_interpreter->ScriptedProcess_Launch(m_python_object_sp); + + if (status.Success()) + this->SetPrivateState(eStateStopped); + + return status; +}; + +Status ScriptedProcess::DoResume() { return Status(); } + +Status ScriptedProcess::DoDestroy() { return Status(); } + +bool ScriptedProcess::IsAlive() { return true; } + +size_t ScriptedProcess::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { + return DoReadMemory(addr, buf, size, error); +} + +size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { + + m_interpreter->ScriptedProcess_ReadMemoryAtAddress(m_python_object_sp, addr, + size); + return size; +} + +ArchSpec ScriptedProcess::GetArchitecture() { + return GetTarget().GetArchitecture(); +} + +Status ScriptedProcess::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion) { + return Status(); +} + +Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos ®ion_list) { + Status error; + auto size = + m_interpreter->ScriptedProcess_GetNumMemoryRegions(m_python_object_sp); + + if (size == LLDB_INVALID_ADDRESS) { + error.SetErrorString("ScriptedProcess: Invalid number of memory region!"); + return error; + } + + for (uint64_t i = 0; i < size; i++) { + // FIXME: Update interface method to handle extra arg (index) + MemoryRegionInfoSP mem_region_sp = + m_interpreter->ScriptedProcess_GetMemoryRegionAtIndex( + m_python_object_sp, i); + + if (!mem_region_sp) { + // FIXME: Interpolate index in error string + error.SetErrorString( + "ScriptedProcess: Couldn't fetch memory region at index BLA"); + return error; + } + region_list.push_back(*mem_region_sp.get()); + } + + return error; +} + +void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); } + +bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { + return new_thread_list.GetSize(false) > 0; +} + +bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) { + info.Clear(); + info.SetProcessID(GetID()); + info.SetArchitecture(GetArchitecture()); + lldb::ModuleSP module_sp = GetTarget().GetExecutableModule(); + if (module_sp) { + const bool add_exe_file_as_first_arg = false; + info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(), + add_exe_file_as_first_arg); + } + return true; +} diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2950,7 +2950,7 @@ // If we're not already connected to the process, and if we have a platform // that can launch a process for debugging, go ahead and do that here. if (state != eStateConnected && platform_sp && - platform_sp->CanDebugProcess()) { + platform_sp->CanDebugProcess() && !launch_info.IsScriptedProcess()) { LLDB_LOGF(log, "Target::%s asking the platform to debug the process", __FUNCTION__);