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

Reply via email to