LLDB mainline
ScriptedPythonInterface.h
Go to the documentation of this file.
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_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
10#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
11
12#if LLDB_ENABLE_PYTHON
13
14#include <optional>
15#include <sstream>
16#include <tuple>
17#include <type_traits>
18#include <utility>
19
20#include "lldb/Host/Config.h"
23
25#include "../SWIGPythonBridge.h"
27
28namespace lldb_private {
29class ScriptInterpreterPythonImpl;
30class ScriptedPythonInterface : virtual public ScriptedInterface {
31public:
32 ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
33 ~ScriptedPythonInterface() override = default;
34
35 enum class AbstractMethodCheckerCases {
36 eNotImplemented,
37 eNotAllocated,
38 eNotCallable,
39 eUnknownArgumentCount,
40 eInvalidArgumentCount,
41 eValid
42 };
43
44 struct AbstractMethodCheckerPayload {
45
46 struct InvalidArgumentCountPayload {
47 InvalidArgumentCountPayload(size_t required, size_t actual)
48 : required_argument_count(required), actual_argument_count(actual) {}
49
50 size_t required_argument_count;
51 size_t actual_argument_count;
52 };
53
54 AbstractMethodCheckerCases checker_case;
55 std::variant<std::monostate, InvalidArgumentCountPayload> payload;
56 };
57
58 llvm::Expected<FileSpec> GetScriptedModulePath() override {
59 using namespace python;
60 using Locker = ScriptInterpreterPythonImpl::Locker;
61
62 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
63 Locker::FreeLock);
64
65 if (!m_object_instance_sp)
66 return llvm::createStringError("scripted Interface has invalid object");
67
68 PythonObject py_obj =
69 PythonObject(PyRefType::Borrowed,
70 static_cast<PyObject *>(m_object_instance_sp->GetValue()));
71
72 if (!py_obj.IsAllocated())
73 return llvm::createStringError(
74 "scripted Interface has invalid python object");
75
76 PythonObject py_obj_class = py_obj.GetAttributeValue("__class__");
77 if (!py_obj_class.IsValid())
78 return llvm::createStringError(
79 "scripted Interface python object is missing '__class__' attribute");
80
81 PythonObject py_obj_module = py_obj_class.GetAttributeValue("__module__");
82 if (!py_obj_module.IsValid())
83 return llvm::createStringError(
84 "scripted Interface python object '__class__' is missing "
85 "'__module__' attribute");
86
87 PythonString py_obj_module_str = py_obj_module.Str();
88 if (!py_obj_module_str.IsValid())
89 return llvm::createStringError(
90 "scripted Interface python object '__class__.__module__' attribute "
91 "is not a string");
92
93 llvm::StringRef py_obj_module_str_ref = py_obj_module_str.GetString();
94 PythonModule py_module = PythonModule::AddModule(py_obj_module_str_ref);
95 if (!py_module.IsValid())
96 return llvm::createStringError("failed to import '%s' module",
97 py_obj_module_str_ref.data());
98
99 PythonObject py_module_file = py_module.GetAttributeValue("__file__");
100 if (!py_module_file.IsValid())
101 return llvm::createStringError(
102 "module '%s' is missing '__file__' attribute",
103 py_obj_module_str_ref.data());
104
105 PythonString py_module_file_str = py_module_file.Str();
106 if (!py_module_file_str.IsValid())
107 return llvm::createStringError(
108 "module '%s.__file__' attribute is not a string",
109 py_obj_module_str_ref.data());
110
111 return FileSpec(py_module_file_str.GetString());
112 }
113
114 llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerPayload>>
115 CheckAbstractMethodImplementation(
116 const python::PythonDictionary &class_dict) const {
117
118 using namespace python;
119
120 std::map<llvm::StringLiteral, AbstractMethodCheckerPayload> checker;
121#define SET_CASE_AND_CONTINUE(method_name, case) \
122 { \
123 checker[method_name] = {case, {}}; \
124 continue; \
125 }
126
127 for (const AbstractMethodRequirement &requirement :
128 GetAbstractMethodRequirements()) {
129 llvm::StringLiteral method_name = requirement.name;
130 if (!class_dict.HasKey(method_name))
131 SET_CASE_AND_CONTINUE(method_name,
132 AbstractMethodCheckerCases::eNotImplemented)
133 llvm::Expected<PythonObject> callable_or_err =
134 class_dict.GetItem(method_name);
135 if (!callable_or_err) {
136 llvm::consumeError(callable_or_err.takeError());
137 SET_CASE_AND_CONTINUE(method_name,
138 AbstractMethodCheckerCases::eNotAllocated)
139 }
140
141 PythonCallable callable = callable_or_err->AsType<PythonCallable>();
142 if (!callable)
143 SET_CASE_AND_CONTINUE(method_name,
144 AbstractMethodCheckerCases::eNotCallable)
145
146 if (!requirement.min_arg_count)
147 SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid)
148
149 auto arg_info_or_err = callable.GetArgInfo();
150 if (!arg_info_or_err) {
151 llvm::consumeError(arg_info_or_err.takeError());
152 SET_CASE_AND_CONTINUE(method_name,
153 AbstractMethodCheckerCases::eUnknownArgumentCount)
154 }
155
156 PythonCallable::ArgInfo arg_info = *arg_info_or_err;
157 if (requirement.min_arg_count <= arg_info.max_positional_args) {
158 SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid)
159 } else {
160 checker[method_name] = {
161 AbstractMethodCheckerCases::eInvalidArgumentCount,
162 AbstractMethodCheckerPayload::InvalidArgumentCountPayload(
163 requirement.min_arg_count, arg_info.max_positional_args)};
164 }
165 }
166
167#undef SET_CASE_AND_CONTINUE
168
169 return checker;
170 }
171
172 template <typename... Args>
173 llvm::Expected<StructuredData::GenericSP>
174 CreatePluginObject(llvm::StringRef class_name,
175 StructuredData::Generic *script_obj, Args... args) {
176 using namespace python;
177 using Locker = ScriptInterpreterPythonImpl::Locker;
178
179 Log *log = GetLog(LLDBLog::Script);
180 auto create_error = [](llvm::StringLiteral format, auto &&...ts) {
181 return llvm::createStringError(
182 llvm::formatv(format.data(), std::forward<decltype(ts)>(ts)...)
183 .str());
184 };
185
186 bool has_class_name = !class_name.empty();
187 bool has_interpreter_dict =
188 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());
189 if (!has_class_name && !has_interpreter_dict && !script_obj) {
190 if (!has_class_name)
191 return create_error("Missing script class name.");
192 else if (!has_interpreter_dict)
193 return create_error("Invalid script interpreter dictionary.");
194 else
195 return create_error("Missing scripting object.");
196 }
197
198 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
199 Locker::FreeLock);
200
201 PythonObject result = {};
202
203 if (script_obj) {
204 result = PythonObject(PyRefType::Borrowed,
205 static_cast<PyObject *>(script_obj->GetValue()));
206 } else {
207 auto dict =
208 PythonModule::MainModule().ResolveName<python::PythonDictionary>(
209 m_interpreter.GetDictionaryName());
210 if (!dict.IsAllocated())
211 return create_error("Could not find interpreter dictionary: {0}",
212 m_interpreter.GetDictionaryName());
213
214 auto init =
215 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
216 class_name, dict);
217 if (!init.IsAllocated())
218 return create_error("Could not find script class: {0}",
219 class_name.data());
220
221 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
222 auto transformed_args = TransformArgs(original_args);
223
224 std::string error_string;
225 llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();
226 if (!arg_info) {
227 llvm::handleAllErrors(
228 arg_info.takeError(),
229 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
230 [&](const llvm::ErrorInfoBase &E) {
231 error_string.append(E.message());
232 });
233 return llvm::createStringError(llvm::inconvertibleErrorCode(),
234 error_string);
235 }
236
237 llvm::Expected<PythonObject> expected_return_object =
238 create_error("Resulting object is not initialized.");
239
240 // This relax the requirement on the number of argument for
241 // initializing scripting extension if the size of the interface
242 // parameter pack contains 1 less element than the extension maximum
243 // number of positional arguments for this initializer.
244 //
245 // This addresses the cases where the embedded interpreter session
246 // dictionary is passed to the extension initializer which is not used
247 // most of the time.
248 // Note, though none of our API's suggest defining the interfaces with
249 // varargs, we have some extant clients that were doing that. To keep
250 // from breaking them, we just say putting a varargs in these signatures
251 // turns off argument checking.
252 size_t num_args = sizeof...(Args);
253 if (arg_info->max_positional_args != PythonCallable::ArgInfo::UNBOUNDED &&
254 num_args != arg_info->max_positional_args) {
255 if (num_args != arg_info->max_positional_args - 1)
256 return create_error("Passed arguments ({0}) doesn't match the number "
257 "of expected arguments ({1}).",
258 num_args, arg_info->max_positional_args);
259
260 std::apply(
261 [&init, &expected_return_object](auto &&...args) {
262 llvm::consumeError(expected_return_object.takeError());
263 expected_return_object = init(args...);
264 },
265 std::tuple_cat(transformed_args, std::make_tuple(dict)));
266 } else {
267 std::apply(
268 [&init, &expected_return_object](auto &&...args) {
269 llvm::consumeError(expected_return_object.takeError());
270 expected_return_object = init(args...);
271 },
272 transformed_args);
273 }
274
275 if (!expected_return_object)
276 return expected_return_object.takeError();
277 result = expected_return_object.get();
278 }
279
280 if (!result.IsValid())
281 return create_error("Resulting object is not a valid Python Object.");
282 if (!result.HasAttribute("__class__"))
283 return create_error("Resulting object doesn't have '__class__' member.");
284
285 PythonObject obj_class = result.GetAttributeValue("__class__");
286 if (!obj_class.IsValid())
287 return create_error("Resulting class object is not a valid.");
288 if (!obj_class.HasAttribute("__name__"))
289 return create_error(
290 "Resulting object class doesn't have '__name__' member.");
291 PythonString obj_class_name =
292 obj_class.GetAttributeValue("__name__").AsType<PythonString>();
293
294 PythonObject object_class_mapping_proxy =
295 obj_class.GetAttributeValue("__dict__");
296 if (!obj_class.HasAttribute("__dict__"))
297 return create_error(
298 "Resulting object class doesn't have '__dict__' member.");
299
300 PythonCallable dict_converter = PythonModule::BuiltinsModule()
301 .ResolveName("dict")
302 .AsType<PythonCallable>();
303 if (!dict_converter.IsAllocated())
304 return create_error(
305 "Python 'builtins' module doesn't have 'dict' class.");
306
307 PythonDictionary object_class_dict =
308 dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>();
309 if (!object_class_dict.IsAllocated())
310 return create_error("Coudn't create dictionary from resulting object "
311 "class mapping proxy object.");
312
313 auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict);
314 if (!checker_or_err)
315 return checker_or_err.takeError();
316
317 llvm::Error abstract_method_errors = llvm::Error::success();
318 for (const auto &method_checker : *checker_or_err)
319 switch (method_checker.second.checker_case) {
320 case AbstractMethodCheckerCases::eNotImplemented:
321 abstract_method_errors = llvm::joinErrors(
322 std::move(abstract_method_errors),
323 std::move(create_error("Abstract method {0}.{1} not implemented.",
324 obj_class_name.GetString(),
325 method_checker.first)));
326 break;
327 case AbstractMethodCheckerCases::eNotAllocated:
328 abstract_method_errors = llvm::joinErrors(
329 std::move(abstract_method_errors),
330 std::move(create_error("Abstract method {0}.{1} not allocated.",
331 obj_class_name.GetString(),
332 method_checker.first)));
333 break;
334 case AbstractMethodCheckerCases::eNotCallable:
335 abstract_method_errors = llvm::joinErrors(
336 std::move(abstract_method_errors),
337 std::move(create_error("Abstract method {0}.{1} not callable.",
338 obj_class_name.GetString(),
339 method_checker.first)));
340 break;
341 case AbstractMethodCheckerCases::eUnknownArgumentCount:
342 abstract_method_errors = llvm::joinErrors(
343 std::move(abstract_method_errors),
344 std::move(create_error(
345 "Abstract method {0}.{1} has unknown argument count.",
346 obj_class_name.GetString(), method_checker.first)));
347 break;
348 case AbstractMethodCheckerCases::eInvalidArgumentCount: {
349 auto &payload_variant = method_checker.second.payload;
350 if (!std::holds_alternative<
351 AbstractMethodCheckerPayload::InvalidArgumentCountPayload>(
352 payload_variant)) {
353 abstract_method_errors = llvm::joinErrors(
354 std::move(abstract_method_errors),
355 std::move(create_error(
356 "Abstract method {0}.{1} has unexpected argument count.",
357 obj_class_name.GetString(), method_checker.first)));
358 } else {
359 auto payload = std::get<
360 AbstractMethodCheckerPayload::InvalidArgumentCountPayload>(
361 payload_variant);
362 abstract_method_errors = llvm::joinErrors(
363 std::move(abstract_method_errors),
364 std::move(
365 create_error("Abstract method {0}.{1} has unexpected "
366 "argument count (expected {2} but has {3}).",
367 obj_class_name.GetString(), method_checker.first,
368 payload.required_argument_count,
369 payload.actual_argument_count)));
370 }
371 } break;
372 case AbstractMethodCheckerCases::eValid:
373 LLDB_LOG(log, "Abstract method {0}.{1} implemented & valid.",
374 obj_class_name.GetString(), method_checker.first);
375 break;
376 }
377
378 if (abstract_method_errors) {
379 Status error = Status::FromError(std::move(abstract_method_errors));
380 LLDB_LOG(log, "Abstract method error in {0}:\n{1}", class_name,
381 error.AsCString());
382 return error.ToError();
383 }
384
385 m_object_instance_sp = StructuredData::GenericSP(
386 new StructuredPythonObject(std::move(result)));
387 return m_object_instance_sp;
388 }
389
390 /// Call a static method on a Python class without creating an instance.
391 ///
392 /// This method resolves a Python class by name and calls a static method
393 /// on it, returning the result. This is useful for calling class-level
394 /// methods that don't require an instance.
395 ///
396 /// \param class_name The fully-qualified name of the Python class.
397 /// \param method_name The name of the static method to call.
398 /// \param error Output parameter to receive error information if the call
399 /// fails.
400 /// \param args Arguments to pass to the static method.
401 ///
402 /// \return The return value of the static method call, or an error value.
403 template <typename T = StructuredData::ObjectSP, typename... Args>
404 T CallStaticMethod(llvm::StringRef class_name, llvm::StringRef method_name,
405 Status &error, Args &&...args) {
406 using namespace python;
407 using Locker = ScriptInterpreterPythonImpl::Locker;
408
409 std::string caller_signature =
410 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
411 llvm::Twine(class_name) + llvm::Twine(".") +
412 llvm::Twine(method_name) + llvm::Twine(")"))
413 .str();
414
415 if (class_name.empty())
416 return ErrorWithMessage<T>(caller_signature, "missing script class name",
417 error);
418
419 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
420 Locker::FreeLock);
421
422 // Get the interpreter dictionary.
423 auto dict =
424 PythonModule::MainModule().ResolveName<python::PythonDictionary>(
425 m_interpreter.GetDictionaryName());
426 if (!dict.IsAllocated())
427 return ErrorWithMessage<T>(
428 caller_signature,
429 llvm::formatv("could not find interpreter dictionary: {0}",
430 m_interpreter.GetDictionaryName())
431 .str(),
432 error);
433
434 // Resolve the class.
435 auto class_obj =
436 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
437 class_name, dict);
438 if (!class_obj.IsAllocated())
439 return ErrorWithMessage<T>(
440 caller_signature,
441 llvm::formatv("could not find script class: {0}", class_name).str(),
442 error);
443
444 // Get the static method from the class.
445 if (!class_obj.HasAttribute(method_name))
446 return ErrorWithMessage<T>(
447 caller_signature,
448 llvm::formatv("class {0} does not have method {1}", class_name,
449 method_name)
450 .str(),
451 error);
452
453 PythonCallable method =
454 class_obj.GetAttributeValue(method_name).AsType<PythonCallable>();
455 if (!method.IsAllocated())
456 return ErrorWithMessage<T>(caller_signature,
457 llvm::formatv("method {0}.{1} is not callable",
458 class_name, method_name)
459 .str(),
460 error);
461
462 // Transform the arguments.
463 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
464 auto transformed_args = TransformArgs(original_args);
465
466 // Call the static method.
467 llvm::Expected<PythonObject> expected_return_object =
468 llvm::make_error<llvm::StringError>("Not initialized.",
469 llvm::inconvertibleErrorCode());
470 std::apply(
471 [&method, &expected_return_object](auto &&...args) {
472 llvm::consumeError(expected_return_object.takeError());
473 expected_return_object = method(args...);
474 },
475 transformed_args);
476
477 if (llvm::Error e = expected_return_object.takeError()) {
478 error = Status::FromError(std::move(e));
479 return ErrorWithMessage<T>(
480 caller_signature, "python static method could not be called", error);
481 }
482
483 PythonObject py_return = std::move(expected_return_object.get());
484
485 // Re-assign reference and pointer arguments if needed.
486 if (sizeof...(Args) > 0)
487 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
488 return ErrorWithMessage<T>(
489 caller_signature,
490 "couldn't re-assign reference and pointer arguments", error);
491
492 // Extract value from Python object (handles unallocated case).
493 return ExtractValueFromPythonObject<T>(py_return, error);
494 }
495
496protected:
497 template <typename T = StructuredData::ObjectSP>
498 T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
499 return p.CreateStructuredObject();
500 }
501
502 template <typename T = StructuredData::ObjectSP, typename... Args>
503 T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) {
504 using namespace python;
505 using Locker = ScriptInterpreterPythonImpl::Locker;
506
507 std::string caller_signature =
508 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
509 llvm::Twine(method_name) + llvm::Twine(")"))
510 .str();
511 if (!m_object_instance_sp)
512 return ErrorWithMessage<T>(caller_signature, "python object ill-formed",
513 error);
514
515 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
516 Locker::FreeLock);
517
518 PythonObject implementor(PyRefType::Borrowed,
519 (PyObject *)m_object_instance_sp->GetValue());
520
521 if (!implementor.IsAllocated())
522 return llvm::is_contained(GetAbstractMethods(), method_name)
523 ? ErrorWithMessage<T>(caller_signature,
524 "python implementor not allocated",
525 error)
526 : T{};
527
528 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
529 auto transformed_args = TransformArgs(original_args);
530
531 llvm::Expected<PythonObject> expected_return_object =
532 llvm::make_error<llvm::StringError>("Not initialized.",
533 llvm::inconvertibleErrorCode());
534 std::apply(
535 [&implementor, &method_name, &expected_return_object](auto &&...args) {
536 llvm::consumeError(expected_return_object.takeError());
537 expected_return_object =
538 implementor.CallMethod(method_name.data(), args...);
539 },
540 transformed_args);
541
542 if (llvm::Error e = expected_return_object.takeError()) {
543 error = Status::FromError(std::move(e));
544 return ErrorWithMessage<T>(caller_signature,
545 "python method could not be called", error);
546 }
547
548 PythonObject py_return = std::move(expected_return_object.get());
549
550 // Now that we called the python method with the transformed arguments,
551 // we need to iterate again over both the original and transformed
552 // parameter pack, and transform back the parameter that were passed in
553 // the original parameter pack as references or pointers.
554 if (sizeof...(Args) > 0)
555 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
556 return ErrorWithMessage<T>(
557 caller_signature,
558 "couldn't re-assign reference and pointer arguments", error);
559
560 if (!py_return.IsAllocated())
561 return {};
562 return ExtractValueFromPythonObject<T>(py_return, error);
563 }
564
565 template <typename... Args>
566 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {
568 Dispatch<Status>(method_name, error, std::forward<Args>(args)...);
569
570 return error;
571 }
572
573 template <typename T> T Transform(T object) {
574 // No Transformation for generic usage
575 return {object};
576 }
577
578 python::PythonObject Transform(bool arg) {
579 // Boolean arguments need to be turned into python objects.
580 return python::PythonBoolean(arg);
581 }
582
583 python::PythonObject Transform(const Status &arg) {
584 return python::SWIGBridge::ToSWIGWrapper(arg.Clone());
585 }
586
587 python::PythonObject Transform(Status &&arg) {
588 return python::SWIGBridge::ToSWIGWrapper(std::move(arg));
589 }
590
591 python::PythonObject Transform(const StructuredDataImpl &arg) {
592 return python::SWIGBridge::ToSWIGWrapper(arg);
593 }
594
595 python::PythonObject Transform(lldb::ExecutionContextRefSP arg) {
596 return python::SWIGBridge::ToSWIGWrapper(arg);
597 }
598
599 python::PythonObject Transform(lldb::TargetSP arg) {
600 return python::SWIGBridge::ToSWIGWrapper(arg);
601 }
602
603 python::PythonObject Transform(lldb::BreakpointSP arg) {
604 return python::SWIGBridge::ToSWIGWrapper(arg);
605 }
606
607 python::PythonObject Transform(lldb::BreakpointLocationSP arg) {
608 return python::SWIGBridge::ToSWIGWrapper(arg);
609 }
610
611 python::PythonObject Transform(lldb::ProcessSP arg) {
612 return python::SWIGBridge::ToSWIGWrapper(arg);
613 }
614
615 python::PythonObject Transform(lldb::ThreadSP arg) {
616 return python::SWIGBridge::ToSWIGWrapper(arg);
617 }
618
619 python::PythonObject Transform(lldb::StackFrameListSP arg) {
620 return python::SWIGBridge::ToSWIGWrapper(arg);
621 }
622
623 python::PythonObject Transform(lldb::ThreadPlanSP arg) {
624 return python::SWIGBridge::ToSWIGWrapper(arg);
625 }
626
627 python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) {
628 return python::SWIGBridge::ToSWIGWrapper(arg);
629 }
630
631 python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) {
632 return python::SWIGBridge::ToSWIGWrapper(arg);
633 }
634
635 python::PythonObject Transform(Event *arg) {
636 return python::SWIGBridge::ToSWIGWrapper(arg);
637 }
638
639 python::PythonObject Transform(const SymbolContext &arg) {
640 return python::SWIGBridge::ToSWIGWrapper(arg);
641 }
642
643 python::PythonObject Transform(lldb::StreamSP arg) {
644 return python::SWIGBridge::ToSWIGWrapper(arg.get());
645 }
646
647 python::PythonObject Transform(lldb::StackFrameSP arg) {
648 return python::SWIGBridge::ToSWIGWrapper(arg);
649 }
650
651 python::PythonObject Transform(lldb::DataExtractorSP arg) {
652 return python::SWIGBridge::ToSWIGWrapper(arg);
653 }
654
655 python::PythonObject Transform(lldb::DescriptionLevel arg) {
656 return python::SWIGBridge::ToSWIGWrapper(arg);
657 }
658
659 template <typename T, typename U>
660 void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
661 // If U is not a PythonObject, don't touch it!
662 }
663
664 template <typename T>
665 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,
666 Status &error) {
667 original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error);
668 }
669
670 void ReverseTransform(bool &original_arg,
671 python::PythonObject transformed_arg, Status &error) {
672 python::PythonBoolean boolean_arg = python::PythonBoolean(
673 python::PyRefType::Borrowed, transformed_arg.get());
674 if (boolean_arg.IsValid())
675 original_arg = boolean_arg.GetValue();
676 else
677 error = Status::FromErrorStringWithFormatv(
678 "{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION);
679 }
680
681 template <std::size_t... I, typename... Args>
682 auto TransformTuple(const std::tuple<Args...> &args,
683 std::index_sequence<I...>) {
684 return std::make_tuple(Transform(std::get<I>(args))...);
685 }
686
687 // This will iterate over the Dispatch parameter pack and replace in-place
688 // every `lldb_private` argument that has a SB counterpart.
689 template <typename... Args>
690 auto TransformArgs(const std::tuple<Args...> &args) {
691 return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>());
692 }
693
694 template <typename T, typename U>
695 void TransformBack(T &original_arg, U transformed_arg, Status &error) {
696 ReverseTransform(original_arg, transformed_arg, error);
697 }
698
699 template <std::size_t... I, typename... Ts, typename... Us>
700 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
701 std::tuple<Us...> &transformed_args,
702 std::index_sequence<I...>) {
704 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
705 error),
706 ...);
707 return error.Success();
708 }
709
710 template <typename... Ts, typename... Us>
711 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
712 std::tuple<Us...> &transformed_args) {
713 if (sizeof...(Ts) != sizeof...(Us))
714 return false;
715
716 return ReassignPtrsOrRefsArgs(original_args, transformed_args,
717 std::make_index_sequence<sizeof...(Ts)>());
718 }
719
720 template <typename T, typename... Args>
721 void FormatArgs(std::string &fmt, T arg, Args... args) const {
722 FormatArgs(fmt, arg);
723 FormatArgs(fmt, args...);
724 }
725
726 template <typename T> void FormatArgs(std::string &fmt, T arg) const {
727 fmt += python::PythonFormat<T>::format;
728 }
729
730 void FormatArgs(std::string &fmt) const {}
731
732 // The lifetime is managed by the ScriptInterpreter
733 ScriptInterpreterPythonImpl &m_interpreter;
734};
735
736template <>
738ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
739 python::PythonObject &p, Status &error);
740
741template <>
743ScriptedPythonInterface::ExtractValueFromPythonObject<
744 StructuredData::DictionarySP>(python::PythonObject &p, Status &error);
745
746template <>
747Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
748 python::PythonObject &p, Status &error);
749
750template <>
751Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(
752 python::PythonObject &p, Status &error);
753
754template <>
756ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>(
757 python::PythonObject &p, Status &error);
758
759template <>
761ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
762 python::PythonObject &p, Status &error);
763
764template <>
766ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ThreadSP>(
767 python::PythonObject &p, Status &error);
768
769template <>
771ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameSP>(
772 python::PythonObject &p, Status &error);
773
774template <>
776ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
777 python::PythonObject &p, Status &error);
778
779template <>
781ScriptedPythonInterface::ExtractValueFromPythonObject<
782 lldb::BreakpointLocationSP>(python::PythonObject &p, Status &error);
783
784template <>
785lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
786 lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error);
787
788template <>
789lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
790 lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error);
791
792template <>
794ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
795 python::PythonObject &p, Status &error);
796
797template <>
798std::optional<MemoryRegionInfo>
799ScriptedPythonInterface::ExtractValueFromPythonObject<
800 std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
801
802template <>
804ScriptedPythonInterface::ExtractValueFromPythonObject<
805 lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error);
806
807template <>
809ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DescriptionLevel>(
810 python::PythonObject &p, Status &error);
811
812template <>
814ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameListSP>(
815 python::PythonObject &p, Status &error);
816
817} // namespace lldb_private
818
819#endif // LLDB_ENABLE_PYTHON
820#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:369
An error handling class.
Definition Status.h:118
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Array > ArraySP
Defines a symbol context baton that can be handed other debug core functions.
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.
Definition Log.h:332
std::shared_ptr< lldb_private::ThreadPlan > ThreadPlanSP
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::BreakpointLocation > BreakpointLocationSP
DescriptionLevel
Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls.
std::shared_ptr< lldb_private::Thread > ThreadSP
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::StackFrameList > StackFrameListSP
std::shared_ptr< lldb_private::ExecutionContextRef > ExecutionContextRefSP