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_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
10#define LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
11
12#include <optional>
13#include <sstream>
14#include <tuple>
15#include <type_traits>
16#include <utility>
17
21#include "lldb/Utility/Policy.h"
22
24#include "../SWIGPythonBridge.h"
26
27namespace lldb_private {
30public:
32 ~ScriptedPythonInterface() override = default;
33
42
44
52
54 std::variant<std::monostate, InvalidArgumentCountPayload, std::string>
56 };
57
58 llvm::Expected<FileSpec> GetScriptedModulePath() override {
59 using namespace python;
61
64
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>>
116 const python::PythonObject &obj_class) 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 :
129 llvm::StringLiteral method_name = requirement.name;
130 // Look up via attribute access so inherited methods are found; the
131 // class's own __dict__ omits anything defined on a base class.
132 if (!obj_class.HasAttribute(method_name))
133 SET_CASE_AND_CONTINUE(method_name,
135 PythonObject attr = obj_class.GetAttributeValue(method_name);
136 if (!attr.IsAllocated())
137 SET_CASE_AND_CONTINUE(method_name,
139
140 PythonCallable callable = attr.AsType<PythonCallable>();
141 if (!callable)
142 SET_CASE_AND_CONTINUE(method_name,
144
145 if (!requirement.min_arg_count)
147
148 auto arg_info_or_err = callable.GetArgInfo();
149 if (!arg_info_or_err) {
150 checker[method_name] = {
152 ExtractPythonError(arg_info_or_err.takeError())};
153 continue;
154 }
155
156 PythonCallable::ArgInfo arg_info = *arg_info_or_err;
157 if (requirement.min_arg_count <= arg_info.max_positional_args) {
159 } else {
160 checker[method_name] = {
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(const ScriptedMetadata &scripted_metadata,
175 StructuredData::Generic *script_obj, Args... args) {
176 using namespace python;
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 m_scripted_metadata = scripted_metadata;
187 llvm::StringRef class_name = scripted_metadata.GetClassName();
188 bool has_class_name = !class_name.empty();
189 bool has_interpreter_dict =
190 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());
191 if (!has_class_name && !has_interpreter_dict && !script_obj) {
192 if (!has_class_name)
193 return create_error("Missing script class name.");
194 else if (!has_interpreter_dict)
195 return create_error("Invalid script interpreter dictionary.");
196 else
197 return create_error("Missing scripting object.");
198 }
199
200 std::optional<PolicyStack::Guard> policy_guard;
201 if (!UserCanRunDirectly())
203
206
207 PythonObject result = {};
208
209 if (script_obj) {
210 result = PythonObject(PyRefType::Borrowed,
211 static_cast<PyObject *>(script_obj->GetValue()));
212 } else {
213 auto dict =
214 PythonModule::MainModule().ResolveName<python::PythonDictionary>(
215 m_interpreter.GetDictionaryName());
216 if (!dict.IsAllocated())
217 return create_error("Could not find interpreter dictionary: {0}",
218 m_interpreter.GetDictionaryName());
219
220 auto init =
221 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
222 class_name, dict);
223 if (!init.IsAllocated())
224 return create_error("Could not find script class: {0}",
225 class_name.data());
226
227 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
228 auto transformed_args = TransformArgs(original_args);
229
230 std::string error_string;
231 llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();
232 if (!arg_info) {
233 llvm::handleAllErrors(
234 arg_info.takeError(),
235 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
236 [&](const llvm::ErrorInfoBase &E) {
237 error_string.append(E.message());
238 });
239 return llvm::createStringError(llvm::inconvertibleErrorCode(),
240 error_string);
241 }
242
243 llvm::Expected<PythonObject> expected_return_object =
244 create_error("Resulting object is not initialized.");
245
246 // This relax the requirement on the number of argument for
247 // initializing scripting extension if the size of the interface
248 // parameter pack contains 1 less element than the extension maximum
249 // number of positional arguments for this initializer.
250 //
251 // This addresses the cases where the embedded interpreter session
252 // dictionary is passed to the extension initializer which is not used
253 // most of the time.
254 // Note, though none of our API's suggest defining the interfaces with
255 // varargs, we have some extant clients that were doing that. To keep
256 // from breaking them, we just say putting a varargs in these signatures
257 // turns off argument checking.
258 size_t num_args = sizeof...(Args);
259 if (arg_info->max_positional_args != PythonCallable::ArgInfo::UNBOUNDED &&
260 num_args != arg_info->max_positional_args) {
261 if (num_args != arg_info->max_positional_args - 1) {
262 // `expected_return_object` starts in an error state; consume it
263 // before we return with a different error, or its destructor
264 // will abort.
265 llvm::consumeError(expected_return_object.takeError());
266 return create_error("Passed arguments ({0}) doesn't match the number "
267 "of expected arguments ({1}).",
268 num_args, arg_info->max_positional_args);
269 }
270
271 std::apply(
272 [&init, &expected_return_object](auto &&...args) {
273 if (!expected_return_object)
274 llvm::consumeError(expected_return_object.takeError());
275 expected_return_object = init.Call(args...);
276 },
277 std::tuple_cat(transformed_args, std::make_tuple(dict)));
278 } else {
279 std::apply(
280 [&init, &expected_return_object](auto &&...args) {
281 if (!expected_return_object)
282 llvm::consumeError(expected_return_object.takeError());
283 expected_return_object = init.Call(args...);
284 },
285 transformed_args);
286 }
287
288 if (!expected_return_object)
289 // Drain the Python exception into a plain string while the GIL is
290 // still held: `PythonException` owns raw `PyObject*` references, and
291 // `py_lock` (and the GIL it holds) is released as this function
292 // returns, before the caller gets a chance to touch the error.
293 return llvm::createStringError(
294 ExtractPythonError(expected_return_object.takeError()));
295 result = expected_return_object.get();
296 }
297
298 if (!result.IsValid())
299 return create_error("Resulting object is not a valid Python Object.");
300 if (!result.HasAttribute("__class__"))
301 return create_error("Resulting object doesn't have '__class__' member.");
302
303 PythonObject obj_class = result.GetAttributeValue("__class__");
304 if (!obj_class.IsValid())
305 return create_error("Resulting class object is not a valid.");
306 if (!obj_class.HasAttribute("__name__"))
307 return create_error(
308 "Resulting object class doesn't have '__name__' member.");
309 PythonString obj_class_name =
310 obj_class.GetAttributeValue("__name__").AsType<PythonString>();
311
312 auto checker_or_err = CheckAbstractMethodImplementation(obj_class);
313 if (!checker_or_err)
314 return checker_or_err.takeError();
315
316 llvm::Error abstract_method_errors = llvm::Error::success();
317 for (const auto &method_checker : *checker_or_err)
318 switch (method_checker.second.checker_case) {
320 abstract_method_errors = llvm::joinErrors(
321 std::move(abstract_method_errors),
322 std::move(create_error("Abstract method {0}.{1} not implemented.",
323 obj_class_name.GetString(),
324 method_checker.first)));
325 break;
327 abstract_method_errors = llvm::joinErrors(
328 std::move(abstract_method_errors),
329 std::move(create_error("Abstract method {0}.{1} not allocated.",
330 obj_class_name.GetString(),
331 method_checker.first)));
332 break;
334 abstract_method_errors = llvm::joinErrors(
335 std::move(abstract_method_errors),
336 std::move(create_error("Abstract method {0}.{1} not callable.",
337 obj_class_name.GetString(),
338 method_checker.first)));
339 break;
341 const std::string *py_error =
342 std::get_if<std::string>(&method_checker.second.payload);
343 abstract_method_errors = llvm::joinErrors(
344 std::move(abstract_method_errors),
345 std::move(create_error(
346 "abstract method {0}.{1} has unknown argument count: {2}",
347 obj_class_name.GetString(), method_checker.first,
348 py_error ? *py_error : "<no further information>")));
349 } break;
351 auto &payload_variant = method_checker.second.payload;
352 if (!std::holds_alternative<
354 payload_variant)) {
355 abstract_method_errors = llvm::joinErrors(
356 std::move(abstract_method_errors),
357 std::move(create_error(
358 "Abstract method {0}.{1} has unexpected argument count.",
359 obj_class_name.GetString(), method_checker.first)));
360 } else {
361 auto payload = std::get<
363 payload_variant);
364 abstract_method_errors = llvm::joinErrors(
365 std::move(abstract_method_errors),
366 std::move(
367 create_error("Abstract method {0}.{1} has unexpected "
368 "argument count (expected {2} but has {3}).",
369 obj_class_name.GetString(), method_checker.first,
370 payload.required_argument_count,
371 payload.actual_argument_count)));
372 }
373 } break;
375 LLDB_LOG(log, "Abstract method {0}.{1} implemented & valid.",
376 obj_class_name.GetString(), method_checker.first);
377 break;
378 }
379
380 if (abstract_method_errors) {
381 Status error = Status::FromError(std::move(abstract_method_errors));
382 LLDB_LOG(log, "Abstract method error in {0}:\n{1}", class_name,
383 error.AsCString());
384 return error.ToError();
385 }
386
388 new StructuredPythonObject(std::move(result)));
390 }
391
392 /// Call a static method on a Python class without creating an instance.
393 ///
394 /// This method resolves a Python class by name and calls a static method
395 /// on it, returning the result. This is useful for calling class-level
396 /// methods that don't require an instance.
397 ///
398 /// \param class_name The fully-qualified name of the Python class.
399 /// \param method_name The name of the static method to call.
400 /// \param error Output parameter to receive error information if the call
401 /// fails.
402 /// \param args Arguments to pass to the static method.
403 ///
404 /// \return The return value of the static method call, or an error value.
405 template <typename T = StructuredData::ObjectSP, typename... Args>
406 T CallStaticMethod(llvm::StringRef class_name, llvm::StringRef method_name,
407 Status &error, Args &&...args) {
408 using namespace python;
410
411 std::string caller_signature =
412 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
413 llvm::Twine(class_name) + llvm::Twine(".") +
414 llvm::Twine(method_name) + llvm::Twine(")"))
415 .str();
416
417 if (class_name.empty())
418 return ErrorWithMessage<T>(caller_signature, "missing script class name",
419 error);
420
421 std::optional<PolicyStack::Guard> policy_guard;
422 if (!UserCanRunDirectly())
424
427
428 // Get the interpreter dictionary.
429 auto dict =
430 PythonModule::MainModule().ResolveName<python::PythonDictionary>(
431 m_interpreter.GetDictionaryName());
432 if (!dict.IsAllocated())
433 return ErrorWithMessage<T>(
434 caller_signature,
435 llvm::formatv("could not find interpreter dictionary: {0}",
436 m_interpreter.GetDictionaryName())
437 .str(),
438 error);
439
440 // Resolve the class.
441 auto class_obj =
442 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
443 class_name, dict);
444 if (!class_obj.IsAllocated())
445 return ErrorWithMessage<T>(
446 caller_signature,
447 llvm::formatv("could not find script class: {0}", class_name).str(),
448 error);
449
450 // Get the static method from the class.
451 if (!class_obj.HasAttribute(method_name))
452 return ErrorWithMessage<T>(
453 caller_signature,
454 llvm::formatv("class {0} does not have method {1}", class_name,
455 method_name)
456 .str(),
457 error);
458
459 PythonCallable method =
460 class_obj.GetAttributeValue(method_name).AsType<PythonCallable>();
461 if (!method.IsAllocated())
462 return ErrorWithMessage<T>(caller_signature,
463 llvm::formatv("method {0}.{1} is not callable",
464 class_name, method_name)
465 .str(),
466 error);
467
468 // Transform the arguments.
469 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
470 auto transformed_args = TransformArgs(original_args);
471
472 // Call the static method.
473 llvm::Expected<PythonObject> expected_return_object =
474 llvm::createStringError("not initialized");
475 std::apply(
476 [&method, &expected_return_object](auto &&...args) {
477 if (!expected_return_object)
478 llvm::consumeError(expected_return_object.takeError());
479 expected_return_object = method.Call(args...);
480 },
481 transformed_args);
482
483 if (llvm::Error e = expected_return_object.takeError()) {
484 // TODO: Stringify `args` and include them in the message so users
485 // can see what was passed to the failing call (e.g.
486 // `read_memory_at_address(0x500000000, 4)`). Requires a SFINAE
487 // helper that falls back to a placeholder for types without a
488 // format_provider / operator<<.
489 error = Status::FromErrorString(ExtractPythonError(std::move(e)).c_str());
490
491 return ErrorWithMessage<T>(
492 caller_signature,
493 llvm::formatv("python exception in {0} method '{1}'", class_name,
494 method_name)
495 .str(),
496 error);
497 }
498
499 PythonObject py_return = std::move(expected_return_object.get());
500
501 // Re-assign reference and pointer arguments if needed.
502 if (sizeof...(Args) > 0)
503 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
504 return ErrorWithMessage<T>(
505 caller_signature,
506 "couldn't re-assign reference and pointer arguments", error);
507
508 // Extract value from Python object (handles unallocated case).
509 return ExtractValueFromPythonObject<T>(py_return, error);
510 }
511
512protected:
513 /// Extract detailed error message including Python backtrace if available.
514 ///
515 /// This helper processes llvm::Error objects that may contain PythonException
516 /// instances, extracting full Python backtraces when available.
517 ///
518 /// \param error The llvm::Error to extract information from.
519 /// \return A string containing the error message, including full Python
520 /// backtrace if the error was a PythonException.
521 static std::string ExtractPythonError(llvm::Error error) {
522 std::string error_msg;
523 llvm::handleAllErrors(
524 std::move(error),
525 [&](python::PythonException &E) { error_msg = E.ReadBacktrace(); },
526 [&](const llvm::ErrorInfoBase &E) { error_msg = E.message(); });
527 return error_msg;
528 }
529
530 template <typename T = StructuredData::ObjectSP>
534
535 template <typename T = StructuredData::ObjectSP, typename... Args>
536 T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) {
537 using namespace python;
539
540 std::string caller_signature =
541 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
542 llvm::Twine(method_name) + llvm::Twine(")"))
543 .str();
545 return ErrorWithMessage<T>(caller_signature, "python object ill-formed",
546 error);
547
548 std::optional<PolicyStack::Guard> policy_guard;
549 if (!UserCanRunDirectly())
551
554
555 PythonObject implementor(PyRefType::Borrowed,
556 (PyObject *)m_object_instance_sp->GetValue());
557
558 if (!implementor.IsAllocated())
559 return llvm::is_contained(GetAbstractMethods(), method_name)
560 ? ErrorWithMessage<T>(caller_signature,
561 "python implementor not allocated",
562 error)
563 : T{};
564
565 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
566 auto transformed_args = TransformArgs(original_args);
567
568 // Trim trailing args if the Python method accepts fewer positional
569 // parameters than we're passing (e.g. `num_children(self)` vs.
570 // `num_children(self, max_count)`).
571 size_t call_arity = sizeof...(Args);
572 if (PythonObject py_method = implementor.GetAttributeValue(method_name);
573 py_method.IsAllocated()) {
574 PythonCallable callable = py_method.AsType<PythonCallable>();
575 if (callable.IsAllocated()) {
576 if (llvm::Expected<PythonCallable::ArgInfo> arg_info =
577 callable.GetArgInfo()) {
578 if (arg_info->max_positional_args !=
579 PythonCallable::ArgInfo::UNBOUNDED &&
580 arg_info->max_positional_args < call_arity)
581 call_arity = arg_info->max_positional_args;
582 } else {
583 llvm::consumeError(arg_info.takeError());
584 }
585 }
586 }
587
588 llvm::Expected<PythonObject> expected_return_object =
589 llvm::createStringError("not initialized");
590 CallWithArity(call_arity, transformed_args,
591 std::make_index_sequence<sizeof...(Args) + 1>{},
592 [&implementor, &method_name,
593 &expected_return_object](auto &&...call_args) {
594 if (!expected_return_object)
595 llvm::consumeError(expected_return_object.takeError());
596 expected_return_object = implementor.CallMethod(
597 method_name.data(), call_args...);
598 });
599
600 if (llvm::Error e = expected_return_object.takeError()) {
601 // TODO: Stringify `args` and include them in the message so users
602 // can see what was passed to the failing call (e.g.
603 // `read_memory_at_address(0x500000000, 4)`). Requires a SFINAE
604 // helper that falls back to a placeholder for types without a
605 // format_provider / operator<<.
606 error = Status::FromErrorString(ExtractPythonError(std::move(e)).c_str());
607
608 return ErrorWithMessage<T>(
609 caller_signature,
610 llvm::formatv("python exception in {0} method '{1}'",
612 ? GetScriptedMetadata()->GetClassName()
613 : "<unknown>",
614 method_name)
615 .str(),
616 error);
617 }
618
619 PythonObject py_return = std::move(expected_return_object.get());
620
621 // Now that we called the python method with the transformed arguments,
622 // we need to iterate again over both the original and transformed
623 // parameter pack, and transform back the parameter that were passed in
624 // the original parameter pack as references or pointers.
625 if (sizeof...(Args) > 0)
626 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
627 return ErrorWithMessage<T>(
628 caller_signature,
629 "couldn't re-assign reference and pointer arguments", error);
630
631 if (!py_return.IsAllocated())
632 return {};
633 return ExtractValueFromPythonObject<T>(py_return, error);
634 }
635
636 template <typename... Args>
637 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {
639 Dispatch<Status>(method_name, error, std::forward<Args>(args)...);
640
641 return error;
642 }
643
644 template <typename T> T Transform(T object) {
645 // No Transformation for generic usage
646 return {object};
647 }
648
650 // Boolean arguments need to be turned into python objects.
651 return python::PythonBoolean(arg);
652 }
653
657
659 return python::SWIGBridge::ToSWIGWrapper(std::move(arg));
660 }
661
665
666 template <typename T, typename = std::enable_if_t<
667 std::is_base_of_v<StructuredData::Object, T>>>
668 python::PythonObject Transform(std::shared_ptr<T> arg) {
669 return Transform(StructuredDataImpl(arg));
670 }
671
675
679
683
687
691
695
699
703
707
711
715
719
723
727
731
735
739
743
744 python::PythonObject Transform(const std::vector<std::string> &arg) {
746 for (const std::string &s : arg)
748 return list;
749 }
750
755
759
760 template <typename T, typename U>
761 void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
762 // If U is not a PythonObject, don't touch it!
763 }
764
765 template <typename T>
766 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,
767 Status &error) {
768 original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error);
769 }
770
771 // Read-only arguments (passed as `const T&`) have nothing to write back:
772 // there's no `T` value to reassign into a const reference, and no
773 // `ExtractValueFromPythonObject<T>` specialization should be required just
774 // to satisfy this round-trip for a value the callee never mutates.
775 template <typename T>
776 void ReverseTransform(const T &original_arg,
777 python::PythonObject transformed_arg, Status &error) {}
778
779 void ReverseTransform(bool &original_arg,
780 python::PythonObject transformed_arg, Status &error) {
782 python::PyRefType::Borrowed, transformed_arg.get());
783 if (boolean_arg.IsValid())
784 original_arg = boolean_arg.GetValue();
785 else
787 "{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION);
788 }
789
790 template <std::size_t... I, typename... Args>
791 auto TransformTuple(const std::tuple<Args...> &args,
792 std::index_sequence<I...>) {
793 return std::make_tuple(Transform(std::get<I>(args))...);
794 }
795
796 // This will iterate over the Dispatch parameter pack and replace in-place
797 // every `lldb_private` argument that has a SB counterpart.
798 template <typename... Args>
799 auto TransformArgs(const std::tuple<Args...> &args) {
800 return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>());
801 }
802
803 // Apply `fn` with the first `N` elements of `t`, for compile-time `N`.
804 template <std::size_t N, typename Tuple, typename Fn, std::size_t... I>
805 static void ApplyPrefixImpl(Tuple &&t, Fn &&fn, std::index_sequence<I...>) {
806 std::forward<Fn>(fn)(std::get<I>(std::forward<Tuple>(t))...);
807 }
808
809 template <std::size_t N, typename Tuple, typename Fn>
810 static void ApplyPrefix(Tuple &&t, Fn &&fn) {
811 ApplyPrefixImpl<N>(std::forward<Tuple>(t), std::forward<Fn>(fn),
812 std::make_index_sequence<N>{});
813 }
814
815 // Call `fn` with a runtime-selected prefix of `t`: exactly `call_arity`
816 // leading elements. `Is...` enumerates every compile-time count in
817 // `[0, sizeof...(Args)]`; the runtime check picks the matching one.
818 template <typename Tuple, std::size_t... Is, typename Fn>
819 static void CallWithArity(size_t call_arity, Tuple &&t,
820 std::index_sequence<Is...>, Fn &&fn) {
821 (void)std::initializer_list<int>{(
822 Is == call_arity
823 ? (ApplyPrefix<Is>(std::forward<Tuple>(t), std::forward<Fn>(fn)), 0)
824 : 0)...};
825 }
826
827 template <typename T, typename U>
828 void TransformBack(T &original_arg, U transformed_arg, Status &error) {
829 ReverseTransform(original_arg, transformed_arg, error);
830 }
831
832 // ScopedPythonObject is non-copyable — passing it through the generic
833 // TransformBack would trigger the deleted copy ctor. It manages its own
834 // cleanup via the destructor when the transformed-args tuple destructs, so
835 // there is nothing to reverse-transform back into the original arg.
836 template <typename T, typename SB>
837 void TransformBack(T &original_arg,
838 python::ScopedPythonObject<SB> &transformed_arg,
839 Status &error) {}
840
841 template <std::size_t... I, typename... Ts, typename... Us>
842 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
843 std::tuple<Us...> &transformed_args,
844 std::index_sequence<I...>) {
846 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
847 error),
848 ...);
849 return error.Success();
850 }
851
852 template <typename... Ts, typename... Us>
853 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
854 std::tuple<Us...> &transformed_args) {
855 if (sizeof...(Ts) != sizeof...(Us))
856 return false;
857
858 return ReassignPtrsOrRefsArgs(original_args, transformed_args,
859 std::make_index_sequence<sizeof...(Ts)>());
860 }
861
862 template <typename T, typename... Args>
863 void FormatArgs(std::string &fmt, T arg, Args... args) const {
864 FormatArgs(fmt, arg);
865 FormatArgs(fmt, args...);
866 }
867
868 template <typename T> void FormatArgs(std::string &fmt, T arg) const {
870 }
871
872 void FormatArgs(std::string &fmt) const {}
873
874 // The lifetime is managed by the ScriptInterpreter
876};
877
878template <>
882
883template <>
887
888template <>
891
892template <>
895
896template <>
900
901template <>
905
906template <>
910
911template <>
915
916template <>
920
921template <>
925
926template <>
929
930template <>
933
934template <>
938
939template <>
940std::optional<MemoryRegionInfo>
942 std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
943
944template <>
948
949template <>
953
954template <>
958
959template <>
963
964template <>
968
969template <>
973
974template <>
975std::optional<lldb::ValueType>
977 std::optional<lldb::ValueType>>(python::PythonObject &p, Status &error);
978
979template <>
983
984template <>
985std::vector<std::string>
988
989} // namespace lldb_private
990
991#endif // LLDB_SOURCE_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:375
ScriptInterpreterPythonImpl::Locker Locker
#define SET_CASE_AND_CONTINUE(method_name, case)
A command line argument class.
Definition Args.h:33
A file utility class.
Definition FileSpec.h:56
Guard PushScriptedExtensionCall()
Definition Policy.h:145
static PolicyStack & Get()
Definition Policy.cpp:21
static Ret ErrorWithMessage(llvm::StringRef caller_name, llvm::StringRef user_msg, Status &error, LLDBLog log_category=LLDBLog::Process)
std::optional< ScriptedMetadata > m_scripted_metadata
llvm::SmallVector< llvm::StringLiteral > const GetAbstractMethods() const
virtual llvm::SmallVector< AbstractMethodRequirement > GetAbstractMethodRequirements() const =0
virtual bool UserCanRunDirectly() const
Whether the user can invoke this extension directly, the way a scripted command can.
const std::optional< ScriptedMetadata > & GetScriptedMetadata() const
StructuredData::GenericSP m_object_instance_sp
llvm::StringRef GetClassName() const
python::ScopedPythonObject< lldb::SBCommandReturnObject > Transform(CommandReturnObject *arg)
python::PythonObject Transform(lldb::StackFrameListSP arg)
python::PythonObject Transform(lldb::ThreadPlanSP arg)
Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args)
python::PythonObject Transform(lldb::ProcessSP arg)
static void ApplyPrefix(Tuple &&t, Fn &&fn)
void TransformBack(T &original_arg, U transformed_arg, Status &error)
ScriptInterpreterPythonImpl & m_interpreter
python::PythonObject Transform(Event *arg)
auto TransformArgs(const std::tuple< Args... > &args)
python::PythonObject Transform(lldb::ExecutionContextRefSP arg)
python::PythonObject Transform(lldb::ThreadSP arg)
python::PythonObject Transform(const StructuredDataImpl &arg)
T ExtractValueFromPythonObject(python::PythonObject &p, Status &error)
~ScriptedPythonInterface() override=default
static void CallWithArity(size_t call_arity, Tuple &&t, std::index_sequence< Is... >, Fn &&fn)
python::PythonObject Transform(const TypeSummaryOptions &arg)
llvm::Expected< FileSpec > GetScriptedModulePath() override
python::PythonObject Transform(lldb::DescriptionLevel arg)
python::PythonObject Transform(const Status &arg)
python::PythonObject Transform(const SymbolContext &arg)
llvm::Expected< std::map< llvm::StringLiteral, AbstractMethodCheckerPayload > > CheckAbstractMethodImplementation(const python::PythonObject &obj_class) const
void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, Status &error)
void FormatArgs(std::string &fmt, T arg, Args... args) const
python::PythonObject Transform(lldb::BreakpointSP arg)
void FormatArgs(std::string &fmt, T arg) const
python::PythonObject Transform(lldb::DebuggerSP arg)
static std::string ExtractPythonError(llvm::Error error)
Extract detailed error message including Python backtrace if available.
ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter)
python::PythonObject Transform(const std::vector< std::string > &arg)
void ReverseTransform(T &original_arg, U transformed_arg, Status &error)
T CallStaticMethod(llvm::StringRef class_name, llvm::StringRef method_name, Status &error, Args &&...args)
Call a static method on a Python class without creating an instance.
T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args)
python::PythonObject Transform(lldb::BreakpointLocationSP arg)
python::PythonObject Transform(std::shared_ptr< T > arg)
bool ReassignPtrsOrRefsArgs(std::tuple< Ts... > &original_args, std::tuple< Us... > &transformed_args)
python::PythonObject Transform(lldb::StreamSP arg)
python::PythonObject Transform(Status &&arg)
python::PythonObject Transform(lldb::DataExtractorSP arg)
python::PythonObject Transform(lldb::StackFrameSP arg)
bool ReassignPtrsOrRefsArgs(std::tuple< Ts... > &original_args, std::tuple< Us... > &transformed_args, std::index_sequence< I... >)
python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg)
llvm::Expected< StructuredData::GenericSP > CreatePluginObject(const ScriptedMetadata &scripted_metadata, StructuredData::Generic *script_obj, Args... args)
python::PythonObject Transform(lldb::TargetSP arg)
void TransformBack(T &original_arg, python::ScopedPythonObject< SB > &transformed_arg, Status &error)
auto TransformTuple(const std::tuple< Args... > &args, std::index_sequence< I... >)
static void ApplyPrefixImpl(Tuple &&t, Fn &&fn, std::index_sequence< I... >)
void ReverseTransform(bool &original_arg, python::PythonObject transformed_arg, Status &error)
python::PythonObject Transform(lldb::ValueObjectSP arg)
void ReverseTransform(const T &original_arg, python::PythonObject transformed_arg, Status &error)
python::PythonObject Transform(lldb::ProcessAttachInfoSP arg)
An error handling class.
Definition Status.h:118
Status Clone() const
Don't call this function in new code.
Definition Status.h:174
static Status FromErrorString(const char *str)
Definition Status.h:141
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:136
std::shared_ptr< Generic > GenericSP
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Object > ObjectSP
std::shared_ptr< Array > ArraySP
Defines a symbol context baton that can be handed other debug core functions.
void AppendItem(const PythonObject &object)
StructuredData::ObjectSP CreateStructuredObject() const
PythonObject GetAttributeValue(llvm::StringRef attribute) const
bool HasAttribute(llvm::StringRef attribute) const
static PythonObject ToSWIGWrapper(std::unique_ptr< lldb::SBValue > value_sb)
A class that automatically clears an SB object when it goes out of scope.
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:338
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::ValueObject > ValueObjectSP
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::ValueObjectList > ValueObjectListSP
std::shared_ptr< lldb_private::Debugger > DebuggerSP
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
std::variant< std::monostate, InvalidArgumentCountPayload, std::string > payload