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