9#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
10#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
20#include "lldb/Host/Config.h"
24#include "../PythonDataObjects.h"
25#include "../SWIGPythonBridge.h"
26#include "../ScriptInterpreterPythonImpl.h"
29class ScriptInterpreterPythonImpl;
30class ScriptedPythonInterface :
virtual public ScriptedInterface {
32 ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
33 ~ScriptedPythonInterface()
override =
default;
35 enum class AbstractMethodCheckerCases {
42 llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>>
43 CheckAbstractMethodImplementation(
44 const python::PythonDictionary &class_dict)
const {
46 using namespace python;
48 std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker;
49#define SET_ERROR_AND_CONTINUE(method_name, error) \
51 checker[method_name] = error; \
55 for (
const llvm::StringLiteral &method_name : GetAbstractMethods()) {
56 if (!class_dict.HasKey(method_name))
57 SET_ERROR_AND_CONTINUE(method_name,
58 AbstractMethodCheckerCases::eNotImplemented)
59 auto callable_or_err = class_dict.GetItem(method_name);
61 SET_ERROR_AND_CONTINUE(method_name,
62 AbstractMethodCheckerCases::eNotAllocated)
63 if (!PythonCallable::Check(callable_or_err.get().get()))
64 SET_ERROR_AND_CONTINUE(method_name,
65 AbstractMethodCheckerCases::eNotCallable)
66 checker[method_name] = AbstractMethodCheckerCases::eValid;
74 template <
typename... Args>
75 llvm::Expected<StructuredData::GenericSP>
76 CreatePluginObject(llvm::StringRef class_name,
77 StructuredData::Generic *script_obj, Args... args) {
78 using namespace python;
79 using Locker = ScriptInterpreterPythonImpl::Locker;
81 auto create_error = [](std::string message) {
82 return llvm::createStringError(llvm::inconvertibleErrorCode(), message);
85 bool has_class_name = !class_name.empty();
86 bool has_interpreter_dict =
87 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());
88 if (!has_class_name && !has_interpreter_dict && !script_obj) {
90 return create_error(
"Missing script class name.");
91 else if (!has_interpreter_dict)
92 return create_error(
"Invalid script interpreter dictionary.");
94 return create_error(
"Missing scripting object.");
97 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
100 PythonObject result = {};
103 result = PythonObject(PyRefType::Borrowed,
104 static_cast<PyObject *
>(script_obj->GetValue()));
107 PythonModule::MainModule().ResolveName<python::PythonDictionary>(
108 m_interpreter.GetDictionaryName());
109 if (!dict.IsAllocated())
111 llvm::formatv(
"Could not find interpreter dictionary: %s",
112 m_interpreter.GetDictionaryName()));
115 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
117 if (!init.IsAllocated())
118 return create_error(llvm::formatv(
"Could not find script class: %s",
121 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
122 auto transformed_args = TransformArgs(original_args);
124 std::string error_string;
125 llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();
127 llvm::handleAllErrors(
128 arg_info.takeError(),
129 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
130 [&](
const llvm::ErrorInfoBase &E) {
131 error_string.append(E.message());
133 return llvm::createStringError(llvm::inconvertibleErrorCode(),
137 llvm::Expected<PythonObject> expected_return_object =
138 create_error(
"Resulting object is not initialized.");
141 [&init, &expected_return_object](
auto &&...args) {
142 llvm::consumeError(expected_return_object.takeError());
143 expected_return_object = init(args...);
147 if (!expected_return_object)
148 return expected_return_object.takeError();
149 result = expected_return_object.get();
152 if (!result.IsValid())
153 return create_error(
"Resulting object is not a valid Python Object.");
154 if (!result.HasAttribute(
"__class__"))
155 return create_error(
"Resulting object doesn't have '__class__' member.");
157 PythonObject obj_class = result.GetAttributeValue(
"__class__");
158 if (!obj_class.IsValid())
159 return create_error(
"Resulting class object is not a valid.");
160 if (!obj_class.HasAttribute(
"__name__"))
162 "Resulting object class doesn't have '__name__' member.");
163 PythonString obj_class_name =
164 obj_class.GetAttributeValue(
"__name__").AsType<PythonString>();
166 PythonObject object_class_mapping_proxy =
167 obj_class.GetAttributeValue(
"__dict__");
168 if (!obj_class.HasAttribute(
"__dict__"))
170 "Resulting object class doesn't have '__dict__' member.");
172 PythonCallable dict_converter = PythonModule::BuiltinsModule()
174 .AsType<PythonCallable>();
175 if (!dict_converter.IsAllocated())
177 "Python 'builtins' module doesn't have 'dict' class.");
179 PythonDictionary object_class_dict =
180 dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>();
181 if (!object_class_dict.IsAllocated())
182 return create_error(
"Coudn't create dictionary from resulting object "
183 "class mapping proxy object.");
185 auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict);
187 return checker_or_err.takeError();
189 for (
const auto &method_checker : *checker_or_err)
190 switch (method_checker.second) {
191 case AbstractMethodCheckerCases::eNotImplemented:
193 "Abstract method {0}.{1} not implemented.",
194 obj_class_name.GetString(), method_checker.first);
196 case AbstractMethodCheckerCases::eNotAllocated:
198 "Abstract method {0}.{1} not allocated.",
199 obj_class_name.GetString(), method_checker.first);
201 case AbstractMethodCheckerCases::eNotCallable:
203 "Abstract method {0}.{1} not callable.",
204 obj_class_name.GetString(), method_checker.first);
206 case AbstractMethodCheckerCases::eValid:
208 "Abstract method {0}.{1} implemented & valid.",
209 obj_class_name.GetString(), method_checker.first);
213 for (
const auto &method_checker : *checker_or_err)
214 if (method_checker.second != AbstractMethodCheckerCases::eValid)
216 llvm::formatv(
"Abstract method {0}.{1} missing. Enable lldb "
217 "script log for more details.",
218 obj_class_name.GetString(), method_checker.first));
220 m_object_instance_sp = StructuredData::GenericSP(
221 new StructuredPythonObject(std::move(result)));
222 return m_object_instance_sp;
226 template <
typename T = StructuredData::ObjectSP>
227 T ExtractValueFromPythonObject(python::PythonObject &p, Status &
error) {
228 return p.CreateStructuredObject();
231 template <
typename T = StructuredData::ObjectSP,
typename... Args>
232 T Dispatch(llvm::StringRef method_name, Status &
error, Args &&...args) {
233 using namespace python;
234 using Locker = ScriptInterpreterPythonImpl::Locker;
236 std::string caller_signature =
237 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(
" (") +
238 llvm::Twine(method_name) + llvm::Twine(
")"))
240 if (!m_object_instance_sp)
241 return ErrorWithMessage<T>(caller_signature,
"Python object ill-formed",
244 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
247 PythonObject implementor(PyRefType::Borrowed,
248 (PyObject *)m_object_instance_sp->GetValue());
250 if (!implementor.IsAllocated())
251 return ErrorWithMessage<T>(caller_signature,
252 "Python implementor not allocated.",
error);
254 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
255 auto transformed_args = TransformArgs(original_args);
257 llvm::Expected<PythonObject> expected_return_object =
258 llvm::make_error<llvm::StringError>(
"Not initialized.",
259 llvm::inconvertibleErrorCode());
261 [&implementor, &method_name, &expected_return_object](
auto &&...args) {
262 llvm::consumeError(expected_return_object.takeError());
263 expected_return_object =
264 implementor.CallMethod(method_name.data(), args...);
268 if (llvm::Error e = expected_return_object.takeError()) {
269 error.SetErrorString(llvm::toString(std::move(e)).c_str());
270 return ErrorWithMessage<T>(caller_signature,
271 "Python method could not be called.",
error);
274 PythonObject py_return = std::move(expected_return_object.get());
280 if (
sizeof...(Args) > 0)
281 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
282 return ErrorWithMessage<T>(
284 "Couldn't re-assign reference and pointer arguments.",
error);
286 if (!py_return.IsAllocated())
288 return ExtractValueFromPythonObject<T>(py_return,
error);
291 template <
typename... Args>
292 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {
294 Dispatch<Status>(method_name,
error, std::forward<Args>(args)...);
299 template <
typename T> T Transform(T
object) {
304 python::PythonObject Transform(
bool arg) {
306 return python::PythonBoolean(arg);
309 python::PythonObject Transform(Status arg) {
310 return python::SWIGBridge::ToSWIGWrapper(arg);
313 python::PythonObject Transform(
const StructuredDataImpl &arg) {
314 return python::SWIGBridge::ToSWIGWrapper(arg);
318 return python::SWIGBridge::ToSWIGWrapper(arg);
322 return python::SWIGBridge::ToSWIGWrapper(arg);
326 return python::SWIGBridge::ToSWIGWrapper(arg);
330 return python::SWIGBridge::ToSWIGWrapper(arg);
334 return python::SWIGBridge::ToSWIGWrapper(arg);
337 template <
typename T,
typename U>
338 void ReverseTransform(T &original_arg, U transformed_arg, Status &
error) {
343 template <
typename T>
344 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,
346 original_arg = ExtractValueFromPythonObject<T>(transformed_arg,
error);
349 void ReverseTransform(
bool &original_arg,
350 python::PythonObject transformed_arg, Status &
error) {
351 python::PythonBoolean boolean_arg = python::PythonBoolean(
352 python::PyRefType::Borrowed, transformed_arg.get());
353 if (boolean_arg.IsValid())
354 original_arg = boolean_arg.GetValue();
356 error.SetErrorString(
357 llvm::formatv(
"{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION)
361 template <std::size_t... I,
typename... Args>
362 auto TransformTuple(
const std::tuple<Args...> &args,
363 std::index_sequence<I...>) {
364 return std::make_tuple(Transform(std::get<I>(args))...);
369 template <
typename... Args>
370 auto TransformArgs(
const std::tuple<Args...> &args) {
371 return TransformTuple(args, std::make_index_sequence<
sizeof...(Args)>());
374 template <
typename T,
typename U>
375 void TransformBack(T &original_arg, U transformed_arg, Status &
error) {
376 ReverseTransform(original_arg, transformed_arg,
error);
379 template <std::size_t... I,
typename... Ts,
typename... Us>
380 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
381 std::tuple<Us...> &transformed_args,
382 std::index_sequence<I...>) {
384 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
387 return error.Success();
390 template <
typename... Ts,
typename... Us>
391 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
392 std::tuple<Us...> &transformed_args) {
393 if (
sizeof...(Ts) !=
sizeof...(Us))
396 return ReassignPtrsOrRefsArgs(original_args, transformed_args,
397 std::make_index_sequence<
sizeof...(Ts)>());
400 template <
typename T,
typename... Args>
401 void FormatArgs(std::string &fmt, T arg, Args... args)
const {
402 FormatArgs(fmt, arg);
403 FormatArgs(fmt, args...);
406 template <
typename T>
void FormatArgs(std::string &fmt, T arg)
const {
407 fmt += python::PythonFormat<T>::format;
410 void FormatArgs(std::string &fmt)
const {}
413 ScriptInterpreterPythonImpl &m_interpreter;
418ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
419 python::PythonObject &p, Status &
error);
423ScriptedPythonInterface::ExtractValueFromPythonObject<
427Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
428 python::PythonObject &p, Status &
error);
432ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
433 python::PythonObject &p, Status &
error);
445ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
446 python::PythonObject &p, Status &
error);
449std::optional<MemoryRegionInfo>
450ScriptedPythonInterface::ExtractValueFromPythonObject<
451 std::optional<MemoryRegionInfo>>(python::PythonObject &p,
Status &
error);
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Array > ArraySP
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::ProcessAttachInfo > ProcessAttachInfoSP
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::DataExtractor > DataExtractorSP
std::shared_ptr< lldb_private::ProcessLaunchInfo > ProcessLaunchInfoSP
std::shared_ptr< lldb_private::ExecutionContextRef > ExecutionContextRefSP