mib updated this revision to Diff 370258.
mib marked an inline comment as done.
mib added a comment.

Tighten to PythonInterpreter Lock.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D107521/new/

https://reviews.llvm.org/D107521

Files:
  lldb/bindings/interface/SBMemoryRegionInfo.i
  lldb/bindings/interface/SBMemoryRegionInfoList.i
  lldb/bindings/python/python-wrapper.swig
  lldb/examples/python/scripted_process/main.stack-dump
  lldb/examples/python/scripted_process/my_scripted_process.py
  lldb/include/lldb/API/SBMemoryRegionInfo.h
  lldb/include/lldb/API/SBMemoryRegionInfoList.h
  lldb/include/lldb/Interpreter/ScriptInterpreter.h
  lldb/include/lldb/Interpreter/ScriptedInterface.h
  lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
  lldb/source/API/SBMemoryRegionInfo.cpp
  lldb/source/API/SBMemoryRegionInfoList.cpp
  lldb/source/Interpreter/ScriptInterpreter.cpp
  lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
  lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
  
lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
  lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
  lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
  lldb/test/API/functionalities/scripted_process/main.c
  lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp

Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
@@ -0,0 +1,38 @@
+//===-- 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;
+
+ScriptedPythonInterface::ScriptedPythonInterface(
+    ScriptInterpreterPythonImpl &interpreter)
+    : ScriptedInterface(), m_interpreter(interpreter) {}
+
+Status
+ScriptedPythonInterface::GetStatusFromMethod(llvm::StringRef method_name) {
+  Status error;
+  Dispatch<Status>(method_name, error);
+
+  return error;
+}
+
+#endif
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
+++ 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;
@@ -49,16 +50,6 @@
   lldb::pid_t GetProcessID() override;
 
   bool IsAlive() override;
-
-protected:
-  llvm::Optional<unsigned long long>
-  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
 
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -13,8 +13,6 @@
 
 #if LLDB_ENABLE_PYTHON
 
-#include "ScriptedProcessPythonInterface.h"
-
 #include "lldb/Breakpoint/BreakpointOptions.h"
 #include "lldb/Core/IOHandler.h"
 #include "lldb/Core/StructuredDataImpl.h"
Index: lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -11,6 +11,7 @@
   PythonDataObjects.cpp
   PythonReadline.cpp
   ScriptInterpreterPython.cpp
+  ScriptedPythonInterface.cpp
   ScriptedProcessPythonInterface.cpp
   SWIGPythonBridge.cpp
 
Index: lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
===================================================================
--- lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
+++ lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
@@ -11,20 +11,18 @@
 
 #include "lldb/Core/StructuredDataImpl.h"
 #include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/ScriptedInterface.h"
+
 #include "lldb/lldb-private.h"
 
 #include <string>
 
 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(llvm::StringRef class_name, ExecutionContext &exe_ctx,
+                     StructuredData::DictionarySP args_sp) override {
     return nullptr;
   }
 
@@ -59,9 +57,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
 
Index: lldb/include/lldb/Interpreter/ScriptedInterface.h
===================================================================
--- /dev/null
+++ lldb/include/lldb/Interpreter/ScriptedInterface.h
@@ -0,0 +1,32 @@
+//===-- 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 <string>
+
+namespace lldb_private {
+class ScriptedInterface {
+public:
+  ScriptedInterface() = default;
+  virtual ~ScriptedInterface() = default;
+
+  virtual StructuredData::GenericSP
+  CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
+                     StructuredData::DictionarySP args_sp) = 0;
+
+protected:
+  StructuredData::GenericSP m_object_instance_sp;
+};
+} // namespace lldb_private
+#endif // LLDB_INTERPRETER_SCRIPTEDINTERFACE_H
Index: lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
===================================================================
--- lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -12,7 +12,7 @@
 
 #include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
 #include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h"
-#include "lldb/API/SBError.h"
+
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/HostInfo.h"
 
Index: lldb/test/API/functionalities/scripted_process/main.c
===================================================================
--- lldb/test/API/functionalities/scripted_process/main.c
+++ lldb/test/API/functionalities/scripted_process/main.c
@@ -1,5 +1,8 @@
-#include <stdlib.h>
-
-int main() {
-  return 0; // break here
+int bar(int i) {
+  int j = i * i;
+  return j; // break here
 }
+
+int foo(int i) { return bar(i); }
+
+int main() { return foo(42); }
Index: lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
@@ -0,0 +1,90 @@
+import os,struct, signal
+
+from typing import Any, Dict
+
+import lldb
+from lldb.plugins.scripted_process import ScriptedProcess
+from lldb.plugins.scripted_process import ScriptedThread
+
+class DummyScriptedProcess(ScriptedProcess):
+    def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
+        super().__init__(target, args)
+
+    def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
+        return self.memory_regions[0]
+
+    def get_thread_with_id(self, tid: int):
+        return {}
+
+    def get_registers_for_thread(self, tid: int):
+        return {}
+
+    def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData:
+        data = lldb.SBData().CreateDataFromCString(
+                                    self.target.GetByteOrder(),
+                                    self.target.GetCodeByteSize(),
+                                    "Hello, world!")
+        return data
+
+    def get_loaded_images(self):
+        return self.loaded_images
+
+    def get_process_id(self) -> int:
+        return 42
+
+    def should_stop(self) -> bool:
+        return True
+
+    def is_alive(self) -> bool:
+        return True
+
+    def get_scripted_thread_plugin(self):
+        return DummyScriptedThread.__module__ + "." + DummyScriptedThread.__name__
+
+
+class DummyScriptedThread(ScriptedThread):
+    def __init__(self, target):
+        super().__init__(target)
+
+    def get_thread_id(self) -> int:
+        return 0x19
+
+    def get_name(self) -> str:
+        return DummyScriptedThread.__name__ + ".thread-1"
+
+    def get_state(self) -> int:
+        return lldb.eStateStopped
+
+    def get_stop_reason(self) -> Dict[str, Any]:
+        return { "type": lldb.eStopReasonSignal, "data": {
+            "signal": signal.SIGINT
+        } }
+
+    def get_stackframes(self):
+        class ScriptedStackFrame:
+            def __init__(idx, cfa, pc, symbol_ctx):
+                self.idx = idx
+                self.cfa = cfa
+                self.pc = pc
+                self.symbol_ctx = symbol_ctx
+
+
+        symbol_ctx = lldb.SBSymbolContext()
+        frame_zero = ScriptedStackFrame(0, 0x42424242, 0x5000000, symbol_ctx)
+        self.frames.append(frame_zero)
+
+        return self.frame_zero[0:0]
+
+    def get_register_context(self) -> str:
+        return struct.pack(
+                '21Q', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
+
+
+def __lldb_init_module(debugger, dict):
+    if not 'SKIP_SCRIPTED_PROCESS_LAUNCH' in os.environ:
+        debugger.HandleCommand(
+            "process launch -C %s.%s" % (__name__,
+                                     DummyScriptedProcess.__name__))
+    else:
+        print("Name of the class that will manage the scripted process: '%s.%s'"
+                % (__name__, DummyScriptedProcess.__name__))
\ No newline at end of file
Index: lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
===================================================================
--- lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
+++ lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
@@ -43,41 +43,35 @@
         self.expect('script dir(ScriptedProcess)',
                     substrs=["launch"])
 
-    def test_launch_scripted_process_sbapi(self):
+    def test_scripted_process_and_scripted_thread(self):
         """Test that we can launch an lldb scripted process using the SBAPI,
-        check its process ID and read string from memory."""
+        check its process ID, read string from memory, check scripted thread
+        id, name stop reason and register context.
+        """
         self.build()
         target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
         self.assertTrue(target, VALID_TARGET)
 
-        scripted_process_example_relpath = ['..','..','..','..','examples','python','scripted_process','my_scripted_process.py']
+        scripted_process_example_relpath = 'dummy_scripted_process.py'
         os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
         self.runCmd("command script import " + os.path.join(self.getSourceDir(),
-                                                            *scripted_process_example_relpath))
+                                                            scripted_process_example_relpath))
 
         launch_info = lldb.SBLaunchInfo(None)
         launch_info.SetProcessPluginName("ScriptedProcess")
-        launch_info.SetScriptedProcessClassName("my_scripted_process.MyScriptedProcess")
+        launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess")
 
         error = lldb.SBError()
         process = target.Launch(launch_info, error)
         self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
         self.assertEqual(process.GetProcessID(), 42)
 
-        hello_world = "Hello, world!"
-        memory_read = process.ReadCStringFromMemory(0x50000000000,
-                                                    len(hello_world) + 1, # NULL byte
-                                                    error)
-
-        self.assertTrue(error.Success(), "Failed to read memory from scripted process.")
-        self.assertEqual(hello_world, memory_read)
-
         self.assertEqual(process.GetNumThreads(), 1)
 
         thread = process.GetSelectedThread()
         self.assertTrue(thread, "Invalid thread.")
         self.assertEqual(thread.GetThreadID(), 0x19)
-        self.assertEqual(thread.GetName(), "MyScriptedThread.thread-1")
+        self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
         self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
 
         self.assertGreater(thread.GetNumFrames(), 0)
@@ -94,13 +88,21 @@
         for idx, reg in enumerate(registers, start=1):
             self.assertEqual(idx, int(reg.value, 16))
 
-    def test_launch_scripted_process_cli(self):
+    def test_launch_scripted_process_stack_frames(self):
         """Test that we can launch an lldb scripted process from the command
         line, check its process ID and read string from memory."""
         self.build()
         target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
         self.assertTrue(target, VALID_TARGET)
 
+        for module in target.modules:
+            if 'a.out' in module.GetFileSpec().GetFilename():
+                main_module = module
+
+        self.assertTrue(main_module, "Invalid main module.")
+        error = target.SetModuleLoadAddress(main_module, 0)
+        self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")
+
         scripted_process_example_relpath = ['..','..','..','..','examples','python','scripted_process','my_scripted_process.py']
         self.runCmd("command script import " + os.path.join(self.getSourceDir(),
                                                             *scripted_process_example_relpath))
@@ -108,12 +110,21 @@
         process = target.GetProcess()
         self.assertTrue(process, PROCESS_IS_VALID)
         self.assertEqual(process.GetProcessID(), 42)
+        self.assertEqual(process.GetNumThreads(), 1)
 
         error = lldb.SBError()
         hello_world = "Hello, world!"
         memory_read = process.ReadCStringFromMemory(0x50000000000,
                                                     len(hello_world) + 1, # NULL byte
                                                     error)
+        thread = process.GetSelectedThread()
+        self.assertTrue(thread, "Invalid thread.")
+        self.assertEqual(thread.GetThreadID(), 0x19)
+        self.assertEqual(thread.GetName(), "MyScriptedThread.thread-1")
 
-        self.assertTrue(error.Success(), "Failed to read memory from scripted process.")
-        self.assertEqual(hello_world, memory_read)
+        self.assertEqual(thread.GetNumFrames(), 4)
+        frame = thread.GetSelectedFrame()
+        self.assertTrue(frame, "Invalid frame.")
+        self.assertEqual(frame.GetFunctionName(), "bar")
+        self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
+        self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
@@ -0,0 +1,151 @@
+//===-- 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"
+#include "lldb/Utility/DataBufferHeap.h"
+
+#include "PythonDataObjects.h"
+#include "SWIGPythonBridge.h"
+#include "ScriptInterpreterPythonImpl.h"
+
+namespace lldb_private {
+class ScriptInterpreterPythonImpl;
+class ScriptedPythonInterface : virtual public ScriptedInterface {
+public:
+  ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
+  virtual ~ScriptedPythonInterface() = default;
+
+protected:
+  template <typename T = StructuredData::ObjectSP>
+  T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
+    return p.CreateStructuredObject();
+  }
+
+  template <>
+  Status ExtractValueFromPythonObject<Status>(python::PythonObject &p,
+                                              Status &error) {
+    if (lldb::SBError *sb_error = reinterpret_cast<lldb::SBError *>(
+            LLDBSWIGPython_CastPyObjectToSBError(p.get())))
+      error = m_interpreter.GetStatusFromSBError(*sb_error);
+    else
+      error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status.");
+
+    return error;
+  }
+
+  template <>
+  lldb::DataExtractorSP
+  ExtractValueFromPythonObject<lldb::DataExtractorSP>(python::PythonObject &p,
+                                                      Status &error) {
+    lldb::SBData *sb_data = reinterpret_cast<lldb::SBData *>(
+        LLDBSWIGPython_CastPyObjectToSBData(p.get()));
+
+    if (!sb_data) {
+      error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status.");
+      return nullptr;
+    }
+
+    return m_interpreter.GetDataExtractorFromSBData(*sb_data);
+  }
+
+  template <typename T = StructuredData::ObjectSP, typename... Args>
+  T Dispatch(llvm::StringRef method_name, Status &error, Args... args) {
+    using namespace python;
+    using Locker = ScriptInterpreterPythonImpl::Locker;
+
+    auto error_with_message = [&method_name, &error](llvm::StringRef message) {
+      error.SetErrorStringWithFormatv(
+          "ScriptedPythonInterface::{0} ({1}) ERROR = {2}", __FUNCTION__,
+          method_name, message);
+      return T();
+    };
+
+    if (!m_object_instance_sp)
+      return error_with_message("Python object ill-formed");
+
+    Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+                   Locker::FreeLock);
+
+    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(), method_name.str().c_str()));
+
+    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();
+
+    const char *format = nullptr;
+    std::string format_buffer;
+
+    if (sizeof...(Args) > 0) {
+      FormatArgs(format_buffer, args...);
+      format = format_buffer.c_str();
+    }
+
+    PythonObject py_return(PyRefType::Owned,
+                           PyObject_CallMethod(implementor.get(),
+                                               method_name.data(), format,
+                                               args...));
+
+    if (PyErr_Occurred()) {
+      PyErr_Print();
+      PyErr_Clear();
+      return error_with_message("Python method could not be called.");
+    }
+
+    if (!py_return.IsAllocated())
+      return error_with_message("Returned object is null.");
+
+    return ExtractValueFromPythonObject<T>(py_return, error);
+  }
+
+  Status GetStatusFromMethod(llvm::StringRef method_name);
+
+  template <typename T, typename... Args>
+  void FormatArgs(std::string &fmt, T arg, Args... args) const {
+    FormatArgs(fmt, arg);
+    FormatArgs(fmt, args...);
+  }
+
+  template <typename T> void FormatArgs(std::string &fmt, T arg) const {
+    fmt += GetPythonValueFormatString(arg);
+  }
+
+  void FormatArgs(std::string &fmt) const {}
+
+  // The lifetime is managed by the ScriptInterpreter
+  ScriptInterpreterPythonImpl &m_interpreter;
+};
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
+++ 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,
+    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 @@
 }
 
 bool ScriptedProcessPythonInterface::ShouldStop() {
-  llvm::Optional<unsigned long long> 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<bool>(*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<unsigned long long>
-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<unsigned long long> 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<lldb::DataExtractorSP>("read_memory_at_address", error,
+                                         address, size);
 }
 
 StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() {
   // TODO: Implement
-  return nullptr;
+  return {};
 }
 
 lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() {
-  llvm::Optional<unsigned long long> 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<unsigned long long> 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<bool>(*is_alive);
+  return obj->GetBooleanValue();
 }
 
 #endif
Index: lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -53,6 +53,7 @@
 extern "C" void *LLDBSWIGPython_CastPyObjectToSBData(void *data);
 extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data);
 extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data);
+extern "C" void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(void *data);
 
 } // namespace lldb_private
 
Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
===================================================================
--- lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -109,8 +109,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()) {
Index: lldb/source/Interpreter/ScriptInterpreter.cpp
===================================================================
--- lldb/source/Interpreter/ScriptInterpreter.cpp
+++ lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -83,6 +83,11 @@
   return Status();
 }
 
+lldb::MemoryRegionInfoSP ScriptInterpreter::GetOpaquePtrFromSBMemoryRegionInfo(
+    const lldb::SBMemoryRegionInfo &mem_region) const {
+  return mem_region.m_opaque_sp;
+}
+
 lldb::ScriptLanguage
 ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
   if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))
Index: lldb/source/API/SBMemoryRegionInfoList.cpp
===================================================================
--- lldb/source/API/SBMemoryRegionInfoList.cpp
+++ lldb/source/API/SBMemoryRegionInfoList.cpp
@@ -48,6 +48,17 @@
 
   void Clear() { m_regions.clear(); }
 
+  bool GetMemoryRegionContainingAddress(lldb::addr_t addr,
+                                        MemoryRegionInfo &region_info) {
+    for (auto &region : m_regions) {
+      if (region.GetRange().Contains(addr)) {
+        region_info = region;
+        return true;
+      }
+    }
+    return false;
+  }
+
   bool GetMemoryRegionInfoAtIndex(size_t index,
                                   MemoryRegionInfo &region_info) {
     if (index >= GetSize())
@@ -103,6 +114,15 @@
   return m_opaque_up->GetSize();
 }
 
+bool SBMemoryRegionInfoList::GetMemoryRegionContainingAddress(
+    lldb::addr_t addr, SBMemoryRegionInfo &region_info) {
+  LLDB_RECORD_METHOD(
+      bool, SBMemoryRegionInfoList, GetMemoryRegionContainingAddress,
+      (lldb::addr_t, lldb::SBMemoryRegionInfo &), addr, region_info);
+
+  return m_opaque_up->GetMemoryRegionContainingAddress(addr, region_info.ref());
+}
+
 bool SBMemoryRegionInfoList::GetMemoryRegionAtIndex(
     uint32_t idx, SBMemoryRegionInfo &region_info) {
   LLDB_RECORD_METHOD(bool, SBMemoryRegionInfoList, GetMemoryRegionAtIndex,
@@ -153,6 +173,9 @@
       SBMemoryRegionInfoList, operator=,(
                                   const lldb::SBMemoryRegionInfoList &));
   LLDB_REGISTER_METHOD_CONST(uint32_t, SBMemoryRegionInfoList, GetSize, ());
+  LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfoList,
+                       GetMemoryRegionContainingAddress,
+                       (lldb::addr_t, lldb::SBMemoryRegionInfo &));
   LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfoList, GetMemoryRegionAtIndex,
                        (uint32_t, lldb::SBMemoryRegionInfo &));
   LLDB_REGISTER_METHOD(void, SBMemoryRegionInfoList, Clear, ());
Index: lldb/source/API/SBMemoryRegionInfo.cpp
===================================================================
--- lldb/source/API/SBMemoryRegionInfo.cpp
+++ lldb/source/API/SBMemoryRegionInfo.cpp
@@ -18,21 +18,39 @@
 using namespace lldb;
 using namespace lldb_private;
 
-SBMemoryRegionInfo::SBMemoryRegionInfo() : m_opaque_up(new MemoryRegionInfo()) {
+SBMemoryRegionInfo::SBMemoryRegionInfo() : m_opaque_sp(new MemoryRegionInfo()) {
   LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBMemoryRegionInfo);
 }
 
+SBMemoryRegionInfo::SBMemoryRegionInfo(const char *name, lldb::addr_t begin,
+                                       lldb::addr_t end, uint32_t permissions,
+                                       bool mapped, bool stack_memory)
+    : SBMemoryRegionInfo() {
+  LLDB_RECORD_CONSTRUCTOR(
+      SBMemoryRegionInfo,
+      (const char *, lldb::addr_t, lldb::addr_t, uint32_t, bool, bool), name,
+      begin, end, permissions, mapped, stack_memory);
+  m_opaque_sp->SetName(name);
+  m_opaque_sp->GetRange().SetRangeBase(begin);
+  m_opaque_sp->GetRange().SetRangeEnd(end);
+  m_opaque_sp->SetLLDBPermissions(permissions);
+  m_opaque_sp->SetMapped(mapped ? MemoryRegionInfo::eYes
+                                : MemoryRegionInfo::eNo);
+  m_opaque_sp->SetIsStackMemory(stack_memory ? MemoryRegionInfo::eYes
+                                             : MemoryRegionInfo::eNo);
+}
+
 SBMemoryRegionInfo::SBMemoryRegionInfo(const MemoryRegionInfo *lldb_object_ptr)
-    : m_opaque_up(new MemoryRegionInfo()) {
+    : m_opaque_sp(new MemoryRegionInfo()) {
   if (lldb_object_ptr)
     ref() = *lldb_object_ptr;
 }
 
 SBMemoryRegionInfo::SBMemoryRegionInfo(const SBMemoryRegionInfo &rhs)
-    : m_opaque_up() {
+    : m_opaque_sp() {
   LLDB_RECORD_CONSTRUCTOR(SBMemoryRegionInfo,
                           (const lldb::SBMemoryRegionInfo &), rhs);
-  m_opaque_up = clone(rhs.m_opaque_up);
+  m_opaque_sp = clone(rhs.m_opaque_sp);
 }
 
 const SBMemoryRegionInfo &SBMemoryRegionInfo::
@@ -42,7 +60,7 @@
       SBMemoryRegionInfo, operator=,(const lldb::SBMemoryRegionInfo &), rhs);
 
   if (this != &rhs)
-    m_opaque_up = clone(rhs.m_opaque_up);
+    m_opaque_sp = clone(rhs.m_opaque_sp);
   return LLDB_RECORD_RESULT(*this);
 }
 
@@ -51,7 +69,7 @@
 void SBMemoryRegionInfo::Clear() {
   LLDB_RECORD_METHOD_NO_ARGS(void, SBMemoryRegionInfo, Clear);
 
-  m_opaque_up->Clear();
+  m_opaque_sp->Clear();
 }
 
 bool SBMemoryRegionInfo::operator==(const SBMemoryRegionInfo &rhs) const {
@@ -70,56 +88,56 @@
   return ref() != rhs.ref();
 }
 
-MemoryRegionInfo &SBMemoryRegionInfo::ref() { return *m_opaque_up; }
+MemoryRegionInfo &SBMemoryRegionInfo::ref() { return *m_opaque_sp; }
 
-const MemoryRegionInfo &SBMemoryRegionInfo::ref() const { return *m_opaque_up; }
+const MemoryRegionInfo &SBMemoryRegionInfo::ref() const { return *m_opaque_sp; }
 
 lldb::addr_t SBMemoryRegionInfo::GetRegionBase() {
   LLDB_RECORD_METHOD_NO_ARGS(lldb::addr_t, SBMemoryRegionInfo, GetRegionBase);
 
-  return m_opaque_up->GetRange().GetRangeBase();
+  return m_opaque_sp->GetRange().GetRangeBase();
 }
 
 lldb::addr_t SBMemoryRegionInfo::GetRegionEnd() {
   LLDB_RECORD_METHOD_NO_ARGS(lldb::addr_t, SBMemoryRegionInfo, GetRegionEnd);
 
-  return m_opaque_up->GetRange().GetRangeEnd();
+  return m_opaque_sp->GetRange().GetRangeEnd();
 }
 
 bool SBMemoryRegionInfo::IsReadable() {
   LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, IsReadable);
 
-  return m_opaque_up->GetReadable() == MemoryRegionInfo::eYes;
+  return m_opaque_sp->GetReadable() == MemoryRegionInfo::eYes;
 }
 
 bool SBMemoryRegionInfo::IsWritable() {
   LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, IsWritable);
 
-  return m_opaque_up->GetWritable() == MemoryRegionInfo::eYes;
+  return m_opaque_sp->GetWritable() == MemoryRegionInfo::eYes;
 }
 
 bool SBMemoryRegionInfo::IsExecutable() {
   LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, IsExecutable);
 
-  return m_opaque_up->GetExecutable() == MemoryRegionInfo::eYes;
+  return m_opaque_sp->GetExecutable() == MemoryRegionInfo::eYes;
 }
 
 bool SBMemoryRegionInfo::IsMapped() {
   LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, IsMapped);
 
-  return m_opaque_up->GetMapped() == MemoryRegionInfo::eYes;
+  return m_opaque_sp->GetMapped() == MemoryRegionInfo::eYes;
 }
 
 const char *SBMemoryRegionInfo::GetName() {
   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBMemoryRegionInfo, GetName);
 
-  return m_opaque_up->GetName().AsCString();
+  return m_opaque_sp->GetName().AsCString();
 }
 
 bool SBMemoryRegionInfo::HasDirtyMemoryPageList() {
   LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, HasDirtyMemoryPageList);
 
-  return m_opaque_up->GetDirtyPageList().hasValue();
+  return m_opaque_sp->GetDirtyPageList().hasValue();
 }
 
 uint32_t SBMemoryRegionInfo::GetNumDirtyPages() {
@@ -127,7 +145,7 @@
 
   uint32_t num_dirty_pages = 0;
   llvm::Optional<std::vector<addr_t>> dirty_page_list =
-      m_opaque_up->GetDirtyPageList();
+      m_opaque_sp->GetDirtyPageList();
   if (dirty_page_list.hasValue())
     num_dirty_pages = dirty_page_list.getValue().size();
 
@@ -140,7 +158,7 @@
 
   addr_t dirty_page_addr = LLDB_INVALID_ADDRESS;
   const llvm::Optional<std::vector<addr_t>> &dirty_page_list =
-      m_opaque_up->GetDirtyPageList();
+      m_opaque_sp->GetDirtyPageList();
   if (dirty_page_list.hasValue() && idx < dirty_page_list.getValue().size())
     dirty_page_addr = dirty_page_list.getValue()[idx];
 
@@ -150,7 +168,7 @@
 int SBMemoryRegionInfo::GetPageSize() {
   LLDB_RECORD_METHOD_NO_ARGS(int, SBMemoryRegionInfo, GetPageSize);
 
-  return m_opaque_up->GetPageSize();
+  return m_opaque_sp->GetPageSize();
 }
 
 bool SBMemoryRegionInfo::GetDescription(SBStream &description) {
@@ -158,13 +176,13 @@
                      (lldb::SBStream &), description);
 
   Stream &strm = description.ref();
-  const addr_t load_addr = m_opaque_up->GetRange().base;
+  const addr_t load_addr = m_opaque_sp->GetRange().base;
 
   strm.Printf("[0x%16.16" PRIx64 "-0x%16.16" PRIx64 " ", load_addr,
-              load_addr + m_opaque_up->GetRange().size);
-  strm.Printf(m_opaque_up->GetReadable() ? "R" : "-");
-  strm.Printf(m_opaque_up->GetWritable() ? "W" : "-");
-  strm.Printf(m_opaque_up->GetExecutable() ? "X" : "-");
+              load_addr + m_opaque_sp->GetRange().size);
+  strm.Printf(m_opaque_sp->GetReadable() ? "R" : "-");
+  strm.Printf(m_opaque_sp->GetWritable() ? "W" : "-");
+  strm.Printf(m_opaque_sp->GetExecutable() ? "X" : "-");
   strm.Printf("]");
 
   return true;
@@ -178,6 +196,9 @@
   LLDB_REGISTER_CONSTRUCTOR(SBMemoryRegionInfo, ());
   LLDB_REGISTER_CONSTRUCTOR(SBMemoryRegionInfo,
                             (const lldb::SBMemoryRegionInfo &));
+  LLDB_REGISTER_CONSTRUCTOR(
+      SBMemoryRegionInfo,
+      (const char *, lldb::addr_t, lldb::addr_t, uint32_t, bool, bool));
   LLDB_REGISTER_METHOD(
       const lldb::SBMemoryRegionInfo &,
       SBMemoryRegionInfo, operator=,(const lldb::SBMemoryRegionInfo &));
Index: lldb/include/lldb/Interpreter/ScriptInterpreter.h
===================================================================
--- lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -11,6 +11,7 @@
 
 #include "lldb/API/SBData.h"
 #include "lldb/API/SBError.h"
+#include "lldb/API/SBMemoryRegionInfo.h"
 #include "lldb/Breakpoint/BreakpointOptions.h"
 #include "lldb/Core/Communication.h"
 #include "lldb/Core/PluginInterface.h"
@@ -564,6 +565,9 @@
 
   Status GetStatusFromSBError(const lldb::SBError &error) const;
 
+  lldb::MemoryRegionInfoSP GetOpaquePtrFromSBMemoryRegionInfo(
+      const lldb::SBMemoryRegionInfo &mem_region) const;
+
 protected:
   Debugger &m_debugger;
   lldb::ScriptLanguage m_script_lang;
Index: lldb/include/lldb/API/SBMemoryRegionInfoList.h
===================================================================
--- lldb/include/lldb/API/SBMemoryRegionInfoList.h
+++ lldb/include/lldb/API/SBMemoryRegionInfoList.h
@@ -27,6 +27,9 @@
 
   uint32_t GetSize() const;
 
+  bool GetMemoryRegionContainingAddress(lldb::addr_t addr,
+                                        SBMemoryRegionInfo &region_info);
+
   bool GetMemoryRegionAtIndex(uint32_t idx, SBMemoryRegionInfo &region_info);
 
   void Append(lldb::SBMemoryRegionInfo &region);
Index: lldb/include/lldb/API/SBMemoryRegionInfo.h
===================================================================
--- lldb/include/lldb/API/SBMemoryRegionInfo.h
+++ lldb/include/lldb/API/SBMemoryRegionInfo.h
@@ -20,6 +20,10 @@
 
   SBMemoryRegionInfo(const lldb::SBMemoryRegionInfo &rhs);
 
+  SBMemoryRegionInfo(const char *name, lldb::addr_t begin, lldb::addr_t end,
+                     uint32_t permissions, bool mapped,
+                     bool stack_memory = false);
+
   ~SBMemoryRegionInfo();
 
   const lldb::SBMemoryRegionInfo &
@@ -117,6 +121,8 @@
   friend class SBProcess;
   friend class SBMemoryRegionInfoList;
 
+  friend class lldb_private::ScriptInterpreter;
+
   lldb_private::MemoryRegionInfo &ref();
 
   const lldb_private::MemoryRegionInfo &ref() const;
@@ -124,7 +130,7 @@
   // Unused.
   SBMemoryRegionInfo(const lldb_private::MemoryRegionInfo *lldb_object_ptr);
 
-  lldb::MemoryRegionInfoUP m_opaque_up;
+  lldb::MemoryRegionInfoSP m_opaque_sp;
 };
 
 } // namespace lldb
Index: lldb/examples/python/scripted_process/my_scripted_process.py
===================================================================
--- lldb/examples/python/scripted_process/my_scripted_process.py
+++ lldb/examples/python/scripted_process/my_scripted_process.py
@@ -7,11 +7,22 @@
 from lldb.plugins.scripted_process import ScriptedThread
 
 class MyScriptedProcess(ScriptedProcess):
+    memory_regions = [
+        lldb.SBMemoryRegionInfo("stack", 0x1040b2000, 0x1040b4000, 0b110, True,
+                                True)
+    ]
+
+    stack_memory_dump = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                     'main.stack-dump')
+
     def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
         super().__init__(target, args)
 
     def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
-        return self.memory_regions[0]
+        for region in self.memory_regions:
+            if region.GetRegionBase() <= addr < region.GetRegionEnd():
+                return region
+        return None
 
     def get_thread_with_id(self, tid: int):
         return {}
@@ -20,10 +31,25 @@
         return {}
 
     def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData:
-        data = lldb.SBData().CreateDataFromCString(
+        data = lldb.SBData()
+
+        with open(self.stack_memory_dump, 'rb') as f:
+            stack_mem = f.read(-1)
+            if not stack_mem:
+                return data
+
+            mem_region = self.get_memory_region_containing_address(addr)
+
+            if not mem_region or addr + size > mem_region.GetRegionEnd():
+                return data
+
+            offset = addr - mem_region.GetRegionBase()
+            shrunk_stack_mem = stack_mem[offset:offset + size]
+
+            error = lldb.SBError()
+            data.SetData(error, shrunk_stack_mem,
                                     self.target.GetByteOrder(),
-                                    self.target.GetCodeByteSize(),
-                                    "Hello, world!")
+                                    self.target.GetAddressByteSize())
         return data
 
     def get_loaded_images(self):
@@ -43,6 +69,30 @@
 
 
 class MyScriptedThread(ScriptedThread):
+    registers = {
+        "rax":0x00000000000006e4,
+        "rbx":0x00000001040b6060,
+        "rcx":0x00000001040b2e00,
+        "rdx":0x00000001040b2ba8,
+        "rdi":0x000000000000002a,
+        "rsi":0x00000001040b2b98,
+        "rbp":0x00000001040b2a20,
+        "rsp":0x00000001040b2a20,
+        "r8":0x00000000003e131e,
+        "r9":0xffffffff00000000,
+        "r10":0x0000000000000000,
+        "r11":0x0000000000000246,
+        "r12":0x000000010007c3a0,
+        "r13":0x00000001040b2b18,
+        "r14":0x0000000100003f90,
+        "r15":0x00000001040b2b88,
+        "rip":0x0000000100003f61,
+        "rflags":0x0000000000000206,
+        "cs":0x000000000000002b,
+        "fs":0x0000000000000000,
+        "gs":0x0000000000000000,
+    }
+
     def __init__(self, target):
         super().__init__(target)
 
@@ -76,8 +126,7 @@
         return self.frame_zero[0:0]
 
     def get_register_context(self) -> str:
-        return struct.pack(
-                '21Q', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
+        return struct.pack(f"{len(self.registers)}Q", *self.registers.values())
 
 
 def __lldb_init_module(debugger, dict):
Index: lldb/bindings/python/python-wrapper.swig
===================================================================
--- lldb/bindings/python/python-wrapper.swig
+++ 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<PythonDictionary>(session_dictionary_name);
Index: lldb/bindings/interface/SBMemoryRegionInfoList.i
===================================================================
--- lldb/bindings/interface/SBMemoryRegionInfoList.i
+++ lldb/bindings/interface/SBMemoryRegionInfoList.i
@@ -24,6 +24,9 @@
     uint32_t
     GetSize () const;
 
+    bool
+    GetMemoryRegionContainingAddress (lldb::addr_t addr, SBMemoryRegionInfo &region_info);
+
     bool
     GetMemoryRegionAtIndex (uint32_t idx, SBMemoryRegionInfo &region_info);
 
Index: lldb/bindings/interface/SBMemoryRegionInfo.i
===================================================================
--- lldb/bindings/interface/SBMemoryRegionInfo.i
+++ lldb/bindings/interface/SBMemoryRegionInfo.i
@@ -20,6 +20,9 @@
 
     SBMemoryRegionInfo (const lldb::SBMemoryRegionInfo &rhs);
 
+    SBMemoryRegionInfo::SBMemoryRegionInfo(const char *name, lldb::addr_t begin,
+    lldb::addr_t end, uint32_t permissions, bool mapped, bool stack_memory);
+
     ~SBMemoryRegionInfo ();
 
     void
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to