mib updated this revision to Diff 370261.
mib added a comment.

Tighten PythonInterpreter Lock.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D107585

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/examples/python/scripted_process/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/ScriptedProcessInterface.h
  lldb/include/lldb/lldb-forward.h
  lldb/source/API/SBMemoryRegionInfo.cpp
  lldb/source/API/SBMemoryRegionInfoList.cpp
  lldb/source/Interpreter/ScriptInterpreter.cpp
  lldb/source/Plugins/Process/scripted/CMakeLists.txt
  lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
  lldb/source/Plugins/Process/scripted/ScriptedProcess.h
  lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
  lldb/source/Plugins/Process/scripted/ScriptedThread.h
  lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
  lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
  
lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.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/ScriptedThreadPythonInterface.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.h
@@ -0,0 +1,49 @@
+//===-- ScriptedThreadPythonInterface.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_SCRIPTEDTHREADPYTHONINTERFACE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDTHREADPYTHONINTERFACE_H
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
+
+#include "ScriptedPythonInterface.h"
+#include "lldb/Interpreter/ScriptedProcessInterface.h"
+
+namespace lldb_private {
+class ScriptedThreadPythonInterface : public ScriptedThreadInterface,
+                                      public ScriptedPythonInterface {
+public:
+  ScriptedThreadPythonInterface(ScriptInterpreterPythonImpl &interpreter);
+
+  StructuredData::GenericSP
+  CreatePluginObject(const llvm::StringRef class_name,
+                     ExecutionContext &exe_ctx,
+                     StructuredData::DictionarySP args_sp) override;
+
+  lldb::tid_t GetThreadID() override;
+
+  llvm::Optional<std::string> GetName() override;
+
+  lldb::StateType GetState() override;
+
+  llvm::Optional<std::string> GetQueue() override;
+
+  StructuredData::DictionarySP GetStopReason() override;
+
+  StructuredData::ArraySP GetStackFrames() override;
+
+  StructuredData::DictionarySP GetRegisterInfo() override;
+
+  llvm::Optional<std::string> GetRegisterContext() override;
+};
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPROCESSTHREADINTERFACE_H
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
@@ -0,0 +1,205 @@
+//===-- ScriptedThreadPythonInterface.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 "ScriptedThreadPythonInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ScriptedThreadPythonInterface::ScriptedThreadPythonInterface(
+    ScriptInterpreterPythonImpl &interpreter)
+    : ScriptedThreadInterface(), ScriptedPythonInterface(interpreter) {}
+
+StructuredData::GenericSP ScriptedThreadPythonInterface::CreatePluginObject(
+    const 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();
+
+  Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+                 Locker::FreeLock);
+
+  void *ret_val = LLDBSwigPythonCreateScriptedThread(
+      class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp,
+      error_string);
+
+  if (!ret_val)
+    return {};
+
+  m_object_instance_sp =
+      StructuredData::GenericSP(new StructuredPythonObject(ret_val));
+
+  return m_object_instance_sp;
+}
+
+lldb::tid_t ScriptedThreadPythonInterface::GetThreadID() {
+  Status error;
+  StructuredData::ObjectSP obj = Dispatch("get_thread_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_THREAD_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_THREAD_ID);
+}
+
+llvm::Optional<std::string> ScriptedThreadPythonInterface::GetName() {
+  Status error;
+  StructuredData::ObjectSP obj = Dispatch("get_name", error);
+
+  auto error_with_message = [](llvm::StringRef message) {
+    LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+              "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+    return llvm::None;
+  };
+
+  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->GetStringValue().str();
+}
+
+lldb::StateType ScriptedThreadPythonInterface::GetState() {
+  Status error;
+  StructuredData::ObjectSP obj = Dispatch("get_state", error);
+
+  auto error_with_message = [](llvm::StringRef message) {
+    LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+              "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+    return eStateInvalid;
+  };
+
+  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<StateType>(obj->GetIntegerValue(eStateInvalid));
+}
+
+llvm::Optional<std::string> ScriptedThreadPythonInterface::GetQueue() {
+  Status error;
+  StructuredData::ObjectSP obj = Dispatch("get_queue", error);
+
+  auto error_with_message = [](llvm::StringRef message) {
+    LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+              "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+    return llvm::None;
+  };
+
+  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->GetStringValue().str();
+}
+
+StructuredData::DictionarySP ScriptedThreadPythonInterface::GetStopReason() {
+  Status error;
+  StructuredData::DictionarySP dict =
+      Dispatch<StructuredData::DictionarySP>("get_stop_reason", error);
+
+  auto error_with_message = [](llvm::StringRef message) {
+    LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+              "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+    return StructuredData::DictionarySP();
+  };
+
+  if (!dict || !dict->IsValid() || error.Fail()) {
+    return error_with_message(llvm::Twine("Null or invalid object (" +
+                                          llvm::Twine(error.AsCString()) +
+                                          llvm::Twine(")."))
+                                  .str());
+  }
+
+  return dict;
+}
+
+StructuredData::ArraySP ScriptedThreadPythonInterface::GetStackFrames() {
+  return nullptr;
+}
+
+StructuredData::DictionarySP ScriptedThreadPythonInterface::GetRegisterInfo() {
+  Status error;
+  StructuredData::DictionarySP dict =
+      Dispatch<StructuredData::DictionarySP>("get_register_info", error);
+
+  auto error_with_message = [](llvm::StringRef message) {
+    LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+              "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+    return StructuredData::DictionarySP();
+  };
+
+  if (!dict || !dict->IsValid() || error.Fail()) {
+    return error_with_message(llvm::Twine("Null or invalid object (" +
+                                          llvm::Twine(error.AsCString()) +
+                                          llvm::Twine(")."))
+                                  .str());
+  }
+
+  return dict;
+}
+
+llvm::Optional<std::string>
+ScriptedThreadPythonInterface::GetRegisterContext() {
+  Status error;
+  StructuredData::ObjectSP obj = Dispatch("get_register_context", error);
+
+  auto error_with_message = [](llvm::StringRef message) {
+    LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+              "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+    return llvm::None;
+  };
+
+  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->GetAsString()->GetValue().str();
+}
+
+#endif
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
@@ -50,6 +50,11 @@
   lldb::pid_t GetProcessID() override;
 
   bool IsAlive() override;
+
+  llvm::Optional<std::string> GetScriptedThreadPluginName() override;
+
+private:
+  lldb::ScriptedThreadInterfaceSP GetScriptedThreadInterface() override;
 };
 } // namespace lldb_private
 
Index: lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -13,6 +13,7 @@
   ScriptInterpreterPython.cpp
   ScriptedPythonInterface.cpp
   ScriptedProcessPythonInterface.cpp
+  ScriptedThreadPythonInterface.cpp
   SWIGPythonBridge.cpp
 
   LINK_LIBS
Index: lldb/source/Plugins/Process/scripted/ScriptedThread.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/scripted/ScriptedThread.h
@@ -0,0 +1,71 @@
+//===-- ScriptedThread.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_SOURCE_PLUGINS_SCRIPTED_THREAD_H
+#define LLDB_SOURCE_PLUGINS_SCRIPTED_THREAD_H
+
+#include <string>
+
+#include "ScriptedProcess.h"
+
+#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
+#include "Plugins/Process/Utility/RegisterContextMemory.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/Thread.h"
+
+namespace lldb_private {
+class ScriptedProcess;
+}
+
+namespace lldb_private {
+
+class ScriptedThread : public lldb_private::Thread {
+public:
+  ScriptedThread(ScriptedProcess &process, Status &error);
+
+  ~ScriptedThread() override;
+
+  lldb::RegisterContextSP GetRegisterContext() override;
+
+  lldb::RegisterContextSP
+  CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+  bool CalculateStopInfo() override;
+
+  const char *GetInfo() override { return nullptr; }
+
+  const char *GetName() override;
+
+  const char *GetQueueName() override;
+
+  void WillResume(lldb::StateType resume_state) override;
+
+  void RefreshStateAfterStop() override;
+
+  void ClearStackFrames() override;
+
+private:
+  void CheckInterpreterAndScriptObject() const;
+  lldb::ScriptedThreadInterfaceSP GetInterface() const;
+
+  ScriptedThread(const ScriptedThread &) = delete;
+  const ScriptedThread &operator=(const ScriptedThread &) = delete;
+
+  std::shared_ptr<DynamicRegisterInfo> GetDynamicRegisterInfo();
+
+  const ScriptedProcess &m_scripted_process;
+  std::string m_name;
+  std::string m_queue;
+  lldb::StopInfoSP m_cached_stop_info_sp = nullptr;
+  std::shared_ptr<DynamicRegisterInfo> m_register_info_sp = nullptr;
+  lldb_private::StructuredData::ObjectSP m_script_object_sp = nullptr;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_THREAD_H
Index: lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -0,0 +1,230 @@
+//===-- ScriptedThread.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 "ScriptedThread.h"
+
+#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+void ScriptedThread::CheckInterpreterAndScriptObject() const {
+  lldbassert(m_script_object_sp && "Invalid Script Object.");
+  lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
+}
+
+ScriptedThread::ScriptedThread(ScriptedProcess &process, Status &error)
+    : Thread(process, LLDB_INVALID_THREAD_ID), m_scripted_process(process),
+      m_name(), m_queue() {
+
+  auto error_with_message = [&](llvm::StringRef message) {
+    error.SetErrorStringWithFormat("ScriptedThread::%s () - ERROR: %s",
+                                   __FUNCTION__, message.data());
+  };
+
+  if (!process.IsValid()) {
+    error_with_message("Invalid scripted process");
+    return;
+  }
+
+  process.CheckInterpreterAndScriptObject();
+
+  auto scripted_thread_interface = GetInterface();
+  if (!scripted_thread_interface) {
+    error_with_message("Failed to get scripted thread interface.");
+    return;
+  }
+
+  llvm::Optional<std::string> class_name =
+      process.GetInterface().GetScriptedThreadPluginName();
+  if (!class_name || class_name->empty()) {
+    error_with_message("Failed to get scripted thread class name.");
+    return;
+  }
+
+  ExecutionContext exe_ctx(process);
+
+  StructuredData::GenericSP object_sp =
+      scripted_thread_interface->CreatePluginObject(
+          class_name->c_str(), exe_ctx,
+          process.m_scripted_process_info.GetDictionarySP());
+  if (!object_sp || !object_sp->IsValid()) {
+    error_with_message("Failed to create valid script object");
+    return;
+  }
+
+  m_script_object_sp = object_sp;
+
+  SetID(scripted_thread_interface->GetThreadID());
+
+  llvm::Optional<std::string> reg_data =
+      scripted_thread_interface->GetRegisterContext();
+  if (!reg_data) {
+    error_with_message("Failed to get scripted thread registers data.");
+    return;
+  }
+
+  DataBufferSP data_sp(
+      std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
+
+  if (!data_sp->GetByteSize()) {
+    error_with_message("Failed to copy raw registers data.");
+    return;
+  }
+
+  std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
+      std::make_shared<RegisterContextMemory>(
+          *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
+  if (!reg_ctx_memory) {
+    error_with_message("Failed to create a register context.");
+    return;
+  }
+
+  reg_ctx_memory->SetAllRegisterData(data_sp);
+  m_reg_context_sp = reg_ctx_memory;
+}
+
+ScriptedThread::~ScriptedThread() { DestroyThread(); }
+
+const char *ScriptedThread::GetName() {
+  if (m_name.empty()) {
+    CheckInterpreterAndScriptObject();
+    llvm::Optional<std::string> thread_name = GetInterface()->GetName();
+    if (!thread_name)
+      return nullptr;
+    m_name = *thread_name;
+  }
+  return m_name.c_str();
+}
+
+const char *ScriptedThread::GetQueueName() {
+  if (m_queue.empty()) {
+    CheckInterpreterAndScriptObject();
+    llvm::Optional<std::string> queue_name = GetInterface()->GetQueue();
+    if (!queue_name)
+      return nullptr;
+    m_queue = *queue_name;
+  }
+  return m_queue.c_str();
+}
+
+void ScriptedThread::WillResume(StateType resume_state) {}
+
+void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
+
+RegisterContextSP ScriptedThread::GetRegisterContext() {
+  if (!m_reg_context_sp) {
+    m_reg_context_sp = std::make_shared<RegisterContextThreadMemory>(
+        *this, LLDB_INVALID_ADDRESS);
+    GetInterface()->GetRegisterContext();
+  }
+  return m_reg_context_sp;
+}
+
+RegisterContextSP
+ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
+  uint32_t concrete_frame_idx = 0;
+
+  if (frame)
+    concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+  if (concrete_frame_idx == 0)
+    return GetRegisterContext();
+  return GetUnwinder().CreateRegisterContextForFrame(frame);
+}
+
+bool ScriptedThread::CalculateStopInfo() {
+  auto error_with_message = [](llvm::StringRef message) {
+    LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+              "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+    return false;
+  };
+
+  if (m_cached_stop_info_sp) {
+    SetStopInfo(m_cached_stop_info_sp);
+  } else {
+    StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
+
+    lldb::StopReason stop_reason_type;
+
+    if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
+      return error_with_message(
+          "Couldn't find value for key 'type' in stop reason dictionary.");
+
+    StructuredData::Dictionary *data_dict;
+    if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
+      return error_with_message(
+          "Couldn't find value for key 'type' in stop reason dictionary.");
+
+    switch (stop_reason_type) {
+    case lldb::eStopReasonNone:
+      m_cached_stop_info_sp.reset();
+      break;
+    case lldb::eStopReasonBreakpoint: {
+      lldb::break_id_t break_id;
+      data_dict->GetValueForKeyAsInteger("break_id", break_id,
+                                         LLDB_INVALID_BREAK_ID);
+      m_cached_stop_info_sp =
+          StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
+    } break;
+    case lldb::eStopReasonSignal: {
+      int signal;
+      llvm::StringRef description;
+      data_dict->GetValueForKeyAsInteger("signal", signal,
+                                         LLDB_INVALID_SIGNAL_NUMBER);
+      data_dict->GetValueForKeyAsString("desc", description);
+      m_cached_stop_info_sp = StopInfo::CreateStopReasonWithSignal(
+          *this, signal, description.data());
+    } break;
+    default:
+      return error_with_message(llvm::Twine("Unsupported stop reason type (" +
+                                            llvm::Twine(stop_reason_type) +
+                                            llvm::Twine(")."))
+                                    .str());
+    }
+  }
+  SetStopInfo(m_cached_stop_info_sp);
+  return true;
+}
+
+void ScriptedThread::RefreshStateAfterStop() {
+  // TODO: Implement
+  if (m_reg_context_sp)
+    m_reg_context_sp->InvalidateAllRegisters();
+}
+
+lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
+  return m_scripted_process.GetInterface().GetScriptedThreadInterface();
+}
+
+std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
+  CheckInterpreterAndScriptObject();
+
+  if (!m_register_info_sp) {
+    StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
+    if (!reg_info)
+      return nullptr;
+
+    m_register_info_sp = std::make_shared<DynamicRegisterInfo>(
+        *reg_info, m_scripted_process.GetTarget().GetArchitecture());
+    assert(m_register_info_sp->GetNumRegisters() > 0);
+    assert(m_register_info_sp->GetNumRegisterSets() > 0);
+  }
+
+  return m_register_info_sp;
+}
Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.h
===================================================================
--- lldb/source/Plugins/Process/scripted/ScriptedProcess.h
+++ lldb/source/Plugins/Process/scripted/ScriptedProcess.h
@@ -13,6 +13,8 @@
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/Status.h"
 
+#include "ScriptedThread.h"
+
 #include <mutex>
 
 namespace lldb_private {
@@ -103,6 +105,8 @@
                           ThreadList &new_thread_list) override;
 
 private:
+  friend class ScriptedThread;
+
   void CheckInterpreterAndScriptObject() const;
   ScriptedProcessInterface &GetInterface() const;
   static bool IsScriptLanguageSupported(lldb::ScriptLanguage language);
Index: lldb/source/Plugins/Process/scripted/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Process/scripted/CMakeLists.txt
+++ lldb/source/Plugins/Process/scripted/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_lldb_library(lldbPluginScriptedProcess PLUGIN
   ScriptedProcess.cpp
+  ScriptedThread.cpp
 
   LINK_LIBS
     lldbCore
Index: lldb/include/lldb/lldb-forward.h
===================================================================
--- lldb/include/lldb/lldb-forward.h
+++ lldb/include/lldb/lldb-forward.h
@@ -175,6 +175,7 @@
 class ScriptInterpreter;
 class ScriptInterpreterLocker;
 class ScriptedProcessInterface;
+class ScriptedThreadInterface;
 class ScriptedSyntheticChildren;
 class SearchFilter;
 class Section;
@@ -395,6 +396,8 @@
 typedef std::unique_ptr<lldb_private::ScriptInterpreter> ScriptInterpreterUP;
 typedef std::unique_ptr<lldb_private::ScriptedProcessInterface>
     ScriptedProcessInterfaceUP;
+typedef std::shared_ptr<lldb_private::ScriptedThreadInterface>
+    ScriptedThreadInterfaceSP;
 typedef std::shared_ptr<lldb_private::Section> SectionSP;
 typedef std::unique_ptr<lldb_private::SectionList> SectionListUP;
 typedef std::weak_ptr<lldb_private::Section> SectionWP;
Index: lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
===================================================================
--- lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
+++ lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
@@ -57,6 +57,46 @@
   virtual lldb::pid_t GetProcessID() { return LLDB_INVALID_PROCESS_ID; }
 
   virtual bool IsAlive() { return true; }
+
+  virtual llvm::Optional<std::string> GetScriptedThreadPluginName() {
+    return llvm::None;
+  }
+
+protected:
+  friend class ScriptedThread;
+  virtual lldb::ScriptedThreadInterfaceSP GetScriptedThreadInterface() {
+    return nullptr;
+  }
+
+  lldb::ScriptedThreadInterfaceSP m_scripted_thread_interface_sp = nullptr;
+};
+
+class ScriptedThreadInterface : virtual public ScriptedInterface {
+public:
+  StructuredData::GenericSP
+  CreatePluginObject(const llvm::StringRef class_name,
+                     ExecutionContext &exe_ctx,
+                     StructuredData::DictionarySP args_sp) override {
+    return nullptr;
+  }
+
+  virtual lldb::tid_t GetThreadID() { return LLDB_INVALID_THREAD_ID; }
+
+  virtual llvm::Optional<std::string> GetName() { return llvm::None; }
+
+  virtual lldb::StateType GetState() { return lldb::eStateInvalid; }
+
+  virtual llvm::Optional<std::string> GetQueue() { return llvm::None; }
+
+  virtual StructuredData::DictionarySP GetStopReason() { return nullptr; }
+
+  virtual StructuredData::ArraySP GetStackFrames() { return nullptr; }
+
+  virtual StructuredData::DictionarySP GetRegisterInfo() { return nullptr; }
+
+  virtual llvm::Optional<std::string> GetRegisterContext() {
+    return llvm::None;
+  }
 };
 } // namespace lldb_private
 
Index: lldb/examples/python/scripted_process/scripted_process.py
===================================================================
--- lldb/examples/python/scripted_process/scripted_process.py
+++ lldb/examples/python/scripted_process/scripted_process.py
@@ -163,3 +163,163 @@
             bool: True if scripted process is alive. False otherwise.
         """
         pass
+
+    @abstractmethod
+    def get_scripted_thread_plugin(self):
+        """ Get scripted thread plugin name.
+
+        Returns:
+            str: Name of the scripted thread plugin.
+        """
+        return None
+
+@six.add_metaclass(ABCMeta)
+class ScriptedThread:
+
+    """
+    The base class for a scripted thread.
+
+    Most of the base class methods are `@abstractmethod` that need to be
+    overwritten by the inheriting class.
+
+    DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE.
+                THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE.
+    """
+
+    @abstractmethod
+    def __init__(self, target):
+        """ Construct a scripted thread.
+
+        Args:
+            target (lldb.SBTarget): The target launching the scripted process.
+            args (lldb.SBStructuredData): A Dictionary holding arbitrary
+                key/value pairs used by the scripted process.
+        """
+        self.target = None
+        self.args = None
+        if isinstance(target, lldb.SBTarget) and target.IsValid():
+            self.target = target
+
+        self.id = None
+        self.name = None
+        self.queue = None
+        self.state = None
+        self.stop_reason = None
+        self.register_info = None
+        self.register_ctx = []
+        self.frames = []
+
+    @abstractmethod
+    def get_thread_id(self):
+        """ Get the scripted thread identifier.
+
+        Returns:
+            int: The identifier of the scripted thread.
+        """
+        pass
+
+    @abstractmethod
+    def get_name(self):
+        """ Get the scripted thread name.
+
+        Returns:
+            str: The name of the scripted thread.
+        """
+        pass
+
+    @abstractmethod
+    def get_state(self):
+        """ Get the scripted thread state type.
+
+            eStateStopped,   ///< Process or thread is stopped and can be examined.
+            eStateRunning,   ///< Process or thread is running and can't be examined.
+            eStateStepping,  ///< Process or thread is in the process of stepping and can
+                             /// not be examined.
+
+        Returns:
+            int: The state type of the scripted thread.
+        """
+        pass
+
+    # @abstractmethod
+    def get_queue(self):
+        """ Get the scripted thread associated queue name.
+
+        Returns:
+            str: The queue name associated with the scripted thread.
+        """
+        pass
+
+    # @abstractmethod
+    def get_stop_reason(self):
+        """ Get the dictionary describing the stop reason type with some data.
+
+        Returns:
+            Dict: The dictionary holding the stop reason type and the possibly
+            the stop reason data.
+        """
+        pass
+
+    # @abstractmethod
+    def get_stackframes(self):
+        """ Get the list of stack frames for the scripted thread.
+
+        ```
+        class ScriptedStackFrame:
+            def __init__(idx, cfa, pc, symbol_ctx):
+                self.idx = idx
+                self.cfa = cfa
+                self.pc = pc
+                self.symbol_ctx = symbol_ctx
+        ```
+
+        Returns:
+            List[ScriptedFrame]: A list of `ScriptedStackFrame`
+                containing for each entry, the frame index, the canonical
+                frame address, the program counter value for that frame
+                and a symbol context.
+                None if the list is empty.
+        """
+        return 0
+
+    def get_register_info(self):
+        if self.register_info is None:
+            self.register_info = dict()
+            triple = self.target.triple
+            if triple:
+                arch = triple.split('-')[0]
+                if arch == 'x86_64':
+                    self.register_info['sets'] = ['GPR', 'FPU', 'EXC']
+                    self.register_info['registers'] = [
+                        {'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0},
+                        {'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3},
+                        {'name': 'rcx', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg4', 'alt-name': 'arg4', },
+                        {'name': 'rdx', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg3', 'alt-name': 'arg3', },
+                        {'name': 'rdi', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg1', 'alt-name': 'arg1', },
+                        {'name': 'rsi', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg2', 'alt-name': 'arg2', },
+                        {'name': 'rbp', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'fp', 'alt-name': 'fp', },
+                        {'name': 'rsp', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'sp', 'alt-name': 'sp', },
+                        {'name': 'r8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8, 'generic': 'arg5', 'alt-name': 'arg5', },
+                        {'name': 'r9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9, 'generic': 'arg6', 'alt-name': 'arg6', },
+                        {'name': 'r10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10},
+                        {'name': 'r11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11},
+                        {'name': 'r12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12},
+                        {'name': 'r13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13},
+                        {'name': 'r14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14},
+                        {'name': 'r15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15},
+                        {'name': 'rip', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16, 'generic': 'pc', 'alt-name': 'pc'},
+                        {'name': 'rflags', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'generic': 'flags', 'alt-name': 'flags'},
+                        {'name': 'cs', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0},
+                        {'name': 'fs', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0},
+                        {'name': 'gs', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0},
+                    ]
+        return self.register_info
+
+    @abstractmethod
+    def get_register_context(self):
+        """ Get the scripted thread register context
+
+        Returns:
+            str: A byte representing all register's value.
+        """
+        pass
Index: lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
===================================================================
--- lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -223,6 +223,12 @@
   return nullptr;
 }
 
+extern "C" void *LLDBSwigPythonCreateScriptedThread(
+    const char *python_class_name, const char *session_dictionary_name,
+    const lldb::TargetSP &target_sp, std::string &error_string) {
+  return nullptr;
+}
+
 extern "C" void *
 LLDBSWIGPython_CreateFrameRecognizer(const char *python_class_name,
                                      const char *session_dictionary_name) {
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
@@ -72,6 +72,28 @@
         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.GetStopReason(), lldb.eStopReasonSignal)
+
+        self.assertGreater(thread.GetNumFrames(), 0)
+
+        frame = thread.GetFrameAtIndex(0)
+        register_set = frame.registers # Returns an SBValueList.
+        for regs in register_set:
+            if 'GPR' in regs.name:
+                registers  = regs
+                break
+
+        self.assertTrue(registers, "Invalid General Purpose Registers Set")
+        self.assertEqual(registers.GetNumChildren(), 21)
+        for idx, reg in enumerate(registers, start=1):
+            self.assertEqual(idx, int(reg.value, 16))
+
     def test_launch_scripted_process_cli(self):
         """Test that we can launch an lldb scripted process from the command
         line, check its process ID and read string from memory."""
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
@@ -33,6 +33,14 @@
     return p.CreateStructuredObject();
   }
 
+  template <>
+  StructuredData::DictionarySP
+  ExtractValueFromPythonObject<StructuredData::DictionarySP>(
+      python::PythonObject &p, Status &error) {
+    python::PythonDictionary result_dict(python::PyRefType::Borrowed, p.get());
+    return result_dict.CreateStructuredDictionary();
+  }
+
   template <>
   Status ExtractValueFromPythonObject<Status>(python::PythonObject &p,
                                               Status &error) {
@@ -53,7 +61,8 @@
         LLDBSWIGPython_CastPyObjectToSBData(p.get()));
 
     if (!sb_data) {
-      error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status.");
+      error.SetErrorString(
+          "Couldn't cast lldb::SBData to lldb::DataExtractorSP.");
       return nullptr;
     }
 
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
@@ -19,6 +19,7 @@
 #include "SWIGPythonBridge.h"
 #include "ScriptInterpreterPythonImpl.h"
 #include "ScriptedProcessPythonInterface.h"
+#include "ScriptedThreadPythonInterface.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -68,15 +69,15 @@
 }
 
 bool ScriptedProcessPythonInterface::ShouldStop() {
-  Status error;
-  StructuredData::ObjectSP obj = Dispatch("is_alive", error);
-
   auto error_with_message = [](llvm::StringRef message) {
     LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
               "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
     return false;
   };
 
+  Status error;
+  StructuredData::ObjectSP obj = Dispatch("is_alive", error);
+
   if (!obj || !obj->IsValid() || error.Fail()) {
     return error_with_message(llvm::Twine("Null or invalid object (" +
                                           llvm::Twine(error.AsCString()) +
@@ -100,9 +101,6 @@
 
 StructuredData::DictionarySP
 ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) {
-  Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
-                 Locker::FreeLock);
-
   auto error_with_message = [](llvm::StringRef message) {
     LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
               "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
@@ -181,4 +179,34 @@
   return obj->GetBooleanValue();
 }
 
+llvm::Optional<std::string>
+ScriptedProcessPythonInterface::GetScriptedThreadPluginName() {
+  Status error;
+  StructuredData::ObjectSP obj = Dispatch("get_scripted_thread_plugin", error);
+
+  auto error_with_message = [](llvm::StringRef message) {
+    LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+              "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+    return llvm::None;
+  };
+
+  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->GetStringValue().str();
+}
+
+lldb::ScriptedThreadInterfaceSP
+ScriptedProcessPythonInterface::GetScriptedThreadInterface() {
+  if (!m_scripted_thread_interface_sp)
+    m_scripted_thread_interface_sp =
+        std::make_shared<ScriptedThreadPythonInterface>(m_interpreter);
+
+  return m_scripted_thread_interface_sp;
+}
+
 #endif
Index: lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -46,6 +46,10 @@
     const lldb::TargetSP &target_sp, StructuredDataImpl *args_impl,
     std::string &error_string);
 
+extern "C" void *LLDBSwigPythonCreateScriptedThread(
+    const char *python_class_name, const char *session_dictionary_name,
+    const lldb::TargetSP &target_sp, std::string &error_string);
+
 extern "C" void *LLDBSWIGPython_CastPyObjectToSBData(void *data);
 extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data);
 extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data);
Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
===================================================================
--- lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -294,6 +294,33 @@
   // This is supposed to get the current set of threads, if any of them are in
   // old_thread_list then they get copied to new_thread_list, and then any
   // actually new threads will get added to new_thread_list.
+
+  CheckInterpreterAndScriptObject();
+
+  auto error_with_message = [](llvm::StringRef message) {
+    LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+              "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+    return false;
+  };
+
+  ScriptLanguage language = m_interpreter->GetLanguage();
+
+  if (language != eScriptLanguagePython)
+    return error_with_message(
+        (llvm::Twine("ScriptInterpreter language (") +
+         llvm::Twine(m_interpreter->LanguageToString(language)) +
+         llvm::Twine(") not supported."))
+            .str());
+
+  Status error;
+  lldb::ThreadSP thread_sp;
+  thread_sp = std::make_shared<ScriptedThread>(*this, error);
+
+  if (!thread_sp || error.Fail())
+    return error_with_message(error.AsCString());
+
+  new_thread_list.AddThread(thread_sp);
+
   return new_thread_list.GetSize(false) > 0;
 }
 
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
@@ -1,7 +1,10 @@
-import os
+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 MyScriptedProcess(ScriptedProcess):
     def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
@@ -35,6 +38,48 @@
     def is_alive(self) -> bool:
         return True
 
+    def get_scripted_thread_plugin(self):
+        return MyScriptedThread.__module__ + "." + MyScriptedThread.__name__
+
+
+class MyScriptedThread(ScriptedThread):
+    def __init__(self, target):
+        super().__init__(target)
+
+    def get_thread_id(self) -> int:
+        return 0x19
+
+    def get_name(self) -> str:
+        return MyScriptedThread.__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(
Index: lldb/bindings/python/python-wrapper.swig
===================================================================
--- lldb/bindings/python/python-wrapper.swig
+++ lldb/bindings/python/python-wrapper.swig
@@ -340,6 +340,63 @@
     Py_RETURN_NONE;
 }
 
+SWIGEXPORT void*
+LLDBSwigPythonCreateScriptedThread
+(
+    const char *python_class_name,
+    const char *session_dictionary_name,
+    const lldb::TargetSP& target_sp,
+    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 == 1) {
+        result = pfunc(target_arg);
+    } 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
 (
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