diff options
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp')
-rw-r--r-- | lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp | 266 |
1 files changed, 117 insertions, 149 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp index 10de1d11744..4d956d5dbe1 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp @@ -20,184 +20,152 @@ using namespace lldb_private; PythonExceptionState::PythonExceptionState(bool restore_on_exit) - : m_restore_on_exit(restore_on_exit) -{ - Acquire(restore_on_exit); + : m_restore_on_exit(restore_on_exit) { + Acquire(restore_on_exit); } -PythonExceptionState::~PythonExceptionState() -{ - if (m_restore_on_exit) - Restore(); +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::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(); +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(); } -bool -PythonExceptionState::HasErrorOccurred() -{ - return PyErr_Occurred(); +void PythonExceptionState::Discard() { + m_type.Reset(); + m_value.Reset(); + m_traceback.Reset(); } -bool -PythonExceptionState::IsError() const -{ - return m_type.IsValid() || m_value.IsValid() || m_traceback.IsValid(); -} - -PythonObject -PythonExceptionState::GetType() const -{ - return m_type; +void PythonExceptionState::Reset() { + if (m_restore_on_exit) + Restore(); + else + Discard(); } -PythonObject -PythonExceptionState::GetValue() const -{ - return m_value; -} +bool PythonExceptionState::HasErrorOccurred() { return PyErr_Occurred(); } -PythonObject -PythonExceptionState::GetTraceback() const -{ - return m_traceback; +bool PythonExceptionState::IsError() const { + return m_type.IsValid() || m_value.IsValid() || m_traceback.IsValid(); } -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(); +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"); +std::string PythonExceptionState::ReadBacktrace() const { + std::string retval("backtrace unavailable"); - auto traceback_module = PythonModule::ImportModule("traceback"); + auto traceback_module = PythonModule::ImportModule("traceback"); #if PY_MAJOR_VERSION >= 3 - auto stringIO_module = PythonModule::ImportModule("io"); + auto stringIO_module = PythonModule::ImportModule("io"); #else - auto stringIO_module = PythonModule::ImportModule("StringIO"); + auto stringIO_module = PythonModule::ImportModule("StringIO"); #endif - if (!m_traceback.IsAllocated()) - return retval; + if (!m_traceback.IsAllocated()) + return retval; - if (!traceback_module.IsAllocated() || !stringIO_module.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_builder = + stringIO_module.ResolveName<PythonCallable>("StringIO"); + if (!stringIO_builder.IsAllocated()) + return retval; - auto stringIO_buffer = stringIO_builder(); - if (!stringIO_buffer.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 = 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_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; + 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()); + llvm::StringRef string_data(printTB_string.GetString()); + retval.assign(string_data.data(), string_data.size()); - return retval; + return retval; } #endif |