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 template <typename... Args> 36 llvm::Expected<StructuredData::GenericSP> 37 CreatePluginObject(llvm::StringRef class_name, 38 StructuredData::Generic *script_obj, Args... args) { 39 using namespace python; 40 using Locker = ScriptInterpreterPythonImpl::Locker; 41 42 bool has_class_name = !class_name.empty(); 43 bool has_interpreter_dict = 44 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty()); 45 if (!has_class_name && !has_interpreter_dict && !script_obj) { 46 if (!has_class_name) 47 return llvm::createStringError(llvm::inconvertibleErrorCode(), 48 "Missing script class name."); 49 else if (!has_interpreter_dict) 50 return llvm::createStringError( 51 llvm::inconvertibleErrorCode(), 52 "Invalid script interpreter dictionary."); 53 else 54 return llvm::createStringError(llvm::inconvertibleErrorCode(), 55 "Missing scripting object."); 56 } 57 58 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 59 Locker::FreeLock); 60 61 PythonObject result = {}; 62 63 if (script_obj) { 64 result = PythonObject(PyRefType::Borrowed, 65 static_cast<PyObject *>(script_obj->GetValue())); 66 } else { 67 auto dict = 68 PythonModule::MainModule().ResolveName<python::PythonDictionary>( 69 m_interpreter.GetDictionaryName()); 70 if (!dict.IsAllocated()) { 71 return llvm::createStringError( 72 llvm::inconvertibleErrorCode(), 73 "Could not find interpreter dictionary: %s", 74 m_interpreter.GetDictionaryName()); 75 } 76 77 auto method = 78 PythonObject::ResolveNameWithDictionary<python::PythonCallable>( 79 class_name, dict); 80 if (!method.IsAllocated()) 81 return llvm::createStringError(llvm::inconvertibleErrorCode(), 82 "Could not find script class: %s", 83 class_name.data()); 84 85 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 86 auto transformed_args = TransformArgs(original_args); 87 88 std::string error_string; 89 llvm::Expected<PythonCallable::ArgInfo> arg_info = method.GetArgInfo(); 90 if (!arg_info) { 91 llvm::handleAllErrors( 92 arg_info.takeError(), 93 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, 94 [&](const llvm::ErrorInfoBase &E) { 95 error_string.append(E.message()); 96 }); 97 return llvm::createStringError(llvm::inconvertibleErrorCode(), 98 error_string); 99 } 100 101 llvm::Expected<PythonObject> expected_return_object = 102 llvm::createStringError(llvm::inconvertibleErrorCode(), 103 "Resulting object is not initialized."); 104 105 std::apply( 106 [&method, &expected_return_object](auto &&...args) { 107 llvm::consumeError(expected_return_object.takeError()); 108 expected_return_object = method(args...); 109 }, 110 transformed_args); 111 112 if (llvm::Error e = expected_return_object.takeError()) 113 return std::move(e); 114 result = std::move(expected_return_object.get()); 115 } 116 117 if (!result.IsValid()) 118 return llvm::createStringError( 119 llvm::inconvertibleErrorCode(), 120 "Resulting object is not a valid Python Object."); 121 122 m_object_instance_sp = StructuredData::GenericSP( 123 new StructuredPythonObject(std::move(result))); 124 return m_object_instance_sp; 125 } 126 127 protected: 128 template <typename T = StructuredData::ObjectSP> 129 T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { 130 return p.CreateStructuredObject(); 131 } 132 133 template <typename T = StructuredData::ObjectSP, typename... Args> 134 T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) { 135 using namespace python; 136 using Locker = ScriptInterpreterPythonImpl::Locker; 137 138 std::string caller_signature = 139 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") + 140 llvm::Twine(method_name) + llvm::Twine(")")) 141 .str(); 142 if (!m_object_instance_sp) 143 return ErrorWithMessage<T>(caller_signature, "Python object ill-formed", 144 error); 145 146 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 147 Locker::FreeLock); 148 149 PythonObject implementor(PyRefType::Borrowed, 150 (PyObject *)m_object_instance_sp->GetValue()); 151 152 if (!implementor.IsAllocated()) 153 return ErrorWithMessage<T>(caller_signature, 154 "Python implementor not allocated.", error); 155 156 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 157 auto transformed_args = TransformArgs(original_args); 158 159 llvm::Expected<PythonObject> expected_return_object = 160 llvm::make_error<llvm::StringError>("Not initialized.", 161 llvm::inconvertibleErrorCode()); 162 std::apply( 163 [&implementor, &method_name, &expected_return_object](auto &&...args) { 164 llvm::consumeError(expected_return_object.takeError()); 165 expected_return_object = 166 implementor.CallMethod(method_name.data(), args...); 167 }, 168 transformed_args); 169 170 if (llvm::Error e = expected_return_object.takeError()) { 171 error.SetErrorString(llvm::toString(std::move(e)).c_str()); 172 return ErrorWithMessage<T>(caller_signature, 173 "Python method could not be called.", error); 174 } 175 176 PythonObject py_return = std::move(expected_return_object.get()); 177 178 // Now that we called the python method with the transformed arguments, 179 // we need to interate again over both the original and transformed 180 // parameter pack, and transform back the parameter that were passed in 181 // the original parameter pack as references or pointers. 182 if (sizeof...(Args) > 0) 183 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args)) 184 return ErrorWithMessage<T>( 185 caller_signature, 186 "Couldn't re-assign reference and pointer arguments.", error); 187 188 if (!py_return.IsAllocated()) 189 return {}; 190 return ExtractValueFromPythonObject<T>(py_return, error); 191 } 192 193 template <typename... Args> 194 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) { 195 Status error; 196 Dispatch<Status>(method_name, error, std::forward<Args>(args)...); 197 198 return error; 199 } 200 201 template <typename T> T Transform(T object) { 202 // No Transformation for generic usage 203 return {object}; 204 } 205 206 python::PythonObject Transform(bool arg) { 207 // Boolean arguments need to be turned into python objects. 208 return python::PythonBoolean(arg); 209 } 210 211 python::PythonObject Transform(Status arg) { 212 return python::SWIGBridge::ToSWIGWrapper(arg); 213 } 214 215 python::PythonObject Transform(const StructuredDataImpl &arg) { 216 return python::SWIGBridge::ToSWIGWrapper(arg); 217 } 218 219 python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { 220 return python::SWIGBridge::ToSWIGWrapper(arg); 221 } 222 223 python::PythonObject Transform(lldb::ProcessSP arg) { 224 return python::SWIGBridge::ToSWIGWrapper(arg); 225 } 226 227 python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { 228 return python::SWIGBridge::ToSWIGWrapper(arg); 229 } 230 231 python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { 232 return python::SWIGBridge::ToSWIGWrapper(arg); 233 } 234 235 python::PythonObject Transform(lldb::DataExtractorSP arg) { 236 return python::SWIGBridge::ToSWIGWrapper(arg); 237 } 238 239 template <typename T, typename U> 240 void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { 241 // If U is not a PythonObject, don't touch it! 242 return; 243 } 244 245 template <typename T> 246 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, 247 Status &error) { 248 original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); 249 } 250 251 void ReverseTransform(bool &original_arg, 252 python::PythonObject transformed_arg, Status &error) { 253 python::PythonBoolean boolean_arg = python::PythonBoolean( 254 python::PyRefType::Borrowed, transformed_arg.get()); 255 if (boolean_arg.IsValid()) 256 original_arg = boolean_arg.GetValue(); 257 else 258 error.SetErrorString( 259 llvm::formatv("{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION) 260 .str()); 261 } 262 263 template <std::size_t... I, typename... Args> 264 auto TransformTuple(const std::tuple<Args...> &args, 265 std::index_sequence<I...>) { 266 return std::make_tuple(Transform(std::get<I>(args))...); 267 } 268 269 // This will iterate over the Dispatch parameter pack and replace in-place 270 // every `lldb_private` argument that has a SB counterpart. 271 template <typename... Args> 272 auto TransformArgs(const std::tuple<Args...> &args) { 273 return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>()); 274 } 275 276 template <typename T, typename U> 277 void TransformBack(T &original_arg, U transformed_arg, Status &error) { 278 ReverseTransform(original_arg, transformed_arg, error); 279 } 280 281 template <std::size_t... I, typename... Ts, typename... Us> 282 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 283 std::tuple<Us...> &transformed_args, 284 std::index_sequence<I...>) { 285 Status error; 286 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args), 287 error), 288 ...); 289 return error.Success(); 290 } 291 292 template <typename... Ts, typename... Us> 293 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 294 std::tuple<Us...> &transformed_args) { 295 if (sizeof...(Ts) != sizeof...(Us)) 296 return false; 297 298 return ReassignPtrsOrRefsArgs(original_args, transformed_args, 299 std::make_index_sequence<sizeof...(Ts)>()); 300 } 301 302 template <typename T, typename... Args> 303 void FormatArgs(std::string &fmt, T arg, Args... args) const { 304 FormatArgs(fmt, arg); 305 FormatArgs(fmt, args...); 306 } 307 308 template <typename T> void FormatArgs(std::string &fmt, T arg) const { 309 fmt += python::PythonFormat<T>::format; 310 } 311 312 void FormatArgs(std::string &fmt) const {} 313 314 // The lifetime is managed by the ScriptInterpreter 315 ScriptInterpreterPythonImpl &m_interpreter; 316 }; 317 318 template <> 319 StructuredData::ArraySP 320 ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( 321 python::PythonObject &p, Status &error); 322 323 template <> 324 StructuredData::DictionarySP 325 ScriptedPythonInterface::ExtractValueFromPythonObject< 326 StructuredData::DictionarySP>(python::PythonObject &p, Status &error); 327 328 template <> 329 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( 330 python::PythonObject &p, Status &error); 331 332 template <> 333 lldb::BreakpointSP 334 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( 335 python::PythonObject &p, Status &error); 336 337 template <> 338 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 339 lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error); 340 341 template <> 342 lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 343 lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error); 344 345 template <> 346 lldb::DataExtractorSP 347 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( 348 python::PythonObject &p, Status &error); 349 350 template <> 351 std::optional<MemoryRegionInfo> 352 ScriptedPythonInterface::ExtractValueFromPythonObject< 353 std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); 354 355 } // namespace lldb_private 356 357 #endif // LLDB_ENABLE_PYTHON 358 #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 359