1 //===-- ScriptedPythonInterface.h -------------------------------*- 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_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
10 #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
11 
12 #include "lldb/Host/Config.h"
13 
14 #if LLDB_ENABLE_PYTHON
15 
16 #include "lldb/Interpreter/ScriptedInterface.h"
17 #include "lldb/Utility/DataBufferHeap.h"
18 
19 #include "PythonDataObjects.h"
20 #include "SWIGPythonBridge.h"
21 #include "ScriptInterpreterPythonImpl.h"
22 
23 namespace lldb_private {
24 class ScriptInterpreterPythonImpl;
25 class ScriptedPythonInterface : virtual public ScriptedInterface {
26 public:
27   ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
28   virtual ~ScriptedPythonInterface() = default;
29 
30 protected:
31   template <typename T = StructuredData::ObjectSP>
32   T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
33     return p.CreateStructuredObject();
34   }
35 
36   template <typename T = StructuredData::ObjectSP, typename... Args>
37   T Dispatch(llvm::StringRef method_name, Status &error, Args... args) {
38     using namespace python;
39     using Locker = ScriptInterpreterPythonImpl::Locker;
40 
41     auto error_with_message = [&method_name, &error](llvm::StringRef message) {
42       error.SetErrorStringWithFormatv(
43           "ScriptedPythonInterface::{0} ({1}) ERROR = {2}", __FUNCTION__,
44           method_name, message);
45       return T();
46     };
47 
48     if (!m_object_instance_sp)
49       return error_with_message("Python object ill-formed");
50 
51     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
52                    Locker::FreeLock);
53 
54     PythonObject implementor(PyRefType::Borrowed,
55                              (PyObject *)m_object_instance_sp->GetValue());
56 
57     if (!implementor.IsAllocated())
58       return error_with_message("Python implementor not allocated.");
59 
60     PythonObject pmeth(
61         PyRefType::Owned,
62         PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
63 
64     if (PyErr_Occurred())
65       PyErr_Clear();
66 
67     if (!pmeth.IsAllocated())
68       return error_with_message("Python method not allocated.");
69 
70     if (PyCallable_Check(pmeth.get()) == 0) {
71       if (PyErr_Occurred())
72         PyErr_Clear();
73       return error_with_message("Python method not callable.");
74     }
75 
76     if (PyErr_Occurred())
77       PyErr_Clear();
78 
79     // TODO: make `const char *` when removing support for Python 2.
80     char *format = nullptr;
81     std::string format_buffer;
82 
83     if (sizeof...(Args) > 0) {
84       FormatArgs(format_buffer, args...);
85       // TODO: make `const char *` when removing support for Python 2.
86       format = const_cast<char *>(format_buffer.c_str());
87     }
88 
89     // TODO: make `const char *` when removing support for Python 2.
90     PythonObject py_return(
91         PyRefType::Owned,
92         PyObject_CallMethod(implementor.get(),
93                             const_cast<char *>(method_name.data()), format,
94                             args...));
95 
96     if (PyErr_Occurred()) {
97       PyErr_Print();
98       PyErr_Clear();
99       return error_with_message("Python method could not be called.");
100     }
101 
102     if (!py_return.IsAllocated())
103       return error_with_message("Returned object is null.");
104 
105     return ExtractValueFromPythonObject<T>(py_return, error);
106   }
107 
108   Status GetStatusFromMethod(llvm::StringRef method_name);
109 
110   template <typename T, typename... Args>
111   void FormatArgs(std::string &fmt, T arg, Args... args) const {
112     FormatArgs(fmt, arg);
113     FormatArgs(fmt, args...);
114   }
115 
116   template <typename T> void FormatArgs(std::string &fmt, T arg) const {
117     fmt += GetPythonValueFormatString(arg);
118   }
119 
120   void FormatArgs(std::string &fmt) const {}
121 
122   // The lifetime is managed by the ScriptInterpreter
123   ScriptInterpreterPythonImpl &m_interpreter;
124 };
125 
126 template <>
127 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
128     python::PythonObject &p, Status &error);
129 
130 template <>
131 lldb::DataExtractorSP
132 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
133     python::PythonObject &p, Status &error);
134 
135 } // namespace lldb_private
136 
137 #endif // LLDB_ENABLE_PYTHON
138 #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
139