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     std::string caller_signature =
42         llvm::Twine(__PRETTY_FUNCTION__ + llvm::Twine(" (") +
43                     llvm::Twine(method_name) + llvm::Twine(")"))
44             .str();
45     if (!m_object_instance_sp)
46       return ErrorWithMessage<T>(caller_signature, "Python object ill-formed",
47                                  error);
48 
49     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
50                    Locker::FreeLock);
51 
52     PythonObject implementor(PyRefType::Borrowed,
53                              (PyObject *)m_object_instance_sp->GetValue());
54 
55     if (!implementor.IsAllocated())
56       return ErrorWithMessage<T>(caller_signature,
57                                  "Python implementor not allocated.", error);
58 
59     PythonObject pmeth(
60         PyRefType::Owned,
61         PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
62 
63     if (PyErr_Occurred())
64       PyErr_Clear();
65 
66     if (!pmeth.IsAllocated())
67       return ErrorWithMessage<T>(caller_signature,
68                                  "Python method not allocated.", error);
69 
70     if (PyCallable_Check(pmeth.get()) == 0) {
71       if (PyErr_Occurred())
72         PyErr_Clear();
73       return ErrorWithMessage<T>(caller_signature,
74                                  "Python method not callable.", error);
75     }
76 
77     if (PyErr_Occurred())
78       PyErr_Clear();
79 
80     // TODO: make `const char *` when removing support for Python 2.
81     char *format = nullptr;
82     std::string format_buffer;
83 
84     if (sizeof...(Args) > 0) {
85       FormatArgs(format_buffer, args...);
86       // TODO: make `const char *` when removing support for Python 2.
87       format = const_cast<char *>(format_buffer.c_str());
88     }
89 
90     // TODO: make `const char *` when removing support for Python 2.
91     PythonObject py_return(
92         PyRefType::Owned,
93         PyObject_CallMethod(implementor.get(),
94                             const_cast<char *>(method_name.data()), format,
95                             args...));
96 
97     if (PyErr_Occurred()) {
98       PyErr_Print();
99       PyErr_Clear();
100       return ErrorWithMessage<T>(caller_signature,
101                                  "Python method could not be called.", error);
102     }
103 
104     if (!py_return.IsAllocated())
105       return ErrorWithMessage<T>(caller_signature, "Returned object is null.",
106                                  error);
107 
108     return ExtractValueFromPythonObject<T>(py_return, error);
109   }
110 
111   Status GetStatusFromMethod(llvm::StringRef method_name);
112 
113   template <typename T, typename... Args>
114   void FormatArgs(std::string &fmt, T arg, Args... args) const {
115     FormatArgs(fmt, arg);
116     FormatArgs(fmt, args...);
117   }
118 
119   template <typename T> void FormatArgs(std::string &fmt, T arg) const {
120     fmt += GetPythonValueFormatString(arg);
121   }
122 
123   void FormatArgs(std::string &fmt) const {}
124 
125   // The lifetime is managed by the ScriptInterpreter
126   ScriptInterpreterPythonImpl &m_interpreter;
127 };
128 
129 template <>
130 StructuredData::DictionarySP
131 ScriptedPythonInterface::ExtractValueFromPythonObject<
132     StructuredData::DictionarySP>(python::PythonObject &p, Status &error);
133 
134 template <>
135 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
136     python::PythonObject &p, Status &error);
137 
138 template <>
139 lldb::DataExtractorSP
140 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
141     python::PythonObject &p, Status &error);
142 
143 template <>
144 llvm::Optional<MemoryRegionInfo>
145 ScriptedPythonInterface::ExtractValueFromPythonObject<
146     llvm::Optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
147 
148 } // namespace lldb_private
149 
150 #endif // LLDB_ENABLE_PYTHON
151 #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
152