1 //===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 10 #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 11 12 #if LLDB_ENABLE_PYTHON 13 14 #include <optional> 15 #include <sstream> 16 #include <tuple> 17 #include <type_traits> 18 #include <utility> 19 20 #include "lldb/Host/Config.h" 21 #include "lldb/Interpreter/Interfaces/ScriptedInterface.h" 22 #include "lldb/Utility/DataBufferHeap.h" 23 24 #include "../PythonDataObjects.h" 25 #include "../SWIGPythonBridge.h" 26 #include "../ScriptInterpreterPythonImpl.h" 27 28 namespace lldb_private { 29 class ScriptInterpreterPythonImpl; 30 class ScriptedPythonInterface : virtual public ScriptedInterface { 31 public: 32 ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); 33 ~ScriptedPythonInterface() override = default; 34 35 enum class AbstractMethodCheckerCases { 36 eNotImplemented, 37 eNotAllocated, 38 eNotCallable, 39 eUnknownArgumentCount, 40 eInvalidArgumentCount, 41 eValid 42 }; 43 44 struct AbstrackMethodCheckerPayload { 45 46 struct InvalidArgumentCountPayload { 47 InvalidArgumentCountPayload(size_t required, size_t actual) 48 : required_argument_count(required), actual_argument_count(actual) {} 49 50 size_t required_argument_count; 51 size_t actual_argument_count; 52 }; 53 54 AbstractMethodCheckerCases checker_case; 55 std::variant<std::monostate, InvalidArgumentCountPayload> payload; 56 }; 57 58 llvm::Expected<std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload>> 59 CheckAbstractMethodImplementation( 60 const python::PythonDictionary &class_dict) const { 61 62 using namespace python; 63 64 std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload> checker; 65 #define SET_CASE_AND_CONTINUE(method_name, case) \ 66 { \ 67 checker[method_name] = {case, {}}; \ 68 continue; \ 69 } 70 71 for (const AbstractMethodRequirement &requirement : 72 GetAbstractMethodRequirements()) { 73 llvm::StringLiteral method_name = requirement.name; 74 if (!class_dict.HasKey(method_name)) 75 SET_CASE_AND_CONTINUE(method_name, 76 AbstractMethodCheckerCases::eNotImplemented) 77 auto callable_or_err = class_dict.GetItem(method_name); 78 if (!callable_or_err) { 79 llvm::consumeError(callable_or_err.takeError()); 80 SET_CASE_AND_CONTINUE(method_name, 81 AbstractMethodCheckerCases::eNotAllocated) 82 } 83 84 PythonCallable callable = callable_or_err->AsType<PythonCallable>(); 85 if (!callable) 86 SET_CASE_AND_CONTINUE(method_name, 87 AbstractMethodCheckerCases::eNotCallable) 88 89 if (!requirement.min_arg_count) 90 SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid) 91 92 auto arg_info_or_err = callable.GetArgInfo(); 93 if (!arg_info_or_err) { 94 llvm::consumeError(arg_info_or_err.takeError()); 95 SET_CASE_AND_CONTINUE(method_name, 96 AbstractMethodCheckerCases::eUnknownArgumentCount) 97 } 98 99 PythonCallable::ArgInfo arg_info = *arg_info_or_err; 100 if (requirement.min_arg_count <= arg_info.max_positional_args) { 101 SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid) 102 } else { 103 checker[method_name] = { 104 AbstractMethodCheckerCases::eInvalidArgumentCount, 105 AbstrackMethodCheckerPayload::InvalidArgumentCountPayload( 106 requirement.min_arg_count, arg_info.max_positional_args)}; 107 } 108 } 109 110 #undef SET_CASE_AND_CONTINUE 111 112 return checker; 113 } 114 115 template <typename... Args> 116 llvm::Expected<StructuredData::GenericSP> 117 CreatePluginObject(llvm::StringRef class_name, 118 StructuredData::Generic *script_obj, Args... args) { 119 using namespace python; 120 using Locker = ScriptInterpreterPythonImpl::Locker; 121 122 Log *log = GetLog(LLDBLog::Script); 123 auto create_error = [](llvm::StringLiteral format, auto &&...ts) { 124 return llvm::createStringError( 125 llvm::formatv(format.data(), std::forward<decltype(ts)>(ts)...) 126 .str()); 127 }; 128 129 bool has_class_name = !class_name.empty(); 130 bool has_interpreter_dict = 131 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty()); 132 if (!has_class_name && !has_interpreter_dict && !script_obj) { 133 if (!has_class_name) 134 return create_error("Missing script class name."); 135 else if (!has_interpreter_dict) 136 return create_error("Invalid script interpreter dictionary."); 137 else 138 return create_error("Missing scripting object."); 139 } 140 141 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 142 Locker::FreeLock); 143 144 PythonObject result = {}; 145 146 if (script_obj) { 147 result = PythonObject(PyRefType::Borrowed, 148 static_cast<PyObject *>(script_obj->GetValue())); 149 } else { 150 auto dict = 151 PythonModule::MainModule().ResolveName<python::PythonDictionary>( 152 m_interpreter.GetDictionaryName()); 153 if (!dict.IsAllocated()) 154 return create_error("Could not find interpreter dictionary: {0}", 155 m_interpreter.GetDictionaryName()); 156 157 auto init = 158 PythonObject::ResolveNameWithDictionary<python::PythonCallable>( 159 class_name, dict); 160 if (!init.IsAllocated()) 161 return create_error("Could not find script class: {0}", 162 class_name.data()); 163 164 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 165 auto transformed_args = TransformArgs(original_args); 166 167 std::string error_string; 168 llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo(); 169 if (!arg_info) { 170 llvm::handleAllErrors( 171 arg_info.takeError(), 172 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, 173 [&](const llvm::ErrorInfoBase &E) { 174 error_string.append(E.message()); 175 }); 176 return llvm::createStringError(llvm::inconvertibleErrorCode(), 177 error_string); 178 } 179 180 llvm::Expected<PythonObject> expected_return_object = 181 create_error("Resulting object is not initialized."); 182 183 // This relax the requirement on the number of argument for 184 // initializing scripting extension if the size of the interface 185 // parameter pack contains 1 less element than the extension maximum 186 // number of positional arguments for this initializer. 187 // 188 // This addresses the cases where the embedded interpreter session 189 // dictionary is passed to the extension initializer which is not used 190 // most of the time. 191 size_t num_args = sizeof...(Args); 192 if (num_args != arg_info->max_positional_args) { 193 if (num_args != arg_info->max_positional_args - 1) 194 return create_error("Passed arguments ({0}) doesn't match the number " 195 "of expected arguments ({1}).", 196 num_args, arg_info->max_positional_args); 197 198 std::apply( 199 [&init, &expected_return_object](auto &&...args) { 200 llvm::consumeError(expected_return_object.takeError()); 201 expected_return_object = init(args...); 202 }, 203 std::tuple_cat(transformed_args, std::make_tuple(dict))); 204 } else { 205 std::apply( 206 [&init, &expected_return_object](auto &&...args) { 207 llvm::consumeError(expected_return_object.takeError()); 208 expected_return_object = init(args...); 209 }, 210 transformed_args); 211 } 212 213 if (!expected_return_object) 214 return expected_return_object.takeError(); 215 result = expected_return_object.get(); 216 } 217 218 if (!result.IsValid()) 219 return create_error("Resulting object is not a valid Python Object."); 220 if (!result.HasAttribute("__class__")) 221 return create_error("Resulting object doesn't have '__class__' member."); 222 223 PythonObject obj_class = result.GetAttributeValue("__class__"); 224 if (!obj_class.IsValid()) 225 return create_error("Resulting class object is not a valid."); 226 if (!obj_class.HasAttribute("__name__")) 227 return create_error( 228 "Resulting object class doesn't have '__name__' member."); 229 PythonString obj_class_name = 230 obj_class.GetAttributeValue("__name__").AsType<PythonString>(); 231 232 PythonObject object_class_mapping_proxy = 233 obj_class.GetAttributeValue("__dict__"); 234 if (!obj_class.HasAttribute("__dict__")) 235 return create_error( 236 "Resulting object class doesn't have '__dict__' member."); 237 238 PythonCallable dict_converter = PythonModule::BuiltinsModule() 239 .ResolveName("dict") 240 .AsType<PythonCallable>(); 241 if (!dict_converter.IsAllocated()) 242 return create_error( 243 "Python 'builtins' module doesn't have 'dict' class."); 244 245 PythonDictionary object_class_dict = 246 dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>(); 247 if (!object_class_dict.IsAllocated()) 248 return create_error("Coudn't create dictionary from resulting object " 249 "class mapping proxy object."); 250 251 auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict); 252 if (!checker_or_err) 253 return checker_or_err.takeError(); 254 255 llvm::Error abstract_method_errors = llvm::Error::success(); 256 for (const auto &method_checker : *checker_or_err) 257 switch (method_checker.second.checker_case) { 258 case AbstractMethodCheckerCases::eNotImplemented: 259 abstract_method_errors = llvm::joinErrors( 260 std::move(abstract_method_errors), 261 std::move(create_error("Abstract method {0}.{1} not implemented.", 262 obj_class_name.GetString(), 263 method_checker.first))); 264 break; 265 case AbstractMethodCheckerCases::eNotAllocated: 266 abstract_method_errors = llvm::joinErrors( 267 std::move(abstract_method_errors), 268 std::move(create_error("Abstract method {0}.{1} not allocated.", 269 obj_class_name.GetString(), 270 method_checker.first))); 271 break; 272 case AbstractMethodCheckerCases::eNotCallable: 273 abstract_method_errors = llvm::joinErrors( 274 std::move(abstract_method_errors), 275 std::move(create_error("Abstract method {0}.{1} not callable.", 276 obj_class_name.GetString(), 277 method_checker.first))); 278 break; 279 case AbstractMethodCheckerCases::eUnknownArgumentCount: 280 abstract_method_errors = llvm::joinErrors( 281 std::move(abstract_method_errors), 282 std::move(create_error( 283 "Abstract method {0}.{1} has unknown argument count.", 284 obj_class_name.GetString(), method_checker.first))); 285 break; 286 case AbstractMethodCheckerCases::eInvalidArgumentCount: { 287 auto &payload_variant = method_checker.second.payload; 288 if (!std::holds_alternative< 289 AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>( 290 payload_variant)) { 291 abstract_method_errors = llvm::joinErrors( 292 std::move(abstract_method_errors), 293 std::move(create_error( 294 "Abstract method {0}.{1} has unexpected argument count.", 295 obj_class_name.GetString(), method_checker.first))); 296 } else { 297 auto payload = std::get< 298 AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>( 299 payload_variant); 300 abstract_method_errors = llvm::joinErrors( 301 std::move(abstract_method_errors), 302 std::move( 303 create_error("Abstract method {0}.{1} has unexpected " 304 "argument count (expected {2} but has {3}).", 305 obj_class_name.GetString(), method_checker.first, 306 payload.required_argument_count, 307 payload.actual_argument_count))); 308 } 309 } break; 310 case AbstractMethodCheckerCases::eValid: 311 LLDB_LOG(log, "Abstract method {0}.{1} implemented & valid.", 312 obj_class_name.GetString(), method_checker.first); 313 break; 314 } 315 316 if (abstract_method_errors) { 317 Status error = Status::FromError(std::move(abstract_method_errors)); 318 LLDB_LOG(log, "Abstract method error in {0}:\n{1}", class_name, 319 error.AsCString()); 320 return error.ToError(); 321 } 322 323 m_object_instance_sp = StructuredData::GenericSP( 324 new StructuredPythonObject(std::move(result))); 325 return m_object_instance_sp; 326 } 327 328 protected: 329 template <typename T = StructuredData::ObjectSP> 330 T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { 331 return p.CreateStructuredObject(); 332 } 333 334 template <typename T = StructuredData::ObjectSP, typename... Args> 335 T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) { 336 using namespace python; 337 using Locker = ScriptInterpreterPythonImpl::Locker; 338 339 std::string caller_signature = 340 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") + 341 llvm::Twine(method_name) + llvm::Twine(")")) 342 .str(); 343 if (!m_object_instance_sp) 344 return ErrorWithMessage<T>(caller_signature, "Python object ill-formed", 345 error); 346 347 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 348 Locker::FreeLock); 349 350 PythonObject implementor(PyRefType::Borrowed, 351 (PyObject *)m_object_instance_sp->GetValue()); 352 353 if (!implementor.IsAllocated()) 354 return llvm::is_contained(GetAbstractMethods(), method_name) 355 ? ErrorWithMessage<T>(caller_signature, 356 "Python implementor not allocated.", 357 error) 358 : T{}; 359 360 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 361 auto transformed_args = TransformArgs(original_args); 362 363 llvm::Expected<PythonObject> expected_return_object = 364 llvm::make_error<llvm::StringError>("Not initialized.", 365 llvm::inconvertibleErrorCode()); 366 std::apply( 367 [&implementor, &method_name, &expected_return_object](auto &&...args) { 368 llvm::consumeError(expected_return_object.takeError()); 369 expected_return_object = 370 implementor.CallMethod(method_name.data(), args...); 371 }, 372 transformed_args); 373 374 if (llvm::Error e = expected_return_object.takeError()) { 375 error = Status::FromError(std::move(e)); 376 return ErrorWithMessage<T>(caller_signature, 377 "Python method could not be called.", error); 378 } 379 380 PythonObject py_return = std::move(expected_return_object.get()); 381 382 // Now that we called the python method with the transformed arguments, 383 // we need to interate again over both the original and transformed 384 // parameter pack, and transform back the parameter that were passed in 385 // the original parameter pack as references or pointers. 386 if (sizeof...(Args) > 0) 387 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args)) 388 return ErrorWithMessage<T>( 389 caller_signature, 390 "Couldn't re-assign reference and pointer arguments.", error); 391 392 if (!py_return.IsAllocated()) 393 return {}; 394 return ExtractValueFromPythonObject<T>(py_return, error); 395 } 396 397 template <typename... Args> 398 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) { 399 Status error; 400 Dispatch<Status>(method_name, error, std::forward<Args>(args)...); 401 402 return error; 403 } 404 405 template <typename T> T Transform(T object) { 406 // No Transformation for generic usage 407 return {object}; 408 } 409 410 python::PythonObject Transform(bool arg) { 411 // Boolean arguments need to be turned into python objects. 412 return python::PythonBoolean(arg); 413 } 414 415 python::PythonObject Transform(const Status &arg) { 416 return python::SWIGBridge::ToSWIGWrapper(arg.Clone()); 417 } 418 419 python::PythonObject Transform(Status &&arg) { 420 return python::SWIGBridge::ToSWIGWrapper(std::move(arg)); 421 } 422 423 python::PythonObject Transform(const StructuredDataImpl &arg) { 424 return python::SWIGBridge::ToSWIGWrapper(arg); 425 } 426 427 python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { 428 return python::SWIGBridge::ToSWIGWrapper(arg); 429 } 430 431 python::PythonObject Transform(lldb::TargetSP arg) { 432 return python::SWIGBridge::ToSWIGWrapper(arg); 433 } 434 435 python::PythonObject Transform(lldb::ProcessSP arg) { 436 return python::SWIGBridge::ToSWIGWrapper(arg); 437 } 438 439 python::PythonObject Transform(lldb::ThreadPlanSP arg) { 440 return python::SWIGBridge::ToSWIGWrapper(arg); 441 } 442 443 python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { 444 return python::SWIGBridge::ToSWIGWrapper(arg); 445 } 446 447 python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { 448 return python::SWIGBridge::ToSWIGWrapper(arg); 449 } 450 451 python::PythonObject Transform(Event *arg) { 452 return python::SWIGBridge::ToSWIGWrapper(arg); 453 } 454 455 python::PythonObject Transform(lldb::StreamSP arg) { 456 return python::SWIGBridge::ToSWIGWrapper(arg.get()); 457 } 458 459 python::PythonObject Transform(lldb::DataExtractorSP arg) { 460 return python::SWIGBridge::ToSWIGWrapper(arg); 461 } 462 463 template <typename T, typename U> 464 void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { 465 // If U is not a PythonObject, don't touch it! 466 return; 467 } 468 469 template <typename T> 470 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, 471 Status &error) { 472 original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); 473 } 474 475 void ReverseTransform(bool &original_arg, 476 python::PythonObject transformed_arg, Status &error) { 477 python::PythonBoolean boolean_arg = python::PythonBoolean( 478 python::PyRefType::Borrowed, transformed_arg.get()); 479 if (boolean_arg.IsValid()) 480 original_arg = boolean_arg.GetValue(); 481 else 482 error = Status::FromErrorStringWithFormatv( 483 "{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION); 484 } 485 486 template <std::size_t... I, typename... Args> 487 auto TransformTuple(const std::tuple<Args...> &args, 488 std::index_sequence<I...>) { 489 return std::make_tuple(Transform(std::get<I>(args))...); 490 } 491 492 // This will iterate over the Dispatch parameter pack and replace in-place 493 // every `lldb_private` argument that has a SB counterpart. 494 template <typename... Args> 495 auto TransformArgs(const std::tuple<Args...> &args) { 496 return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>()); 497 } 498 499 template <typename T, typename U> 500 void TransformBack(T &original_arg, U transformed_arg, Status &error) { 501 ReverseTransform(original_arg, transformed_arg, error); 502 } 503 504 template <std::size_t... I, typename... Ts, typename... Us> 505 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 506 std::tuple<Us...> &transformed_args, 507 std::index_sequence<I...>) { 508 Status error; 509 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args), 510 error), 511 ...); 512 return error.Success(); 513 } 514 515 template <typename... Ts, typename... Us> 516 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 517 std::tuple<Us...> &transformed_args) { 518 if (sizeof...(Ts) != sizeof...(Us)) 519 return false; 520 521 return ReassignPtrsOrRefsArgs(original_args, transformed_args, 522 std::make_index_sequence<sizeof...(Ts)>()); 523 } 524 525 template <typename T, typename... Args> 526 void FormatArgs(std::string &fmt, T arg, Args... args) const { 527 FormatArgs(fmt, arg); 528 FormatArgs(fmt, args...); 529 } 530 531 template <typename T> void FormatArgs(std::string &fmt, T arg) const { 532 fmt += python::PythonFormat<T>::format; 533 } 534 535 void FormatArgs(std::string &fmt) const {} 536 537 // The lifetime is managed by the ScriptInterpreter 538 ScriptInterpreterPythonImpl &m_interpreter; 539 }; 540 541 template <> 542 StructuredData::ArraySP 543 ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( 544 python::PythonObject &p, Status &error); 545 546 template <> 547 StructuredData::DictionarySP 548 ScriptedPythonInterface::ExtractValueFromPythonObject< 549 StructuredData::DictionarySP>(python::PythonObject &p, Status &error); 550 551 template <> 552 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( 553 python::PythonObject &p, Status &error); 554 555 template <> 556 Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( 557 python::PythonObject &p, Status &error); 558 559 template <> 560 lldb::StreamSP 561 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( 562 python::PythonObject &p, Status &error); 563 564 template <> 565 lldb::BreakpointSP 566 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( 567 python::PythonObject &p, Status &error); 568 569 template <> 570 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 571 lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error); 572 573 template <> 574 lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 575 lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error); 576 577 template <> 578 lldb::DataExtractorSP 579 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( 580 python::PythonObject &p, Status &error); 581 582 template <> 583 std::optional<MemoryRegionInfo> 584 ScriptedPythonInterface::ExtractValueFromPythonObject< 585 std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); 586 587 template <> 588 lldb::ExecutionContextRefSP 589 ScriptedPythonInterface::ExtractValueFromPythonObject< 590 lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error); 591 592 } // namespace lldb_private 593 594 #endif // LLDB_ENABLE_PYTHON 595 #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 596