xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1*f6aab3d8Srobert //===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===//
2*f6aab3d8Srobert //
3*f6aab3d8Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*f6aab3d8Srobert // See https://llvm.org/LICENSE.txt for license information.
5*f6aab3d8Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*f6aab3d8Srobert //
7*f6aab3d8Srobert //===----------------------------------------------------------------------===//
8*f6aab3d8Srobert 
9*f6aab3d8Srobert #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
10*f6aab3d8Srobert #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
11*f6aab3d8Srobert 
12*f6aab3d8Srobert #if LLDB_ENABLE_PYTHON
13*f6aab3d8Srobert 
14*f6aab3d8Srobert #include <optional>
15*f6aab3d8Srobert #include <sstream>
16*f6aab3d8Srobert #include <tuple>
17*f6aab3d8Srobert #include <type_traits>
18*f6aab3d8Srobert #include <utility>
19*f6aab3d8Srobert 
20*f6aab3d8Srobert #include "lldb/Host/Config.h"
21*f6aab3d8Srobert #include "lldb/Interpreter/ScriptedInterface.h"
22*f6aab3d8Srobert #include "lldb/Utility/DataBufferHeap.h"
23*f6aab3d8Srobert 
24*f6aab3d8Srobert #include "PythonDataObjects.h"
25*f6aab3d8Srobert #include "SWIGPythonBridge.h"
26*f6aab3d8Srobert #include "ScriptInterpreterPythonImpl.h"
27*f6aab3d8Srobert 
28*f6aab3d8Srobert namespace lldb_private {
29*f6aab3d8Srobert class ScriptInterpreterPythonImpl;
30*f6aab3d8Srobert class ScriptedPythonInterface : virtual public ScriptedInterface {
31*f6aab3d8Srobert public:
32*f6aab3d8Srobert   ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
33*f6aab3d8Srobert   ~ScriptedPythonInterface() override = default;
34*f6aab3d8Srobert 
35*f6aab3d8Srobert protected:
36*f6aab3d8Srobert   template <typename T = StructuredData::ObjectSP>
ExtractValueFromPythonObject(python::PythonObject & p,Status & error)37*f6aab3d8Srobert   T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
38*f6aab3d8Srobert     return p.CreateStructuredObject();
39*f6aab3d8Srobert   }
40*f6aab3d8Srobert 
41*f6aab3d8Srobert   template <typename T = StructuredData::ObjectSP, typename... Args>
Dispatch(llvm::StringRef method_name,Status & error,Args &&...args)42*f6aab3d8Srobert   T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) {
43*f6aab3d8Srobert     using namespace python;
44*f6aab3d8Srobert     using Locker = ScriptInterpreterPythonImpl::Locker;
45*f6aab3d8Srobert 
46*f6aab3d8Srobert     std::string caller_signature =
47*f6aab3d8Srobert         llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
48*f6aab3d8Srobert                     llvm::Twine(method_name) + llvm::Twine(")"))
49*f6aab3d8Srobert             .str();
50*f6aab3d8Srobert     if (!m_object_instance_sp)
51*f6aab3d8Srobert       return ErrorWithMessage<T>(caller_signature, "Python object ill-formed",
52*f6aab3d8Srobert                                  error);
53*f6aab3d8Srobert 
54*f6aab3d8Srobert     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
55*f6aab3d8Srobert                    Locker::FreeLock);
56*f6aab3d8Srobert 
57*f6aab3d8Srobert     PythonObject implementor(PyRefType::Borrowed,
58*f6aab3d8Srobert                              (PyObject *)m_object_instance_sp->GetValue());
59*f6aab3d8Srobert 
60*f6aab3d8Srobert     if (!implementor.IsAllocated())
61*f6aab3d8Srobert       return ErrorWithMessage<T>(caller_signature,
62*f6aab3d8Srobert                                  "Python implementor not allocated.", error);
63*f6aab3d8Srobert 
64*f6aab3d8Srobert     std::tuple<Args...> original_args = std::forward_as_tuple(args...);
65*f6aab3d8Srobert     auto transformed_args = TransformArgs(original_args);
66*f6aab3d8Srobert 
67*f6aab3d8Srobert     llvm::Expected<PythonObject> expected_return_object =
68*f6aab3d8Srobert         llvm::make_error<llvm::StringError>("Not initialized.",
69*f6aab3d8Srobert                                             llvm::inconvertibleErrorCode());
70*f6aab3d8Srobert     std::apply(
71*f6aab3d8Srobert         [&implementor, &method_name, &expected_return_object](auto &&...args) {
72*f6aab3d8Srobert           llvm::consumeError(expected_return_object.takeError());
73*f6aab3d8Srobert           expected_return_object =
74*f6aab3d8Srobert               implementor.CallMethod(method_name.data(), args...);
75*f6aab3d8Srobert         },
76*f6aab3d8Srobert         transformed_args);
77*f6aab3d8Srobert 
78*f6aab3d8Srobert     if (llvm::Error e = expected_return_object.takeError()) {
79*f6aab3d8Srobert       error.SetErrorString(llvm::toString(std::move(e)).c_str());
80*f6aab3d8Srobert       return ErrorWithMessage<T>(caller_signature,
81*f6aab3d8Srobert                                  "Python method could not be called.", error);
82*f6aab3d8Srobert     }
83*f6aab3d8Srobert 
84*f6aab3d8Srobert     PythonObject py_return = std::move(expected_return_object.get());
85*f6aab3d8Srobert 
86*f6aab3d8Srobert     if (!py_return.IsAllocated())
87*f6aab3d8Srobert       return ErrorWithMessage<T>(caller_signature, "Returned object is null.",
88*f6aab3d8Srobert                                  error);
89*f6aab3d8Srobert 
90*f6aab3d8Srobert     // Now that we called the python method with the transformed arguments,
91*f6aab3d8Srobert     // we need to interate again over both the original and transformed
92*f6aab3d8Srobert     // parameter pack, and transform back the parameter that were passed in
93*f6aab3d8Srobert     // the original parameter pack as references or pointers.
94*f6aab3d8Srobert     if (sizeof...(Args) > 0)
95*f6aab3d8Srobert       if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
96*f6aab3d8Srobert         return ErrorWithMessage<T>(
97*f6aab3d8Srobert             caller_signature,
98*f6aab3d8Srobert             "Couldn't re-assign reference and pointer arguments.", error);
99*f6aab3d8Srobert 
100*f6aab3d8Srobert     return ExtractValueFromPythonObject<T>(py_return, error);
101*f6aab3d8Srobert   }
102*f6aab3d8Srobert 
103*f6aab3d8Srobert   template <typename... Args>
GetStatusFromMethod(llvm::StringRef method_name,Args &&...args)104*f6aab3d8Srobert   Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {
105*f6aab3d8Srobert     Status error;
106*f6aab3d8Srobert     Dispatch<Status>(method_name, error, std::forward<Args>(args)...);
107*f6aab3d8Srobert 
108*f6aab3d8Srobert     return error;
109*f6aab3d8Srobert   }
110*f6aab3d8Srobert 
Transform(T object)111*f6aab3d8Srobert   template <typename T> T Transform(T object) {
112*f6aab3d8Srobert     // No Transformation for generic usage
113*f6aab3d8Srobert     return {object};
114*f6aab3d8Srobert   }
115*f6aab3d8Srobert 
Transform(Status arg)116*f6aab3d8Srobert   python::PythonObject Transform(Status arg) {
117*f6aab3d8Srobert     return python::ToSWIGWrapper(arg);
118*f6aab3d8Srobert   }
119*f6aab3d8Srobert 
120*f6aab3d8Srobert   template <typename T, typename U>
ReverseTransform(T & original_arg,U transformed_arg,Status & error)121*f6aab3d8Srobert   void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
122*f6aab3d8Srobert     // If U is not a PythonObject, don't touch it!
123*f6aab3d8Srobert     return;
124*f6aab3d8Srobert   }
125*f6aab3d8Srobert 
126*f6aab3d8Srobert   template <typename T>
ReverseTransform(T & original_arg,python::PythonObject transformed_arg,Status & error)127*f6aab3d8Srobert   void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,
128*f6aab3d8Srobert                         Status &error) {
129*f6aab3d8Srobert     original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error);
130*f6aab3d8Srobert   }
131*f6aab3d8Srobert 
132*f6aab3d8Srobert   template <std::size_t... I, typename... Args>
TransformTuple(const std::tuple<Args...> & args,std::index_sequence<I...>)133*f6aab3d8Srobert   auto TransformTuple(const std::tuple<Args...> &args,
134*f6aab3d8Srobert                       std::index_sequence<I...>) {
135*f6aab3d8Srobert     return std::make_tuple(Transform(std::get<I>(args))...);
136*f6aab3d8Srobert   }
137*f6aab3d8Srobert 
138*f6aab3d8Srobert   // This will iterate over the Dispatch parameter pack and replace in-place
139*f6aab3d8Srobert   // every `lldb_private` argument that has a SB counterpart.
140*f6aab3d8Srobert   template <typename... Args>
TransformArgs(const std::tuple<Args...> & args)141*f6aab3d8Srobert   auto TransformArgs(const std::tuple<Args...> &args) {
142*f6aab3d8Srobert     return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>());
143*f6aab3d8Srobert   }
144*f6aab3d8Srobert 
145*f6aab3d8Srobert   template <typename T, typename U>
TransformBack(T & original_arg,U transformed_arg,Status & error)146*f6aab3d8Srobert   void TransformBack(T &original_arg, U transformed_arg, Status &error) {
147*f6aab3d8Srobert     ReverseTransform(original_arg, transformed_arg, error);
148*f6aab3d8Srobert   }
149*f6aab3d8Srobert 
150*f6aab3d8Srobert   template <std::size_t... I, typename... Ts, typename... Us>
ReassignPtrsOrRefsArgs(std::tuple<Ts...> & original_args,std::tuple<Us...> & transformed_args,std::index_sequence<I...>)151*f6aab3d8Srobert   bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
152*f6aab3d8Srobert                               std::tuple<Us...> &transformed_args,
153*f6aab3d8Srobert                               std::index_sequence<I...>) {
154*f6aab3d8Srobert     Status error;
155*f6aab3d8Srobert     (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
156*f6aab3d8Srobert                    error),
157*f6aab3d8Srobert      ...);
158*f6aab3d8Srobert     return error.Success();
159*f6aab3d8Srobert   }
160*f6aab3d8Srobert 
161*f6aab3d8Srobert   template <typename... Ts, typename... Us>
ReassignPtrsOrRefsArgs(std::tuple<Ts...> & original_args,std::tuple<Us...> & transformed_args)162*f6aab3d8Srobert   bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
163*f6aab3d8Srobert                               std::tuple<Us...> &transformed_args) {
164*f6aab3d8Srobert     if (sizeof...(Ts) != sizeof...(Us))
165*f6aab3d8Srobert       return false;
166*f6aab3d8Srobert 
167*f6aab3d8Srobert     return ReassignPtrsOrRefsArgs(original_args, transformed_args,
168*f6aab3d8Srobert                                   std::make_index_sequence<sizeof...(Ts)>());
169*f6aab3d8Srobert   }
170*f6aab3d8Srobert 
171*f6aab3d8Srobert   template <typename T, typename... Args>
FormatArgs(std::string & fmt,T arg,Args...args)172*f6aab3d8Srobert   void FormatArgs(std::string &fmt, T arg, Args... args) const {
173*f6aab3d8Srobert     FormatArgs(fmt, arg);
174*f6aab3d8Srobert     FormatArgs(fmt, args...);
175*f6aab3d8Srobert   }
176*f6aab3d8Srobert 
FormatArgs(std::string & fmt,T arg)177*f6aab3d8Srobert   template <typename T> void FormatArgs(std::string &fmt, T arg) const {
178*f6aab3d8Srobert     fmt += python::PythonFormat<T>::format;
179*f6aab3d8Srobert   }
180*f6aab3d8Srobert 
FormatArgs(std::string & fmt)181*f6aab3d8Srobert   void FormatArgs(std::string &fmt) const {}
182*f6aab3d8Srobert 
183*f6aab3d8Srobert   // The lifetime is managed by the ScriptInterpreter
184*f6aab3d8Srobert   ScriptInterpreterPythonImpl &m_interpreter;
185*f6aab3d8Srobert };
186*f6aab3d8Srobert 
187*f6aab3d8Srobert template <>
188*f6aab3d8Srobert StructuredData::ArraySP
189*f6aab3d8Srobert ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
190*f6aab3d8Srobert     python::PythonObject &p, Status &error);
191*f6aab3d8Srobert 
192*f6aab3d8Srobert template <>
193*f6aab3d8Srobert StructuredData::DictionarySP
194*f6aab3d8Srobert ScriptedPythonInterface::ExtractValueFromPythonObject<
195*f6aab3d8Srobert     StructuredData::DictionarySP>(python::PythonObject &p, Status &error);
196*f6aab3d8Srobert 
197*f6aab3d8Srobert template <>
198*f6aab3d8Srobert Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
199*f6aab3d8Srobert     python::PythonObject &p, Status &error);
200*f6aab3d8Srobert 
201*f6aab3d8Srobert template <>
202*f6aab3d8Srobert lldb::DataExtractorSP
203*f6aab3d8Srobert ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
204*f6aab3d8Srobert     python::PythonObject &p, Status &error);
205*f6aab3d8Srobert 
206*f6aab3d8Srobert template <>
207*f6aab3d8Srobert std::optional<MemoryRegionInfo>
208*f6aab3d8Srobert ScriptedPythonInterface::ExtractValueFromPythonObject<
209*f6aab3d8Srobert     std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
210*f6aab3d8Srobert 
211*f6aab3d8Srobert } // namespace lldb_private
212*f6aab3d8Srobert 
213*f6aab3d8Srobert #endif // LLDB_ENABLE_PYTHON
214*f6aab3d8Srobert #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H
215