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