9#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
10#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
20#include "lldb/Host/Config.h"
24#include "../PythonDataObjects.h"
25#include "../SWIGPythonBridge.h"
26#include "../ScriptInterpreterPythonImpl.h"
29class ScriptInterpreterPythonImpl;
30class ScriptedPythonInterface :
virtual public ScriptedInterface {
32 ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);
33 ~ScriptedPythonInterface()
override =
default;
35 enum class AbstractMethodCheckerCases {
42 llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>>
43 CheckAbstractMethodImplementation(
44 const python::PythonDictionary &class_dict)
const {
46 using namespace python;
48 std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker;
49#define SET_ERROR_AND_CONTINUE(method_name, error) \
51 checker[method_name] = error; \
55 for (
const llvm::StringLiteral &method_name : GetAbstractMethods()) {
56 if (!class_dict.HasKey(method_name))
57 SET_ERROR_AND_CONTINUE(method_name,
58 AbstractMethodCheckerCases::eNotImplemented)
59 auto callable_or_err = class_dict.GetItem(method_name);
61 SET_ERROR_AND_CONTINUE(method_name,
62 AbstractMethodCheckerCases::eNotAllocated)
63 if (!PythonCallable::Check(callable_or_err.get().get()))
64 SET_ERROR_AND_CONTINUE(method_name,
65 AbstractMethodCheckerCases::eNotCallable)
66 checker[method_name] = AbstractMethodCheckerCases::eValid;
74 template <
typename... Args>
75 llvm::Expected<StructuredData::GenericSP>
76 CreatePluginObject(llvm::StringRef class_name,
77 StructuredData::Generic *script_obj, Args... args) {
78 using namespace python;
79 using Locker = ScriptInterpreterPythonImpl::Locker;
81 auto create_error = [](std::string message) {
82 return llvm::createStringError(llvm::inconvertibleErrorCode(), message);
85 bool has_class_name = !class_name.empty();
86 bool has_interpreter_dict =
87 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());
88 if (!has_class_name && !has_interpreter_dict && !script_obj) {
90 return create_error(
"Missing script class name.");
91 else if (!has_interpreter_dict)
92 return create_error(
"Invalid script interpreter dictionary.");
94 return create_error(
"Missing scripting object.");
97 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
100 PythonObject result = {};
103 result = PythonObject(PyRefType::Borrowed,
104 static_cast<PyObject *
>(script_obj->GetValue()));
107 PythonModule::MainModule().ResolveName<python::PythonDictionary>(
108 m_interpreter.GetDictionaryName());
109 if (!dict.IsAllocated())
111 llvm::formatv(
"Could not find interpreter dictionary: %s",
112 m_interpreter.GetDictionaryName()));
115 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
117 if (!init.IsAllocated())
118 return create_error(llvm::formatv(
"Could not find script class: {0}",
121 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
122 auto transformed_args = TransformArgs(original_args);
124 std::string error_string;
125 llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();
127 llvm::handleAllErrors(
128 arg_info.takeError(),
129 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
130 [&](
const llvm::ErrorInfoBase &E) {
131 error_string.append(E.message());
133 return llvm::createStringError(llvm::inconvertibleErrorCode(),
137 llvm::Expected<PythonObject> expected_return_object =
138 create_error(
"Resulting object is not initialized.");
141 [&init, &expected_return_object](
auto &&...args) {
142 llvm::consumeError(expected_return_object.takeError());
143 expected_return_object = init(args...);
147 if (!expected_return_object)
148 return expected_return_object.takeError();
149 result = expected_return_object.get();
152 if (!result.IsValid())
153 return create_error(
"Resulting object is not a valid Python Object.");
154 if (!result.HasAttribute(
"__class__"))
155 return create_error(
"Resulting object doesn't have '__class__' member.");
157 PythonObject obj_class = result.GetAttributeValue(
"__class__");
158 if (!obj_class.IsValid())
159 return create_error(
"Resulting class object is not a valid.");
160 if (!obj_class.HasAttribute(
"__name__"))
162 "Resulting object class doesn't have '__name__' member.");
163 PythonString obj_class_name =
164 obj_class.GetAttributeValue(
"__name__").AsType<PythonString>();
166 PythonObject object_class_mapping_proxy =
167 obj_class.GetAttributeValue(
"__dict__");
168 if (!obj_class.HasAttribute(
"__dict__"))
170 "Resulting object class doesn't have '__dict__' member.");
172 PythonCallable dict_converter = PythonModule::BuiltinsModule()
174 .AsType<PythonCallable>();
175 if (!dict_converter.IsAllocated())
177 "Python 'builtins' module doesn't have 'dict' class.");
179 PythonDictionary object_class_dict =
180 dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>();
181 if (!object_class_dict.IsAllocated())
182 return create_error(
"Coudn't create dictionary from resulting object "
183 "class mapping proxy object.");
185 auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict);
187 return checker_or_err.takeError();
189 for (
const auto &method_checker : *checker_or_err)
190 switch (method_checker.second) {
191 case AbstractMethodCheckerCases::eNotImplemented:
193 "Abstract method {0}.{1} not implemented.",
194 obj_class_name.GetString(), method_checker.first);
196 case AbstractMethodCheckerCases::eNotAllocated:
198 "Abstract method {0}.{1} not allocated.",
199 obj_class_name.GetString(), method_checker.first);
201 case AbstractMethodCheckerCases::eNotCallable:
203 "Abstract method {0}.{1} not callable.",
204 obj_class_name.GetString(), method_checker.first);
206 case AbstractMethodCheckerCases::eValid:
208 "Abstract method {0}.{1} implemented & valid.",
209 obj_class_name.GetString(), method_checker.first);
213 for (
const auto &method_checker : *checker_or_err)
214 if (method_checker.second != AbstractMethodCheckerCases::eValid)
216 llvm::formatv(
"Abstract method {0}.{1} missing. Enable lldb "
217 "script log for more details.",
218 obj_class_name.GetString(), method_checker.first));
220 m_object_instance_sp = StructuredData::GenericSP(
221 new StructuredPythonObject(std::move(result)));
222 return m_object_instance_sp;
226 template <
typename T = StructuredData::ObjectSP>
227 T ExtractValueFromPythonObject(python::PythonObject &p, Status &
error) {
228 return p.CreateStructuredObject();
231 template <
typename T = StructuredData::ObjectSP,
typename... Args>
232 T Dispatch(llvm::StringRef method_name, Status &
error, Args &&...args) {
233 using namespace python;
234 using Locker = ScriptInterpreterPythonImpl::Locker;
236 std::string caller_signature =
237 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(
" (") +
238 llvm::Twine(method_name) + llvm::Twine(
")"))
240 if (!m_object_instance_sp)
241 return ErrorWithMessage<T>(caller_signature,
"Python object ill-formed",
244 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
247 PythonObject implementor(PyRefType::Borrowed,
248 (PyObject *)m_object_instance_sp->GetValue());
250 if (!implementor.IsAllocated())
251 return llvm::is_contained(GetAbstractMethods(), method_name)
252 ? ErrorWithMessage<T>(caller_signature,
253 "Python implementor not allocated.",
257 std::tuple<Args...> original_args = std::forward_as_tuple(args...);
258 auto transformed_args = TransformArgs(original_args);
260 llvm::Expected<PythonObject> expected_return_object =
261 llvm::make_error<llvm::StringError>(
"Not initialized.",
262 llvm::inconvertibleErrorCode());
264 [&implementor, &method_name, &expected_return_object](
auto &&...args) {
265 llvm::consumeError(expected_return_object.takeError());
266 expected_return_object =
267 implementor.CallMethod(method_name.data(), args...);
271 if (llvm::Error e = expected_return_object.takeError()) {
272 error.SetErrorString(llvm::toString(std::move(e)).c_str());
273 return ErrorWithMessage<T>(caller_signature,
274 "Python method could not be called.",
error);
277 PythonObject py_return = std::move(expected_return_object.get());
283 if (
sizeof...(Args) > 0)
284 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
285 return ErrorWithMessage<T>(
287 "Couldn't re-assign reference and pointer arguments.",
error);
289 if (!py_return.IsAllocated())
291 return ExtractValueFromPythonObject<T>(py_return,
error);
294 template <
typename... Args>
295 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {
297 Dispatch<Status>(method_name,
error, std::forward<Args>(args)...);
302 template <
typename T> T Transform(T
object) {
307 python::PythonObject Transform(
bool arg) {
309 return python::PythonBoolean(arg);
312 python::PythonObject Transform(Status arg) {
313 return python::SWIGBridge::ToSWIGWrapper(arg);
316 python::PythonObject Transform(
const StructuredDataImpl &arg) {
317 return python::SWIGBridge::ToSWIGWrapper(arg);
321 return python::SWIGBridge::ToSWIGWrapper(arg);
325 return python::SWIGBridge::ToSWIGWrapper(arg);
329 return python::SWIGBridge::ToSWIGWrapper(arg);
333 return python::SWIGBridge::ToSWIGWrapper(arg);
337 return python::SWIGBridge::ToSWIGWrapper(arg);
340 python::PythonObject Transform(Event *arg) {
341 return python::SWIGBridge::ToSWIGWrapper(arg);
345 return python::SWIGBridge::ToSWIGWrapper(arg.get());
349 return python::SWIGBridge::ToSWIGWrapper(arg);
352 template <
typename T,
typename U>
353 void ReverseTransform(T &original_arg, U transformed_arg, Status &
error) {
358 template <
typename T>
359 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,
361 original_arg = ExtractValueFromPythonObject<T>(transformed_arg,
error);
364 void ReverseTransform(
bool &original_arg,
365 python::PythonObject transformed_arg, Status &
error) {
366 python::PythonBoolean boolean_arg = python::PythonBoolean(
367 python::PyRefType::Borrowed, transformed_arg.get());
368 if (boolean_arg.IsValid())
369 original_arg = boolean_arg.GetValue();
371 error.SetErrorString(
372 llvm::formatv(
"{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION)
376 template <std::size_t... I,
typename... Args>
377 auto TransformTuple(
const std::tuple<Args...> &args,
378 std::index_sequence<I...>) {
379 return std::make_tuple(Transform(std::get<I>(args))...);
384 template <
typename... Args>
385 auto TransformArgs(
const std::tuple<Args...> &args) {
386 return TransformTuple(args, std::make_index_sequence<
sizeof...(Args)>());
389 template <
typename T,
typename U>
390 void TransformBack(T &original_arg, U transformed_arg, Status &
error) {
391 ReverseTransform(original_arg, transformed_arg,
error);
394 template <std::size_t... I,
typename... Ts,
typename... Us>
395 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
396 std::tuple<Us...> &transformed_args,
397 std::index_sequence<I...>) {
399 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
402 return error.Success();
405 template <
typename... Ts,
typename... Us>
406 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
407 std::tuple<Us...> &transformed_args) {
408 if (
sizeof...(Ts) !=
sizeof...(Us))
411 return ReassignPtrsOrRefsArgs(original_args, transformed_args,
412 std::make_index_sequence<
sizeof...(Ts)>());
415 template <
typename T,
typename... Args>
416 void FormatArgs(std::string &fmt, T arg, Args... args)
const {
417 FormatArgs(fmt, arg);
418 FormatArgs(fmt, args...);
421 template <
typename T>
void FormatArgs(std::string &fmt, T arg)
const {
422 fmt += python::PythonFormat<T>::format;
425 void FormatArgs(std::string &fmt)
const {}
428 ScriptInterpreterPythonImpl &m_interpreter;
433ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
434 python::PythonObject &p, Status &
error);
438ScriptedPythonInterface::ExtractValueFromPythonObject<
442Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
443 python::PythonObject &p, Status &
error);
446Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(
447 python::PythonObject &p, Status &
error);
451ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
452 python::PythonObject &p, Status &
error);
456ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
457 python::PythonObject &p, Status &
error);
469ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
470 python::PythonObject &p, Status &
error);
473std::optional<MemoryRegionInfo>
474ScriptedPythonInterface::ExtractValueFromPythonObject<
475 std::optional<MemoryRegionInfo>>(python::PythonObject &p,
Status &
error);
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Array > ArraySP
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::ThreadPlan > ThreadPlanSP
std::shared_ptr< lldb_private::ProcessAttachInfo > ProcessAttachInfoSP
std::shared_ptr< lldb_private::Stream > StreamSP
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::DataExtractor > DataExtractorSP
std::shared_ptr< lldb_private::ProcessLaunchInfo > ProcessLaunchInfoSP
std::shared_ptr< lldb_private::ExecutionContextRef > ExecutionContextRefSP