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(key: method_name)) |
75 | SET_CASE_AND_CONTINUE(method_name, |
76 | AbstractMethodCheckerCases::eNotImplemented) |
77 | auto callable_or_err = class_dict.GetItem(key: method_name); |
78 | if (!callable_or_err) { |
79 | llvm::consumeError(Err: 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(Err: 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 | .checker_case: AbstractMethodCheckerCases::eInvalidArgumentCount, |
105 | .payload: 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(mask: 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 | name: 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 | name: 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(str: E.ReadBacktrace()); }, |
173 | [&](const llvm::ErrorInfoBase &E) { |
174 | error_string.append(str: E.message()); |
175 | }); |
176 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
177 | S: 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(Err: expected_return_object.takeError()); |
201 | expected_return_object = init(args...); |
202 | }, |
203 | std::tuple_cat(transformed_args, std::make_tuple(args&: dict))); |
204 | } else { |
205 | std::apply( |
206 | [&init, &expected_return_object](auto &&...args) { |
207 | llvm::consumeError(Err: 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(attribute: "__class__" )) |
221 | return create_error("Resulting object doesn't have '__class__' member." ); |
222 | |
223 | PythonObject obj_class = result.GetAttributeValue(attribute: "__class__" ); |
224 | if (!obj_class.IsValid()) |
225 | return create_error("Resulting class object is not a valid." ); |
226 | if (!obj_class.HasAttribute(attribute: "__name__" )) |
227 | return create_error( |
228 | "Resulting object class doesn't have '__name__' member." ); |
229 | PythonString obj_class_name = |
230 | obj_class.GetAttributeValue(attribute: "__name__" ).AsType<PythonString>(); |
231 | |
232 | PythonObject object_class_mapping_proxy = |
233 | obj_class.GetAttributeValue(attribute: "__dict__" ); |
234 | if (!obj_class.HasAttribute(attribute: "__dict__" )) |
235 | return create_error( |
236 | "Resulting object class doesn't have '__dict__' member." ); |
237 | |
238 | PythonCallable dict_converter = PythonModule::BuiltinsModule() |
239 | .ResolveName(name: "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(class_dict: 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 | E1: std::move(abstract_method_errors), |
261 | E2: 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 | E1: std::move(abstract_method_errors), |
268 | E2: 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 | E1: std::move(abstract_method_errors), |
275 | E2: 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 | E1: std::move(abstract_method_errors), |
282 | E2: 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 | v: payload_variant)) { |
291 | abstract_method_errors = llvm::joinErrors( |
292 | E1: std::move(abstract_method_errors), |
293 | E2: 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 | v: payload_variant); |
300 | abstract_method_errors = llvm::joinErrors( |
301 | E1: std::move(abstract_method_errors), |
302 | E2: 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(error: 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 (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(Range: GetAbstractMethods(), Element: 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>(Args: "Not initialized." , |
365 | Args: llvm::inconvertibleErrorCode()); |
366 | std::apply( |
367 | [&implementor, &method_name, &expected_return_object](auto &&...args) { |
368 | llvm::consumeError(Err: 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(error: 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(status: arg.Clone()); |
417 | } |
418 | |
419 | python::PythonObject Transform(Status &&arg) { |
420 | return python::SWIGBridge::ToSWIGWrapper(status: std::move(arg)); |
421 | } |
422 | |
423 | python::PythonObject Transform(const StructuredDataImpl &arg) { |
424 | return python::SWIGBridge::ToSWIGWrapper(data_impl: arg); |
425 | } |
426 | |
427 | python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { |
428 | return python::SWIGBridge::ToSWIGWrapper(ctx_sp: arg); |
429 | } |
430 | |
431 | python::PythonObject Transform(lldb::TargetSP arg) { |
432 | return python::SWIGBridge::ToSWIGWrapper(target_sp: arg); |
433 | } |
434 | |
435 | python::PythonObject Transform(lldb::ProcessSP arg) { |
436 | return python::SWIGBridge::ToSWIGWrapper(process_sp: arg); |
437 | } |
438 | |
439 | python::PythonObject Transform(lldb::ThreadPlanSP arg) { |
440 | return python::SWIGBridge::ToSWIGWrapper(thread_plan_sp: arg); |
441 | } |
442 | |
443 | python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { |
444 | return python::SWIGBridge::ToSWIGWrapper(attach_info_sp: arg); |
445 | } |
446 | |
447 | python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { |
448 | return python::SWIGBridge::ToSWIGWrapper(launch_info_sp: arg); |
449 | } |
450 | |
451 | python::PythonObject Transform(Event *arg) { |
452 | return python::SWIGBridge::ToSWIGWrapper(event: arg); |
453 | } |
454 | |
455 | python::PythonObject Transform(lldb::StreamSP arg) { |
456 | return python::SWIGBridge::ToSWIGWrapper(stream: arg.get()); |
457 | } |
458 | |
459 | python::PythonObject (lldb::DataExtractorSP arg) { |
460 | return python::SWIGBridge::ToSWIGWrapper(data_extractor_sp: 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 | } |
467 | |
468 | template <typename T> |
469 | void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, |
470 | Status &error) { |
471 | original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); |
472 | } |
473 | |
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 | format: "{}: Invalid boolean argument." , LLVM_PRETTY_FUNCTION); |
483 | } |
484 | |
485 | template <std::size_t... I, typename... Args> |
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> |
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> |
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> |
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> |
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> |
525 | void FormatArgs(std::string &fmt, T arg, Args... args) const { |
526 | FormatArgs(fmt, arg); |
527 | FormatArgs(fmt, args...); |
528 | } |
529 | |
530 | template <typename T> void FormatArgs(std::string &fmt, T arg) const { |
531 | fmt += python::PythonFormat<T>::format; |
532 | } |
533 | |
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 | |