diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig --- a/lldb/bindings/python/python-wrapper.swig +++ b/lldb/bindings/python/python-wrapper.swig @@ -288,7 +288,6 @@ if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) Py_RETURN_NONE; - PyErr_Cleaner py_err_cleaner(true); auto dict = PythonModule::MainModule().ResolveName(session_dictionary_name); diff --git a/lldb/include/lldb/Interpreter/ScriptedInterface.h b/lldb/include/lldb/Interpreter/ScriptedInterface.h new file mode 100644 --- /dev/null +++ b/lldb/include/lldb/Interpreter/ScriptedInterface.h @@ -0,0 +1,33 @@ +//===-- ScriptedInterface.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_INTERPRETER_SCRIPTEDINTERFACE_H +#define LLDB_INTERPRETER_SCRIPTEDINTERFACE_H + +#include "lldb/Core/StructuredDataImpl.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/lldb-private.h" + +#include + +namespace lldb_private { +class ScriptedInterface { +public: + ScriptedInterface() = default; + virtual ~ScriptedInterface() = default; + + virtual StructuredData::GenericSP + CreatePluginObject(const llvm::StringRef class_name, + ExecutionContext &exe_ctx, + StructuredData::DictionarySP args_sp) = 0; + +protected: + StructuredData::GenericSP m_object_instance_sp = nullptr; +}; +} // namespace lldb_private +#endif // LLDB_INTERPRETER_SCRIPTEDINTERFACE_H diff --git a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h --- a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h +++ b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h @@ -11,20 +11,19 @@ #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Interpreter/ScriptedInterface.h" + #include "lldb/lldb-private.h" #include namespace lldb_private { -class ScriptedProcessInterface { +class ScriptedProcessInterface : virtual public ScriptedInterface { public: - ScriptedProcessInterface() : m_object_instance_sp(nullptr) {} - - virtual ~ScriptedProcessInterface() = default; - - virtual StructuredData::GenericSP - CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp, - StructuredData::DictionarySP args_sp) { + StructuredData::GenericSP + CreatePluginObject(const llvm::StringRef class_name, + ExecutionContext &exe_ctx, + StructuredData::DictionarySP args_sp) override { return nullptr; } @@ -59,9 +58,6 @@ virtual lldb::pid_t GetProcessID() { return LLDB_INVALID_PROCESS_ID; } virtual bool IsAlive() { return true; } - -private: - StructuredData::ObjectSP m_object_instance_sp; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp --- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -25,6 +25,8 @@ #include "lldb/Utility/Logging.h" #include "lldb/Utility/State.h" +#include "llvm/ADT/Twine.h" + #include LLDB_PLUGIN_DEFINE(ScriptedProcess) @@ -109,8 +111,10 @@ return; } - StructuredData::ObjectSP object_sp = GetInterface().CreatePluginObject( - m_scripted_process_info.GetClassName().c_str(), target_sp, + ExecutionContext exe_ctx(target_sp, /*get_process=*/false); + + StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject( + m_scripted_process_info.GetClassName().c_str(), exe_ctx, m_scripted_process_info.GetDictionarySP()); if (!object_sp || !object_sp->IsValid()) { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -11,6 +11,7 @@ PythonDataObjects.cpp PythonReadline.cpp ScriptInterpreterPython.cpp + ScriptedPythonInterface.cpp ScriptedProcessPythonInterface.cpp SWIGPythonBridge.cpp diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h @@ -13,17 +13,18 @@ #if LLDB_ENABLE_PYTHON +#include "ScriptedPythonInterface.h" #include "lldb/Interpreter/ScriptedProcessInterface.h" namespace lldb_private { -class ScriptInterpreterPythonImpl; -class ScriptedProcessPythonInterface : public ScriptedProcessInterface { +class ScriptedProcessPythonInterface : public ScriptedProcessInterface, + public ScriptedPythonInterface { public: - ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter) - : ScriptedProcessInterface(), m_interpreter(interpreter) {} + ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter); StructuredData::GenericSP - CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp, + CreatePluginObject(const llvm::StringRef class_name, + ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp) override; Status Launch() override; @@ -34,8 +35,8 @@ Status Stop() override; - lldb::MemoryRegionInfoSP - GetMemoryRegionContainingAddress(lldb::addr_t address) override; + // lldb::MemoryRegionInfoSP + // GetMemoryRegionContainingAddress(lldb::addr_t address) override; StructuredData::DictionarySP GetThreadWithID(lldb::tid_t tid) override; @@ -50,15 +51,8 @@ bool IsAlive() override; -protected: - llvm::Optional - GetGenericInteger(llvm::StringRef method_name); - Status GetStatusFromMethod(llvm::StringRef method_name); private: - // The lifetime is managed by the ScriptInterpreter - ScriptInterpreterPythonImpl &m_interpreter; - StructuredData::GenericSP m_object_instance_sp; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp --- 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::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, + const llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp) { if (class_name.empty()) return {}; - std::string error_string; + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + 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); + 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)); @@ -76,137 +81,66 @@ return GetStatusFromMethod("stop"); } -Status ScriptedProcessPythonInterface::GetStatusFromMethod( - llvm::StringRef method_name) { +StructuredData::DictionarySP +ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) { 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; - } + auto error_with_message = [](llvm::StringRef message) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), + "ScriptedProcess::%s ERROR = %s", __FUNCTION__, + message.str().c_str()); + return StructuredData::DictionarySP(); + }; - return Status("Returned object is null."); -} - -llvm::Optional -ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) { - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); + static char callee_name[] = "get_thread_with_id"; + std::string param_format = GetPythonValueFormatString(tid); if (!m_object_instance_sp) - return llvm::None; + return error_with_message("Python object ill-formed."); if (!m_object_instance_sp) - return llvm::None; + return error_with_message("Python method not callable."); + PythonObject implementor(PyRefType::Borrowed, (PyObject *)m_object_instance_sp->GetValue()); if (!implementor.IsAllocated()) - return llvm::None; + return error_with_message("Python implementor not allocated."); - PythonObject pmeth( - PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); + PythonObject pmeth(PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), callee_name)); if (PyErr_Occurred()) PyErr_Clear(); if (!pmeth.IsAllocated()) - return llvm::None; + return error_with_message("Python method not allocated."); if (PyCallable_Check(pmeth.get()) == 0) { if (PyErr_Occurred()) PyErr_Clear(); - return llvm::None; + return error_with_message("Python method not callable."); } if (PyErr_Occurred()) PyErr_Clear(); PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), - method_name.str().c_str(), - nullptr)); + PyObject_CallMethod(implementor.get(), callee_name, + param_format.c_str(), tid)); if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); + return error_with_message("Python method could not be called."); } if (!py_return.get()) - return llvm::None; - - llvm::Expected size = py_return.AsUnsignedLongLong(); - // FIXME: Handle error. - if (!size) - return llvm::None; - - return *size; -} - -lldb::MemoryRegionInfoSP -ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress( - lldb::addr_t address) { - // TODO: Implement - return nullptr; -} + return error_with_message("Returned object is null."); -StructuredData::DictionarySP -ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) { - // TODO: Implement - return nullptr; + PythonDictionary result_dict(PyRefType::Borrowed, py_return.get()); + return result_dict.CreateStructuredDictionary(); } StructuredData::DictionarySP diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h @@ -0,0 +1,38 @@ +//===-- ScriptedPythonInterface.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_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON + +#include "lldb/Interpreter/ScriptedInterface.h" + +namespace lldb_private { +class ScriptInterpreterPythonImpl; +class ScriptedPythonInterface : virtual public ScriptedInterface { +public: + ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); + virtual ~ScriptedPythonInterface() = default; + +protected: + llvm::Optional + GetGenericInteger(llvm::StringRef method_name); + llvm::Optional GetGenericString(llvm::StringRef method_name); + Status GetStatusFromMethod(llvm::StringRef method_name); + +protected: + // The lifetime is managed by the ScriptInterpreter + ScriptInterpreterPythonImpl &m_interpreter; +}; +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp @@ -0,0 +1,204 @@ +//===-- ScriptedPythonInterface.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 "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" +#include "lldb/lldb-enumerations.h" + +#if LLDB_ENABLE_PYTHON + +// LLDB Python header must be included first +#include "lldb-python.h" + +#include "SWIGPythonBridge.h" +#include "ScriptInterpreterPythonImpl.h" +#include "ScriptedPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::python; +using Locker = ScriptInterpreterPythonImpl::Locker; + +ScriptedPythonInterface::ScriptedPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedInterface(), m_interpreter(interpreter) {} + +llvm::Optional +ScriptedPythonInterface::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; +} + +llvm::Optional +ScriptedPythonInterface::GetGenericString(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; + + PythonString result_string(PyRefType::Borrowed, py_return.get()); + return result_string.GetString(); +} + +Status +ScriptedPythonInterface::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; + } + + return Status("Returned object is null."); +} + +#endif