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 <[email protected]>
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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits