mib created this revision. mib added reviewers: jingham, JDevlieghere, jasonmolenda, labath, LLDB. mib added a project: LLDB. mib requested review of this revision. Herald added a subscriber: lldb-commits.
This patch adds a ScriptedProcess interface to the ScriptInterpreter and more specifically, to the ScriptInterpreterPython. This interface will be used in the C++ `ScriptProcess` Process Plugin to call the script methods. At the moment, not all methods are implemented, they will upstreamed in upcoming patches. rdar://65508855 Signed-off-by: Med Ismail Bennani <medismail.benn...@gmail.com> Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D95711 Files: lldb/bindings/python/python-wrapper.swig lldb/include/lldb/Interpreter/ScriptInterpreter.h lldb/include/lldb/lldb-forward.h lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
Index: lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp =================================================================== --- lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -157,6 +157,10 @@ return nullptr; } +extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data) { + return nullptr; +} + extern lldb::ValueObjectSP LLDBSWIGPython_GetValueObjectSPFromSBValue(void *data) { return nullptr; Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -74,6 +74,46 @@ StructuredData::GenericSP CreateScriptCommandObject(const char *class_name) override; + StructuredData::GenericSP ScriptedProcess_CreatePluginObject( + const char *class_name, lldb::TargetSP target_sp, + StructuredData::DictionarySP args_sp) override; + + Status ScriptedProcess_Launch( + StructuredData::ObjectSP scripted_process_object_sp) override; + + size_t ScriptedProcess_GetNumMemoryRegions( + StructuredData::ObjectSP scripted_process_object_sp) override; + + lldb::MemoryRegionInfoSP ScriptedProcess_GetMemoryRegionAtIndex( + StructuredData::ObjectSP scripted_process_object_sp, + size_t index) override; + + size_t ScriptedProcess_GetNumThreads( + StructuredData::ObjectSP scripted_process_object_sp) override; + + lldb::ThreadSP ScriptedProcess_GetThreadAtIndex( + StructuredData::ObjectSP scripted_process_object_sp, + size_t index) override; + + StructuredData::DictionarySP ScriptedProcess_GetRegisterForThread( + StructuredData::ObjectSP scripted_process_object_sp) override; + + size_t ScriptedProcess_ReadMemoryAtAddress( + StructuredData::ObjectSP scripted_process_object_sp, lldb::addr_t address, + size_t size) override; + + StructuredData::DictionarySP ScriptedProcess_GetLoadedImages( + StructuredData::ObjectSP scripted_process_object_sp) override; + + lldb::pid_t ScriptedProcess_GetProcessID( + StructuredData::ObjectSP scripted_process_object_sp) override; + + bool ScriptedProcess_CanDebug( + StructuredData::ObjectSP scripted_process_object_sp) override; + + bool ScriptedProcess_IsAlive( + StructuredData::ObjectSP scripted_process_object_sp) override; + StructuredData::ObjectSP CreateScriptedThreadPlan(const char *class_name, StructuredDataImpl *args_data, Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -17,6 +17,7 @@ #include "PythonDataObjects.h" #include "PythonReadline.h" #include "ScriptInterpreterPythonImpl.h" +#include "lldb/API/SBError.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBValue.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" @@ -111,6 +112,11 @@ const char *session_dictionary_name, const lldb::DebuggerSP debugger_sp); +extern "C" void *LLDBSwigPythonCreateScriptedProcess( + const char *python_class_name, const char *session_dictionary_name, + const lldb::TargetSP &target_sp, StructuredDataImpl *args_impl, + std::string &error_string); + extern "C" void *LLDBSwigPythonCreateScriptedThreadPlan( const char *python_class_name, const char *session_dictionary_name, StructuredDataImpl *args_data, @@ -150,6 +156,8 @@ extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data); +extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data); + extern lldb::ValueObjectSP LLDBSWIGPython_GetValueObjectSPFromSBValue(void *data); @@ -2148,6 +2156,212 @@ return StructuredData::GenericSP(new StructuredPythonObject(ret_val)); } +#pragma mark ScriptedProcessInterface + +StructuredData::GenericSP +ScriptInterpreterPythonImpl::ScriptedProcess_CreatePluginObject( + const char *class_name, lldb::TargetSP target_sp, + StructuredData::DictionarySP args_sp) { + if (class_name == nullptr || class_name[0] == '\0') + return {}; + + std::string error_string; + StructuredDataImpl *args_impl = nullptr; + if (args_sp) { + args_impl = new StructuredDataImpl(); + args_impl->SetObjectSP(args_sp); + } + + void *ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + ret_val = LLDBSwigPythonCreateScriptedProcess( + class_name, m_dictionary_name.c_str(), target_sp, args_impl, + error_string); + } + + return StructuredData::GenericSP(new StructuredPythonObject(ret_val)); +} + +Status ScriptInterpreterPythonImpl::ScriptedProcess_Launch( + StructuredData::ObjectSP scripted_process_object_sp) { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "launch"; + + if (!scripted_process_object_sp) + return Status("Python object ill-formed."); + + StructuredData::Generic *generic = scripted_process_object_sp->GetAsGeneric(); + if (!generic) + return Status("Cannot convert Python object to StructuredData::Generic."); + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)generic->GetValue()); + + if (!implementor.IsAllocated()) + return Status("Python implementor not allocated."); + + PythonObject pmeth(PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), callee_name)); + + 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(); + + // right now we know this function exists and is callable.. + PythonObject py_return( + PyRefType::Owned, + PyObject_CallMethod(implementor.get(), callee_name, nullptr)); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + + 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."); + + if (sb_error->Fail()) + return Status("error: %s", sb_error->GetCString()); + + return Status(); + } + + return Status("Returned object is null."); +} + +size_t ScriptInterpreterPythonImpl::ScriptedProcess_GetNumMemoryRegions( + StructuredData::ObjectSP scripted_process_object_sp) { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "get_num_memory_regions"; + + if (!scripted_process_object_sp) + return LLDB_INVALID_ADDRESS; + + StructuredData::Generic *generic = scripted_process_object_sp->GetAsGeneric(); + if (!generic) + return LLDB_INVALID_ADDRESS; + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)generic->GetValue()); + + if (!implementor.IsAllocated()) + return LLDB_INVALID_ADDRESS; + + PythonObject pmeth(PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), callee_name)); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return LLDB_INVALID_ADDRESS; + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return LLDB_INVALID_ADDRESS; + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + // right now we know this function exists and is callable.. + PythonObject py_return( + PyRefType::Owned, + PyObject_CallMethod(implementor.get(), callee_name, nullptr)); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + + if (py_return.get()) { + PythonDictionary result(PyRefType::Borrowed, py_return.get()); + auto size = result.AsUnsignedLongLong(); + return (size) ? *size : LLDB_INVALID_ADDRESS; + } + return LLDB_INVALID_ADDRESS; +} + +lldb::MemoryRegionInfoSP +ScriptInterpreterPythonImpl::ScriptedProcess_GetMemoryRegionAtIndex( + StructuredData::ObjectSP scripted_process_object_sp, size_t index) { + // TODO: Implement + return nullptr; +} + +size_t ScriptInterpreterPythonImpl::ScriptedProcess_GetNumThreads( + StructuredData::ObjectSP scripted_process_object_sp) { + // TODO: Implement + return LLDB_INVALID_ADDRESS; +} + +lldb::ThreadSP ScriptInterpreterPythonImpl::ScriptedProcess_GetThreadAtIndex( + StructuredData::ObjectSP scripted_process_object_sp, size_t index) { + // TODO: Implement + return nullptr; +} + +StructuredData::DictionarySP +ScriptInterpreterPythonImpl::ScriptedProcess_GetRegisterForThread( + StructuredData::ObjectSP scripted_process_object_sp) { + // TODO: Implement + return nullptr; +} + +size_t ScriptInterpreterPythonImpl::ScriptedProcess_ReadMemoryAtAddress( + StructuredData::ObjectSP scripted_process_object_sp, lldb::addr_t address, + size_t size) { + // TODO: Implement + return LLDB_INVALID_ADDRESS; +} + +StructuredData::DictionarySP +ScriptInterpreterPythonImpl::ScriptedProcess_GetLoadedImages( + StructuredData::ObjectSP scripted_process_object_sp) { + // TODO: Implement + return nullptr; +} + +lldb::pid_t ScriptInterpreterPythonImpl::ScriptedProcess_GetProcessID( + StructuredData::ObjectSP scripted_process_object_sp) { + // TODO: Implement + return LLDB_INVALID_PROCESS_ID; +} + +bool ScriptInterpreterPythonImpl::ScriptedProcess_CanDebug( + StructuredData::ObjectSP scripted_process_object_sp) { + // TODO: Implement + return true; +} + +bool ScriptInterpreterPythonImpl::ScriptedProcess_IsAlive( + StructuredData::ObjectSP scripted_process_object_sp) { + // TODO: Implement + return true; +} + bool ScriptInterpreterPythonImpl::GenerateTypeScriptFunction( const char *oneliner, std::string &output, const void *name_token) { StringList input; Index: lldb/include/lldb/lldb-forward.h =================================================================== --- lldb/include/lldb/lldb-forward.h +++ lldb/include/lldb/lldb-forward.h @@ -341,6 +341,7 @@ typedef std::weak_ptr<lldb_private::Listener> ListenerWP; typedef std::shared_ptr<lldb_private::MemoryHistory> MemoryHistorySP; typedef std::unique_ptr<lldb_private::MemoryRegionInfo> MemoryRegionInfoUP; +typedef std::shared_ptr<lldb_private::MemoryRegionInfo> MemoryRegionInfoSP; typedef std::shared_ptr<lldb_private::Module> ModuleSP; typedef std::weak_ptr<lldb_private::Module> ModuleWP; typedef std::shared_ptr<lldb_private::ObjectFile> ObjectFileSP; Index: lldb/include/lldb/Interpreter/ScriptInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -528,6 +528,71 @@ lldb::ScriptLanguage GetLanguage() { return m_script_lang; } +#pragma mark ScriptedProcessInterface + + virtual StructuredData::GenericSP + ScriptedProcess_CreatePluginObject(const char *class_name, + lldb::TargetSP target_sp, + StructuredData::DictionarySP args_sp) { + return nullptr; + } + + virtual Status + ScriptedProcess_Launch(StructuredData::ObjectSP scripted_process_object_sp) { + return Status("ScriptedProcess did not launch"); + } + + virtual size_t ScriptedProcess_GetNumMemoryRegions( + StructuredData::ObjectSP scripted_process_object_sp) { + return LLDB_INVALID_ADDRESS; + } + + virtual lldb::MemoryRegionInfoSP ScriptedProcess_GetMemoryRegionAtIndex( + StructuredData::ObjectSP scripted_process_object_sp, size_t index) { + return nullptr; + } + + virtual size_t ScriptedProcess_GetNumThreads( + StructuredData::ObjectSP scripted_process_object_sp) { + return LLDB_INVALID_ADDRESS; + } + + virtual lldb::ThreadSP ScriptedProcess_GetThreadAtIndex( + StructuredData::ObjectSP scripted_process_object_sp, size_t index) { + return nullptr; + } + + virtual StructuredData::DictionarySP ScriptedProcess_GetRegisterForThread( + StructuredData::ObjectSP scripted_process_object_sp) { + return nullptr; + } + + virtual size_t ScriptedProcess_ReadMemoryAtAddress( + StructuredData::ObjectSP scripted_process_object_sp, lldb::addr_t address, + size_t size) { + return LLDB_INVALID_ADDRESS; + } + + virtual StructuredData::DictionarySP ScriptedProcess_GetLoadedImages( + StructuredData::ObjectSP scripted_process_object_sp) { + return nullptr; + } + + virtual lldb::pid_t ScriptedProcess_GetProcessID( + StructuredData::ObjectSP scripted_process_object_sp) { + return LLDB_INVALID_PROCESS_ID; + } + + virtual bool ScriptedProcess_CanDebug( + StructuredData::ObjectSP scripted_process_object_sp) { + return true; + } + + virtual bool + ScriptedProcess_IsAlive(StructuredData::ObjectSP scripted_process_object_sp) { + return true; + } + protected: Debugger &m_debugger; lldb::ScriptLanguage m_script_lang; Index: lldb/bindings/python/python-wrapper.swig =================================================================== --- lldb/bindings/python/python-wrapper.swig +++ lldb/bindings/python/python-wrapper.swig @@ -258,6 +258,72 @@ Py_RETURN_NONE; } +SWIGEXPORT void* +LLDBSwigPythonCreateScriptedProcess +( + const char *python_class_name, + const char *session_dictionary_name, + const lldb::TargetSP& target_sp, + lldb_private::StructuredDataImpl *args_impl, + std::string &error_string +) +{ + 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<PythonDictionary>(session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_class_name, dict); + + if (!pfunc.IsAllocated()) { + error_string.append("could not find script class: "); + error_string.append(python_class_name); + return nullptr; + } + + // I do not want the SBTarget to be deallocated when going out of scope + // because python has ownership of it and will manage memory for this + // object by itself + PythonObject target_arg(PyRefType::Owned, SBTypeToSWIGWrapper(new lldb::SBTarget(target_sp))); + + if (!target_arg.IsAllocated()) + Py_RETURN_NONE; + + llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo(); + if (!arg_info) { + llvm::handleAllErrors( + arg_info.takeError(), + [&](PythonException &E) { + error_string.append(E.ReadBacktrace()); + }, + [&](const llvm::ErrorInfoBase &E) { + error_string.append(E.message()); + }); + Py_RETURN_NONE; + } + + PythonObject result = {}; + if (arg_info.get().max_positional_args == 2) { + if (args_impl != nullptr) { + error_string.assign("args passed, but __init__ does not take an args dictionary"); + Py_RETURN_NONE; + } + result = pfunc(target_arg, dict); + } else if (arg_info.get().max_positional_args >= 3) { + PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(new lldb::SBStructuredData(args_impl))); + result = pfunc(target_arg, args_arg, dict); + } else { + error_string.assign("wrong number of arguments in __init__, should be 2 or 3 (not including self)"); + Py_RETURN_NONE; + } + + if (result.IsAllocated()) + return result.release(); + Py_RETURN_NONE; +} + SWIGEXPORT void* LLDBSwigPythonCreateScriptedThreadPlan ( @@ -801,6 +867,22 @@ return sb_ptr; } +SWIGEXPORT void* +LLDBSWIGPython_CastPyObjectToSBError +( + PyObject* data +) +{ + lldb::SBError* sb_ptr = nullptr; + + int valid_cast = SWIG_ConvertPtr(data, (void**)&sb_ptr, SWIGTYPE_p_lldb__SBError, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + SWIGEXPORT bool LLDBSwigPythonCallCommand (
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits