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 34 // want to discard or restore it. Don't allow the potential silent 35 // loss of a 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 49 // to us. 50 m_type.Reset(PyRefType::Owned, py_type); 51 m_value.Reset(PyRefType::Owned, py_value); 52 m_traceback.Reset(PyRefType::Owned, py_traceback); 53 m_restore_on_exit = restore_on_exit; 54 } 55 56 void PythonExceptionState::Restore() { 57 if (m_type.IsValid()) { 58 // The documentation for PyErr_Restore says "Do not pass a null type and 59 // non-null value or traceback. So only restore if type was non-null 60 // to begin with. In this case we're passing ownership back to Python 61 // so release them all. 62 PyErr_Restore(m_type.release(), m_value.release(), m_traceback.release()); 63 } 64 65 // After we restore, we should not hold onto the exception state. Demand that 66 // it be re-acquired. 67 Discard(); 68 } 69 70 void PythonExceptionState::Discard() { 71 m_type.Reset(); 72 m_value.Reset(); 73 m_traceback.Reset(); 74 } 75 76 void PythonExceptionState::Reset() { 77 if (m_restore_on_exit) 78 Restore(); 79 else 80 Discard(); 81 } 82 83 bool PythonExceptionState::HasErrorOccurred() { return PyErr_Occurred(); } 84 85 bool PythonExceptionState::IsError() const { 86 return m_type.IsValid() || m_value.IsValid() || m_traceback.IsValid(); 87 } 88 89 PythonObject PythonExceptionState::GetType() const { return m_type; } 90 91 PythonObject PythonExceptionState::GetValue() const { return m_value; } 92 93 PythonObject PythonExceptionState::GetTraceback() const { return m_traceback; } 94 95 std::string PythonExceptionState::Format() const { 96 // Don't allow this function to modify the error state. 97 PythonExceptionState state(true); 98 99 std::string backtrace = ReadBacktrace(); 100 if (!IsError()) 101 return std::string(); 102 103 // It's possible that ReadPythonBacktrace generated another exception. 104 // If this happens we have to clear the exception, because otherwise 105 // PyObject_Str() will assert below. That's why we needed to do the 106 // save / restore at the beginning of this function. 107 PythonExceptionState bt_error_state(false); 108 109 std::string error_string; 110 llvm::raw_string_ostream error_stream(error_string); 111 error_stream << m_value.Str().GetString() << "\n"; 112 113 if (!bt_error_state.IsError()) { 114 // If we were able to read the backtrace, just append it. 115 error_stream << backtrace << "\n"; 116 } else { 117 // Otherwise, append some information about why we were unable to 118 // obtain the backtrace. 119 PythonString bt_error = bt_error_state.GetValue().Str(); 120 error_stream << "An error occurred while retrieving the backtrace: " 121 << bt_error.GetString() << "\n"; 122 } 123 return error_stream.str(); 124 } 125 126 std::string PythonExceptionState::ReadBacktrace() const { 127 std::string retval("backtrace unavailable"); 128 129 auto traceback_module = PythonModule::ImportModule("traceback"); 130 #if PY_MAJOR_VERSION >= 3 131 auto stringIO_module = PythonModule::ImportModule("io"); 132 #else 133 auto stringIO_module = PythonModule::ImportModule("StringIO"); 134 #endif 135 if (!m_traceback.IsAllocated()) 136 return retval; 137 138 if (!traceback_module.IsAllocated() || !stringIO_module.IsAllocated()) 139 return retval; 140 141 auto stringIO_builder = 142 stringIO_module.ResolveName<PythonCallable>("StringIO"); 143 if (!stringIO_builder.IsAllocated()) 144 return retval; 145 146 auto stringIO_buffer = stringIO_builder(); 147 if (!stringIO_buffer.IsAllocated()) 148 return retval; 149 150 auto printTB = traceback_module.ResolveName<PythonCallable>("print_tb"); 151 if (!printTB.IsAllocated()) 152 return retval; 153 154 auto printTB_result = 155 printTB(m_traceback.get(), Py_None, stringIO_buffer.get()); 156 auto stringIO_getvalue = 157 stringIO_buffer.ResolveName<PythonCallable>("getvalue"); 158 if (!stringIO_getvalue.IsAllocated()) 159 return retval; 160 161 auto printTB_string = stringIO_getvalue().AsType<PythonString>(); 162 if (!printTB_string.IsAllocated()) 163 return retval; 164 165 llvm::StringRef string_data(printTB_string.GetString()); 166 retval.assign(string_data.data(), string_data.size()); 167 168 return retval; 169 } 170 171 #endif 172