]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / ScriptInterpreter / Python / PythonExceptionState.cpp
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