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