From 3925204c1f5880f491e08d8481e88342bbeb7bc4 Mon Sep 17 00:00:00 2001 From: Med Ismail Bennani Date: Fri, 3 Sep 2021 17:35:02 +0000 Subject: [lldb/Plugins] Introduce Scripted Interface Factory This patch splits the previous `ScriptedProcessPythonInterface` into multiple specific classes: 1. The `ScriptedInterface` abstract class that carries the interface instance object and its virtual pure abstract creation method. 2. The `ScriptedPythonInterface` that holds a generic `Dispatch` method that can be used by various interfaces to call python methods and also keeps a reference to the Python Script Interpreter instance. 3. The `ScriptedProcessInterface` that describes the base Scripted Process model with all the methods used in the underlying script. All these components are used to refactor the `ScriptedProcessPythonInterface` class, making it more modular. This patch is also a requirement for the upcoming work on `ScriptedThread`. Differential Revision: https://reviews.llvm.org/D107521 Signed-off-by: Med Ismail Bennani --- .../Python/ScriptedProcessPythonInterface.cpp | 294 ++++++--------------- 1 file changed, 86 insertions(+), 208 deletions(-) (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp') diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp index ce262c9..7cc7480 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" #include "lldb/lldb-enumerations.h" #if LLDB_ENABLE_PYTHON @@ -23,30 +25,33 @@ using namespace lldb_private; using namespace lldb_private::python; using Locker = ScriptInterpreterPythonImpl::Locker; +ScriptedProcessPythonInterface::ScriptedProcessPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedProcessInterface(), ScriptedPythonInterface(interpreter) {} + StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject( - const llvm::StringRef class_name, lldb::TargetSP target_sp, + llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp) { if (class_name.empty()) return {}; - std::string error_string; + TargetSP target_sp = exe_ctx.GetTargetSP(); StructuredDataImpl *args_impl = nullptr; if (args_sp) { args_impl = new StructuredDataImpl(); args_impl->SetObjectSP(args_sp); } + std::string error_string; - void *ret_val; - - { + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); + void *ret_val = LLDBSwigPythonCreateScriptedProcess( + class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp, + args_impl, error_string); - ret_val = LLDBSwigPythonCreateScriptedProcess( - class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp, - args_impl, error_string); - } + if (!ret_val) + return {}; m_object_instance_sp = StructuredData::GenericSP(new StructuredPythonObject(ret_val)); @@ -63,244 +68,117 @@ Status ScriptedProcessPythonInterface::Resume() { } bool ScriptedProcessPythonInterface::ShouldStop() { - llvm::Optional should_stop = - GetGenericInteger("should_stop"); + Status error; + StructuredData::ObjectSP obj = Dispatch("is_alive", error); - if (!should_stop) + auto error_with_message = [](llvm::StringRef message) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data()); return false; + }; - return static_cast(*should_stop); -} - -Status ScriptedProcessPythonInterface::Stop() { - return GetStatusFromMethod("stop"); -} - -Status ScriptedProcessPythonInterface::GetStatusFromMethod( - llvm::StringRef method_name) { - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - if (!m_object_instance_sp) - return Status("Python object ill-formed."); - - if (!m_object_instance_sp) - return Status("Cannot convert Python object to StructuredData::Generic."); - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)m_object_instance_sp->GetValue()); - - if (!implementor.IsAllocated()) - return Status("Python implementor not allocated."); - - PythonObject pmeth( - PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); - - if (PyErr_Occurred()) - PyErr_Clear(); - - if (!pmeth.IsAllocated()) - return Status("Python method not allocated."); - - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return Status("Python method not callable."); - } - - if (PyErr_Occurred()) - PyErr_Clear(); - - PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), - method_name.str().c_str(), - nullptr)); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - return Status("Python method could not be called."); - } - - if (PyObject *py_ret_ptr = py_return.get()) { - lldb::SBError *sb_error = - (lldb::SBError *)LLDBSWIGPython_CastPyObjectToSBError(py_ret_ptr); - - if (!sb_error) - return Status("Couldn't cast lldb::SBError to lldb::Status."); - - Status status = m_interpreter.GetStatusFromSBError(*sb_error); - - if (status.Fail()) - return Status("error: %s", status.AsCString()); - - return status; + if (!obj || !obj->IsValid() || error.Fail()) { + return error_with_message(llvm::Twine("Null or invalid object (" + + llvm::Twine(error.AsCString()) + + llvm::Twine(").")) + .str()); } - return Status("Returned object is null."); + return obj->GetBooleanValue(); } -llvm::Optional -ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) { - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - if (!m_object_instance_sp) - return llvm::None; - - if (!m_object_instance_sp) - return llvm::None; - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)m_object_instance_sp->GetValue()); - - if (!implementor.IsAllocated()) - return llvm::None; - - PythonObject pmeth( - PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); - - if (PyErr_Occurred()) - PyErr_Clear(); - - if (!pmeth.IsAllocated()) - return llvm::None; - - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return llvm::None; - } - - if (PyErr_Occurred()) - PyErr_Clear(); - - PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), - method_name.str().c_str(), - nullptr)); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - } - - if (!py_return.get()) - return llvm::None; - - llvm::Expected size = py_return.AsUnsignedLongLong(); - // FIXME: Handle error. - if (!size) - return llvm::None; - - return *size; +Status ScriptedProcessPythonInterface::Stop() { + return GetStatusFromMethod("stop"); } lldb::MemoryRegionInfoSP ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress( lldb::addr_t address) { // TODO: Implement - return nullptr; + return {}; } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) { - // TODO: Implement - return nullptr; -} - -StructuredData::DictionarySP -ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) { - // TODO: Implement - return nullptr; -} - -lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress( - lldb::addr_t address, size_t size, Status &error) { Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); - auto error_with_message = [&error](llvm::StringRef message) { - error.SetErrorString(message); - return nullptr; + auto error_with_message = [](llvm::StringRef message) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data()); + return StructuredData::DictionarySP(); }; - static char callee_name[] = "read_memory_at_address"; - std::string param_format = GetPythonValueFormatString(address); - param_format += GetPythonValueFormatString(size); - - if (!m_object_instance_sp) - return error_with_message("Python object ill-formed."); - - if (!m_object_instance_sp) - return error_with_message("Python method not callable."); - - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)m_object_instance_sp->GetValue()); - - if (!implementor.IsAllocated()) - return error_with_message("Python implementor not allocated."); - - PythonObject pmeth(PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), callee_name)); + Status error; + StructuredData::ObjectSP obj = Dispatch("get_thread_with_id", error, tid); - if (PyErr_Occurred()) - PyErr_Clear(); - - if (!pmeth.IsAllocated()) - return error_with_message("Python method not allocated."); - - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return error_with_message("Python method not callable."); - } - - if (PyErr_Occurred()) - PyErr_Clear(); - - PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), callee_name, - param_format.c_str(), address, - size)); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - return error_with_message("Python method could not be called."); + if (!obj || !obj->IsValid() || error.Fail()) { + return error_with_message(llvm::Twine("Null or invalid object (" + + llvm::Twine(error.AsCString()) + + llvm::Twine(").")) + .str()); } - if (PyObject *py_ret_ptr = py_return.get()) { - lldb::SBData *sb_data = - (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr); + StructuredData::DictionarySP dict{obj->GetAsDictionary()}; - if (!sb_data) - return error_with_message( - "Couldn't cast lldb::SBData to lldb::DataExtractor."); + return dict; +} - return m_interpreter.GetDataExtractorFromSBData(*sb_data); - } +StructuredData::DictionarySP +ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) { + // TODO: Implement + return {}; +} - return error_with_message("Returned object is null."); +lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress( + lldb::addr_t address, size_t size, Status &error) { + return Dispatch("read_memory_at_address", error, + address, size); } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() { // TODO: Implement - return nullptr; + return {}; } lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() { - llvm::Optional pid = GetGenericInteger("get_process_id"); - return (!pid) ? LLDB_INVALID_PROCESS_ID : *pid; + Status error; + StructuredData::ObjectSP obj = Dispatch("get_process_id", error); + + auto error_with_message = [](llvm::StringRef message) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data()); + return LLDB_INVALID_PROCESS_ID; + }; + + if (!obj || !obj->IsValid() || error.Fail()) { + return error_with_message(llvm::Twine("Null or invalid object (" + + llvm::Twine(error.AsCString()) + + llvm::Twine(").")) + .str()); + } + + return obj->GetIntegerValue(LLDB_INVALID_PROCESS_ID); } bool ScriptedProcessPythonInterface::IsAlive() { - llvm::Optional is_alive = GetGenericInteger("is_alive"); + Status error; + StructuredData::ObjectSP obj = Dispatch("is_alive", error); - if (!is_alive) + auto error_with_message = [](llvm::StringRef message) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data()); return false; + }; + + if (!obj || !obj->IsValid() || error.Fail()) { + return error_with_message(llvm::Twine("Null or invalid object (" + + llvm::Twine(error.AsCString()) + + llvm::Twine(").")) + .str()); + } - return static_cast(*is_alive); + return obj->GetBooleanValue(); } #endif -- cgit v1.1