[Lldb-commits] [lldb] 3925204 - [lldb/Plugins] Introduce Scripted Interface Factory
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 3 10:37:33 PDT 2021
Author: Med Ismail Bennani
Date: 2021-09-03T19:37:25+02:00
New Revision: 3925204c1f5880f491e08d8481e88342bbeb7bc4
URL: https://github.com/llvm/llvm-project/commit/3925204c1f5880f491e08d8481e88342bbeb7bc4
DIFF: https://github.com/llvm/llvm-project/commit/3925204c1f5880f491e08d8481e88342bbeb7bc4.diff
LOG: [lldb/Plugins] Introduce Scripted Interface Factory
This patch splits the previous `ScriptedProcessPythonInterface` into
multiple specific classes:
1. The `ScriptedInterface` abstract class that carries the interface
instance object and its virtual pure abstract creation method.
2. The `ScriptedPythonInterface` that holds a generic `Dispatch` method that
can be used by various interfaces to call python methods and also keeps a
reference to the Python Script Interpreter instance.
3. The `ScriptedProcessInterface` that describes the base Scripted
Process model with all the methods used in the underlying script.
All these components are used to refactor the `ScriptedProcessPythonInterface`
class, making it more modular.
This patch is also a requirement for the upcoming work on `ScriptedThread`.
Differential Revision: https://reviews.llvm.org/D107521
Signed-off-by: Med Ismail Bennani <medismail.bennani at gmail.com>
Added:
lldb/include/lldb/Interpreter/ScriptedInterface.h
lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
Modified:
lldb/bindings/python/python-wrapper.swig
lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
Removed:
################################################################################
diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig
index 4c39e9c2c776a..a148ec3544ab8 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -288,7 +288,6 @@ LLDBSwigPythonCreateScriptedProcess
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);
diff --git a/lldb/include/lldb/Interpreter/ScriptedInterface.h b/lldb/include/lldb/Interpreter/ScriptedInterface.h
new file mode 100644
index 0000000000000..7cd0c6a1a7772
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/ScriptedInterface.h
@@ -0,0 +1,32 @@
+//===-- ScriptedInterface.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_INTERPRETER_SCRIPTEDINTERFACE_H
+#define LLDB_INTERPRETER_SCRIPTEDINTERFACE_H
+
+#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/lldb-private.h"
+
+#include <string>
+
+namespace lldb_private {
+class ScriptedInterface {
+public:
+ ScriptedInterface() = default;
+ virtual ~ScriptedInterface() = default;
+
+ virtual StructuredData::GenericSP
+ CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
+ StructuredData::DictionarySP args_sp) = 0;
+
+protected:
+ StructuredData::GenericSP m_object_instance_sp;
+};
+} // namespace lldb_private
+#endif // LLDB_INTERPRETER_SCRIPTEDINTERFACE_H
diff --git a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
index 223e89be87ee6..9682ba76383b7 100644
--- a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
+++ b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
@@ -11,20 +11,18 @@
#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/ScriptedInterface.h"
+
#include "lldb/lldb-private.h"
#include <string>
namespace lldb_private {
-class ScriptedProcessInterface {
+class ScriptedProcessInterface : virtual public ScriptedInterface {
public:
- ScriptedProcessInterface() : m_object_instance_sp(nullptr) {}
-
- virtual ~ScriptedProcessInterface() = default;
-
- virtual StructuredData::GenericSP
- CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp,
- StructuredData::DictionarySP args_sp) {
+ StructuredData::GenericSP
+ CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
+ StructuredData::DictionarySP args_sp) override {
return nullptr;
}
@@ -59,9 +57,6 @@ class ScriptedProcessInterface {
virtual lldb::pid_t GetProcessID() { return LLDB_INVALID_PROCESS_ID; }
virtual bool IsAlive() { return true; }
-
-private:
- StructuredData::ObjectSP m_object_instance_sp;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
index 09e9375b6f66f..93b8d5f457a49 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -109,8 +109,10 @@ ScriptedProcess::ScriptedProcess(
return;
}
- StructuredData::ObjectSP object_sp = GetInterface().CreatePluginObject(
- m_scripted_process_info.GetClassName().c_str(), target_sp,
+ ExecutionContext exe_ctx(target_sp, /*get_process=*/false);
+
+ StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject(
+ m_scripted_process_info.GetClassName().c_str(), exe_ctx,
m_scripted_process_info.GetDictionarySP());
if (!object_sp || !object_sp->IsValid()) {
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index 84115aae01a5c..98dc552ba6489 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -11,6 +11,7 @@ add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
PythonDataObjects.cpp
PythonReadline.cpp
ScriptInterpreterPython.cpp
+ ScriptedPythonInterface.cpp
ScriptedProcessPythonInterface.cpp
SWIGPythonBridge.cpp
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
index b8b9781182181..5a75c0a655e58 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -13,8 +13,6 @@
#if LLDB_ENABLE_PYTHON
-#include "ScriptedProcessPythonInterface.h"
-
#include "lldb/Breakpoint/BreakpointOptions.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/StructuredDataImpl.h"
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
index ce262c930f8b7..7cc74803bd613 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/Config.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
#include "lldb/lldb-enumerations.h"
#if LLDB_ENABLE_PYTHON
@@ -23,30 +25,33 @@ using namespace lldb_private;
using namespace lldb_private::python;
using Locker = ScriptInterpreterPythonImpl::Locker;
+ScriptedProcessPythonInterface::ScriptedProcessPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedProcessInterface(), ScriptedPythonInterface(interpreter) {}
+
StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject(
- const llvm::StringRef class_name, lldb::TargetSP target_sp,
+ llvm::StringRef class_name, ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp) {
if (class_name.empty())
return {};
- std::string error_string;
+ TargetSP target_sp = exe_ctx.GetTargetSP();
StructuredDataImpl *args_impl = nullptr;
if (args_sp) {
args_impl = new StructuredDataImpl();
args_impl->SetObjectSP(args_sp);
}
+ std::string error_string;
- void *ret_val;
-
- {
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
- Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
- Locker::FreeLock);
+ void *ret_val = LLDBSwigPythonCreateScriptedProcess(
+ class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp,
+ args_impl, error_string);
- ret_val = LLDBSwigPythonCreateScriptedProcess(
- class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp,
- args_impl, error_string);
- }
+ if (!ret_val)
+ return {};
m_object_instance_sp =
StructuredData::GenericSP(new StructuredPythonObject(ret_val));
@@ -63,244 +68,117 @@ Status ScriptedProcessPythonInterface::Resume() {
}
bool ScriptedProcessPythonInterface::ShouldStop() {
- llvm::Optional<unsigned long long> should_stop =
- GetGenericInteger("should_stop");
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("is_alive", error);
- if (!should_stop)
+ auto error_with_message = [](llvm::StringRef message) {
+ LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+ "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
return false;
+ };
- return static_cast<bool>(*should_stop);
-}
-
-Status ScriptedProcessPythonInterface::Stop() {
- return GetStatusFromMethod("stop");
-}
-
-Status ScriptedProcessPythonInterface::GetStatusFromMethod(
- llvm::StringRef method_name) {
- Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
- Locker::FreeLock);
-
- if (!m_object_instance_sp)
- return Status("Python object ill-formed.");
-
- if (!m_object_instance_sp)
- return Status("Cannot convert Python object to StructuredData::Generic.");
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)m_object_instance_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return Status("Python implementor not allocated.");
-
- PythonObject pmeth(
- PyRefType::Owned,
- PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- if (!pmeth.IsAllocated())
- return Status("Python method not allocated.");
-
- if (PyCallable_Check(pmeth.get()) == 0) {
- if (PyErr_Occurred())
- PyErr_Clear();
- return Status("Python method not callable.");
- }
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- PythonObject py_return(PyRefType::Owned,
- PyObject_CallMethod(implementor.get(),
- method_name.str().c_str(),
- nullptr));
-
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- return Status("Python method could not be called.");
- }
-
- if (PyObject *py_ret_ptr = py_return.get()) {
- lldb::SBError *sb_error =
- (lldb::SBError *)LLDBSWIGPython_CastPyObjectToSBError(py_ret_ptr);
-
- if (!sb_error)
- return Status("Couldn't cast lldb::SBError to lldb::Status.");
-
- Status status = m_interpreter.GetStatusFromSBError(*sb_error);
-
- if (status.Fail())
- return Status("error: %s", status.AsCString());
-
- return status;
+ if (!obj || !obj->IsValid() || error.Fail()) {
+ return error_with_message(llvm::Twine("Null or invalid object (" +
+ llvm::Twine(error.AsCString()) +
+ llvm::Twine(")."))
+ .str());
}
- return Status("Returned object is null.");
+ return obj->GetBooleanValue();
}
-llvm::Optional<unsigned long long>
-ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) {
- Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
- Locker::FreeLock);
-
- if (!m_object_instance_sp)
- return llvm::None;
-
- if (!m_object_instance_sp)
- return llvm::None;
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)m_object_instance_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return llvm::None;
-
- PythonObject pmeth(
- PyRefType::Owned,
- PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- if (!pmeth.IsAllocated())
- return llvm::None;
-
- if (PyCallable_Check(pmeth.get()) == 0) {
- if (PyErr_Occurred())
- PyErr_Clear();
- return llvm::None;
- }
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- PythonObject py_return(PyRefType::Owned,
- PyObject_CallMethod(implementor.get(),
- method_name.str().c_str(),
- nullptr));
-
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- }
-
- if (!py_return.get())
- return llvm::None;
-
- llvm::Expected<unsigned long long> size = py_return.AsUnsignedLongLong();
- // FIXME: Handle error.
- if (!size)
- return llvm::None;
-
- return *size;
+Status ScriptedProcessPythonInterface::Stop() {
+ return GetStatusFromMethod("stop");
}
lldb::MemoryRegionInfoSP
ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress(
lldb::addr_t address) {
// TODO: Implement
- return nullptr;
+ return {};
}
StructuredData::DictionarySP
ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) {
- // TODO: Implement
- return nullptr;
-}
-
-StructuredData::DictionarySP
-ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) {
- // TODO: Implement
- return nullptr;
-}
-
-lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress(
- lldb::addr_t address, size_t size, Status &error) {
Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
Locker::FreeLock);
- auto error_with_message = [&error](llvm::StringRef message) {
- error.SetErrorString(message);
- return nullptr;
+ auto error_with_message = [](llvm::StringRef message) {
+ LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+ "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+ return StructuredData::DictionarySP();
};
- static char callee_name[] = "read_memory_at_address";
- std::string param_format = GetPythonValueFormatString(address);
- param_format += GetPythonValueFormatString(size);
-
- if (!m_object_instance_sp)
- return error_with_message("Python object ill-formed.");
-
- if (!m_object_instance_sp)
- return error_with_message("Python method not callable.");
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)m_object_instance_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return error_with_message("Python implementor not allocated.");
-
- PythonObject pmeth(PyRefType::Owned,
- PyObject_GetAttrString(implementor.get(), callee_name));
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_thread_with_id", error, tid);
- if (PyErr_Occurred())
- PyErr_Clear();
-
- if (!pmeth.IsAllocated())
- return error_with_message("Python method not allocated.");
-
- if (PyCallable_Check(pmeth.get()) == 0) {
- if (PyErr_Occurred())
- PyErr_Clear();
- return error_with_message("Python method not callable.");
- }
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- PythonObject py_return(PyRefType::Owned,
- PyObject_CallMethod(implementor.get(), callee_name,
- param_format.c_str(), address,
- size));
-
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- return error_with_message("Python method could not be called.");
+ if (!obj || !obj->IsValid() || error.Fail()) {
+ return error_with_message(llvm::Twine("Null or invalid object (" +
+ llvm::Twine(error.AsCString()) +
+ llvm::Twine(")."))
+ .str());
}
- if (PyObject *py_ret_ptr = py_return.get()) {
- lldb::SBData *sb_data =
- (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr);
+ StructuredData::DictionarySP dict{obj->GetAsDictionary()};
- if (!sb_data)
- return error_with_message(
- "Couldn't cast lldb::SBData to lldb::DataExtractor.");
+ return dict;
+}
- return m_interpreter.GetDataExtractorFromSBData(*sb_data);
- }
+StructuredData::DictionarySP
+ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) {
+ // TODO: Implement
+ return {};
+}
- return error_with_message("Returned object is null.");
+lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress(
+ lldb::addr_t address, size_t size, Status &error) {
+ return Dispatch<lldb::DataExtractorSP>("read_memory_at_address", error,
+ address, size);
}
StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() {
// TODO: Implement
- return nullptr;
+ return {};
}
lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() {
- llvm::Optional<unsigned long long> pid = GetGenericInteger("get_process_id");
- return (!pid) ? LLDB_INVALID_PROCESS_ID : *pid;
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_process_id", error);
+
+ auto error_with_message = [](llvm::StringRef message) {
+ LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+ "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
+ return LLDB_INVALID_PROCESS_ID;
+ };
+
+ if (!obj || !obj->IsValid() || error.Fail()) {
+ return error_with_message(llvm::Twine("Null or invalid object (" +
+ llvm::Twine(error.AsCString()) +
+ llvm::Twine(")."))
+ .str());
+ }
+
+ return obj->GetIntegerValue(LLDB_INVALID_PROCESS_ID);
}
bool ScriptedProcessPythonInterface::IsAlive() {
- llvm::Optional<unsigned long long> is_alive = GetGenericInteger("is_alive");
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("is_alive", error);
- if (!is_alive)
+ auto error_with_message = [](llvm::StringRef message) {
+ LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS),
+ "ScriptedProcess::%s ERROR = %s", __FUNCTION__, message.data());
return false;
+ };
+
+ if (!obj || !obj->IsValid() || error.Fail()) {
+ return error_with_message(llvm::Twine("Null or invalid object (" +
+ llvm::Twine(error.AsCString()) +
+ llvm::Twine(")."))
+ .str());
+ }
- return static_cast<bool>(*is_alive);
+ return obj->GetBooleanValue();
}
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
index 30cb5a882af27..3ad1cdf6e18a8 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
@@ -13,17 +13,18 @@
#if LLDB_ENABLE_PYTHON
+#include "ScriptedPythonInterface.h"
#include "lldb/Interpreter/ScriptedProcessInterface.h"
namespace lldb_private {
-class ScriptInterpreterPythonImpl;
-class ScriptedProcessPythonInterface : public ScriptedProcessInterface {
+class ScriptedProcessPythonInterface : public ScriptedProcessInterface,
+ public ScriptedPythonInterface {
public:
- ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter)
- : ScriptedProcessInterface(), m_interpreter(interpreter) {}
+ ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter);
StructuredData::GenericSP
- CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp,
+ CreatePluginObject(const llvm::StringRef class_name,
+ ExecutionContext &exe_ctx,
StructuredData::DictionarySP args_sp) override;
Status Launch() override;
@@ -49,16 +50,6 @@ class ScriptedProcessPythonInterface : public ScriptedProcessInterface {
lldb::pid_t GetProcessID() override;
bool IsAlive() override;
-
-protected:
- llvm::Optional<unsigned long long>
- GetGenericInteger(llvm::StringRef method_name);
- Status GetStatusFromMethod(llvm::StringRef method_name);
-
-private:
- // The lifetime is managed by the ScriptInterpreter
- ScriptInterpreterPythonImpl &m_interpreter;
- StructuredData::GenericSP m_object_instance_sp;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
new file mode 100644
index 0000000000000..097cbbdb6fc7e
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
@@ -0,0 +1,38 @@
+//===-- ScriptedPythonInterface.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Config.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
+#include "lldb/lldb-enumerations.h"
+
+#if LLDB_ENABLE_PYTHON
+
+// LLDB Python header must be included first
+#include "lldb-python.h"
+
+#include "SWIGPythonBridge.h"
+#include "ScriptInterpreterPythonImpl.h"
+#include "ScriptedPythonInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ScriptedPythonInterface::ScriptedPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedInterface(), m_interpreter(interpreter) {}
+
+Status
+ScriptedPythonInterface::GetStatusFromMethod(llvm::StringRef method_name) {
+ Status error;
+ Dispatch<Status>(method_name, error);
+
+ return error;
+}
+
+#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
new file mode 100644
index 0000000000000..85ec167e1463f
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
@@ -0,0 +1,155 @@
+//===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
+
+#include "lldb/Interpreter/ScriptedInterface.h"
+#include "lldb/Utility/DataBufferHeap.h"
+
+#include "PythonDataObjects.h"
+#include "SWIGPythonBridge.h"
+#include "ScriptInterpreterPythonImpl.h"
+
+namespace lldb_private {
+class ScriptInterpreterPythonImpl;
+class ScriptedPythonInterface : virtual public ScriptedInterface {
+public:
+ ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
+ virtual ~ScriptedPythonInterface() = default;
+
+protected:
+ template <typename T = StructuredData::ObjectSP>
+ T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
+ return p.CreateStructuredObject();
+ }
+
+ template <>
+ Status ExtractValueFromPythonObject<Status>(python::PythonObject &p,
+ Status &error) {
+ if (lldb::SBError *sb_error = reinterpret_cast<lldb::SBError *>(
+ LLDBSWIGPython_CastPyObjectToSBError(p.get())))
+ error = m_interpreter.GetStatusFromSBError(*sb_error);
+ else
+ error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status.");
+
+ return error;
+ }
+
+ template <>
+ lldb::DataExtractorSP
+ ExtractValueFromPythonObject<lldb::DataExtractorSP>(python::PythonObject &p,
+ Status &error) {
+ lldb::SBData *sb_data = reinterpret_cast<lldb::SBData *>(
+ LLDBSWIGPython_CastPyObjectToSBData(p.get()));
+
+ if (!sb_data) {
+ error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status.");
+ return nullptr;
+ }
+
+ return m_interpreter.GetDataExtractorFromSBData(*sb_data);
+ }
+
+ template <typename T = StructuredData::ObjectSP, typename... Args>
+ T Dispatch(llvm::StringRef method_name, Status &error, Args... args) {
+ using namespace python;
+ using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ auto error_with_message = [&method_name, &error](llvm::StringRef message) {
+ error.SetErrorStringWithFormatv(
+ "ScriptedPythonInterface::{0} ({1}) ERROR = {2}", __FUNCTION__,
+ method_name, message);
+ return T();
+ };
+
+ if (!m_object_instance_sp)
+ return error_with_message("Python object ill-formed");
+
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ PythonObject implementor(PyRefType::Borrowed,
+ (PyObject *)m_object_instance_sp->GetValue());
+
+ if (!implementor.IsAllocated())
+ return error_with_message("Python implementor not allocated.");
+
+ PythonObject pmeth(
+ PyRefType::Owned,
+ PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
+
+ if (PyErr_Occurred())
+ PyErr_Clear();
+
+ if (!pmeth.IsAllocated())
+ return error_with_message("Python method not allocated.");
+
+ if (PyCallable_Check(pmeth.get()) == 0) {
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ return error_with_message("Python method not callable.");
+ }
+
+ if (PyErr_Occurred())
+ PyErr_Clear();
+
+ // TODO: make `const char *` when removing support for Python 2.
+ char *format = nullptr;
+ std::string format_buffer;
+
+ if (sizeof...(Args) > 0) {
+ FormatArgs(format_buffer, args...);
+ // TODO: make `const char *` when removing support for Python 2.
+ format = const_cast<char *>(format_buffer.c_str());
+ }
+
+ // TODO: make `const char *` when removing support for Python 2.
+ PythonObject py_return(
+ PyRefType::Owned,
+ PyObject_CallMethod(implementor.get(),
+ const_cast<char *>(method_name.data()), format,
+ args...));
+
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyErr_Clear();
+ return error_with_message("Python method could not be called.");
+ }
+
+ if (!py_return.IsAllocated())
+ return error_with_message("Returned object is null.");
+
+ return ExtractValueFromPythonObject<T>(py_return, error);
+ }
+
+ Status GetStatusFromMethod(llvm::StringRef method_name);
+
+ template <typename T, typename... Args>
+ void FormatArgs(std::string &fmt, T arg, Args... args) const {
+ FormatArgs(fmt, arg);
+ FormatArgs(fmt, args...);
+ }
+
+ template <typename T> void FormatArgs(std::string &fmt, T arg) const {
+ fmt += GetPythonValueFormatString(arg);
+ }
+
+ void FormatArgs(std::string &fmt) const {}
+
+ // The lifetime is managed by the ScriptInterpreter
+ ScriptInterpreterPythonImpl &m_interpreter;
+};
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
index f93733b3a5b78..eb02ce2243eca 100644
--- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -12,7 +12,7 @@
#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h"
-#include "lldb/API/SBError.h"
+
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
More information about the lldb-commits
mailing list