19f2f44ceSEd Maste //===-- PythonExceptionState.cpp --------------------------------*- C++ -*-===//
29f2f44ceSEd Maste //
39f2f44ceSEd Maste // The LLVM Compiler Infrastructure
49f2f44ceSEd Maste //
59f2f44ceSEd Maste // This file is distributed under the University of Illinois Open Source
69f2f44ceSEd Maste // License. See LICENSE.TXT for details.
79f2f44ceSEd Maste //
89f2f44ceSEd Maste //===----------------------------------------------------------------------===//
99f2f44ceSEd Maste
109f2f44ceSEd Maste #ifndef LLDB_DISABLE_PYTHON
119f2f44ceSEd Maste
12435933ddSDimitry Andric // LLDB Python header must be included first
139f2f44ceSEd Maste #include "lldb-python.h"
14435933ddSDimitry Andric
159f2f44ceSEd Maste #include "PythonExceptionState.h"
169f2f44ceSEd Maste
179f2f44ceSEd Maste #include "llvm/ADT/StringRef.h"
189f2f44ceSEd Maste #include "llvm/Support/raw_ostream.h"
199f2f44ceSEd Maste
209f2f44ceSEd Maste using namespace lldb_private;
219f2f44ceSEd Maste
PythonExceptionState(bool restore_on_exit)229f2f44ceSEd Maste PythonExceptionState::PythonExceptionState(bool restore_on_exit)
23435933ddSDimitry Andric : m_restore_on_exit(restore_on_exit) {
249f2f44ceSEd Maste Acquire(restore_on_exit);
259f2f44ceSEd Maste }
269f2f44ceSEd Maste
~PythonExceptionState()27435933ddSDimitry Andric PythonExceptionState::~PythonExceptionState() {
289f2f44ceSEd Maste if (m_restore_on_exit)
299f2f44ceSEd Maste Restore();
309f2f44ceSEd Maste }
319f2f44ceSEd Maste
Acquire(bool restore_on_exit)32435933ddSDimitry Andric void PythonExceptionState::Acquire(bool restore_on_exit) {
33*4ba319b5SDimitry Andric // If a state is already acquired, the user needs to decide whether they want
34*4ba319b5SDimitry Andric // to discard or restore it. Don't allow the potential silent loss of a
35*4ba319b5SDimitry Andric // valid state.
369f2f44ceSEd Maste assert(!IsError());
379f2f44ceSEd Maste
389f2f44ceSEd Maste if (!HasErrorOccurred())
399f2f44ceSEd Maste return;
409f2f44ceSEd Maste
419f2f44ceSEd Maste PyObject *py_type = nullptr;
429f2f44ceSEd Maste PyObject *py_value = nullptr;
439f2f44ceSEd Maste PyObject *py_traceback = nullptr;
449f2f44ceSEd Maste PyErr_Fetch(&py_type, &py_value, &py_traceback);
459f2f44ceSEd Maste // PyErr_Fetch clears the error flag.
469f2f44ceSEd Maste assert(!HasErrorOccurred());
479f2f44ceSEd Maste
48*4ba319b5SDimitry Andric // Ownership of the objects returned by `PyErr_Fetch` is transferred to us.
499f2f44ceSEd Maste m_type.Reset(PyRefType::Owned, py_type);
509f2f44ceSEd Maste m_value.Reset(PyRefType::Owned, py_value);
519f2f44ceSEd Maste m_traceback.Reset(PyRefType::Owned, py_traceback);
529f2f44ceSEd Maste m_restore_on_exit = restore_on_exit;
539f2f44ceSEd Maste }
549f2f44ceSEd Maste
Restore()55435933ddSDimitry Andric void PythonExceptionState::Restore() {
56435933ddSDimitry Andric if (m_type.IsValid()) {
579f2f44ceSEd Maste // The documentation for PyErr_Restore says "Do not pass a null type and
58*4ba319b5SDimitry Andric // non-null value or traceback. So only restore if type was non-null to
59*4ba319b5SDimitry Andric // begin with. In this case we're passing ownership back to Python so
60*4ba319b5SDimitry Andric // release them all.
619f2f44ceSEd Maste PyErr_Restore(m_type.release(), m_value.release(), m_traceback.release());
629f2f44ceSEd Maste }
639f2f44ceSEd Maste
64*4ba319b5SDimitry Andric // After we restore, we should not hold onto the exception state. Demand
65*4ba319b5SDimitry Andric // that it be re-acquired.
669f2f44ceSEd Maste Discard();
679f2f44ceSEd Maste }
689f2f44ceSEd Maste
Discard()69435933ddSDimitry Andric void PythonExceptionState::Discard() {
709f2f44ceSEd Maste m_type.Reset();
719f2f44ceSEd Maste m_value.Reset();
729f2f44ceSEd Maste m_traceback.Reset();
739f2f44ceSEd Maste }
749f2f44ceSEd Maste
Reset()75435933ddSDimitry Andric void PythonExceptionState::Reset() {
769f2f44ceSEd Maste if (m_restore_on_exit)
779f2f44ceSEd Maste Restore();
789f2f44ceSEd Maste else
799f2f44ceSEd Maste Discard();
809f2f44ceSEd Maste }
819f2f44ceSEd Maste
HasErrorOccurred()82435933ddSDimitry Andric bool PythonExceptionState::HasErrorOccurred() { return PyErr_Occurred(); }
839f2f44ceSEd Maste
IsError() const84435933ddSDimitry Andric bool PythonExceptionState::IsError() const {
859f2f44ceSEd Maste return m_type.IsValid() || m_value.IsValid() || m_traceback.IsValid();
869f2f44ceSEd Maste }
879f2f44ceSEd Maste
GetType() const88435933ddSDimitry Andric PythonObject PythonExceptionState::GetType() const { return m_type; }
899f2f44ceSEd Maste
GetValue() const90435933ddSDimitry Andric PythonObject PythonExceptionState::GetValue() const { return m_value; }
919f2f44ceSEd Maste
GetTraceback() const92435933ddSDimitry Andric PythonObject PythonExceptionState::GetTraceback() const { return m_traceback; }
939f2f44ceSEd Maste
Format() const94435933ddSDimitry Andric std::string PythonExceptionState::Format() const {
959f2f44ceSEd Maste // Don't allow this function to modify the error state.
969f2f44ceSEd Maste PythonExceptionState state(true);
979f2f44ceSEd Maste
989f2f44ceSEd Maste std::string backtrace = ReadBacktrace();
999f2f44ceSEd Maste if (!IsError())
1009f2f44ceSEd Maste return std::string();
1019f2f44ceSEd Maste
102*4ba319b5SDimitry Andric // It's possible that ReadPythonBacktrace generated another exception. If
103*4ba319b5SDimitry Andric // this happens we have to clear the exception, because otherwise
104*4ba319b5SDimitry Andric // PyObject_Str() will assert below. That's why we needed to do the save /
105*4ba319b5SDimitry Andric // restore at the beginning of this function.
1069f2f44ceSEd Maste PythonExceptionState bt_error_state(false);
1079f2f44ceSEd Maste
1089f2f44ceSEd Maste std::string error_string;
1099f2f44ceSEd Maste llvm::raw_string_ostream error_stream(error_string);
1109f2f44ceSEd Maste error_stream << m_value.Str().GetString() << "\n";
1119f2f44ceSEd Maste
112435933ddSDimitry Andric if (!bt_error_state.IsError()) {
1139f2f44ceSEd Maste // If we were able to read the backtrace, just append it.
1149f2f44ceSEd Maste error_stream << backtrace << "\n";
115435933ddSDimitry Andric } else {
116*4ba319b5SDimitry Andric // Otherwise, append some information about why we were unable to obtain
117*4ba319b5SDimitry Andric // the backtrace.
1189f2f44ceSEd Maste PythonString bt_error = bt_error_state.GetValue().Str();
119435933ddSDimitry Andric error_stream << "An error occurred while retrieving the backtrace: "
120435933ddSDimitry Andric << bt_error.GetString() << "\n";
1219f2f44ceSEd Maste }
1229f2f44ceSEd Maste return error_stream.str();
1239f2f44ceSEd Maste }
1249f2f44ceSEd Maste
ReadBacktrace() const125435933ddSDimitry Andric std::string PythonExceptionState::ReadBacktrace() const {
1269f2f44ceSEd Maste std::string retval("backtrace unavailable");
1279f2f44ceSEd Maste
1289f2f44ceSEd Maste auto traceback_module = PythonModule::ImportModule("traceback");
1299f2f44ceSEd Maste #if PY_MAJOR_VERSION >= 3
1309f2f44ceSEd Maste auto stringIO_module = PythonModule::ImportModule("io");
1319f2f44ceSEd Maste #else
1329f2f44ceSEd Maste auto stringIO_module = PythonModule::ImportModule("StringIO");
1339f2f44ceSEd Maste #endif
1349f2f44ceSEd Maste if (!m_traceback.IsAllocated())
1359f2f44ceSEd Maste return retval;
1369f2f44ceSEd Maste
1379f2f44ceSEd Maste if (!traceback_module.IsAllocated() || !stringIO_module.IsAllocated())
1389f2f44ceSEd Maste return retval;
1399f2f44ceSEd Maste
140435933ddSDimitry Andric auto stringIO_builder =
141435933ddSDimitry Andric stringIO_module.ResolveName<PythonCallable>("StringIO");
1429f2f44ceSEd Maste if (!stringIO_builder.IsAllocated())
1439f2f44ceSEd Maste return retval;
1449f2f44ceSEd Maste
1459f2f44ceSEd Maste auto stringIO_buffer = stringIO_builder();
1469f2f44ceSEd Maste if (!stringIO_buffer.IsAllocated())
1479f2f44ceSEd Maste return retval;
1489f2f44ceSEd Maste
1499f2f44ceSEd Maste auto printTB = traceback_module.ResolveName<PythonCallable>("print_tb");
1509f2f44ceSEd Maste if (!printTB.IsAllocated())
1519f2f44ceSEd Maste return retval;
1529f2f44ceSEd Maste
153435933ddSDimitry Andric auto printTB_result =
154435933ddSDimitry Andric printTB(m_traceback.get(), Py_None, stringIO_buffer.get());
155435933ddSDimitry Andric auto stringIO_getvalue =
156435933ddSDimitry Andric stringIO_buffer.ResolveName<PythonCallable>("getvalue");
1579f2f44ceSEd Maste if (!stringIO_getvalue.IsAllocated())
1589f2f44ceSEd Maste return retval;
1599f2f44ceSEd Maste
1609f2f44ceSEd Maste auto printTB_string = stringIO_getvalue().AsType<PythonString>();
1619f2f44ceSEd Maste if (!printTB_string.IsAllocated())
1629f2f44ceSEd Maste return retval;
1639f2f44ceSEd Maste
1649f2f44ceSEd Maste llvm::StringRef string_data(printTB_string.GetString());
1659f2f44ceSEd Maste retval.assign(string_data.data(), string_data.size());
1669f2f44ceSEd Maste
1679f2f44ceSEd Maste return retval;
1689f2f44ceSEd Maste }
1699f2f44ceSEd Maste
1709f2f44ceSEd Maste #endif
171