177374d3bSMed Ismail Bennani //===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===// 277374d3bSMed Ismail Bennani // 377374d3bSMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 477374d3bSMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information. 577374d3bSMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 677374d3bSMed Ismail Bennani // 777374d3bSMed Ismail Bennani //===----------------------------------------------------------------------===// 877374d3bSMed Ismail Bennani 977374d3bSMed Ismail Bennani #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 1077374d3bSMed Ismail Bennani #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 1177374d3bSMed Ismail Bennani 1277374d3bSMed Ismail Bennani #if LLDB_ENABLE_PYTHON 1377374d3bSMed Ismail Bennani 1477374d3bSMed Ismail Bennani #include <optional> 1577374d3bSMed Ismail Bennani #include <sstream> 1677374d3bSMed Ismail Bennani #include <tuple> 1777374d3bSMed Ismail Bennani #include <type_traits> 1877374d3bSMed Ismail Bennani #include <utility> 1977374d3bSMed Ismail Bennani 20e8504cb0SMed Ismail Bennani #include "lldb/Host/Config.h" 21e8504cb0SMed Ismail Bennani #include "lldb/Interpreter/Interfaces/ScriptedInterface.h" 22e8504cb0SMed Ismail Bennani #include "lldb/Utility/DataBufferHeap.h" 23c1d1a752SMed Ismail Bennani 2477374d3bSMed Ismail Bennani #include "../PythonDataObjects.h" 2577374d3bSMed Ismail Bennani #include "../SWIGPythonBridge.h" 2677374d3bSMed Ismail Bennani #include "../ScriptInterpreterPythonImpl.h" 2777374d3bSMed Ismail Bennani 2877374d3bSMed Ismail Bennani namespace lldb_private { 2977374d3bSMed Ismail Bennani class ScriptInterpreterPythonImpl; 3077374d3bSMed Ismail Bennani class ScriptedPythonInterface : virtual public ScriptedInterface { 3177374d3bSMed Ismail Bennani public: 3277374d3bSMed Ismail Bennani ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); 3377374d3bSMed Ismail Bennani ~ScriptedPythonInterface() override = default; 3477374d3bSMed Ismail Bennani 350a211446SMed Ismail Bennani enum class AbstractMethodCheckerCases { 360a211446SMed Ismail Bennani eNotImplemented, 370a211446SMed Ismail Bennani eNotAllocated, 380a211446SMed Ismail Bennani eNotCallable, 3921026073SMed Ismail Bennani eUnknownArgumentCount, 4021026073SMed Ismail Bennani eInvalidArgumentCount, 410a211446SMed Ismail Bennani eValid 420a211446SMed Ismail Bennani }; 430a211446SMed Ismail Bennani 4421026073SMed Ismail Bennani struct AbstrackMethodCheckerPayload { 4521026073SMed Ismail Bennani 4621026073SMed Ismail Bennani struct InvalidArgumentCountPayload { 4721026073SMed Ismail Bennani InvalidArgumentCountPayload(size_t required, size_t actual) 4821026073SMed Ismail Bennani : required_argument_count(required), actual_argument_count(actual) {} 4921026073SMed Ismail Bennani 5021026073SMed Ismail Bennani size_t required_argument_count; 5121026073SMed Ismail Bennani size_t actual_argument_count; 5221026073SMed Ismail Bennani }; 5321026073SMed Ismail Bennani 5421026073SMed Ismail Bennani AbstractMethodCheckerCases checker_case; 5521026073SMed Ismail Bennani std::variant<std::monostate, InvalidArgumentCountPayload> payload; 5621026073SMed Ismail Bennani }; 5721026073SMed Ismail Bennani 5821026073SMed Ismail Bennani llvm::Expected<std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload>> 590a211446SMed Ismail Bennani CheckAbstractMethodImplementation( 600a211446SMed Ismail Bennani const python::PythonDictionary &class_dict) const { 610a211446SMed Ismail Bennani 620a211446SMed Ismail Bennani using namespace python; 630a211446SMed Ismail Bennani 6421026073SMed Ismail Bennani std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload> checker; 6521026073SMed Ismail Bennani #define SET_CASE_AND_CONTINUE(method_name, case) \ 660a211446SMed Ismail Bennani { \ 6721026073SMed Ismail Bennani checker[method_name] = {case, {}}; \ 680a211446SMed Ismail Bennani continue; \ 690a211446SMed Ismail Bennani } 700a211446SMed Ismail Bennani 7121026073SMed Ismail Bennani for (const AbstractMethodRequirement &requirement : 7221026073SMed Ismail Bennani GetAbstractMethodRequirements()) { 7321026073SMed Ismail Bennani llvm::StringLiteral method_name = requirement.name; 740a211446SMed Ismail Bennani if (!class_dict.HasKey(method_name)) 7521026073SMed Ismail Bennani SET_CASE_AND_CONTINUE(method_name, 760a211446SMed Ismail Bennani AbstractMethodCheckerCases::eNotImplemented) 770a211446SMed Ismail Bennani auto callable_or_err = class_dict.GetItem(method_name); 7821026073SMed Ismail Bennani if (!callable_or_err) { 7921026073SMed Ismail Bennani llvm::consumeError(callable_or_err.takeError()); 8021026073SMed Ismail Bennani SET_CASE_AND_CONTINUE(method_name, 810a211446SMed Ismail Bennani AbstractMethodCheckerCases::eNotAllocated) 820a211446SMed Ismail Bennani } 830a211446SMed Ismail Bennani 8421026073SMed Ismail Bennani PythonCallable callable = callable_or_err->AsType<PythonCallable>(); 8521026073SMed Ismail Bennani if (!callable) 8621026073SMed Ismail Bennani SET_CASE_AND_CONTINUE(method_name, 8721026073SMed Ismail Bennani AbstractMethodCheckerCases::eNotCallable) 8821026073SMed Ismail Bennani 8921026073SMed Ismail Bennani if (!requirement.min_arg_count) 9021026073SMed Ismail Bennani SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid) 9121026073SMed Ismail Bennani 9221026073SMed Ismail Bennani auto arg_info_or_err = callable.GetArgInfo(); 9321026073SMed Ismail Bennani if (!arg_info_or_err) { 9421026073SMed Ismail Bennani llvm::consumeError(arg_info_or_err.takeError()); 9521026073SMed Ismail Bennani SET_CASE_AND_CONTINUE(method_name, 9621026073SMed Ismail Bennani AbstractMethodCheckerCases::eUnknownArgumentCount) 9721026073SMed Ismail Bennani } 9821026073SMed Ismail Bennani 9921026073SMed Ismail Bennani PythonCallable::ArgInfo arg_info = *arg_info_or_err; 10021026073SMed Ismail Bennani if (requirement.min_arg_count <= arg_info.max_positional_args) { 10121026073SMed Ismail Bennani SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid) 10221026073SMed Ismail Bennani } else { 10321026073SMed Ismail Bennani checker[method_name] = { 10421026073SMed Ismail Bennani AbstractMethodCheckerCases::eInvalidArgumentCount, 10521026073SMed Ismail Bennani AbstrackMethodCheckerPayload::InvalidArgumentCountPayload( 10621026073SMed Ismail Bennani requirement.min_arg_count, arg_info.max_positional_args)}; 10721026073SMed Ismail Bennani } 10821026073SMed Ismail Bennani } 10921026073SMed Ismail Bennani 11021026073SMed Ismail Bennani #undef SET_CASE_AND_CONTINUE 1110a211446SMed Ismail Bennani 1120a211446SMed Ismail Bennani return checker; 1130a211446SMed Ismail Bennani } 1140a211446SMed Ismail Bennani 115f22d82ceSMed Ismail Bennani template <typename... Args> 116f22d82ceSMed Ismail Bennani llvm::Expected<StructuredData::GenericSP> 117f22d82ceSMed Ismail Bennani CreatePluginObject(llvm::StringRef class_name, 118f22d82ceSMed Ismail Bennani StructuredData::Generic *script_obj, Args... args) { 119f22d82ceSMed Ismail Bennani using namespace python; 120f22d82ceSMed Ismail Bennani using Locker = ScriptInterpreterPythonImpl::Locker; 121f22d82ceSMed Ismail Bennani 12221026073SMed Ismail Bennani Log *log = GetLog(LLDBLog::Script); 12321026073SMed Ismail Bennani auto create_error = [](llvm::StringLiteral format, auto &&...ts) { 12421026073SMed Ismail Bennani return llvm::createStringError( 12521026073SMed Ismail Bennani llvm::formatv(format.data(), std::forward<decltype(ts)>(ts)...) 12621026073SMed Ismail Bennani .str()); 1270a211446SMed Ismail Bennani }; 1280a211446SMed Ismail Bennani 129f22d82ceSMed Ismail Bennani bool has_class_name = !class_name.empty(); 130f22d82ceSMed Ismail Bennani bool has_interpreter_dict = 131f22d82ceSMed Ismail Bennani !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty()); 132a466db2bSDavid Spickett if (!has_class_name && !has_interpreter_dict && !script_obj) { 133f22d82ceSMed Ismail Bennani if (!has_class_name) 1340a211446SMed Ismail Bennani return create_error("Missing script class name."); 135a466db2bSDavid Spickett else if (!has_interpreter_dict) 1360a211446SMed Ismail Bennani return create_error("Invalid script interpreter dictionary."); 137a466db2bSDavid Spickett else 1380a211446SMed Ismail Bennani return create_error("Missing scripting object."); 139a466db2bSDavid Spickett } 140f22d82ceSMed Ismail Bennani 141f22d82ceSMed Ismail Bennani Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 142f22d82ceSMed Ismail Bennani Locker::FreeLock); 143f22d82ceSMed Ismail Bennani 144f22d82ceSMed Ismail Bennani PythonObject result = {}; 145f22d82ceSMed Ismail Bennani 146f22d82ceSMed Ismail Bennani if (script_obj) { 147f22d82ceSMed Ismail Bennani result = PythonObject(PyRefType::Borrowed, 148f22d82ceSMed Ismail Bennani static_cast<PyObject *>(script_obj->GetValue())); 149f22d82ceSMed Ismail Bennani } else { 150f22d82ceSMed Ismail Bennani auto dict = 151f22d82ceSMed Ismail Bennani PythonModule::MainModule().ResolveName<python::PythonDictionary>( 152f22d82ceSMed Ismail Bennani m_interpreter.GetDictionaryName()); 1530a211446SMed Ismail Bennani if (!dict.IsAllocated()) 15421026073SMed Ismail Bennani return create_error("Could not find interpreter dictionary: {0}", 15521026073SMed Ismail Bennani m_interpreter.GetDictionaryName()); 156f22d82ceSMed Ismail Bennani 1570a211446SMed Ismail Bennani auto init = 158f22d82ceSMed Ismail Bennani PythonObject::ResolveNameWithDictionary<python::PythonCallable>( 159f22d82ceSMed Ismail Bennani class_name, dict); 1600a211446SMed Ismail Bennani if (!init.IsAllocated()) 16121026073SMed Ismail Bennani return create_error("Could not find script class: {0}", 16221026073SMed Ismail Bennani class_name.data()); 163f22d82ceSMed Ismail Bennani 164f22d82ceSMed Ismail Bennani std::tuple<Args...> original_args = std::forward_as_tuple(args...); 165f22d82ceSMed Ismail Bennani auto transformed_args = TransformArgs(original_args); 166f22d82ceSMed Ismail Bennani 167f22d82ceSMed Ismail Bennani std::string error_string; 1680a211446SMed Ismail Bennani llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo(); 169f22d82ceSMed Ismail Bennani if (!arg_info) { 170f22d82ceSMed Ismail Bennani llvm::handleAllErrors( 171f22d82ceSMed Ismail Bennani arg_info.takeError(), 172f22d82ceSMed Ismail Bennani [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, 173f22d82ceSMed Ismail Bennani [&](const llvm::ErrorInfoBase &E) { 174f22d82ceSMed Ismail Bennani error_string.append(E.message()); 175f22d82ceSMed Ismail Bennani }); 176f22d82ceSMed Ismail Bennani return llvm::createStringError(llvm::inconvertibleErrorCode(), 177f22d82ceSMed Ismail Bennani error_string); 178f22d82ceSMed Ismail Bennani } 179f22d82ceSMed Ismail Bennani 180f22d82ceSMed Ismail Bennani llvm::Expected<PythonObject> expected_return_object = 1810a211446SMed Ismail Bennani create_error("Resulting object is not initialized."); 182f22d82ceSMed Ismail Bennani 183*f732157aSMed Ismail Bennani // This relax the requirement on the number of argument for 184*f732157aSMed Ismail Bennani // initializing scripting extension if the size of the interface 185*f732157aSMed Ismail Bennani // parameter pack contains 1 less element than the extension maximum 186*f732157aSMed Ismail Bennani // number of positional arguments for this initializer. 187*f732157aSMed Ismail Bennani // 188*f732157aSMed Ismail Bennani // This addresses the cases where the embedded interpreter session 189*f732157aSMed Ismail Bennani // dictionary is passed to the extension initializer which is not used 190*f732157aSMed Ismail Bennani // most of the time. 191*f732157aSMed Ismail Bennani size_t num_args = sizeof...(Args); 192*f732157aSMed Ismail Bennani if (num_args != arg_info->max_positional_args) { 193*f732157aSMed Ismail Bennani if (num_args != arg_info->max_positional_args - 1) 194*f732157aSMed Ismail Bennani return create_error("Passed arguments ({0}) doesn't match the number " 195*f732157aSMed Ismail Bennani "of expected arguments ({1}).", 196*f732157aSMed Ismail Bennani num_args, arg_info->max_positional_args); 197*f732157aSMed Ismail Bennani 198*f732157aSMed Ismail Bennani std::apply( 199*f732157aSMed Ismail Bennani [&init, &expected_return_object](auto &&...args) { 200*f732157aSMed Ismail Bennani llvm::consumeError(expected_return_object.takeError()); 201*f732157aSMed Ismail Bennani expected_return_object = init(args...); 202*f732157aSMed Ismail Bennani }, 203*f732157aSMed Ismail Bennani std::tuple_cat(transformed_args, std::make_tuple(dict))); 204*f732157aSMed Ismail Bennani } else { 205f22d82ceSMed Ismail Bennani std::apply( 2060a211446SMed Ismail Bennani [&init, &expected_return_object](auto &&...args) { 207f22d82ceSMed Ismail Bennani llvm::consumeError(expected_return_object.takeError()); 2080a211446SMed Ismail Bennani expected_return_object = init(args...); 209f22d82ceSMed Ismail Bennani }, 210f22d82ceSMed Ismail Bennani transformed_args); 211*f732157aSMed Ismail Bennani } 212f22d82ceSMed Ismail Bennani 2130a211446SMed Ismail Bennani if (!expected_return_object) 2140a211446SMed Ismail Bennani return expected_return_object.takeError(); 2150a211446SMed Ismail Bennani result = expected_return_object.get(); 216f22d82ceSMed Ismail Bennani } 217f22d82ceSMed Ismail Bennani 218f22d82ceSMed Ismail Bennani if (!result.IsValid()) 2190a211446SMed Ismail Bennani return create_error("Resulting object is not a valid Python Object."); 2200a211446SMed Ismail Bennani if (!result.HasAttribute("__class__")) 2210a211446SMed Ismail Bennani return create_error("Resulting object doesn't have '__class__' member."); 2220a211446SMed Ismail Bennani 2230a211446SMed Ismail Bennani PythonObject obj_class = result.GetAttributeValue("__class__"); 2240a211446SMed Ismail Bennani if (!obj_class.IsValid()) 2250a211446SMed Ismail Bennani return create_error("Resulting class object is not a valid."); 2260a211446SMed Ismail Bennani if (!obj_class.HasAttribute("__name__")) 2270a211446SMed Ismail Bennani return create_error( 2280a211446SMed Ismail Bennani "Resulting object class doesn't have '__name__' member."); 2290a211446SMed Ismail Bennani PythonString obj_class_name = 2300a211446SMed Ismail Bennani obj_class.GetAttributeValue("__name__").AsType<PythonString>(); 2310a211446SMed Ismail Bennani 2320a211446SMed Ismail Bennani PythonObject object_class_mapping_proxy = 2330a211446SMed Ismail Bennani obj_class.GetAttributeValue("__dict__"); 2340a211446SMed Ismail Bennani if (!obj_class.HasAttribute("__dict__")) 2350a211446SMed Ismail Bennani return create_error( 2360a211446SMed Ismail Bennani "Resulting object class doesn't have '__dict__' member."); 2370a211446SMed Ismail Bennani 2380a211446SMed Ismail Bennani PythonCallable dict_converter = PythonModule::BuiltinsModule() 2390a211446SMed Ismail Bennani .ResolveName("dict") 2400a211446SMed Ismail Bennani .AsType<PythonCallable>(); 2410a211446SMed Ismail Bennani if (!dict_converter.IsAllocated()) 2420a211446SMed Ismail Bennani return create_error( 2430a211446SMed Ismail Bennani "Python 'builtins' module doesn't have 'dict' class."); 2440a211446SMed Ismail Bennani 2450a211446SMed Ismail Bennani PythonDictionary object_class_dict = 2460a211446SMed Ismail Bennani dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>(); 2470a211446SMed Ismail Bennani if (!object_class_dict.IsAllocated()) 2480a211446SMed Ismail Bennani return create_error("Coudn't create dictionary from resulting object " 2490a211446SMed Ismail Bennani "class mapping proxy object."); 2500a211446SMed Ismail Bennani 2510a211446SMed Ismail Bennani auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict); 2520a211446SMed Ismail Bennani if (!checker_or_err) 2530a211446SMed Ismail Bennani return checker_or_err.takeError(); 2540a211446SMed Ismail Bennani 25521026073SMed Ismail Bennani llvm::Error abstract_method_errors = llvm::Error::success(); 2560a211446SMed Ismail Bennani for (const auto &method_checker : *checker_or_err) 25721026073SMed Ismail Bennani switch (method_checker.second.checker_case) { 2580a211446SMed Ismail Bennani case AbstractMethodCheckerCases::eNotImplemented: 25921026073SMed Ismail Bennani abstract_method_errors = llvm::joinErrors( 26021026073SMed Ismail Bennani std::move(abstract_method_errors), 26121026073SMed Ismail Bennani std::move(create_error("Abstract method {0}.{1} not implemented.", 26221026073SMed Ismail Bennani obj_class_name.GetString(), 26321026073SMed Ismail Bennani method_checker.first))); 2640a211446SMed Ismail Bennani break; 2650a211446SMed Ismail Bennani case AbstractMethodCheckerCases::eNotAllocated: 26621026073SMed Ismail Bennani abstract_method_errors = llvm::joinErrors( 26721026073SMed Ismail Bennani std::move(abstract_method_errors), 26821026073SMed Ismail Bennani std::move(create_error("Abstract method {0}.{1} not allocated.", 26921026073SMed Ismail Bennani obj_class_name.GetString(), 27021026073SMed Ismail Bennani method_checker.first))); 2710a211446SMed Ismail Bennani break; 2720a211446SMed Ismail Bennani case AbstractMethodCheckerCases::eNotCallable: 27321026073SMed Ismail Bennani abstract_method_errors = llvm::joinErrors( 27421026073SMed Ismail Bennani std::move(abstract_method_errors), 27521026073SMed Ismail Bennani std::move(create_error("Abstract method {0}.{1} not callable.", 27621026073SMed Ismail Bennani obj_class_name.GetString(), 27721026073SMed Ismail Bennani method_checker.first))); 2780a211446SMed Ismail Bennani break; 27921026073SMed Ismail Bennani case AbstractMethodCheckerCases::eUnknownArgumentCount: 28021026073SMed Ismail Bennani abstract_method_errors = llvm::joinErrors( 28121026073SMed Ismail Bennani std::move(abstract_method_errors), 28221026073SMed Ismail Bennani std::move(create_error( 28321026073SMed Ismail Bennani "Abstract method {0}.{1} has unknown argument count.", 28421026073SMed Ismail Bennani obj_class_name.GetString(), method_checker.first))); 28521026073SMed Ismail Bennani break; 28621026073SMed Ismail Bennani case AbstractMethodCheckerCases::eInvalidArgumentCount: { 28721026073SMed Ismail Bennani auto &payload_variant = method_checker.second.payload; 28821026073SMed Ismail Bennani if (!std::holds_alternative< 28921026073SMed Ismail Bennani AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>( 29021026073SMed Ismail Bennani payload_variant)) { 29121026073SMed Ismail Bennani abstract_method_errors = llvm::joinErrors( 29221026073SMed Ismail Bennani std::move(abstract_method_errors), 29321026073SMed Ismail Bennani std::move(create_error( 29421026073SMed Ismail Bennani "Abstract method {0}.{1} has unexpected argument count.", 29521026073SMed Ismail Bennani obj_class_name.GetString(), method_checker.first))); 29621026073SMed Ismail Bennani } else { 29721026073SMed Ismail Bennani auto payload = std::get< 29821026073SMed Ismail Bennani AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>( 29921026073SMed Ismail Bennani payload_variant); 30021026073SMed Ismail Bennani abstract_method_errors = llvm::joinErrors( 30121026073SMed Ismail Bennani std::move(abstract_method_errors), 30221026073SMed Ismail Bennani std::move( 30321026073SMed Ismail Bennani create_error("Abstract method {0}.{1} has unexpected " 30421026073SMed Ismail Bennani "argument count (expected {2} but has {3}).", 30521026073SMed Ismail Bennani obj_class_name.GetString(), method_checker.first, 30621026073SMed Ismail Bennani payload.required_argument_count, 30721026073SMed Ismail Bennani payload.actual_argument_count))); 30821026073SMed Ismail Bennani } 30921026073SMed Ismail Bennani } break; 3100a211446SMed Ismail Bennani case AbstractMethodCheckerCases::eValid: 31121026073SMed Ismail Bennani LLDB_LOG(log, "Abstract method {0}.{1} implemented & valid.", 3120a211446SMed Ismail Bennani obj_class_name.GetString(), method_checker.first); 3130a211446SMed Ismail Bennani break; 3140a211446SMed Ismail Bennani } 3150a211446SMed Ismail Bennani 31621026073SMed Ismail Bennani if (abstract_method_errors) { 31721026073SMed Ismail Bennani Status error = Status::FromError(std::move(abstract_method_errors)); 31821026073SMed Ismail Bennani LLDB_LOG(log, "Abstract method error in {0}:\n{1}", class_name, 31921026073SMed Ismail Bennani error.AsCString()); 32021026073SMed Ismail Bennani return error.ToError(); 32121026073SMed Ismail Bennani } 322f22d82ceSMed Ismail Bennani 323f22d82ceSMed Ismail Bennani m_object_instance_sp = StructuredData::GenericSP( 324f22d82ceSMed Ismail Bennani new StructuredPythonObject(std::move(result))); 325f22d82ceSMed Ismail Bennani return m_object_instance_sp; 326f22d82ceSMed Ismail Bennani } 327f22d82ceSMed Ismail Bennani 32877374d3bSMed Ismail Bennani protected: 32977374d3bSMed Ismail Bennani template <typename T = StructuredData::ObjectSP> 33077374d3bSMed Ismail Bennani T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { 33177374d3bSMed Ismail Bennani return p.CreateStructuredObject(); 33277374d3bSMed Ismail Bennani } 33377374d3bSMed Ismail Bennani 33477374d3bSMed Ismail Bennani template <typename T = StructuredData::ObjectSP, typename... Args> 33577374d3bSMed Ismail Bennani T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) { 33677374d3bSMed Ismail Bennani using namespace python; 33777374d3bSMed Ismail Bennani using Locker = ScriptInterpreterPythonImpl::Locker; 33877374d3bSMed Ismail Bennani 33977374d3bSMed Ismail Bennani std::string caller_signature = 34077374d3bSMed Ismail Bennani llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") + 34177374d3bSMed Ismail Bennani llvm::Twine(method_name) + llvm::Twine(")")) 34277374d3bSMed Ismail Bennani .str(); 34377374d3bSMed Ismail Bennani if (!m_object_instance_sp) 34477374d3bSMed Ismail Bennani return ErrorWithMessage<T>(caller_signature, "Python object ill-formed", 34577374d3bSMed Ismail Bennani error); 34677374d3bSMed Ismail Bennani 34777374d3bSMed Ismail Bennani Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 34877374d3bSMed Ismail Bennani Locker::FreeLock); 34977374d3bSMed Ismail Bennani 35077374d3bSMed Ismail Bennani PythonObject implementor(PyRefType::Borrowed, 35177374d3bSMed Ismail Bennani (PyObject *)m_object_instance_sp->GetValue()); 35277374d3bSMed Ismail Bennani 35377374d3bSMed Ismail Bennani if (!implementor.IsAllocated()) 3549a9ec228SMed Ismail Bennani return llvm::is_contained(GetAbstractMethods(), method_name) 3559a9ec228SMed Ismail Bennani ? ErrorWithMessage<T>(caller_signature, 3569a9ec228SMed Ismail Bennani "Python implementor not allocated.", 3579a9ec228SMed Ismail Bennani error) 3589a9ec228SMed Ismail Bennani : T{}; 35977374d3bSMed Ismail Bennani 36077374d3bSMed Ismail Bennani std::tuple<Args...> original_args = std::forward_as_tuple(args...); 36177374d3bSMed Ismail Bennani auto transformed_args = TransformArgs(original_args); 36277374d3bSMed Ismail Bennani 36377374d3bSMed Ismail Bennani llvm::Expected<PythonObject> expected_return_object = 36477374d3bSMed Ismail Bennani llvm::make_error<llvm::StringError>("Not initialized.", 36577374d3bSMed Ismail Bennani llvm::inconvertibleErrorCode()); 36677374d3bSMed Ismail Bennani std::apply( 36777374d3bSMed Ismail Bennani [&implementor, &method_name, &expected_return_object](auto &&...args) { 36877374d3bSMed Ismail Bennani llvm::consumeError(expected_return_object.takeError()); 36977374d3bSMed Ismail Bennani expected_return_object = 37077374d3bSMed Ismail Bennani implementor.CallMethod(method_name.data(), args...); 37177374d3bSMed Ismail Bennani }, 37277374d3bSMed Ismail Bennani transformed_args); 37377374d3bSMed Ismail Bennani 37477374d3bSMed Ismail Bennani if (llvm::Error e = expected_return_object.takeError()) { 375a0dd90ebSAdrian Prantl error = Status::FromError(std::move(e)); 37677374d3bSMed Ismail Bennani return ErrorWithMessage<T>(caller_signature, 37777374d3bSMed Ismail Bennani "Python method could not be called.", error); 37877374d3bSMed Ismail Bennani } 37977374d3bSMed Ismail Bennani 38077374d3bSMed Ismail Bennani PythonObject py_return = std::move(expected_return_object.get()); 38177374d3bSMed Ismail Bennani 38277374d3bSMed Ismail Bennani // Now that we called the python method with the transformed arguments, 38377374d3bSMed Ismail Bennani // we need to interate again over both the original and transformed 38477374d3bSMed Ismail Bennani // parameter pack, and transform back the parameter that were passed in 38577374d3bSMed Ismail Bennani // the original parameter pack as references or pointers. 38677374d3bSMed Ismail Bennani if (sizeof...(Args) > 0) 38777374d3bSMed Ismail Bennani if (!ReassignPtrsOrRefsArgs(original_args, transformed_args)) 38877374d3bSMed Ismail Bennani return ErrorWithMessage<T>( 38977374d3bSMed Ismail Bennani caller_signature, 39077374d3bSMed Ismail Bennani "Couldn't re-assign reference and pointer arguments.", error); 39177374d3bSMed Ismail Bennani 392f22d82ceSMed Ismail Bennani if (!py_return.IsAllocated()) 393f22d82ceSMed Ismail Bennani return {}; 39477374d3bSMed Ismail Bennani return ExtractValueFromPythonObject<T>(py_return, error); 39577374d3bSMed Ismail Bennani } 39677374d3bSMed Ismail Bennani 39777374d3bSMed Ismail Bennani template <typename... Args> 39877374d3bSMed Ismail Bennani Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) { 39977374d3bSMed Ismail Bennani Status error; 40077374d3bSMed Ismail Bennani Dispatch<Status>(method_name, error, std::forward<Args>(args)...); 40177374d3bSMed Ismail Bennani 40277374d3bSMed Ismail Bennani return error; 40377374d3bSMed Ismail Bennani } 40477374d3bSMed Ismail Bennani 40577374d3bSMed Ismail Bennani template <typename T> T Transform(T object) { 40677374d3bSMed Ismail Bennani // No Transformation for generic usage 40777374d3bSMed Ismail Bennani return {object}; 40877374d3bSMed Ismail Bennani } 40977374d3bSMed Ismail Bennani 41077374d3bSMed Ismail Bennani python::PythonObject Transform(bool arg) { 41177374d3bSMed Ismail Bennani // Boolean arguments need to be turned into python objects. 41277374d3bSMed Ismail Bennani return python::PythonBoolean(arg); 41377374d3bSMed Ismail Bennani } 41477374d3bSMed Ismail Bennani 415b798f4bdSAdrian Prantl python::PythonObject Transform(const Status &arg) { 416b798f4bdSAdrian Prantl return python::SWIGBridge::ToSWIGWrapper(arg.Clone()); 417b798f4bdSAdrian Prantl } 418b798f4bdSAdrian Prantl 419b798f4bdSAdrian Prantl python::PythonObject Transform(Status &&arg) { 420b798f4bdSAdrian Prantl return python::SWIGBridge::ToSWIGWrapper(std::move(arg)); 42177374d3bSMed Ismail Bennani } 42277374d3bSMed Ismail Bennani 423f22d82ceSMed Ismail Bennani python::PythonObject Transform(const StructuredDataImpl &arg) { 424f22d82ceSMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg); 425f22d82ceSMed Ismail Bennani } 426f22d82ceSMed Ismail Bennani 427f22d82ceSMed Ismail Bennani python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { 428f22d82ceSMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg); 429f22d82ceSMed Ismail Bennani } 430f22d82ceSMed Ismail Bennani 431*f732157aSMed Ismail Bennani python::PythonObject Transform(lldb::TargetSP arg) { 432*f732157aSMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg); 433*f732157aSMed Ismail Bennani } 434*f732157aSMed Ismail Bennani 4357a1e8783SMed Ismail Bennani python::PythonObject Transform(lldb::ProcessSP arg) { 4367a1e8783SMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg); 4377a1e8783SMed Ismail Bennani } 4387a1e8783SMed Ismail Bennani 4399a9ec228SMed Ismail Bennani python::PythonObject Transform(lldb::ThreadPlanSP arg) { 4409a9ec228SMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg); 4419a9ec228SMed Ismail Bennani } 4429a9ec228SMed Ismail Bennani 44377374d3bSMed Ismail Bennani python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { 44477374d3bSMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg); 44577374d3bSMed Ismail Bennani } 44677374d3bSMed Ismail Bennani 44777374d3bSMed Ismail Bennani python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { 44877374d3bSMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg); 44977374d3bSMed Ismail Bennani } 45077374d3bSMed Ismail Bennani 4519a9ec228SMed Ismail Bennani python::PythonObject Transform(Event *arg) { 4529a9ec228SMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg); 4539a9ec228SMed Ismail Bennani } 4549a9ec228SMed Ismail Bennani 4556cb45aeaSMed Ismail Bennani python::PythonObject Transform(lldb::StreamSP arg) { 4566cb45aeaSMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg.get()); 4579a9ec228SMed Ismail Bennani } 4589a9ec228SMed Ismail Bennani 45977374d3bSMed Ismail Bennani python::PythonObject Transform(lldb::DataExtractorSP arg) { 46077374d3bSMed Ismail Bennani return python::SWIGBridge::ToSWIGWrapper(arg); 46177374d3bSMed Ismail Bennani } 46277374d3bSMed Ismail Bennani 46377374d3bSMed Ismail Bennani template <typename T, typename U> 46477374d3bSMed Ismail Bennani void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { 46577374d3bSMed Ismail Bennani // If U is not a PythonObject, don't touch it! 46677374d3bSMed Ismail Bennani return; 46777374d3bSMed Ismail Bennani } 46877374d3bSMed Ismail Bennani 46977374d3bSMed Ismail Bennani template <typename T> 47077374d3bSMed Ismail Bennani void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, 47177374d3bSMed Ismail Bennani Status &error) { 47277374d3bSMed Ismail Bennani original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); 47377374d3bSMed Ismail Bennani } 47477374d3bSMed Ismail Bennani 47577374d3bSMed Ismail Bennani void ReverseTransform(bool &original_arg, 47677374d3bSMed Ismail Bennani python::PythonObject transformed_arg, Status &error) { 47777374d3bSMed Ismail Bennani python::PythonBoolean boolean_arg = python::PythonBoolean( 47877374d3bSMed Ismail Bennani python::PyRefType::Borrowed, transformed_arg.get()); 47977374d3bSMed Ismail Bennani if (boolean_arg.IsValid()) 48077374d3bSMed Ismail Bennani original_arg = boolean_arg.GetValue(); 48177374d3bSMed Ismail Bennani else 4820642cd76SAdrian Prantl error = Status::FromErrorStringWithFormatv( 4830642cd76SAdrian Prantl "{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION); 48477374d3bSMed Ismail Bennani } 48577374d3bSMed Ismail Bennani 48677374d3bSMed Ismail Bennani template <std::size_t... I, typename... Args> 48777374d3bSMed Ismail Bennani auto TransformTuple(const std::tuple<Args...> &args, 48877374d3bSMed Ismail Bennani std::index_sequence<I...>) { 48977374d3bSMed Ismail Bennani return std::make_tuple(Transform(std::get<I>(args))...); 49077374d3bSMed Ismail Bennani } 49177374d3bSMed Ismail Bennani 49277374d3bSMed Ismail Bennani // This will iterate over the Dispatch parameter pack and replace in-place 49377374d3bSMed Ismail Bennani // every `lldb_private` argument that has a SB counterpart. 49477374d3bSMed Ismail Bennani template <typename... Args> 49577374d3bSMed Ismail Bennani auto TransformArgs(const std::tuple<Args...> &args) { 49677374d3bSMed Ismail Bennani return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>()); 49777374d3bSMed Ismail Bennani } 49877374d3bSMed Ismail Bennani 49977374d3bSMed Ismail Bennani template <typename T, typename U> 50077374d3bSMed Ismail Bennani void TransformBack(T &original_arg, U transformed_arg, Status &error) { 50177374d3bSMed Ismail Bennani ReverseTransform(original_arg, transformed_arg, error); 50277374d3bSMed Ismail Bennani } 50377374d3bSMed Ismail Bennani 50477374d3bSMed Ismail Bennani template <std::size_t... I, typename... Ts, typename... Us> 50577374d3bSMed Ismail Bennani bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 50677374d3bSMed Ismail Bennani std::tuple<Us...> &transformed_args, 50777374d3bSMed Ismail Bennani std::index_sequence<I...>) { 50877374d3bSMed Ismail Bennani Status error; 50977374d3bSMed Ismail Bennani (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args), 51077374d3bSMed Ismail Bennani error), 51177374d3bSMed Ismail Bennani ...); 51277374d3bSMed Ismail Bennani return error.Success(); 51377374d3bSMed Ismail Bennani } 51477374d3bSMed Ismail Bennani 51577374d3bSMed Ismail Bennani template <typename... Ts, typename... Us> 51677374d3bSMed Ismail Bennani bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 51777374d3bSMed Ismail Bennani std::tuple<Us...> &transformed_args) { 51877374d3bSMed Ismail Bennani if (sizeof...(Ts) != sizeof...(Us)) 51977374d3bSMed Ismail Bennani return false; 52077374d3bSMed Ismail Bennani 52177374d3bSMed Ismail Bennani return ReassignPtrsOrRefsArgs(original_args, transformed_args, 52277374d3bSMed Ismail Bennani std::make_index_sequence<sizeof...(Ts)>()); 52377374d3bSMed Ismail Bennani } 52477374d3bSMed Ismail Bennani 52577374d3bSMed Ismail Bennani template <typename T, typename... Args> 52677374d3bSMed Ismail Bennani void FormatArgs(std::string &fmt, T arg, Args... args) const { 52777374d3bSMed Ismail Bennani FormatArgs(fmt, arg); 52877374d3bSMed Ismail Bennani FormatArgs(fmt, args...); 52977374d3bSMed Ismail Bennani } 53077374d3bSMed Ismail Bennani 53177374d3bSMed Ismail Bennani template <typename T> void FormatArgs(std::string &fmt, T arg) const { 53277374d3bSMed Ismail Bennani fmt += python::PythonFormat<T>::format; 53377374d3bSMed Ismail Bennani } 53477374d3bSMed Ismail Bennani 53577374d3bSMed Ismail Bennani void FormatArgs(std::string &fmt) const {} 53677374d3bSMed Ismail Bennani 53777374d3bSMed Ismail Bennani // The lifetime is managed by the ScriptInterpreter 53877374d3bSMed Ismail Bennani ScriptInterpreterPythonImpl &m_interpreter; 53977374d3bSMed Ismail Bennani }; 54077374d3bSMed Ismail Bennani 54177374d3bSMed Ismail Bennani template <> 54277374d3bSMed Ismail Bennani StructuredData::ArraySP 54377374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( 54477374d3bSMed Ismail Bennani python::PythonObject &p, Status &error); 54577374d3bSMed Ismail Bennani 54677374d3bSMed Ismail Bennani template <> 54777374d3bSMed Ismail Bennani StructuredData::DictionarySP 54877374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject< 54977374d3bSMed Ismail Bennani StructuredData::DictionarySP>(python::PythonObject &p, Status &error); 55077374d3bSMed Ismail Bennani 55177374d3bSMed Ismail Bennani template <> 55277374d3bSMed Ismail Bennani Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( 55377374d3bSMed Ismail Bennani python::PythonObject &p, Status &error); 55477374d3bSMed Ismail Bennani 55577374d3bSMed Ismail Bennani template <> 5569a9ec228SMed Ismail Bennani Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( 5579a9ec228SMed Ismail Bennani python::PythonObject &p, Status &error); 5589a9ec228SMed Ismail Bennani 5599a9ec228SMed Ismail Bennani template <> 5606cb45aeaSMed Ismail Bennani lldb::StreamSP 5616cb45aeaSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( 5629a9ec228SMed Ismail Bennani python::PythonObject &p, Status &error); 5639a9ec228SMed Ismail Bennani 5649a9ec228SMed Ismail Bennani template <> 56577374d3bSMed Ismail Bennani lldb::BreakpointSP 56677374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( 56777374d3bSMed Ismail Bennani python::PythonObject &p, Status &error); 56877374d3bSMed Ismail Bennani 56977374d3bSMed Ismail Bennani template <> 57077374d3bSMed Ismail Bennani lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 57177374d3bSMed Ismail Bennani lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error); 57277374d3bSMed Ismail Bennani 57377374d3bSMed Ismail Bennani template <> 57477374d3bSMed Ismail Bennani lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 57577374d3bSMed Ismail Bennani lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error); 57677374d3bSMed Ismail Bennani 57777374d3bSMed Ismail Bennani template <> 57877374d3bSMed Ismail Bennani lldb::DataExtractorSP 57977374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( 58077374d3bSMed Ismail Bennani python::PythonObject &p, Status &error); 58177374d3bSMed Ismail Bennani 58277374d3bSMed Ismail Bennani template <> 58377374d3bSMed Ismail Bennani std::optional<MemoryRegionInfo> 58477374d3bSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject< 58577374d3bSMed Ismail Bennani std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); 58677374d3bSMed Ismail Bennani 587*f732157aSMed Ismail Bennani template <> 588*f732157aSMed Ismail Bennani lldb::ExecutionContextRefSP 589*f732157aSMed Ismail Bennani ScriptedPythonInterface::ExtractValueFromPythonObject< 590*f732157aSMed Ismail Bennani lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error); 591*f732157aSMed Ismail Bennani 59277374d3bSMed Ismail Bennani } // namespace lldb_private 59377374d3bSMed Ismail Bennani 59477374d3bSMed Ismail Bennani #endif // LLDB_ENABLE_PYTHON 59577374d3bSMed Ismail Bennani #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 596