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 {
39 eUnknownArgumentCount,
40 eInvalidArgumentCount,
44 struct AbstrackMethodCheckerPayload {
46 struct InvalidArgumentCountPayload {
47 InvalidArgumentCountPayload(
size_t required,
size_t actual)
48 : required_argument_count(required), actual_argument_count(actual) {}
50 size_t required_argument_count;
51 size_t actual_argument_count;
54 AbstractMethodCheckerCases checker_case;
55 std::variant<std::monostate, InvalidArgumentCountPayload> payload;
58 llvm::Expected<std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload>>
59 CheckAbstractMethodImplementation(
60 const python::PythonDictionary &class_dict)
const {
62 using namespace python;
64 std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload> checker;
65#define SET_CASE_AND_CONTINUE(method_name, case) \
67 checker[method_name] = {case, {}}; \
71 for (
const AbstractMethodRequirement &requirement :
72 GetAbstractMethodRequirements()) {
73 llvm::StringLiteral method_name = requirement.name;
74 if (!class_dict.HasKey(method_name))
75 SET_CASE_AND_CONTINUE(method_name,
76 AbstractMethodCheckerCases::eNotImplemented)
77 auto callable_or_err = class_dict.GetItem(method_name);
78 if (!callable_or_err) {
79 llvm::consumeError(callable_or_err.takeError());
80 SET_CASE_AND_CONTINUE(method_name,
81 AbstractMethodCheckerCases::eNotAllocated)
84 PythonCallable callable = callable_or_err->AsType<PythonCallable>();
86 SET_CASE_AND_CONTINUE(method_name,
87 AbstractMethodCheckerCases::eNotCallable)
89 if (!requirement.min_arg_count)
90 SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid)
92 auto arg_info_or_err = callable.GetArgInfo();
93 if (!arg_info_or_err) {
94 llvm::consumeError(arg_info_or_err.takeError());
95 SET_CASE_AND_CONTINUE(method_name,
96 AbstractMethodCheckerCases::eUnknownArgumentCount)
99 PythonCallable::ArgInfo arg_info = *arg_info_or_err;
100 if (requirement.min_arg_count <= arg_info.max_positional_args) {
101 SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid)
103 checker[method_name] = {
104 AbstractMethodCheckerCases::eInvalidArgumentCount,
105 AbstrackMethodCheckerPayload::InvalidArgumentCountPayload(
106 requirement.min_arg_count, arg_info.max_positional_args)};
110#undef SET_CASE_AND_CONTINUE
115 template <
typename... Args>
116 llvm::Expected<StructuredData::GenericSP>
117 CreatePluginObject(llvm::StringRef class_name,
118 StructuredData::Generic *script_obj, Args... args) {
119 using namespace python;
120 using Locker = ScriptInterpreterPythonImpl::Locker;
122 Log *log =
GetLog(LLDBLog::Script);
123 auto create_error = [](llvm::StringLiteral format,
auto &&...ts) {
124 return llvm::createStringError(
125 llvm::formatv(format.data(), std::forward<
decltype(ts)>(ts)...)
129 bool has_class_name = !class_name.empty();
130 bool has_interpreter_dict =
131 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());
132 if (!has_class_name && !has_interpreter_dict && !script_obj) {
134 return create_error(
"Missing script class name.");
135 else if (!has_interpreter_dict)
136 return create_error(
"Invalid script interpreter dictionary.");
138 return create_error(
"Missing scripting object.");
141 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
144 PythonObject result = {};
147 result = PythonObject(PyRefType::Borrowed,
148 static_cast<PyObject *
>(script_obj->GetValue()));
151 PythonModule::MainModule().ResolveName<python::PythonDictionary>(
152 m_interpreter.GetDictionaryName());
153 if (!dict.IsAllocated())
154 return create_error(
"Could not find interpreter dictionary: {0}",
155 m_interpreter.GetDictionaryName());
158 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
160 if (!init.IsAllocated())
161 return create_error(
"Could not find script class: {0}",
164 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
165 auto transformed_args = TransformArgs(original_args);
167 std::string error_string;
168 llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();
170 llvm::handleAllErrors(
171 arg_info.takeError(),
172 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
173 [&](
const llvm::ErrorInfoBase &E) {
174 error_string.append(E.message());
176 return llvm::createStringError(llvm::inconvertibleErrorCode(),
180 llvm::Expected<PythonObject> expected_return_object =
181 create_error(
"Resulting object is not initialized.");
191 size_t num_args =
sizeof...(Args);
192 if (num_args != arg_info->max_positional_args) {
193 if (num_args != arg_info->max_positional_args - 1)
194 return create_error(
"Passed arguments ({0}) doesn't match the number "
195 "of expected arguments ({1}).",
196 num_args, arg_info->max_positional_args);
199 [&init, &expected_return_object](
auto &&...args) {
200 llvm::consumeError(expected_return_object.takeError());
201 expected_return_object = init(args...);
203 std::tuple_cat(transformed_args, std::make_tuple(dict)));
206 [&init, &expected_return_object](
auto &&...args) {
207 llvm::consumeError(expected_return_object.takeError());
208 expected_return_object = init(args...);
213 if (!expected_return_object)
214 return expected_return_object.takeError();
215 result = expected_return_object.get();
218 if (!result.IsValid())
219 return create_error(
"Resulting object is not a valid Python Object.");
220 if (!result.HasAttribute(
"__class__"))
221 return create_error(
"Resulting object doesn't have '__class__' member.");
223 PythonObject obj_class = result.GetAttributeValue(
"__class__");
224 if (!obj_class.IsValid())
225 return create_error(
"Resulting class object is not a valid.");
226 if (!obj_class.HasAttribute(
"__name__"))
228 "Resulting object class doesn't have '__name__' member.");
229 PythonString obj_class_name =
230 obj_class.GetAttributeValue(
"__name__").AsType<PythonString>();
232 PythonObject object_class_mapping_proxy =
233 obj_class.GetAttributeValue(
"__dict__");
234 if (!obj_class.HasAttribute(
"__dict__"))
236 "Resulting object class doesn't have '__dict__' member.");
238 PythonCallable dict_converter = PythonModule::BuiltinsModule()
240 .AsType<PythonCallable>();
241 if (!dict_converter.IsAllocated())
243 "Python 'builtins' module doesn't have 'dict' class.");
245 PythonDictionary object_class_dict =
246 dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>();
247 if (!object_class_dict.IsAllocated())
248 return create_error(
"Coudn't create dictionary from resulting object "
249 "class mapping proxy object.");
251 auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict);
253 return checker_or_err.takeError();
255 llvm::Error abstract_method_errors = llvm::Error::success();
256 for (
const auto &method_checker : *checker_or_err)
257 switch (method_checker.second.checker_case) {
258 case AbstractMethodCheckerCases::eNotImplemented:
259 abstract_method_errors = llvm::joinErrors(
260 std::move(abstract_method_errors),
261 std::move(create_error(
"Abstract method {0}.{1} not implemented.",
262 obj_class_name.GetString(),
263 method_checker.first)));
265 case AbstractMethodCheckerCases::eNotAllocated:
266 abstract_method_errors = llvm::joinErrors(
267 std::move(abstract_method_errors),
268 std::move(create_error(
"Abstract method {0}.{1} not allocated.",
269 obj_class_name.GetString(),
270 method_checker.first)));
272 case AbstractMethodCheckerCases::eNotCallable:
273 abstract_method_errors = llvm::joinErrors(
274 std::move(abstract_method_errors),
275 std::move(create_error(
"Abstract method {0}.{1} not callable.",
276 obj_class_name.GetString(),
277 method_checker.first)));
279 case AbstractMethodCheckerCases::eUnknownArgumentCount:
280 abstract_method_errors = llvm::joinErrors(
281 std::move(abstract_method_errors),
282 std::move(create_error(
283 "Abstract method {0}.{1} has unknown argument count.",
284 obj_class_name.GetString(), method_checker.first)));
286 case AbstractMethodCheckerCases::eInvalidArgumentCount: {
287 auto &payload_variant = method_checker.second.payload;
288 if (!std::holds_alternative<
289 AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
291 abstract_method_errors = llvm::joinErrors(
292 std::move(abstract_method_errors),
293 std::move(create_error(
294 "Abstract method {0}.{1} has unexpected argument count.",
295 obj_class_name.GetString(), method_checker.first)));
297 auto payload = std::get<
298 AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
300 abstract_method_errors = llvm::joinErrors(
301 std::move(abstract_method_errors),
303 create_error(
"Abstract method {0}.{1} has unexpected "
304 "argument count (expected {2} but has {3}).",
305 obj_class_name.GetString(), method_checker.first,
306 payload.required_argument_count,
307 payload.actual_argument_count)));
310 case AbstractMethodCheckerCases::eValid:
311 LLDB_LOG(log,
"Abstract method {0}.{1} implemented & valid.",
312 obj_class_name.GetString(), method_checker.first);
316 if (abstract_method_errors) {
317 Status error = Status::FromError(std::move(abstract_method_errors));
318 LLDB_LOG(log,
"Abstract method error in {0}:\n{1}", class_name,
320 return error.ToError();
323 m_object_instance_sp = StructuredData::GenericSP(
324 new StructuredPythonObject(std::move(result)));
325 return m_object_instance_sp;
329 template <
typename T = StructuredData::ObjectSP>
330 T ExtractValueFromPythonObject(python::PythonObject &p, Status &
error) {
331 return p.CreateStructuredObject();
334 template <
typename T = StructuredData::ObjectSP,
typename... Args>
335 T Dispatch(llvm::StringRef method_name, Status &
error, Args &&...args) {
336 using namespace python;
337 using Locker = ScriptInterpreterPythonImpl::Locker;
339 std::string caller_signature =
340 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(
" (") +
341 llvm::Twine(method_name) + llvm::Twine(
")"))
343 if (!m_object_instance_sp)
344 return ErrorWithMessage<T>(caller_signature,
"Python object ill-formed",
347 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
350 PythonObject implementor(PyRefType::Borrowed,
351 (PyObject *)m_object_instance_sp->GetValue());
353 if (!implementor.IsAllocated())
354 return llvm::is_contained(GetAbstractMethods(), method_name)
355 ? ErrorWithMessage<T>(caller_signature,
356 "Python implementor not allocated.",
360 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
361 auto transformed_args = TransformArgs(original_args);
363 llvm::Expected<PythonObject> expected_return_object =
364 llvm::make_error<llvm::StringError>(
"Not initialized.",
365 llvm::inconvertibleErrorCode());
367 [&implementor, &method_name, &expected_return_object](
auto &&...args) {
368 llvm::consumeError(expected_return_object.takeError());
369 expected_return_object =
370 implementor.CallMethod(method_name.data(), args...);
374 if (llvm::Error e = expected_return_object.takeError()) {
375 error = Status::FromError(std::move(e));
376 return ErrorWithMessage<T>(caller_signature,
377 "Python method could not be called.",
error);
380 PythonObject py_return = std::move(expected_return_object.get());
386 if (
sizeof...(Args) > 0)
387 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
388 return ErrorWithMessage<T>(
390 "Couldn't re-assign reference and pointer arguments.",
error);
392 if (!py_return.IsAllocated())
394 return ExtractValueFromPythonObject<T>(py_return,
error);
397 template <
typename... Args>
398 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {
400 Dispatch<Status>(method_name,
error, std::forward<Args>(args)...);
405 template <
typename T> T Transform(T
object) {
410 python::PythonObject Transform(
bool arg) {
412 return python::PythonBoolean(arg);
415 python::PythonObject Transform(
const Status &arg) {
416 return python::SWIGBridge::ToSWIGWrapper(arg.Clone());
419 python::PythonObject Transform(Status &&arg) {
420 return python::SWIGBridge::ToSWIGWrapper(std::move(arg));
423 python::PythonObject Transform(
const StructuredDataImpl &arg) {
424 return python::SWIGBridge::ToSWIGWrapper(arg);
428 return python::SWIGBridge::ToSWIGWrapper(arg);
432 return python::SWIGBridge::ToSWIGWrapper(arg);
436 return python::SWIGBridge::ToSWIGWrapper(arg);
440 return python::SWIGBridge::ToSWIGWrapper(arg);
444 return python::SWIGBridge::ToSWIGWrapper(arg);
448 return python::SWIGBridge::ToSWIGWrapper(arg);
451 python::PythonObject Transform(Event *arg) {
452 return python::SWIGBridge::ToSWIGWrapper(arg);
456 return python::SWIGBridge::ToSWIGWrapper(arg.get());
460 return python::SWIGBridge::ToSWIGWrapper(arg);
463 template <
typename T,
typename U>
464 void ReverseTransform(T &original_arg, U transformed_arg, Status &
error) {
469 template <
typename T>
470 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,
472 original_arg = ExtractValueFromPythonObject<T>(transformed_arg,
error);
475 void ReverseTransform(
bool &original_arg,
476 python::PythonObject transformed_arg, Status &
error) {
477 python::PythonBoolean boolean_arg = python::PythonBoolean(
478 python::PyRefType::Borrowed, transformed_arg.get());
479 if (boolean_arg.IsValid())
480 original_arg = boolean_arg.GetValue();
482 error = Status::FromErrorStringWithFormatv(
483 "{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION);
486 template <std::size_t... I,
typename... Args>
487 auto TransformTuple(
const std::tuple<Args...> &args,
488 std::index_sequence<I...>) {
489 return std::make_tuple(Transform(std::get<I>(args))...);
494 template <
typename... Args>
495 auto TransformArgs(
const std::tuple<Args...> &args) {
496 return TransformTuple(args, std::make_index_sequence<
sizeof...(Args)>());
499 template <
typename T,
typename U>
500 void TransformBack(T &original_arg, U transformed_arg, Status &
error) {
501 ReverseTransform(original_arg, transformed_arg,
error);
504 template <std::size_t... I,
typename... Ts,
typename... Us>
505 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
506 std::tuple<Us...> &transformed_args,
507 std::index_sequence<I...>) {
509 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
512 return error.Success();
515 template <
typename... Ts,
typename... Us>
516 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
517 std::tuple<Us...> &transformed_args) {
518 if (
sizeof...(Ts) !=
sizeof...(Us))
521 return ReassignPtrsOrRefsArgs(original_args, transformed_args,
522 std::make_index_sequence<
sizeof...(Ts)>());
525 template <
typename T,
typename... Args>
526 void FormatArgs(std::string &fmt, T arg, Args... args)
const {
527 FormatArgs(fmt, arg);
528 FormatArgs(fmt, args...);
531 template <
typename T>
void FormatArgs(std::string &fmt, T arg)
const {
532 fmt += python::PythonFormat<T>::format;
535 void FormatArgs(std::string &fmt)
const {}
538 ScriptInterpreterPythonImpl &m_interpreter;
543ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
544 python::PythonObject &p, Status &
error);
548ScriptedPythonInterface::ExtractValueFromPythonObject<
552Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
553 python::PythonObject &p, Status &
error);
556Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(
557 python::PythonObject &p, Status &
error);
561ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
562 python::PythonObject &p, Status &
error);
566ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
567 python::PythonObject &p, Status &
error);
579ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
580 python::PythonObject &p, Status &
error);
583std::optional<MemoryRegionInfo>
584ScriptedPythonInterface::ExtractValueFromPythonObject<
585 std::optional<MemoryRegionInfo>>(python::PythonObject &p,
Status &
error);
589ScriptedPythonInterface::ExtractValueFromPythonObject<
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::ThreadPlan > ThreadPlanSP
std::shared_ptr< lldb_private::ProcessAttachInfo > ProcessAttachInfoSP
std::shared_ptr< lldb_private::Stream > StreamSP
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::DataExtractor > DataExtractorSP
std::shared_ptr< lldb_private::ProcessLaunchInfo > ProcessLaunchInfoSP
std::shared_ptr< lldb_private::ExecutionContextRef > ExecutionContextRefSP