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 { InvalidArgumentCountPayloadAbstrackMethodCheckerPayload::InvalidArgumentCountPayload47 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>> CheckAbstractMethodImplementation(const python::PythonDictionary & class_dict)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> CreatePluginObject(llvm::StringRef class_name,StructuredData::Generic * script_obj,Args...args)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> ExtractValueFromPythonObject(python::PythonObject & p,Status & error)330 T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { 331 return p.CreateStructuredObject(); 332 } 333 334 template <typename T = StructuredData::ObjectSP, typename... Args> Dispatch(llvm::StringRef method_name,Status & error,Args &&...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> GetStatusFromMethod(llvm::StringRef method_name,Args &&...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 Transform(T object)405 template <typename T> T Transform(T object) { 406 // No Transformation for generic usage 407 return {object}; 408 } 409 Transform(bool arg)410 python::PythonObject Transform(bool arg) { 411 // Boolean arguments need to be turned into python objects. 412 return python::PythonBoolean(arg); 413 } 414 Transform(const Status & arg)415 python::PythonObject Transform(const Status &arg) { 416 return python::SWIGBridge::ToSWIGWrapper(arg.Clone()); 417 } 418 Transform(Status && arg)419 python::PythonObject Transform(Status &&arg) { 420 return python::SWIGBridge::ToSWIGWrapper(std::move(arg)); 421 } 422 Transform(const StructuredDataImpl & arg)423 python::PythonObject Transform(const StructuredDataImpl &arg) { 424 return python::SWIGBridge::ToSWIGWrapper(arg); 425 } 426 Transform(lldb::ExecutionContextRefSP arg)427 python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { 428 return python::SWIGBridge::ToSWIGWrapper(arg); 429 } 430 Transform(lldb::TargetSP arg)431 python::PythonObject Transform(lldb::TargetSP arg) { 432 return python::SWIGBridge::ToSWIGWrapper(arg); 433 } 434 Transform(lldb::ProcessSP arg)435 python::PythonObject Transform(lldb::ProcessSP arg) { 436 return python::SWIGBridge::ToSWIGWrapper(arg); 437 } 438 Transform(lldb::ThreadPlanSP arg)439 python::PythonObject Transform(lldb::ThreadPlanSP arg) { 440 return python::SWIGBridge::ToSWIGWrapper(arg); 441 } 442 Transform(lldb::ProcessAttachInfoSP arg)443 python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { 444 return python::SWIGBridge::ToSWIGWrapper(arg); 445 } 446 Transform(lldb::ProcessLaunchInfoSP arg)447 python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { 448 return python::SWIGBridge::ToSWIGWrapper(arg); 449 } 450 Transform(Event * arg)451 python::PythonObject Transform(Event *arg) { 452 return python::SWIGBridge::ToSWIGWrapper(arg); 453 } 454 Transform(lldb::StreamSP arg)455 python::PythonObject Transform(lldb::StreamSP arg) { 456 return python::SWIGBridge::ToSWIGWrapper(arg.get()); 457 } 458 Transform(lldb::DataExtractorSP arg)459 python::PythonObject Transform(lldb::DataExtractorSP arg) { 460 return python::SWIGBridge::ToSWIGWrapper(arg); 461 } 462 463 template <typename T, typename U> ReverseTransform(T & original_arg,U transformed_arg,Status & error)464 void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { 465 // If U is not a PythonObject, don't touch it! 466 } 467 468 template <typename T> ReverseTransform(T & original_arg,python::PythonObject transformed_arg,Status & error)469 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, 470 Status &error) { 471 original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); 472 } 473 ReverseTransform(bool & original_arg,python::PythonObject transformed_arg,Status & error)474 void ReverseTransform(bool &original_arg, 475 python::PythonObject transformed_arg, Status &error) { 476 python::PythonBoolean boolean_arg = python::PythonBoolean( 477 python::PyRefType::Borrowed, transformed_arg.get()); 478 if (boolean_arg.IsValid()) 479 original_arg = boolean_arg.GetValue(); 480 else 481 error = Status::FromErrorStringWithFormatv( 482 "{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION); 483 } 484 485 template <std::size_t... I, typename... Args> TransformTuple(const std::tuple<Args...> & args,std::index_sequence<I...>)486 auto TransformTuple(const std::tuple<Args...> &args, 487 std::index_sequence<I...>) { 488 return std::make_tuple(Transform(std::get<I>(args))...); 489 } 490 491 // This will iterate over the Dispatch parameter pack and replace in-place 492 // every `lldb_private` argument that has a SB counterpart. 493 template <typename... Args> TransformArgs(const std::tuple<Args...> & args)494 auto TransformArgs(const std::tuple<Args...> &args) { 495 return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>()); 496 } 497 498 template <typename T, typename U> TransformBack(T & original_arg,U transformed_arg,Status & error)499 void TransformBack(T &original_arg, U transformed_arg, Status &error) { 500 ReverseTransform(original_arg, transformed_arg, error); 501 } 502 503 template <std::size_t... I, typename... Ts, typename... Us> ReassignPtrsOrRefsArgs(std::tuple<Ts...> & original_args,std::tuple<Us...> & transformed_args,std::index_sequence<I...>)504 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 505 std::tuple<Us...> &transformed_args, 506 std::index_sequence<I...>) { 507 Status error; 508 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args), 509 error), 510 ...); 511 return error.Success(); 512 } 513 514 template <typename... Ts, typename... Us> ReassignPtrsOrRefsArgs(std::tuple<Ts...> & original_args,std::tuple<Us...> & transformed_args)515 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 516 std::tuple<Us...> &transformed_args) { 517 if (sizeof...(Ts) != sizeof...(Us)) 518 return false; 519 520 return ReassignPtrsOrRefsArgs(original_args, transformed_args, 521 std::make_index_sequence<sizeof...(Ts)>()); 522 } 523 524 template <typename T, typename... Args> FormatArgs(std::string & fmt,T arg,Args...args)525 void FormatArgs(std::string &fmt, T arg, Args... args) const { 526 FormatArgs(fmt, arg); 527 FormatArgs(fmt, args...); 528 } 529 FormatArgs(std::string & fmt,T arg)530 template <typename T> void FormatArgs(std::string &fmt, T arg) const { 531 fmt += python::PythonFormat<T>::format; 532 } 533 FormatArgs(std::string & fmt)534 void FormatArgs(std::string &fmt) const {} 535 536 // The lifetime is managed by the ScriptInterpreter 537 ScriptInterpreterPythonImpl &m_interpreter; 538 }; 539 540 template <> 541 StructuredData::ArraySP 542 ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( 543 python::PythonObject &p, Status &error); 544 545 template <> 546 StructuredData::DictionarySP 547 ScriptedPythonInterface::ExtractValueFromPythonObject< 548 StructuredData::DictionarySP>(python::PythonObject &p, Status &error); 549 550 template <> 551 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( 552 python::PythonObject &p, Status &error); 553 554 template <> 555 Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( 556 python::PythonObject &p, Status &error); 557 558 template <> 559 lldb::StreamSP 560 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( 561 python::PythonObject &p, Status &error); 562 563 template <> 564 lldb::BreakpointSP 565 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( 566 python::PythonObject &p, Status &error); 567 568 template <> 569 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 570 lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error); 571 572 template <> 573 lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 574 lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error); 575 576 template <> 577 lldb::DataExtractorSP 578 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( 579 python::PythonObject &p, Status &error); 580 581 template <> 582 std::optional<MemoryRegionInfo> 583 ScriptedPythonInterface::ExtractValueFromPythonObject< 584 std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); 585 586 template <> 587 lldb::ExecutionContextRefSP 588 ScriptedPythonInterface::ExtractValueFromPythonObject< 589 lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error); 590 591 } // namespace lldb_private 592 593 #endif // LLDB_ENABLE_PYTHON 594 #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 595