summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/ScriptInterpreter/Python
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp137
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h115
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp169
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.h56
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp291
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h26
7 files changed, 316 insertions, 479 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index 2c5071bc765..54b5c236f75 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -5,7 +5,6 @@ add_definitions(-DLLDB_PYTHON_RELATIVE_LIBDIR="${LLDB_PYTHON_RELATIVE_PATH}")
add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
PythonDataObjects.cpp
- PythonExceptionState.cpp
ScriptInterpreterPython.cpp
LINK_LIBS
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index d0d593656ef..70d93424fde 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -261,8 +261,7 @@ size_t PythonBytes::GetSize() const {
void PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes) {
const char *data = reinterpret_cast<const char *>(bytes.data());
- PyObject *py_bytes = PyBytes_FromStringAndSize(data, bytes.size());
- PythonObject::Reset(PyRefType::Owned, py_bytes);
+ *this = Take<PythonBytes>(PyBytes_FromStringAndSize(data, bytes.size()));
}
StructuredData::StringSP PythonBytes::CreateStructuredString() const {
@@ -486,7 +485,7 @@ int64_t PythonInteger::GetInteger() const {
}
void PythonInteger::SetInteger(int64_t value) {
- PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value));
+ *this = Take<PythonInteger>(PyLong_FromLongLong(value));
}
StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {
@@ -510,7 +509,7 @@ bool PythonBoolean::GetValue() const {
}
void PythonBoolean::SetValue(bool value) {
- PythonObject::Reset(PyRefType::Owned, PyBool_FromLong(value));
+ *this = Take<PythonBoolean>(PyBool_FromLong(value));
}
StructuredData::BooleanSP PythonBoolean::CreateStructuredBoolean() const {
@@ -826,7 +825,7 @@ static const char get_arg_info_script[] = R"(
from inspect import signature, Parameter, ismethod
from collections import namedtuple
ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs', 'is_bound_method'])
-def get_arg_info(f):
+def main(f):
count = 0
varargs = False
for parameter in signature(f).parameters.values():
@@ -852,28 +851,9 @@ Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const {
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
- // this global is protected by the GIL
- static PythonCallable get_arg_info;
-
- if (!get_arg_info.IsValid()) {
- PythonDictionary globals(PyInitialValue::Empty);
-
- auto builtins = PythonModule::BuiltinsModule();
- Error error = globals.SetItem("__builtins__", builtins);
- if (error)
- return std::move(error);
- PyObject *o = PyRun_String(get_arg_info_script, Py_file_input,
- globals.get(), globals.get());
- if (!o)
- return exception();
- Take<PythonObject>(o);
- auto function = As<PythonCallable>(globals.GetItem("get_arg_info"));
- if (!function)
- return function.takeError();
- get_arg_info = std::move(function.get());
- }
-
- Expected<PythonObject> pyarginfo = get_arg_info.Call(*this);
+ // no need to synchronize access to this global, we already have the GIL
+ static PythonScript get_arg_info(get_arg_info_script);
+ Expected<PythonObject> pyarginfo = get_arg_info(*this);
if (!pyarginfo)
return pyarginfo.takeError();
result.count = cantFail(As<long long>(pyarginfo.get().GetAttribute("count")));
@@ -1056,6 +1036,44 @@ std::error_code PythonException::convertToErrorCode() const {
return llvm::inconvertibleErrorCode();
}
+bool PythonException::Matches(PyObject *exc) const {
+ return PyErr_GivenExceptionMatches(m_exception_type, exc);
+}
+
+const char read_exception_script[] = R"(
+import sys
+from traceback import print_exception
+if sys.version_info.major < 3:
+ from StringIO import StringIO
+else:
+ from io import StringIO
+def main(exc_type, exc_value, tb):
+ f = StringIO()
+ print_exception(exc_type, exc_value, tb, file=f)
+ return f.getvalue()
+)";
+
+std::string PythonException::ReadBacktrace() const {
+
+ if (!m_traceback)
+ return toCString();
+
+ // no need to synchronize access to this global, we already have the GIL
+ static PythonScript read_exception(read_exception_script);
+
+ Expected<std::string> backtrace = As<std::string>(
+ read_exception(m_exception_type, m_exception, m_traceback));
+
+ if (!backtrace) {
+ std::string message =
+ std::string(toCString()) + "\n" +
+ "Traceback unavailble, an error occurred while reading it:\n";
+ return (message + llvm::toString(backtrace.takeError()));
+ }
+
+ return std::move(backtrace.get());
+}
+
char PythonException::ID = 0;
llvm::Expected<File::OpenOptions>
@@ -1496,4 +1514,69 @@ Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) {
return Take<PythonFile>(file_obj);
}
+Error PythonScript::Init() {
+ if (function.IsValid())
+ return Error::success();
+
+ PythonDictionary globals(PyInitialValue::Empty);
+ auto builtins = PythonModule::BuiltinsModule();
+ if (Error error = globals.SetItem("__builtins__", builtins))
+ return error;
+ PyObject *o =
+ PyRun_String(script, Py_file_input, globals.get(), globals.get());
+ if (!o)
+ return exception();
+ Take<PythonObject>(o);
+ auto f = As<PythonCallable>(globals.GetItem("main"));
+ if (!f)
+ return f.takeError();
+ function = std::move(f.get());
+
+ return Error::success();
+}
+
+llvm::Expected<PythonObject>
+python::runStringOneLine(const llvm::Twine &string,
+ const PythonDictionary &globals,
+ const PythonDictionary &locals) {
+ if (!globals.IsValid() || !locals.IsValid())
+ return nullDeref();
+
+ PyObject *code =
+ Py_CompileString(NullTerminated(string), "<string>", Py_eval_input);
+ if (!code) {
+ PyErr_Clear();
+ code =
+ Py_CompileString(NullTerminated(string), "<string>", Py_single_input);
+ }
+ if (!code)
+ return exception();
+ auto code_ref = Take<PythonObject>(code);
+
+#if PY_MAJOR_VERSION < 3
+ PyObject *result =
+ PyEval_EvalCode((PyCodeObject *)code, globals.get(), locals.get());
+#else
+ PyObject *result = PyEval_EvalCode(code, globals.get(), locals.get());
+#endif
+
+ if (!result)
+ return exception();
+
+ return Take<PythonObject>(result);
+}
+
+llvm::Expected<PythonObject>
+python::runStringMultiLine(const llvm::Twine &string,
+ const PythonDictionary &globals,
+ const PythonDictionary &locals) {
+ if (!globals.IsValid() || !locals.IsValid())
+ return nullDeref();
+ PyObject *result = PyRun_String(NullTerminated(string), Py_file_input,
+ globals.get(), locals.get());
+ if (!result)
+ return exception();
+ return Take<PythonObject>(result);
+}
+
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
index 634d6e89601..373d3212697 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
@@ -59,6 +59,7 @@
#include "llvm/ADT/ArrayRef.h"
namespace lldb_private {
+namespace python {
class PythonObject;
class PythonBytes;
@@ -113,7 +114,6 @@ enum class PyRefType {
// not call Py_INCREF.
};
-namespace python {
// Take a reference that you already own, and turn it into
// a PythonObject.
@@ -175,7 +175,19 @@ public:
operator const char *() { return str; }
};
-} // namespace python
+inline llvm::Error nullDeref() {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "A NULL PyObject* was dereferenced");
+}
+
+inline llvm::Error exception(const char *s = nullptr) {
+ return llvm::make_error<PythonException>(s);
+}
+
+inline llvm::Error keyError() {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "key not in dict");
+}
enum class PyInitialValue { Invalid, Empty };
@@ -191,6 +203,11 @@ template <> struct PythonFormat<long long> {
static auto get(long long value) { return value; }
};
+template <> struct PythonFormat<PyObject *> {
+ static constexpr char format = 'O';
+ static auto get(PyObject *value) { return value; }
+};
+
template <typename T>
struct PythonFormat<
T, typename std::enable_if<std::is_base_of<PythonObject, T>::value>::type> {
@@ -202,8 +219,14 @@ class PythonObject {
public:
PythonObject() : m_py_obj(nullptr) {}
- PythonObject(PyRefType type, PyObject *py_obj) : m_py_obj(nullptr) {
- Reset(type, py_obj);
+ PythonObject(PyRefType type, PyObject *py_obj) {
+ m_py_obj = py_obj;
+ // If this is a borrowed reference, we need to convert it to
+ // an owned reference by incrementing it. If it is an owned
+ // reference (for example the caller allocated it with PyDict_New()
+ // then we must *not* increment it.
+ if (m_py_obj && Py_IsInitialized() && type == PyRefType::Borrowed)
+ Py_XINCREF(m_py_obj);
}
PythonObject(const PythonObject &rhs)
@@ -222,23 +245,6 @@ public:
m_py_obj = nullptr;
}
- void Reset(PyRefType type, PyObject *py_obj) {
- if (py_obj == m_py_obj)
- return;
-
- if (Py_IsInitialized())
- Py_XDECREF(m_py_obj);
-
- m_py_obj = py_obj;
-
- // If this is a borrowed reference, we need to convert it to
- // an owned reference by incrementing it. If it is an owned
- // reference (for example the caller allocated it with PyDict_New()
- // then we must *not* increment it.
- if (m_py_obj && Py_IsInitialized() && type == PyRefType::Borrowed)
- Py_XINCREF(m_py_obj);
- }
-
void Dump() const {
if (m_py_obj)
_PyObject_Dump(m_py_obj);
@@ -304,17 +310,6 @@ public:
StructuredData::ObjectSP CreateStructuredObject() const;
protected:
- static llvm::Error nullDeref() {
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "A NULL PyObject* was dereferenced");
- }
- static llvm::Error exception(const char *s = nullptr) {
- return llvm::make_error<PythonException>(s);
- }
- static llvm::Error keyError() {
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "key not in dict");
- }
#if PY_MAJOR_VERSION < 3
// The python 2 API declares some arguments as char* that should
@@ -348,7 +343,6 @@ public:
}
llvm::Expected<PythonObject> GetAttribute(const llvm::Twine &name) const {
- using namespace python;
if (!m_py_obj)
return nullDeref();
PyObject *obj = PyObject_GetAttrString(m_py_obj, NullTerminated(name));
@@ -389,7 +383,6 @@ protected:
PyObject *m_py_obj;
};
-namespace python {
// This is why C++ needs monads.
template <typename T> llvm::Expected<T> As(llvm::Expected<PythonObject> &&obj) {
@@ -409,7 +402,6 @@ llvm::Expected<long long> As<long long>(llvm::Expected<PythonObject> &&obj);
template <>
llvm::Expected<std::string> As<std::string>(llvm::Expected<PythonObject> &&obj);
-} // namespace python
template <class T> class TypedPythonObject : public PythonObject {
public:
@@ -417,16 +409,12 @@ public:
// This can be eliminated once we drop python 2 support.
static void Convert(PyRefType &type, PyObject *&py_obj) {}
- void Reset() { PythonObject::Reset(); }
-
- void Reset(PyRefType type, PyObject *py_obj) = delete;
-
TypedPythonObject(PyRefType type, PyObject *py_obj) {
if (!py_obj)
return;
T::Convert(type, py_obj);
if (T::Check(py_obj))
- PythonObject::Reset(type, py_obj);
+ PythonObject::operator=(PythonObject(type, py_obj));
else if (type == PyRefType::Owned)
Py_DECREF(py_obj);
}
@@ -698,6 +686,8 @@ public:
~PythonException();
void log(llvm::raw_ostream &OS) const override;
std::error_code convertToErrorCode() const override;
+ bool Matches(PyObject *exc) const;
+ std::string ReadBacktrace() const;
};
// This extracts the underlying T out of an Expected<T> and returns it.
@@ -732,7 +722,6 @@ template <typename T> T unwrapOrSetPythonException(llvm::Expected<T> expected) {
return T();
}
-namespace python {
// This is only here to help incrementally migrate old, exception-unsafe
// code.
template <typename T> T unwrapIgnoringErrors(llvm::Expected<T> expected) {
@@ -741,8 +730,50 @@ template <typename T> T unwrapIgnoringErrors(llvm::Expected<T> expected) {
llvm::consumeError(expected.takeError());
return T();
}
-} // namespace python
+llvm::Expected<PythonObject> runStringOneLine(const llvm::Twine &string,
+ const PythonDictionary &globals,
+ const PythonDictionary &locals);
+
+llvm::Expected<PythonObject> runStringMultiLine(const llvm::Twine &string,
+ const PythonDictionary &globals,
+ const PythonDictionary &locals);
+
+// Sometimes the best way to interact with a python interpreter is
+// to run some python code. You construct a PythonScript with
+// script string. The script assigns some function to `_function_`
+// and you get a C++ callable object that calls the python function.
+//
+// Example:
+//
+// const char script[] = R"(
+// def main(x, y):
+// ....
+// )";
+//
+// Expected<PythonObject> cpp_foo_wrapper(PythonObject x, PythonObject y) {
+// // no need to synchronize access to this global, we already have the GIL
+// static PythonScript foo(script)
+// return foo(x, y);
+// }
+class PythonScript {
+ const char *script;
+ PythonCallable function;
+
+ llvm::Error Init();
+
+public:
+ PythonScript(const char *script) : script(script), function() {}
+
+ template <typename... Args>
+ llvm::Expected<PythonObject> operator()(Args &&... args) {
+ if (llvm::Error error = Init())
+ return std::move(error);
+ return function.Call(std::forward<Args>(args)...);
+ }
+};
+
+} // namespace python
} // namespace lldb_private
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp
deleted file mode 100644
index c9d834ce686..00000000000
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-//===-- PythonExceptionState.cpp --------------------------------*- 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_DISABLE_PYTHON
-
-// LLDB Python header must be included first
-#include "lldb-python.h"
-
-#include "PythonExceptionState.h"
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace lldb_private;
-
-PythonExceptionState::PythonExceptionState(bool restore_on_exit)
- : m_restore_on_exit(restore_on_exit) {
- Acquire(restore_on_exit);
-}
-
-PythonExceptionState::~PythonExceptionState() {
- if (m_restore_on_exit)
- Restore();
-}
-
-void PythonExceptionState::Acquire(bool restore_on_exit) {
- // If a state is already acquired, the user needs to decide whether they want
- // to discard or restore it. Don't allow the potential silent loss of a
- // valid state.
- assert(!IsError());
-
- if (!HasErrorOccurred())
- return;
-
- PyObject *py_type = nullptr;
- PyObject *py_value = nullptr;
- PyObject *py_traceback = nullptr;
- PyErr_Fetch(&py_type, &py_value, &py_traceback);
- // PyErr_Fetch clears the error flag.
- assert(!HasErrorOccurred());
-
- // Ownership of the objects returned by `PyErr_Fetch` is transferred to us.
- m_type.Reset(PyRefType::Owned, py_type);
- m_value.Reset(PyRefType::Owned, py_value);
- m_traceback.Reset(PyRefType::Owned, py_traceback);
- m_restore_on_exit = restore_on_exit;
-}
-
-void PythonExceptionState::Restore() {
- if (m_type.IsValid()) {
- // The documentation for PyErr_Restore says "Do not pass a null type and
- // non-null value or traceback. So only restore if type was non-null to
- // begin with. In this case we're passing ownership back to Python so
- // release them all.
- PyErr_Restore(m_type.release(), m_value.release(), m_traceback.release());
- }
-
- // After we restore, we should not hold onto the exception state. Demand
- // that it be re-acquired.
- Discard();
-}
-
-void PythonExceptionState::Discard() {
- m_type.Reset();
- m_value.Reset();
- m_traceback.Reset();
-}
-
-void PythonExceptionState::Reset() {
- if (m_restore_on_exit)
- Restore();
- else
- Discard();
-}
-
-bool PythonExceptionState::HasErrorOccurred() { return PyErr_Occurred(); }
-
-bool PythonExceptionState::IsError() const {
- return m_type.IsValid() || m_value.IsValid() || m_traceback.IsValid();
-}
-
-PythonObject PythonExceptionState::GetType() const { return m_type; }
-
-PythonObject PythonExceptionState::GetValue() const { return m_value; }
-
-PythonObject PythonExceptionState::GetTraceback() const { return m_traceback; }
-
-std::string PythonExceptionState::Format() const {
- // Don't allow this function to modify the error state.
- PythonExceptionState state(true);
-
- std::string backtrace = ReadBacktrace();
- if (!IsError())
- return std::string();
-
- // It's possible that ReadPythonBacktrace generated another exception. If
- // this happens we have to clear the exception, because otherwise
- // PyObject_Str() will assert below. That's why we needed to do the save /
- // restore at the beginning of this function.
- PythonExceptionState bt_error_state(false);
-
- std::string error_string;
- llvm::raw_string_ostream error_stream(error_string);
- error_stream << m_value.Str().GetString() << "\n";
-
- if (!bt_error_state.IsError()) {
- // If we were able to read the backtrace, just append it.
- error_stream << backtrace << "\n";
- } else {
- // Otherwise, append some information about why we were unable to obtain
- // the backtrace.
- PythonString bt_error = bt_error_state.GetValue().Str();
- error_stream << "An error occurred while retrieving the backtrace: "
- << bt_error.GetString() << "\n";
- }
- return error_stream.str();
-}
-
-std::string PythonExceptionState::ReadBacktrace() const {
- std::string retval("backtrace unavailable");
-
- auto traceback_module = PythonModule::ImportModule("traceback");
-#if PY_MAJOR_VERSION >= 3
- auto stringIO_module = PythonModule::ImportModule("io");
-#else
- auto stringIO_module = PythonModule::ImportModule("StringIO");
-#endif
- if (!m_traceback.IsAllocated())
- return retval;
-
- if (!traceback_module.IsAllocated() || !stringIO_module.IsAllocated())
- return retval;
-
- auto stringIO_builder =
- stringIO_module.ResolveName<PythonCallable>("StringIO");
- if (!stringIO_builder.IsAllocated())
- return retval;
-
- auto stringIO_buffer = stringIO_builder();
- if (!stringIO_buffer.IsAllocated())
- return retval;
-
- auto printTB = traceback_module.ResolveName<PythonCallable>("print_tb");
- if (!printTB.IsAllocated())
- return retval;
-
- auto printTB_result =
- printTB(m_traceback.get(), Py_None, stringIO_buffer.get());
- auto stringIO_getvalue =
- stringIO_buffer.ResolveName<PythonCallable>("getvalue");
- if (!stringIO_getvalue.IsAllocated())
- return retval;
-
- auto printTB_string = stringIO_getvalue().AsType<PythonString>();
- if (!printTB_string.IsAllocated())
- return retval;
-
- llvm::StringRef string_data(printTB_string.GetString());
- retval.assign(string_data.data(), string_data.size());
-
- return retval;
-}
-
-#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.h
deleted file mode 100644
index 3a88aa03777..00000000000
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//===-- PythonExceptionState.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_PYTHONEXCEPTIONSTATE_H
-#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONEXCEPTIONSTATE_H
-
-#ifndef LLDB_DISABLE_PYTHON
-
-#include "PythonDataObjects.h"
-
-namespace lldb_private {
-
-class PythonExceptionState {
-public:
- explicit PythonExceptionState(bool restore_on_exit);
- ~PythonExceptionState();
-
- void Acquire(bool restore_on_exit);
-
- void Restore();
-
- void Discard();
-
- void Reset();
-
- static bool HasErrorOccurred();
-
- bool IsError() const;
-
- PythonObject GetType() const;
-
- PythonObject GetValue() const;
-
- PythonObject GetTraceback() const;
-
- std::string Format() const;
-
-private:
- std::string ReadBacktrace() const;
-
- bool m_restore_on_exit;
-
- PythonObject m_type;
- PythonObject m_value;
- PythonObject m_traceback;
-};
-}
-
-#endif
-
-#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 8f713352416..3eee5218414 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -16,7 +16,6 @@
#include "lldb-python.h"
#include "PythonDataObjects.h"
-#include "PythonExceptionState.h"
#include "ScriptInterpreterPythonImpl.h"
#include "lldb/API/SBFrame.h"
@@ -56,6 +55,7 @@
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::python;
+using llvm::Expected;
// Defined in the SWIG source file
#if PY_MAJOR_VERSION >= 3
@@ -747,9 +747,9 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags,
return true;
}
-PythonObject &ScriptInterpreterPythonImpl::GetMainModule() {
+PythonModule &ScriptInterpreterPythonImpl::GetMainModule() {
if (!m_main_module.IsValid())
- m_main_module.Reset(PyRefType::Borrowed, PyImport_AddModule("__main__"));
+ m_main_module = unwrapIgnoringErrors(PythonModule::Import("__main__"));
return m_main_module;
}
@@ -1030,6 +1030,7 @@ bool ScriptInterpreterPythonImpl::Interrupt() {
"can't interrupt");
return false;
}
+
bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn(
llvm::StringRef in_string, ScriptInterpreter::ScriptReturnType return_type,
void *ret_value, const ExecuteScriptOptions &options) {
@@ -1040,151 +1041,111 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn(
Locker::NoSTDIN,
Locker::FreeAcquiredLock | Locker::TearDownSession);
- PythonObject py_return;
- PythonObject &main_module = GetMainModule();
- PythonDictionary globals(PyRefType::Borrowed,
- PyModule_GetDict(main_module.get()));
- PythonObject py_error;
- bool ret_success = false;
- int success;
+ PythonModule &main_module = GetMainModule();
+ PythonDictionary globals = main_module.GetDictionary();
PythonDictionary locals = GetSessionDictionary();
-
- if (!locals.IsValid()) {
+ if (!locals.IsValid())
locals = unwrapIgnoringErrors(
As<PythonDictionary>(globals.GetAttribute(m_dictionary_name)));
- }
-
if (!locals.IsValid())
locals = globals;
- py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
- if (py_error.IsValid())
- PyErr_Clear();
-
- std::string as_string = in_string.str();
- { // scope for PythonInputReaderManager
- // PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL);
- py_return.Reset(PyRefType::Owned,
- PyRun_String(as_string.c_str(), Py_eval_input,
- globals.get(), locals.get()));
- if (!py_return.IsValid()) {
- py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
- if (py_error.IsValid())
- PyErr_Clear();
-
- py_return.Reset(PyRefType::Owned,
- PyRun_String(as_string.c_str(), Py_single_input,
- globals.get(), locals.get()));
- }
+ Expected<PythonObject> maybe_py_return =
+ runStringOneLine(in_string, globals, locals);
+
+ if (!maybe_py_return) {
+ llvm::handleAllErrors(
+ maybe_py_return.takeError(),
+ [&](PythonException &E) {
+ E.Restore();
+ if (options.GetMaskoutErrors()) {
+ if (E.Matches(PyExc_SyntaxError)) {
+ PyErr_Print();
+ }
+ PyErr_Clear();
+ }
+ },
+ [](const llvm::ErrorInfoBase &E) {});
+ return false;
}
- if (py_return.IsValid()) {
- switch (return_type) {
- case eScriptReturnTypeCharPtr: // "char *"
- {
- const char format[3] = "s#";
- success = PyArg_Parse(py_return.get(), format, (char **)ret_value);
- break;
- }
- case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return ==
- // Py_None
- {
- const char format[3] = "z";
- success = PyArg_Parse(py_return.get(), format, (char **)ret_value);
- break;
- }
- case eScriptReturnTypeBool: {
- const char format[2] = "b";
- success = PyArg_Parse(py_return.get(), format, (bool *)ret_value);
- break;
- }
- case eScriptReturnTypeShortInt: {
- const char format[2] = "h";
- success = PyArg_Parse(py_return.get(), format, (short *)ret_value);
- break;
- }
- case eScriptReturnTypeShortIntUnsigned: {
- const char format[2] = "H";
- success =
- PyArg_Parse(py_return.get(), format, (unsigned short *)ret_value);
- break;
- }
- case eScriptReturnTypeInt: {
- const char format[2] = "i";
- success = PyArg_Parse(py_return.get(), format, (int *)ret_value);
- break;
- }
- case eScriptReturnTypeIntUnsigned: {
- const char format[2] = "I";
- success = PyArg_Parse(py_return.get(), format, (unsigned int *)ret_value);
- break;
- }
- case eScriptReturnTypeLongInt: {
- const char format[2] = "l";
- success = PyArg_Parse(py_return.get(), format, (long *)ret_value);
- break;
- }
- case eScriptReturnTypeLongIntUnsigned: {
- const char format[2] = "k";
- success =
- PyArg_Parse(py_return.get(), format, (unsigned long *)ret_value);
- break;
- }
- case eScriptReturnTypeLongLong: {
- const char format[2] = "L";
- success = PyArg_Parse(py_return.get(), format, (long long *)ret_value);
- break;
- }
- case eScriptReturnTypeLongLongUnsigned: {
- const char format[2] = "K";
- success =
- PyArg_Parse(py_return.get(), format, (unsigned long long *)ret_value);
- break;
- }
- case eScriptReturnTypeFloat: {
- const char format[2] = "f";
- success = PyArg_Parse(py_return.get(), format, (float *)ret_value);
- break;
- }
- case eScriptReturnTypeDouble: {
- const char format[2] = "d";
- success = PyArg_Parse(py_return.get(), format, (double *)ret_value);
- break;
- }
- case eScriptReturnTypeChar: {
- const char format[2] = "c";
- success = PyArg_Parse(py_return.get(), format, (char *)ret_value);
- break;
- }
- case eScriptReturnTypeOpaqueObject: {
- success = true;
- PyObject *saved_value = py_return.get();
- Py_XINCREF(saved_value);
- *((PyObject **)ret_value) = saved_value;
- break;
- }
- }
+ PythonObject py_return = std::move(maybe_py_return.get());
+ assert(py_return.IsValid());
- ret_success = success;
+ switch (return_type) {
+ case eScriptReturnTypeCharPtr: // "char *"
+ {
+ const char format[3] = "s#";
+ return PyArg_Parse(py_return.get(), format, (char **)ret_value);
+ }
+ case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return ==
+ // Py_None
+ {
+ const char format[3] = "z";
+ return PyArg_Parse(py_return.get(), format, (char **)ret_value);
+ }
+ case eScriptReturnTypeBool: {
+ const char format[2] = "b";
+ return PyArg_Parse(py_return.get(), format, (bool *)ret_value);
+ }
+ case eScriptReturnTypeShortInt: {
+ const char format[2] = "h";
+ return PyArg_Parse(py_return.get(), format, (short *)ret_value);
+ }
+ case eScriptReturnTypeShortIntUnsigned: {
+ const char format[2] = "H";
+ return PyArg_Parse(py_return.get(), format, (unsigned short *)ret_value);
+ }
+ case eScriptReturnTypeInt: {
+ const char format[2] = "i";
+ return PyArg_Parse(py_return.get(), format, (int *)ret_value);
+ }
+ case eScriptReturnTypeIntUnsigned: {
+ const char format[2] = "I";
+ return PyArg_Parse(py_return.get(), format, (unsigned int *)ret_value);
+ }
+ case eScriptReturnTypeLongInt: {
+ const char format[2] = "l";
+ return PyArg_Parse(py_return.get(), format, (long *)ret_value);
+ }
+ case eScriptReturnTypeLongIntUnsigned: {
+ const char format[2] = "k";
+ return PyArg_Parse(py_return.get(), format, (unsigned long *)ret_value);
+ }
+ case eScriptReturnTypeLongLong: {
+ const char format[2] = "L";
+ return PyArg_Parse(py_return.get(), format, (long long *)ret_value);
+ }
+ case eScriptReturnTypeLongLongUnsigned: {
+ const char format[2] = "K";
+ return PyArg_Parse(py_return.get(), format,
+ (unsigned long long *)ret_value);
+ }
+ case eScriptReturnTypeFloat: {
+ const char format[2] = "f";
+ return PyArg_Parse(py_return.get(), format, (float *)ret_value);
+ }
+ case eScriptReturnTypeDouble: {
+ const char format[2] = "d";
+ return PyArg_Parse(py_return.get(), format, (double *)ret_value);
+ }
+ case eScriptReturnTypeChar: {
+ const char format[2] = "c";
+ return PyArg_Parse(py_return.get(), format, (char *)ret_value);
+ }
+ case eScriptReturnTypeOpaqueObject: {
+ *((PyObject **)ret_value) = py_return.release();
+ return true;
}
-
- py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
- if (py_error.IsValid()) {
- ret_success = false;
- if (options.GetMaskoutErrors()) {
- if (PyErr_GivenExceptionMatches(py_error.get(), PyExc_SyntaxError))
- PyErr_Print();
- PyErr_Clear();
- }
}
-
- return ret_success;
}
Status ScriptInterpreterPythonImpl::ExecuteMultipleLines(
const char *in_string, const ExecuteScriptOptions &options) {
- Status error;
+
+ if (in_string == nullptr)
+ return Status();
Locker locker(this,
Locker::AcquireLock | Locker::InitSession |
@@ -1192,51 +1153,32 @@ Status ScriptInterpreterPythonImpl::ExecuteMultipleLines(
Locker::NoSTDIN,
Locker::FreeAcquiredLock | Locker::TearDownSession);
- PythonObject return_value;
- PythonObject &main_module = GetMainModule();
- PythonDictionary globals(PyRefType::Borrowed,
- PyModule_GetDict(main_module.get()));
- PythonObject py_error;
+ PythonModule &main_module = GetMainModule();
+ PythonDictionary globals = main_module.GetDictionary();
PythonDictionary locals = GetSessionDictionary();
-
if (!locals.IsValid())
locals = unwrapIgnoringErrors(
As<PythonDictionary>(globals.GetAttribute(m_dictionary_name)));
-
if (!locals.IsValid())
locals = globals;
- py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
- if (py_error.IsValid())
- PyErr_Clear();
-
- if (in_string != nullptr) {
- PythonObject code_object;
- code_object.Reset(PyRefType::Owned,
- Py_CompileString(in_string, "temp.py", Py_file_input));
+ Expected<PythonObject> return_value =
+ runStringMultiLine(in_string, globals, locals);
- if (code_object.IsValid()) {
-// In Python 2.x, PyEval_EvalCode takes a PyCodeObject, but in Python 3.x, it
-// takes a PyObject. They are convertible (hence the function
-// PyCode_Check(PyObject*), so we have to do the cast for Python 2.x
-#if PY_MAJOR_VERSION >= 3
- PyObject *py_code_obj = code_object.get();
-#else
- PyCodeObject *py_code_obj =
- reinterpret_cast<PyCodeObject *>(code_object.get());
-#endif
- return_value.Reset(
- PyRefType::Owned,
- PyEval_EvalCode(py_code_obj, globals.get(), locals.get()));
- }
+ if (!return_value) {
+ llvm::Error error =
+ llvm::handleErrors(return_value.takeError(), [&](PythonException &E) {
+ llvm::Error error = llvm::createStringError(
+ llvm::inconvertibleErrorCode(), E.ReadBacktrace());
+ if (!options.GetMaskoutErrors())
+ E.Restore();
+ return error;
+ });
+ return Status(std::move(error));
}
- PythonExceptionState exception_state(!options.GetMaskoutErrors());
- if (exception_state.IsError())
- error.SetErrorString(exception_state.Format().c_str());
-
- return error;
+ return Status();
}
void ScriptInterpreterPythonImpl::CollectDataForBreakpointCommandCallback(
@@ -2030,15 +1972,22 @@ StructuredData::DictionarySP ScriptInterpreterPythonImpl::GetDynamicSettings(
if (!generic)
return StructuredData::DictionarySP();
- PythonObject reply_pyobj;
Locker py_lock(this,
Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
TargetSP target_sp(target->shared_from_this());
- reply_pyobj.Reset(PyRefType::Owned,
- (PyObject *)LLDBSWIGPython_GetDynamicSetting(
- generic->GetValue(), setting_name, target_sp));
- PythonDictionary py_dict(PyRefType::Borrowed, reply_pyobj.get());
+ auto setting = (PyObject *)LLDBSWIGPython_GetDynamicSetting(
+ generic->GetValue(), setting_name, target_sp);
+
+ if (!setting)
+ return StructuredData::DictionarySP();
+
+ PythonDictionary py_dict =
+ unwrapIgnoringErrors(As<PythonDictionary>(Take<PythonObject>(setting)));
+
+ if (!py_dict)
+ return StructuredData::DictionarySP();
+
return py_dict.CreateStructuredDictionary();
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index 373513f8e47..929567e579d 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -363,25 +363,25 @@ public:
eIOHandlerWatchpoint
};
- PythonObject &GetMainModule();
+ python::PythonModule &GetMainModule();
- PythonDictionary &GetSessionDictionary();
+ python::PythonDictionary &GetSessionDictionary();
- PythonDictionary &GetSysModuleDictionary();
+ python::PythonDictionary &GetSysModuleDictionary();
bool GetEmbeddedInterpreterModuleObjects();
bool SetStdHandle(lldb::FileSP file, const char *py_name,
- PythonObject &save_file, const char *mode);
-
- PythonObject m_saved_stdin;
- PythonObject m_saved_stdout;
- PythonObject m_saved_stderr;
- PythonObject m_main_module;
- PythonDictionary m_session_dict;
- PythonDictionary m_sys_module_dict;
- PythonObject m_run_one_line_function;
- PythonObject m_run_one_line_str_global;
+ python::PythonObject &save_file, const char *mode);
+
+ python::PythonObject m_saved_stdin;
+ python::PythonObject m_saved_stdout;
+ python::PythonObject m_saved_stderr;
+ python::PythonModule m_main_module;
+ python::PythonDictionary m_session_dict;
+ python::PythonDictionary m_sys_module_dict;
+ python::PythonObject m_run_one_line_function;
+ python::PythonObject m_run_one_line_str_global;
std::string m_dictionary_name;
ActiveIOHandler m_active_io_handler;
bool m_session_is_active;
OpenPOWER on IntegriCloud