Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
39688 views
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
eValid
40
};
41
42
llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>>
43
CheckAbstractMethodImplementation(
44
const python::PythonDictionary &class_dict) const {
45
46
using namespace python;
47
48
std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker;
49
#define SET_ERROR_AND_CONTINUE(method_name, error) \
50
{ \
51
checker[method_name] = error; \
52
continue; \
53
}
54
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);
60
if (!callable_or_err)
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;
67
}
68
69
#undef HANDLE_ERROR
70
71
return checker;
72
}
73
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;
80
81
auto create_error = [](std::string message) {
82
return llvm::createStringError(llvm::inconvertibleErrorCode(), message);
83
};
84
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) {
89
if (!has_class_name)
90
return create_error("Missing script class name.");
91
else if (!has_interpreter_dict)
92
return create_error("Invalid script interpreter dictionary.");
93
else
94
return create_error("Missing scripting object.");
95
}
96
97
Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
98
Locker::FreeLock);
99
100
PythonObject result = {};
101
102
if (script_obj) {
103
result = PythonObject(PyRefType::Borrowed,
104
static_cast<PyObject *>(script_obj->GetValue()));
105
} else {
106
auto dict =
107
PythonModule::MainModule().ResolveName<python::PythonDictionary>(
108
m_interpreter.GetDictionaryName());
109
if (!dict.IsAllocated())
110
return create_error(
111
llvm::formatv("Could not find interpreter dictionary: %s",
112
m_interpreter.GetDictionaryName()));
113
114
auto init =
115
PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
116
class_name, dict);
117
if (!init.IsAllocated())
118
return create_error(llvm::formatv("Could not find script class: {0}",
119
class_name.data()));
120
121
std::tuple<Args...> original_args = std::forward_as_tuple(args...);
122
auto transformed_args = TransformArgs(original_args);
123
124
std::string error_string;
125
llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();
126
if (!arg_info) {
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());
132
});
133
return llvm::createStringError(llvm::inconvertibleErrorCode(),
134
error_string);
135
}
136
137
llvm::Expected<PythonObject> expected_return_object =
138
create_error("Resulting object is not initialized.");
139
140
std::apply(
141
[&init, &expected_return_object](auto &&...args) {
142
llvm::consumeError(expected_return_object.takeError());
143
expected_return_object = init(args...);
144
},
145
transformed_args);
146
147
if (!expected_return_object)
148
return expected_return_object.takeError();
149
result = expected_return_object.get();
150
}
151
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.");
156
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__"))
161
return create_error(
162
"Resulting object class doesn't have '__name__' member.");
163
PythonString obj_class_name =
164
obj_class.GetAttributeValue("__name__").AsType<PythonString>();
165
166
PythonObject object_class_mapping_proxy =
167
obj_class.GetAttributeValue("__dict__");
168
if (!obj_class.HasAttribute("__dict__"))
169
return create_error(
170
"Resulting object class doesn't have '__dict__' member.");
171
172
PythonCallable dict_converter = PythonModule::BuiltinsModule()
173
.ResolveName("dict")
174
.AsType<PythonCallable>();
175
if (!dict_converter.IsAllocated())
176
return create_error(
177
"Python 'builtins' module doesn't have 'dict' class.");
178
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.");
184
185
auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict);
186
if (!checker_or_err)
187
return checker_or_err.takeError();
188
189
for (const auto &method_checker : *checker_or_err)
190
switch (method_checker.second) {
191
case AbstractMethodCheckerCases::eNotImplemented:
192
LLDB_LOG(GetLog(LLDBLog::Script),
193
"Abstract method {0}.{1} not implemented.",
194
obj_class_name.GetString(), method_checker.first);
195
break;
196
case AbstractMethodCheckerCases::eNotAllocated:
197
LLDB_LOG(GetLog(LLDBLog::Script),
198
"Abstract method {0}.{1} not allocated.",
199
obj_class_name.GetString(), method_checker.first);
200
break;
201
case AbstractMethodCheckerCases::eNotCallable:
202
LLDB_LOG(GetLog(LLDBLog::Script),
203
"Abstract method {0}.{1} not callable.",
204
obj_class_name.GetString(), method_checker.first);
205
break;
206
case AbstractMethodCheckerCases::eValid:
207
LLDB_LOG(GetLog(LLDBLog::Script),
208
"Abstract method {0}.{1} implemented & valid.",
209
obj_class_name.GetString(), method_checker.first);
210
break;
211
}
212
213
for (const auto &method_checker : *checker_or_err)
214
if (method_checker.second != AbstractMethodCheckerCases::eValid)
215
return create_error(
216
llvm::formatv("Abstract method {0}.{1} missing. Enable lldb "
217
"script log for more details.",
218
obj_class_name.GetString(), method_checker.first));
219
220
m_object_instance_sp = StructuredData::GenericSP(
221
new StructuredPythonObject(std::move(result)));
222
return m_object_instance_sp;
223
}
224
225
protected:
226
template <typename T = StructuredData::ObjectSP>
227
T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
228
return p.CreateStructuredObject();
229
}
230
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;
235
236
std::string caller_signature =
237
llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
238
llvm::Twine(method_name) + llvm::Twine(")"))
239
.str();
240
if (!m_object_instance_sp)
241
return ErrorWithMessage<T>(caller_signature, "Python object ill-formed",
242
error);
243
244
Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
245
Locker::FreeLock);
246
247
PythonObject implementor(PyRefType::Borrowed,
248
(PyObject *)m_object_instance_sp->GetValue());
249
250
if (!implementor.IsAllocated())
251
return llvm::is_contained(GetAbstractMethods(), method_name)
252
? ErrorWithMessage<T>(caller_signature,
253
"Python implementor not allocated.",
254
error)
255
: T{};
256
257
std::tuple<Args...> original_args = std::forward_as_tuple(args...);
258
auto transformed_args = TransformArgs(original_args);
259
260
llvm::Expected<PythonObject> expected_return_object =
261
llvm::make_error<llvm::StringError>("Not initialized.",
262
llvm::inconvertibleErrorCode());
263
std::apply(
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...);
268
},
269
transformed_args);
270
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);
275
}
276
277
PythonObject py_return = std::move(expected_return_object.get());
278
279
// Now that we called the python method with the transformed arguments,
280
// we need to interate again over both the original and transformed
281
// parameter pack, and transform back the parameter that were passed in
282
// the original parameter pack as references or pointers.
283
if (sizeof...(Args) > 0)
284
if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
285
return ErrorWithMessage<T>(
286
caller_signature,
287
"Couldn't re-assign reference and pointer arguments.", error);
288
289
if (!py_return.IsAllocated())
290
return {};
291
return ExtractValueFromPythonObject<T>(py_return, error);
292
}
293
294
template <typename... Args>
295
Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {
296
Status error;
297
Dispatch<Status>(method_name, error, std::forward<Args>(args)...);
298
299
return error;
300
}
301
302
template <typename T> T Transform(T object) {
303
// No Transformation for generic usage
304
return {object};
305
}
306
307
python::PythonObject Transform(bool arg) {
308
// Boolean arguments need to be turned into python objects.
309
return python::PythonBoolean(arg);
310
}
311
312
python::PythonObject Transform(Status arg) {
313
return python::SWIGBridge::ToSWIGWrapper(arg);
314
}
315
316
python::PythonObject Transform(const StructuredDataImpl &arg) {
317
return python::SWIGBridge::ToSWIGWrapper(arg);
318
}
319
320
python::PythonObject Transform(lldb::ExecutionContextRefSP arg) {
321
return python::SWIGBridge::ToSWIGWrapper(arg);
322
}
323
324
python::PythonObject Transform(lldb::ProcessSP arg) {
325
return python::SWIGBridge::ToSWIGWrapper(arg);
326
}
327
328
python::PythonObject Transform(lldb::ThreadPlanSP arg) {
329
return python::SWIGBridge::ToSWIGWrapper(arg);
330
}
331
332
python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) {
333
return python::SWIGBridge::ToSWIGWrapper(arg);
334
}
335
336
python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) {
337
return python::SWIGBridge::ToSWIGWrapper(arg);
338
}
339
340
python::PythonObject Transform(Event *arg) {
341
return python::SWIGBridge::ToSWIGWrapper(arg);
342
}
343
344
python::PythonObject Transform(lldb::StreamSP arg) {
345
return python::SWIGBridge::ToSWIGWrapper(arg.get());
346
}
347
348
python::PythonObject Transform(lldb::DataExtractorSP arg) {
349
return python::SWIGBridge::ToSWIGWrapper(arg);
350
}
351
352
template <typename T, typename U>
353
void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
354
// If U is not a PythonObject, don't touch it!
355
return;
356
}
357
358
template <typename T>
359
void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,
360
Status &error) {
361
original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error);
362
}
363
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();
370
else
371
error.SetErrorString(
372
llvm::formatv("{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION)
373
.str());
374
}
375
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))...);
380
}
381
382
// This will iterate over the Dispatch parameter pack and replace in-place
383
// every `lldb_private` argument that has a SB counterpart.
384
template <typename... Args>
385
auto TransformArgs(const std::tuple<Args...> &args) {
386
return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>());
387
}
388
389
template <typename T, typename U>
390
void TransformBack(T &original_arg, U transformed_arg, Status &error) {
391
ReverseTransform(original_arg, transformed_arg, error);
392
}
393
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...>) {
398
Status error;
399
(TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),
400
error),
401
...);
402
return error.Success();
403
}
404
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))
409
return false;
410
411
return ReassignPtrsOrRefsArgs(original_args, transformed_args,
412
std::make_index_sequence<sizeof...(Ts)>());
413
}
414
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...);
419
}
420
421
template <typename T> void FormatArgs(std::string &fmt, T arg) const {
422
fmt += python::PythonFormat<T>::format;
423
}
424
425
void FormatArgs(std::string &fmt) const {}
426
427
// The lifetime is managed by the ScriptInterpreter
428
ScriptInterpreterPythonImpl &m_interpreter;
429
};
430
431
template <>
432
StructuredData::ArraySP
433
ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
434
python::PythonObject &p, Status &error);
435
436
template <>
437
StructuredData::DictionarySP
438
ScriptedPythonInterface::ExtractValueFromPythonObject<
439
StructuredData::DictionarySP>(python::PythonObject &p, Status &error);
440
441
template <>
442
Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
443
python::PythonObject &p, Status &error);
444
445
template <>
446
Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(
447
python::PythonObject &p, Status &error);
448
449
template <>
450
lldb::StreamSP
451
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
452
python::PythonObject &p, Status &error);
453
454
template <>
455
lldb::BreakpointSP
456
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
457
python::PythonObject &p, Status &error);
458
459
template <>
460
lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
461
lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error);
462
463
template <>
464
lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
465
lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error);
466
467
template <>
468
lldb::DataExtractorSP
469
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(
470
python::PythonObject &p, Status &error);
471
472
template <>
473
std::optional<MemoryRegionInfo>
474
ScriptedPythonInterface::ExtractValueFromPythonObject<
475
std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);
476
477
} // namespace lldb_private
478
479
#endif // LLDB_ENABLE_PYTHON
480
#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
481
482