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 // clang-format off 14 // LLDB Python header must be included first 15 #include "../lldb-python.h" 16 //clang-format on 17 #endif 18 19 #include "lldb/Host/Config.h" 20 #include "lldb/Interpreter/Interfaces/ScriptedInterface.h" 21 #include "lldb/Utility/DataBufferHeap.h" 22 23 #include <optional> 24 #include <sstream> 25 #include <tuple> 26 #include <type_traits> 27 #include <utility> 28 29 #if LLDB_ENABLE_PYTHON 30 31 #include "../PythonDataObjects.h" 32 #include "../SWIGPythonBridge.h" 33 #include "../ScriptInterpreterPythonImpl.h" 34 35 namespace lldb_private { 36 class ScriptInterpreterPythonImpl; 37 class ScriptedPythonInterface : virtual public ScriptedInterface { 38 public: 39 ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); 40 ~ScriptedPythonInterface() override = default; 41 42 enum class AbstractMethodCheckerCases { 43 eNotImplemented, 44 eNotAllocated, 45 eNotCallable, 46 eValid 47 }; 48 49 llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>> 50 CheckAbstractMethodImplementation( 51 const python::PythonDictionary &class_dict) const { 52 53 using namespace python; 54 55 std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker; 56 #define SET_ERROR_AND_CONTINUE(method_name, error) \ 57 { \ 58 checker[method_name] = error; \ 59 continue; \ 60 } 61 62 for (const llvm::StringLiteral &method_name : GetAbstractMethods()) { 63 if (!class_dict.HasKey(method_name)) 64 SET_ERROR_AND_CONTINUE(method_name, 65 AbstractMethodCheckerCases::eNotImplemented) 66 auto callable_or_err = class_dict.GetItem(method_name); 67 if (!callable_or_err) 68 SET_ERROR_AND_CONTINUE(method_name, 69 AbstractMethodCheckerCases::eNotAllocated) 70 if (!PythonCallable::Check(callable_or_err.get().get())) 71 SET_ERROR_AND_CONTINUE(method_name, 72 AbstractMethodCheckerCases::eNotCallable) 73 checker[method_name] = AbstractMethodCheckerCases::eValid; 74 } 75 76 #undef HANDLE_ERROR 77 78 return checker; 79 } 80 81 template <typename... Args> 82 llvm::Expected<StructuredData::GenericSP> 83 CreatePluginObject(llvm::StringRef class_name, 84 StructuredData::Generic *script_obj, Args... args) { 85 using namespace python; 86 using Locker = ScriptInterpreterPythonImpl::Locker; 87 88 auto create_error = [](std::string message) { 89 return llvm::createStringError(llvm::inconvertibleErrorCode(), message); 90 }; 91 92 bool has_class_name = !class_name.empty(); 93 bool has_interpreter_dict = 94 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty()); 95 if (!has_class_name && !has_interpreter_dict && !script_obj) { 96 if (!has_class_name) 97 return create_error("Missing script class name."); 98 else if (!has_interpreter_dict) 99 return create_error("Invalid script interpreter dictionary."); 100 else 101 return create_error("Missing scripting object."); 102 } 103 104 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 105 Locker::FreeLock); 106 107 PythonObject result = {}; 108 109 if (script_obj) { 110 result = PythonObject(PyRefType::Borrowed, 111 static_cast<PyObject *>(script_obj->GetValue())); 112 } else { 113 auto dict = 114 PythonModule::MainModule().ResolveName<python::PythonDictionary>( 115 m_interpreter.GetDictionaryName()); 116 if (!dict.IsAllocated()) 117 return create_error( 118 llvm::formatv("Could not find interpreter dictionary: %s", 119 m_interpreter.GetDictionaryName())); 120 121 auto init = 122 PythonObject::ResolveNameWithDictionary<python::PythonCallable>( 123 class_name, dict); 124 if (!init.IsAllocated()) 125 return create_error(llvm::formatv("Could not find script class: {0}", 126 class_name.data())); 127 128 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 129 auto transformed_args = TransformArgs(original_args); 130 131 std::string error_string; 132 llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo(); 133 if (!arg_info) { 134 llvm::handleAllErrors( 135 arg_info.takeError(), 136 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, 137 [&](const llvm::ErrorInfoBase &E) { 138 error_string.append(E.message()); 139 }); 140 return llvm::createStringError(llvm::inconvertibleErrorCode(), 141 error_string); 142 } 143 144 llvm::Expected<PythonObject> expected_return_object = 145 create_error("Resulting object is not initialized."); 146 147 std::apply( 148 [&init, &expected_return_object](auto &&...args) { 149 llvm::consumeError(expected_return_object.takeError()); 150 expected_return_object = init(args...); 151 }, 152 transformed_args); 153 154 if (!expected_return_object) 155 return expected_return_object.takeError(); 156 result = expected_return_object.get(); 157 } 158 159 if (!result.IsValid()) 160 return create_error("Resulting object is not a valid Python Object."); 161 if (!result.HasAttribute("__class__")) 162 return create_error("Resulting object doesn't have '__class__' member."); 163 164 PythonObject obj_class = result.GetAttributeValue("__class__"); 165 if (!obj_class.IsValid()) 166 return create_error("Resulting class object is not a valid."); 167 if (!obj_class.HasAttribute("__name__")) 168 return create_error( 169 "Resulting object class doesn't have '__name__' member."); 170 PythonString obj_class_name = 171 obj_class.GetAttributeValue("__name__").AsType<PythonString>(); 172 173 PythonObject object_class_mapping_proxy = 174 obj_class.GetAttributeValue("__dict__"); 175 if (!obj_class.HasAttribute("__dict__")) 176 return create_error( 177 "Resulting object class doesn't have '__dict__' member."); 178 179 PythonCallable dict_converter = PythonModule::BuiltinsModule() 180 .ResolveName("dict") 181 .AsType<PythonCallable>(); 182 if (!dict_converter.IsAllocated()) 183 return create_error( 184 "Python 'builtins' module doesn't have 'dict' class."); 185 186 PythonDictionary object_class_dict = 187 dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>(); 188 if (!object_class_dict.IsAllocated()) 189 return create_error("Coudn't create dictionary from resulting object " 190 "class mapping proxy object."); 191 192 auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict); 193 if (!checker_or_err) 194 return checker_or_err.takeError(); 195 196 for (const auto &method_checker : *checker_or_err) 197 switch (method_checker.second) { 198 case AbstractMethodCheckerCases::eNotImplemented: 199 LLDB_LOG(GetLog(LLDBLog::Script), 200 "Abstract method {0}.{1} not implemented.", 201 obj_class_name.GetString(), method_checker.first); 202 break; 203 case AbstractMethodCheckerCases::eNotAllocated: 204 LLDB_LOG(GetLog(LLDBLog::Script), 205 "Abstract method {0}.{1} not allocated.", 206 obj_class_name.GetString(), method_checker.first); 207 break; 208 case AbstractMethodCheckerCases::eNotCallable: 209 LLDB_LOG(GetLog(LLDBLog::Script), 210 "Abstract method {0}.{1} not callable.", 211 obj_class_name.GetString(), method_checker.first); 212 break; 213 case AbstractMethodCheckerCases::eValid: 214 LLDB_LOG(GetLog(LLDBLog::Script), 215 "Abstract method {0}.{1} implemented & valid.", 216 obj_class_name.GetString(), method_checker.first); 217 break; 218 } 219 220 for (const auto &method_checker : *checker_or_err) 221 if (method_checker.second != AbstractMethodCheckerCases::eValid) 222 return create_error( 223 llvm::formatv("Abstract method {0}.{1} missing. Enable lldb " 224 "script log for more details.", 225 obj_class_name.GetString(), method_checker.first)); 226 227 m_object_instance_sp = StructuredData::GenericSP( 228 new StructuredPythonObject(std::move(result))); 229 return m_object_instance_sp; 230 } 231 232 protected: 233 template <typename T = StructuredData::ObjectSP> 234 T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { 235 return p.CreateStructuredObject(); 236 } 237 238 template <typename T = StructuredData::ObjectSP, typename... Args> 239 T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) { 240 using namespace python; 241 using Locker = ScriptInterpreterPythonImpl::Locker; 242 243 std::string caller_signature = 244 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") + 245 llvm::Twine(method_name) + llvm::Twine(")")) 246 .str(); 247 if (!m_object_instance_sp) 248 return ErrorWithMessage<T>(caller_signature, "Python object ill-formed", 249 error); 250 251 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 252 Locker::FreeLock); 253 254 PythonObject implementor(PyRefType::Borrowed, 255 (PyObject *)m_object_instance_sp->GetValue()); 256 257 if (!implementor.IsAllocated()) 258 return llvm::is_contained(GetAbstractMethods(), method_name) 259 ? ErrorWithMessage<T>(caller_signature, 260 "Python implementor not allocated.", 261 error) 262 : T{}; 263 264 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 265 auto transformed_args = TransformArgs(original_args); 266 267 llvm::Expected<PythonObject> expected_return_object = 268 llvm::make_error<llvm::StringError>("Not initialized.", 269 llvm::inconvertibleErrorCode()); 270 std::apply( 271 [&implementor, &method_name, &expected_return_object](auto &&...args) { 272 llvm::consumeError(expected_return_object.takeError()); 273 expected_return_object = 274 implementor.CallMethod(method_name.data(), args...); 275 }, 276 transformed_args); 277 278 if (llvm::Error e = expected_return_object.takeError()) { 279 error.SetErrorString(llvm::toString(std::move(e)).c_str()); 280 return ErrorWithMessage<T>(caller_signature, 281 "Python method could not be called.", error); 282 } 283 284 PythonObject py_return = std::move(expected_return_object.get()); 285 286 // Now that we called the python method with the transformed arguments, 287 // we need to interate again over both the original and transformed 288 // parameter pack, and transform back the parameter that were passed in 289 // the original parameter pack as references or pointers. 290 if (sizeof...(Args) > 0) 291 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args)) 292 return ErrorWithMessage<T>( 293 caller_signature, 294 "Couldn't re-assign reference and pointer arguments.", error); 295 296 if (!py_return.IsAllocated()) 297 return {}; 298 return ExtractValueFromPythonObject<T>(py_return, error); 299 } 300 301 template <typename... Args> 302 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) { 303 Status error; 304 Dispatch<Status>(method_name, error, std::forward<Args>(args)...); 305 306 return error; 307 } 308 309 template <typename T> T Transform(T object) { 310 // No Transformation for generic usage 311 return {object}; 312 } 313 314 python::PythonObject Transform(bool arg) { 315 // Boolean arguments need to be turned into python objects. 316 return python::PythonBoolean(arg); 317 } 318 319 python::PythonObject Transform(Status arg) { 320 return python::SWIGBridge::ToSWIGWrapper(arg); 321 } 322 323 python::PythonObject Transform(const StructuredDataImpl &arg) { 324 return python::SWIGBridge::ToSWIGWrapper(arg); 325 } 326 327 python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { 328 return python::SWIGBridge::ToSWIGWrapper(arg); 329 } 330 331 python::PythonObject Transform(lldb::ProcessSP arg) { 332 return python::SWIGBridge::ToSWIGWrapper(arg); 333 } 334 335 python::PythonObject Transform(lldb::ThreadPlanSP arg) { 336 return python::SWIGBridge::ToSWIGWrapper(arg); 337 } 338 339 python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { 340 return python::SWIGBridge::ToSWIGWrapper(arg); 341 } 342 343 python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { 344 return python::SWIGBridge::ToSWIGWrapper(arg); 345 } 346 347 python::PythonObject Transform(Event *arg) { 348 return python::SWIGBridge::ToSWIGWrapper(arg); 349 } 350 351 python::PythonObject Transform(lldb::StreamSP arg) { 352 return python::SWIGBridge::ToSWIGWrapper(arg.get()); 353 } 354 355 python::PythonObject Transform(lldb::DataExtractorSP arg) { 356 return python::SWIGBridge::ToSWIGWrapper(arg); 357 } 358 359 template <typename T, typename U> 360 void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { 361 // If U is not a PythonObject, don't touch it! 362 return; 363 } 364 365 template <typename T> 366 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, 367 Status &error) { 368 original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); 369 } 370 371 void ReverseTransform(bool &original_arg, 372 python::PythonObject transformed_arg, Status &error) { 373 python::PythonBoolean boolean_arg = python::PythonBoolean( 374 python::PyRefType::Borrowed, transformed_arg.get()); 375 if (boolean_arg.IsValid()) 376 original_arg = boolean_arg.GetValue(); 377 else 378 error.SetErrorString( 379 llvm::formatv("{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION) 380 .str()); 381 } 382 383 template <std::size_t... I, typename... Args> 384 auto TransformTuple(const std::tuple<Args...> &args, 385 std::index_sequence<I...>) { 386 return std::make_tuple(Transform(std::get<I>(args))...); 387 } 388 389 // This will iterate over the Dispatch parameter pack and replace in-place 390 // every `lldb_private` argument that has a SB counterpart. 391 template <typename... Args> 392 auto TransformArgs(const std::tuple<Args...> &args) { 393 return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>()); 394 } 395 396 template <typename T, typename U> 397 void TransformBack(T &original_arg, U transformed_arg, Status &error) { 398 ReverseTransform(original_arg, transformed_arg, error); 399 } 400 401 template <std::size_t... I, typename... Ts, typename... Us> 402 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 403 std::tuple<Us...> &transformed_args, 404 std::index_sequence<I...>) { 405 Status error; 406 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args), 407 error), 408 ...); 409 return error.Success(); 410 } 411 412 template <typename... Ts, typename... Us> 413 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 414 std::tuple<Us...> &transformed_args) { 415 if (sizeof...(Ts) != sizeof...(Us)) 416 return false; 417 418 return ReassignPtrsOrRefsArgs(original_args, transformed_args, 419 std::make_index_sequence<sizeof...(Ts)>()); 420 } 421 422 template <typename T, typename... Args> 423 void FormatArgs(std::string &fmt, T arg, Args... args) const { 424 FormatArgs(fmt, arg); 425 FormatArgs(fmt, args...); 426 } 427 428 template <typename T> void FormatArgs(std::string &fmt, T arg) const { 429 fmt += python::PythonFormat<T>::format; 430 } 431 432 void FormatArgs(std::string &fmt) const {} 433 434 // The lifetime is managed by the ScriptInterpreter 435 ScriptInterpreterPythonImpl &m_interpreter; 436 }; 437 438 template <> 439 StructuredData::ArraySP 440 ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( 441 python::PythonObject &p, Status &error); 442 443 template <> 444 StructuredData::DictionarySP 445 ScriptedPythonInterface::ExtractValueFromPythonObject< 446 StructuredData::DictionarySP>(python::PythonObject &p, Status &error); 447 448 template <> 449 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( 450 python::PythonObject &p, Status &error); 451 452 template <> 453 Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( 454 python::PythonObject &p, Status &error); 455 456 template <> 457 lldb::StreamSP 458 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( 459 python::PythonObject &p, Status &error); 460 461 template <> 462 lldb::BreakpointSP 463 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( 464 python::PythonObject &p, Status &error); 465 466 template <> 467 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 468 lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error); 469 470 template <> 471 lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 472 lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error); 473 474 template <> 475 lldb::DataExtractorSP 476 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( 477 python::PythonObject &p, Status &error); 478 479 template <> 480 std::optional<MemoryRegionInfo> 481 ScriptedPythonInterface::ExtractValueFromPythonObject< 482 std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); 483 484 } // namespace lldb_private 485 486 #endif // LLDB_ENABLE_PYTHON 487 #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 488