mib updated this revision to Diff 369566.
mib marked 3 inline comments as done.
mib added a comment.
- Address @JDevlieghere feedbacks
- Use the new `ScriptedPythonInterface::Dispatch` method in
`ScriptedThreadPythonInterface`
- Add Test
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D107585/new/
https://reviews.llvm.org/D107585
Files:
lldb/bindings/python/python-wrapper.swig
lldb/examples/python/scripted_process/my_scripted_process.py
lldb/examples/python/scripted_process/scripted_process.py
lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
lldb/include/lldb/lldb-forward.h
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/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
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/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/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,206 @@
+//===-- 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 {};
+
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ std::string error_string;
+
+ TargetSP target_sp = exe_ctx.GetTargetSP();
+
+ 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/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) {
@@ -55,7 +63,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.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/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/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/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/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
+
[email protected]_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/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
(
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits