9#ifndef LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
10#define LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
53 std::variant<std::monostate, InvalidArgumentCountPayload, std::string>
65 return llvm::createStringError(
"scripted Interface has invalid object");
68 PythonObject(PyRefType::Borrowed,
71 if (!py_obj.IsAllocated())
72 return llvm::createStringError(
73 "scripted Interface has invalid python object");
75 PythonObject py_obj_class = py_obj.GetAttributeValue(
"__class__");
76 if (!py_obj_class.IsValid())
77 return llvm::createStringError(
78 "scripted Interface python object is missing '__class__' attribute");
80 PythonObject py_obj_module = py_obj_class.GetAttributeValue(
"__module__");
81 if (!py_obj_module.IsValid())
82 return llvm::createStringError(
83 "scripted Interface python object '__class__' is missing "
84 "'__module__' attribute");
86 PythonString py_obj_module_str = py_obj_module.Str();
87 if (!py_obj_module_str.IsValid())
88 return llvm::createStringError(
89 "scripted Interface python object '__class__.__module__' attribute "
92 llvm::StringRef py_obj_module_str_ref = py_obj_module_str.GetString();
93 PythonModule py_module = PythonModule::AddModule(py_obj_module_str_ref);
94 if (!py_module.IsValid())
95 return llvm::createStringError(
"failed to import '%s' module",
96 py_obj_module_str_ref.data());
98 PythonObject py_module_file = py_module.GetAttributeValue(
"__file__");
99 if (!py_module_file.IsValid())
100 return llvm::createStringError(
101 "module '%s' is missing '__file__' attribute",
102 py_obj_module_str_ref.data());
104 PythonString py_module_file_str = py_module_file.Str();
105 if (!py_module_file_str.IsValid())
106 return llvm::createStringError(
107 "module '%s.__file__' attribute is not a string",
108 py_obj_module_str_ref.data());
110 return FileSpec(py_module_file_str.GetString());
113 llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerPayload>>
119 std::map<llvm::StringLiteral, AbstractMethodCheckerPayload> checker;
120#define SET_CASE_AND_CONTINUE(method_name, case) \
122 checker[method_name] = {case, {}}; \
128 llvm::StringLiteral method_name = requirement.name;
135 if (!attr.IsAllocated())
139 PythonCallable callable = attr.
AsType<PythonCallable>();
144 if (!requirement.min_arg_count)
147 auto arg_info_or_err = callable.GetArgInfo();
148 if (!arg_info_or_err) {
149 checker[method_name] = {
155 PythonCallable::ArgInfo arg_info = *arg_info_or_err;
156 if (requirement.min_arg_count <= arg_info.max_positional_args) {
159 checker[method_name] = {
162 requirement.min_arg_count, arg_info.max_positional_args)};
166#undef SET_CASE_AND_CONTINUE
171 template <
typename...
Args>
172 llvm::Expected<StructuredData::GenericSP>
179 auto create_error = [](llvm::StringLiteral format,
auto &&...ts) {
180 return llvm::createStringError(
181 llvm::formatv(format.data(), std::forward<
decltype(ts)>(ts)...)
186 llvm::StringRef class_name = scripted_metadata.
GetClassName();
187 bool has_class_name = !class_name.empty();
188 bool has_interpreter_dict =
189 !(llvm::StringRef(
m_interpreter.GetDictionaryName()).empty());
190 if (!has_class_name && !has_interpreter_dict && !script_obj) {
192 return create_error(
"Missing script class name.");
193 else if (!has_interpreter_dict)
194 return create_error(
"Invalid script interpreter dictionary.");
196 return create_error(
"Missing scripting object.");
202 PythonObject result = {};
205 result = PythonObject(PyRefType::Borrowed,
206 static_cast<PyObject *
>(script_obj->
GetValue()));
211 if (!dict.IsAllocated())
212 return create_error(
"Could not find interpreter dictionary: {0}",
216 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
218 if (!init.IsAllocated())
219 return create_error(
"Could not find script class: {0}",
222 std::tuple<
Args...> original_args = std::forward_as_tuple(args...);
225 std::string error_string;
226 llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();
228 llvm::handleAllErrors(
229 arg_info.takeError(),
230 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
231 [&](
const llvm::ErrorInfoBase &E) {
232 error_string.append(E.message());
234 return llvm::createStringError(llvm::inconvertibleErrorCode(),
238 llvm::Expected<PythonObject> expected_return_object =
239 create_error(
"Resulting object is not initialized.");
253 size_t num_args =
sizeof...(Args);
254 if (arg_info->max_positional_args != PythonCallable::ArgInfo::UNBOUNDED &&
255 num_args != arg_info->max_positional_args) {
256 if (num_args != arg_info->max_positional_args - 1) {
260 llvm::consumeError(expected_return_object.takeError());
261 return create_error(
"Passed arguments ({0}) doesn't match the number "
262 "of expected arguments ({1}).",
263 num_args, arg_info->max_positional_args);
267 [&init, &expected_return_object](
auto &&...args) {
268 if (!expected_return_object)
269 llvm::consumeError(expected_return_object.takeError());
270 expected_return_object = init.Call(args...);
272 std::tuple_cat(transformed_args, std::make_tuple(dict)));
275 [&init, &expected_return_object](
auto &&...args) {
276 if (!expected_return_object)
277 llvm::consumeError(expected_return_object.takeError());
278 expected_return_object = init.Call(args...);
283 if (!expected_return_object)
288 return llvm::createStringError(
290 result = expected_return_object.get();
293 if (!result.IsValid())
294 return create_error(
"Resulting object is not a valid Python Object.");
295 if (!result.HasAttribute(
"__class__"))
296 return create_error(
"Resulting object doesn't have '__class__' member.");
298 PythonObject obj_class = result.GetAttributeValue(
"__class__");
299 if (!obj_class.IsValid())
300 return create_error(
"Resulting class object is not a valid.");
301 if (!obj_class.HasAttribute(
"__name__"))
303 "Resulting object class doesn't have '__name__' member.");
304 PythonString obj_class_name =
305 obj_class.GetAttributeValue(
"__name__").AsType<PythonString>();
309 return checker_or_err.takeError();
311 llvm::Error abstract_method_errors = llvm::Error::success();
312 for (
const auto &method_checker : *checker_or_err)
313 switch (method_checker.second.checker_case) {
315 abstract_method_errors = llvm::joinErrors(
316 std::move(abstract_method_errors),
317 std::move(create_error(
"Abstract method {0}.{1} not implemented.",
318 obj_class_name.GetString(),
319 method_checker.first)));
322 abstract_method_errors = llvm::joinErrors(
323 std::move(abstract_method_errors),
324 std::move(create_error(
"Abstract method {0}.{1} not allocated.",
325 obj_class_name.GetString(),
326 method_checker.first)));
329 abstract_method_errors = llvm::joinErrors(
330 std::move(abstract_method_errors),
331 std::move(create_error(
"Abstract method {0}.{1} not callable.",
332 obj_class_name.GetString(),
333 method_checker.first)));
336 const std::string *py_error =
337 std::get_if<std::string>(&method_checker.second.payload);
338 abstract_method_errors = llvm::joinErrors(
339 std::move(abstract_method_errors),
340 std::move(create_error(
341 "abstract method {0}.{1} has unknown argument count: {2}",
342 obj_class_name.GetString(), method_checker.first,
343 py_error ? *py_error :
"<no further information>")));
346 auto &payload_variant = method_checker.second.payload;
347 if (!std::holds_alternative<
350 abstract_method_errors = llvm::joinErrors(
351 std::move(abstract_method_errors),
352 std::move(create_error(
353 "Abstract method {0}.{1} has unexpected argument count.",
354 obj_class_name.GetString(), method_checker.first)));
356 auto payload = std::get<
359 abstract_method_errors = llvm::joinErrors(
360 std::move(abstract_method_errors),
362 create_error(
"Abstract method {0}.{1} has unexpected "
363 "argument count (expected {2} but has {3}).",
364 obj_class_name.GetString(), method_checker.first,
365 payload.required_argument_count,
366 payload.actual_argument_count)));
370 LLDB_LOG(log,
"Abstract method {0}.{1} implemented & valid.",
371 obj_class_name.GetString(), method_checker.first);
375 if (abstract_method_errors) {
377 LLDB_LOG(log,
"Abstract method error in {0}:\n{1}", class_name,
379 return error.ToError();
383 new StructuredPythonObject(std::move(result)));
406 std::string caller_signature =
407 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(
" (") +
408 llvm::Twine(class_name) + llvm::Twine(
".") +
409 llvm::Twine(method_name) + llvm::Twine(
")"))
412 if (class_name.empty())
423 if (!dict.IsAllocated())
426 llvm::formatv(
"could not find interpreter dictionary: {0}",
433 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
435 if (!class_obj.IsAllocated())
438 llvm::formatv(
"could not find script class: {0}", class_name).str(),
442 if (!class_obj.HasAttribute(method_name))
445 llvm::formatv(
"class {0} does not have method {1}", class_name,
450 PythonCallable method =
451 class_obj.GetAttributeValue(method_name).AsType<PythonCallable>();
452 if (!method.IsAllocated())
454 llvm::formatv(
"method {0}.{1} is not callable",
455 class_name, method_name)
460 std::tuple<
Args...> original_args = std::forward_as_tuple(args...);
464 llvm::Expected<PythonObject> expected_return_object =
465 llvm::createStringError(
"not initialized");
467 [&method, &expected_return_object](
auto &&...args) {
468 if (!expected_return_object)
469 llvm::consumeError(expected_return_object.takeError());
470 expected_return_object = method.Call(args...);
474 if (llvm::Error e = expected_return_object.takeError()) {
484 llvm::formatv(
"python exception in {0} method '{1}'", class_name,
490 PythonObject py_return = std::move(expected_return_object.get());
493 if (
sizeof...(
Args) > 0)
497 "couldn't re-assign reference and pointer arguments",
error);
513 std::string error_msg;
514 llvm::handleAllErrors(
517 [&](
const llvm::ErrorInfoBase &E) { error_msg = E.message(); });
521 template <
typename T = StructuredData::ObjectSP>
531 std::string caller_signature =
532 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(
" (") +
533 llvm::Twine(method_name) + llvm::Twine(
")"))
542 PythonObject implementor(PyRefType::Borrowed,
545 if (!implementor.IsAllocated())
548 "python implementor not allocated",
552 std::tuple<
Args...> original_args = std::forward_as_tuple(args...);
558 size_t call_arity =
sizeof...(Args);
559 if (PythonObject py_method = implementor.GetAttributeValue(method_name);
560 py_method.IsAllocated()) {
561 PythonCallable callable = py_method.AsType<PythonCallable>();
562 if (callable.IsAllocated()) {
563 if (llvm::Expected<PythonCallable::ArgInfo> arg_info =
564 callable.GetArgInfo()) {
565 if (arg_info->max_positional_args !=
566 PythonCallable::ArgInfo::UNBOUNDED &&
567 arg_info->max_positional_args < call_arity)
568 call_arity = arg_info->max_positional_args;
570 llvm::consumeError(arg_info.takeError());
575 llvm::Expected<PythonObject> expected_return_object =
576 llvm::createStringError(
"not initialized");
578 std::make_index_sequence<
sizeof...(
Args) + 1>{},
579 [&implementor, &method_name,
580 &expected_return_object](
auto &&...call_args) {
581 if (!expected_return_object)
582 llvm::consumeError(expected_return_object.takeError());
583 expected_return_object = implementor.CallMethod(
584 method_name.data(), call_args...);
587 if (llvm::Error e = expected_return_object.takeError()) {
597 llvm::formatv(
"python exception in {0} method '{1}'",
606 PythonObject py_return = std::move(expected_return_object.get());
612 if (
sizeof...(
Args) > 0)
616 "couldn't re-assign reference and pointer arguments",
error);
618 if (!py_return.IsAllocated())
623 template <
typename...
Args>
653 template <
typename T,
typename = std::enable_if_t<
654 std::is_base_of_v<StructuredData::Object, T>>>
733 for (
const std::string &s : arg)
747 template <
typename T,
typename U>
752 template <
typename T>
762 template <
typename T>
771 original_arg = boolean_arg.
GetValue();
774 "{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION);
777 template <std::size_t... I,
typename...
Args>
779 std::index_sequence<I...>) {
780 return std::make_tuple(
Transform(std::get<I>(args))...);
785 template <
typename...
Args>
791 template <std::size_t N,
typename Tuple,
typename Fn, std::size_t... I>
793 std::forward<Fn>(fn)(std::get<I>(std::forward<Tuple>(t))...);
796 template <std::
size_t N,
typename Tuple,
typename Fn>
799 std::make_index_sequence<N>{});
805 template <
typename Tuple, std::size_t... Is,
typename Fn>
807 std::index_sequence<Is...>, Fn &&fn) {
808 (void)std::initializer_list<int>{(
814 template <
typename T,
typename U>
823 template <
typename T,
typename SB>
828 template <std::size_t... I,
typename... Ts,
typename... Us>
830 std::tuple<Us...> &transformed_args,
831 std::index_sequence<I...>) {
833 (
TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
836 return error.Success();
839 template <
typename... Ts,
typename... Us>
841 std::tuple<Us...> &transformed_args) {
842 if (
sizeof...(Ts) !=
sizeof...(Us))
846 std::make_index_sequence<
sizeof...(Ts)>());
849 template <
typename T,
typename...
Args>
855 template <
typename T>
void FormatArgs(std::string &fmt, T arg)
const {
927std::optional<MemoryRegionInfo>
962std::optional<lldb::ValueType>
972std::vector<std::string>
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
ScriptInterpreterPythonImpl::Locker Locker
#define SET_CASE_AND_CONTINUE(method_name, case)
A command line argument class.
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
ScriptedInterface()=default
const std::optional< ScriptedMetadata > & GetScriptedMetadata() const
StructuredData::GenericSP m_object_instance_sp
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.
void FormatArgs(std::string &fmt) const
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... >)
AbstractMethodCheckerCases
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)
python::PythonObject Transform(bool arg)
Status Clone() const
Don't call this function in new code.
static Status FromErrorString(const char *str)
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
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.
std::string ReadBacktrace() const
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.
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
InvalidArgumentCountPayload(size_t required, size_t actual)
size_t actual_argument_count
size_t required_argument_count
std::variant< std::monostate, InvalidArgumentCountPayload, std::string > payload
AbstractMethodCheckerCases checker_case