Skip to content

Commit 91d993c

Browse files
committed
[lldb/Interpreter] Add requirements to Scripted Interface abstract methods
This patch adds new requirements to the Scripted Interface abstract method checker to check the minimum number of argument for abstract methods. This check is done when creating the interface object so the object is not created if the user implementation doesn't match the abstract method requirement. Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent 04575dc commit 91d993c

File tree

7 files changed

+108
-51
lines changed

7 files changed

+108
-51
lines changed

lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,22 @@ class ScriptedInterface {
3131
return m_object_instance_sp;
3232
}
3333

34-
virtual llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const = 0;
34+
struct AbstractMethodRequirement {
35+
llvm::StringLiteral name;
36+
size_t min_arg_count = 0;
37+
};
38+
39+
virtual llvm::SmallVector<AbstractMethodRequirement>
40+
GetAbstractMethodRequirements() const = 0;
41+
42+
llvm::SmallVector<llvm::StringLiteral> const GetAbstractMethods() const {
43+
llvm::SmallVector<llvm::StringLiteral> abstract_methods;
44+
llvm::transform(GetAbstractMethodRequirements(), abstract_methods.begin(),
45+
[](const AbstractMethodRequirement &requirement) {
46+
return requirement.name;
47+
});
48+
return abstract_methods;
49+
}
3550

3651
template <typename Ret>
3752
static Ret ErrorWithMessage(llvm::StringRef caller_name,

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/OperatingSystemPythonInterface.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ class OperatingSystemPythonInterface
3131
StructuredData::DictionarySP args_sp,
3232
StructuredData::Generic *script_obj = nullptr) override;
3333

34-
llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override {
35-
return llvm::SmallVector<llvm::StringLiteral>({"get_thread_info"});
34+
llvm::SmallVector<AbstractMethodRequirement>
35+
GetAbstractMethodRequirements() const override {
36+
return llvm::SmallVector<AbstractMethodRequirement>({{"get_thread_info"}});
3637
}
3738

3839
StructuredData::DictionarySP CreateThread(lldb::tid_t tid,

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@ class ScriptedPlatformPythonInterface : public ScriptedPlatformInterface,
2929
StructuredData::DictionarySP args_sp,
3030
StructuredData::Generic *script_obj = nullptr) override;
3131

32-
llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override {
33-
return llvm::SmallVector<llvm::StringLiteral>(
34-
{"list_processes", "attach_to_process", "launch_process",
35-
"kill_process"});
32+
llvm::SmallVector<AbstractMethodRequirement>
33+
GetAbstractMethodRequirements() const override {
34+
return llvm::SmallVector<AbstractMethodRequirement>(
35+
{{"list_processes"},
36+
{"attach_to_process", 1},
37+
{"launch_process", 1},
38+
{"kill_process", 1}});
3639
}
3740

3841
StructuredData::DictionarySP ListProcesses() override;

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ class ScriptedProcessPythonInterface : public ScriptedProcessInterface,
3131
StructuredData::DictionarySP args_sp,
3232
StructuredData::Generic *script_obj = nullptr) override;
3333

34-
llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override {
35-
return llvm::SmallVector<llvm::StringLiteral>(
36-
{"read_memory_at_address", "is_alive", "get_scripted_thread_plugin"});
34+
llvm::SmallVector<AbstractMethodRequirement>
35+
GetAbstractMethodRequirements() const override {
36+
return llvm::SmallVector<AbstractMethodRequirement>(
37+
{{"read_memory_at_address", 3},
38+
{"is_alive"},
39+
{"get_scripted_thread_plugin"}});
3740
}
3841

3942
StructuredData::DictionarySP GetCapabilities() override;

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h

Lines changed: 70 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
3636
eNotImplemented,
3737
eNotAllocated,
3838
eNotCallable,
39+
eInvalidArgumentCount,
3940
eValid
4041
};
4142

@@ -46,27 +47,48 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
4647
using namespace python;
4748

4849
std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker;
49-
#define SET_ERROR_AND_CONTINUE(method_name, error) \
50+
#define SET_CASE_AND_CONTINUE(method_name, case) \
5051
{ \
51-
checker[method_name] = error; \
52+
checker[method_name] = case; \
5253
continue; \
5354
}
5455

55-
for (const llvm::StringLiteral &method_name : GetAbstractMethods()) {
56+
for (const AbstractMethodRequirement &requirement :
57+
GetAbstractMethodRequirements()) {
58+
llvm::StringLiteral method_name = requirement.name;
5659
if (!class_dict.HasKey(method_name))
57-
SET_ERROR_AND_CONTINUE(method_name,
58-
AbstractMethodCheckerCases::eNotImplemented)
60+
SET_CASE_AND_CONTINUE(method_name,
61+
AbstractMethodCheckerCases::eNotImplemented)
5962
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;
63+
if (!callable_or_err) {
64+
llvm::consumeError(callable_or_err.takeError());
65+
SET_CASE_AND_CONTINUE(method_name,
66+
AbstractMethodCheckerCases::eNotAllocated)
67+
}
68+
69+
PythonCallable callable = callable_or_err->AsType<PythonCallable>();
70+
if (!callable)
71+
SET_CASE_AND_CONTINUE(method_name,
72+
AbstractMethodCheckerCases::eNotCallable)
73+
74+
if (!requirement.min_arg_count)
75+
SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid)
76+
77+
auto arg_info_or_err = callable.GetArgInfo();
78+
if (!arg_info_or_err) {
79+
llvm::consumeError(arg_info_or_err.takeError());
80+
SET_CASE_AND_CONTINUE(method_name,
81+
AbstractMethodCheckerCases::eInvalidArgumentCount)
82+
}
83+
84+
PythonCallable::ArgInfo arg_info = *arg_info_or_err;
85+
checker[method_name] =
86+
(requirement.min_arg_count <= arg_info.max_positional_args)
87+
? AbstractMethodCheckerCases::eValid
88+
: AbstractMethodCheckerCases::eInvalidArgumentCount;
6789
}
6890

69-
#undef HANDLE_ERROR
91+
#undef SET_CASE_AND_CONTINUE
7092

7193
return checker;
7294
}
@@ -78,8 +100,11 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
78100
using namespace python;
79101
using Locker = ScriptInterpreterPythonImpl::Locker;
80102

81-
auto create_error = [](std::string message) {
82-
return llvm::createStringError(llvm::inconvertibleErrorCode(), message);
103+
Log *log = GetLog(LLDBLog::Script);
104+
auto create_error = [](llvm::StringRef format, auto &&...ts) {
105+
return llvm::createStringError(
106+
llvm::formatv(format.data(), std::forward<decltype(ts)>(ts)...)
107+
.str());
83108
};
84109

85110
bool has_class_name = !class_name.empty();
@@ -107,16 +132,15 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
107132
PythonModule::MainModule().ResolveName<python::PythonDictionary>(
108133
m_interpreter.GetDictionaryName());
109134
if (!dict.IsAllocated())
110-
return create_error(
111-
llvm::formatv("Could not find interpreter dictionary: %s",
112-
m_interpreter.GetDictionaryName()));
135+
return create_error("Could not find interpreter dictionary: {0}",
136+
m_interpreter.GetDictionaryName());
113137

114138
auto init =
115139
PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
116140
class_name, dict);
117141
if (!init.IsAllocated())
118-
return create_error(llvm::formatv("Could not find script class: {0}",
119-
class_name.data()));
142+
return create_error("Could not find script class: {0}",
143+
class_name.data());
120144

121145
std::tuple<Args...> original_args = std::forward_as_tuple(args...);
122146
auto transformed_args = TransformArgs(original_args);
@@ -186,36 +210,45 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
186210
if (!checker_or_err)
187211
return checker_or_err.takeError();
188212

213+
llvm::Error abstract_method_errors = llvm::Error::success();
189214
for (const auto &method_checker : *checker_or_err)
190215
switch (method_checker.second) {
191216
case AbstractMethodCheckerCases::eNotImplemented:
192-
LLDB_LOG(GetLog(LLDBLog::Script),
193-
"Abstract method {0}.{1} not implemented.",
194-
obj_class_name.GetString(), method_checker.first);
217+
abstract_method_errors = llvm::joinErrors(
218+
std::move(abstract_method_errors),
219+
std::move(create_error("Abstract method {0}.{1} not implemented.",
220+
obj_class_name.GetString(),
221+
method_checker.first)));
195222
break;
196223
case AbstractMethodCheckerCases::eNotAllocated:
197-
LLDB_LOG(GetLog(LLDBLog::Script),
198-
"Abstract method {0}.{1} not allocated.",
199-
obj_class_name.GetString(), method_checker.first);
224+
abstract_method_errors = llvm::joinErrors(
225+
std::move(abstract_method_errors),
226+
std::move(create_error("Abstract method {0}.{1} not allocated.",
227+
obj_class_name.GetString(),
228+
method_checker.first)));
200229
break;
201230
case AbstractMethodCheckerCases::eNotCallable:
202-
LLDB_LOG(GetLog(LLDBLog::Script),
203-
"Abstract method {0}.{1} not callable.",
204-
obj_class_name.GetString(), method_checker.first);
231+
abstract_method_errors = llvm::joinErrors(
232+
std::move(abstract_method_errors),
233+
std::move(create_error("Abstract method {0}.{1} not callable.",
234+
obj_class_name.GetString(),
235+
method_checker.first)));
236+
break;
237+
case AbstractMethodCheckerCases::eInvalidArgumentCount:
238+
abstract_method_errors = llvm::joinErrors(
239+
std::move(abstract_method_errors),
240+
std::move(create_error(
241+
"Abstract method {0}.{1} has unexpected argument count.",
242+
obj_class_name.GetString(), method_checker.first)));
205243
break;
206244
case AbstractMethodCheckerCases::eValid:
207-
LLDB_LOG(GetLog(LLDBLog::Script),
208-
"Abstract method {0}.{1} implemented & valid.",
245+
LLDB_LOG(log, "Abstract method {0}.{1} implemented & valid.",
209246
obj_class_name.GetString(), method_checker.first);
210247
break;
211248
}
212249

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));
250+
if (abstract_method_errors)
251+
return abstract_method_errors;
219252

220253
m_object_instance_sp = StructuredData::GenericSP(
221254
new StructuredPythonObject(std::move(result)));

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class ScriptedThreadPlanPythonInterface : public ScriptedThreadPlanInterface,
3030
lldb::ThreadPlanSP thread_plan_sp,
3131
const StructuredDataImpl &args_sp) override;
3232

33-
llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override {
33+
llvm::SmallVector<AbstractMethodRequirement>
34+
GetAbstractMethodRequirements() const override {
3435
return {};
3536
}
3637

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ class ScriptedThreadPythonInterface : public ScriptedThreadInterface,
2828
StructuredData::DictionarySP args_sp,
2929
StructuredData::Generic *script_obj = nullptr) override;
3030

31-
llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override {
32-
return llvm::SmallVector<llvm::StringLiteral>(
33-
{"get_stop_reason", "get_register_context"});
31+
llvm::SmallVector<AbstractMethodRequirement>
32+
GetAbstractMethodRequirements() const override {
33+
return llvm::SmallVector<AbstractMethodRequirement>(
34+
{{"get_stop_reason"}, {"get_register_context"}});
3435
}
3536

3637
lldb::tid_t GetThreadID() override;

0 commit comments

Comments
 (0)