1 //===-- PythonExceptionState.cpp --------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef LLDB_DISABLE_PYTHON 11 12 // LLDB Python header must be included first 13 #include "lldb-python.h" 14 15 #include "PythonExceptionState.h" 16 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/Support/raw_ostream.h" 19 20 using namespace lldb_private; 21 22 PythonExceptionState::PythonExceptionState(bool restore_on_exit) 23 : m_restore_on_exit(restore_on_exit) { 24 Acquire(restore_on_exit); 25 } 26 27 PythonExceptionState::~PythonExceptionState() { 28 if (m_restore_on_exit) 29 Restore(); 30 } 31 32 void PythonExceptionState::Acquire(bool restore_on_exit) { 33 // If a state is already acquired, the user needs to decide whether they want 34 // to discard or restore it. Don't allow the potential silent loss of a 35 // valid state. 36 assert(!IsError()); 37 38 if (!HasErrorOccurred()) 39 return; 40 41 PyObject *py_type = nullptr; 42 PyObject *py_value = nullptr; 43 PyObject *py_traceback = nullptr; 44 PyErr_Fetch(&py_type, &py_value, &py_traceback); 45 // PyErr_Fetch clears the error flag. 46 assert(!HasErrorOccurred()); 47 48 // Ownership of the objects returned by `PyErr_Fetch` is transferred to us. 49 m_type.Reset(PyRefType::Owned, py_type); 50 m_value.Reset(PyRefType::Owned, py_value); 51 m_traceback.Reset(PyRefType::Owned, py_traceback); 52 m_restore_on_exit = restore_on_exit; 53 } 54 55 void PythonExceptionState::Restore() { 56 if (m_type.IsValid()) { 57 // The documentation for PyErr_Restore says "Do not pass a null type and 58 // non-null value or traceback. So only restore if type was non-null to 59 // begin with. In this case we're passing ownership back to Python so 60 // release them all. 61 PyErr_Restore(m_type.release(), m_value.release(), m_traceback.release()); 62 } 63 64 // After we restore, we should not hold onto the exception state. Demand 65 // that it be re-acquired. 66 Discard(); 67 } 68 69 void PythonExceptionState::Discard() { 70 m_type.Reset(); 71 m_value.Reset(); 72 m_traceback.Reset(); 73 } 74 75 void PythonExceptionState::Reset() { 76 if (m_restore_on_exit) 77 Restore(); 78 else 79 Discard(); 80 } 81 82 bool PythonExceptionState::HasErrorOccurred() { return PyErr_Occurred(); } 83 84 bool PythonExceptionState::IsError() const { 85 return m_type.IsValid() || m_value.IsValid() || m_traceback.IsValid(); 86 } 87 88 PythonObject PythonExceptionState::GetType() const { return m_type; } 89 90 PythonObject PythonExceptionState::GetValue() const { return m_value; } 91 92 PythonObject PythonExceptionState::GetTraceback() const { return m_traceback; } 93 94 std::string PythonExceptionState::Format() const { 95 // Don't allow this function to modify the error state. 96 PythonExceptionState state(true); 97 98 std::string backtrace = ReadBacktrace(); 99 if (!IsError()) 100 return std::string(); 101 102 // It's possible that ReadPythonBacktrace generated another exception. If 103 // this happens we have to clear the exception, because otherwise 104 // PyObject_Str() will assert below. That's why we needed to do the save / 105 // restore at the beginning of this function. 106 PythonExceptionState bt_error_state(false); 107 108 std::string error_string; 109 llvm::raw_string_ostream error_stream(error_string); 110 error_stream << m_value.Str().GetString() << "\n"; 111 112 if (!bt_error_state.IsError()) { 113 // If we were able to read the backtrace, just append it. 114 error_stream << backtrace << "\n"; 115 } else { 116 // Otherwise, append some information about why we were unable to obtain 117 // the backtrace. 118 PythonString bt_error = bt_error_state.GetValue().Str(); 119 error_stream << "An error occurred while retrieving the backtrace: " 120 << bt_error.GetString() << "\n"; 121 } 122 return error_stream.str(); 123 } 124 125 std::string PythonExceptionState::ReadBacktrace() const { 126 std::string retval("backtrace unavailable"); 127 128 auto traceback_module = PythonModule::ImportModule("traceback"); 129 #if PY_MAJOR_VERSION >= 3 130 auto stringIO_module = PythonModule::ImportModule("io"); 131 #else 132 auto stringIO_module = PythonModule::ImportModule("StringIO"); 133 #endif 134 if (!m_traceback.IsAllocated()) 135 return retval; 136 137 if (!traceback_module.IsAllocated() || !stringIO_module.IsAllocated()) 138 return retval; 139 140 auto stringIO_builder = 141 stringIO_module.ResolveName<PythonCallable>("StringIO"); 142 if (!stringIO_builder.IsAllocated()) 143 return retval; 144 145 auto stringIO_buffer = stringIO_builder(); 146 if (!stringIO_buffer.IsAllocated()) 147 return retval; 148 149 auto printTB = traceback_module.ResolveName<PythonCallable>("print_tb"); 150 if (!printTB.IsAllocated()) 151 return retval; 152 153 auto printTB_result = 154 printTB(m_traceback.get(), Py_None, stringIO_buffer.get()); 155 auto stringIO_getvalue = 156 stringIO_buffer.ResolveName<PythonCallable>("getvalue"); 157 if (!stringIO_getvalue.IsAllocated()) 158 return retval; 159 160 auto printTB_string = stringIO_getvalue().AsType<PythonString>(); 161 if (!printTB_string.IsAllocated()) 162 return retval; 163 164 llvm::StringRef string_data(printTB_string.GetString()); 165 retval.assign(string_data.data(), string_data.size()); 166 167 return retval; 168 } 169 170 #endif 171