Skip to content

Commit 580f68d

Browse files
committed
First pass at addressing review comments
1 parent a0c72c0 commit 580f68d

File tree

6 files changed

+105
-84
lines changed

6 files changed

+105
-84
lines changed

lldb/bindings/python/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar
9696
${lldb_python_target_dir}
9797
"utils"
9898
FILES "${LLDB_SOURCE_DIR}/examples/python/in_call_stack.py"
99+
"${LLDB_SOURCE_DIR}/examples/python/parsed_cmd.py"
99100
"${LLDB_SOURCE_DIR}/examples/python/symbolication.py"
100-
"${LLDB_SOURCE_DIR}/examples/python/parsed_cmd.py")
101+
)
101102

102103
create_python_package(
103104
${swig_target}

lldb/bindings/python/python-wrapper.swig

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,12 @@ PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedThrea
287287
}
288288

289289
bool lldb_private::python::SWIGBridge::LLDBSWIGPythonCallThreadPlan(
290-
void *implementor, const char *method_name, lldb_private::Event *event,
290+
void *implementer, const char *method_name, lldb_private::Event *event,
291291
bool &got_error) {
292292
got_error = false;
293293

294294
PyErr_Cleaner py_err_cleaner(false);
295-
PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementor));
295+
PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementer));
296296
auto pfunc = self.ResolveName<PythonCallable>(method_name);
297297

298298
if (!pfunc.IsAllocated())
@@ -325,12 +325,12 @@ bool lldb_private::python::SWIGBridge::LLDBSWIGPythonCallThreadPlan(
325325
}
326326

327327
bool lldb_private::python::SWIGBridge::LLDBSWIGPythonCallThreadPlan(
328-
void *implementor, const char *method_name, lldb_private::Stream *stream,
328+
void *implementer, const char *method_name, lldb_private::Stream *stream,
329329
bool &got_error) {
330330
got_error = false;
331331

332332
PyErr_Cleaner py_err_cleaner(false);
333-
PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementor));
333+
PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementer));
334334
auto pfunc = self.ResolveName<PythonCallable>(method_name);
335335

336336
if (!pfunc.IsAllocated())
@@ -845,16 +845,6 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallParsedCommandObject(
845845
return false;
846846

847847
auto cmd_retobj_arg = SWIGBridge::ToSWIGWrapper(cmd_retobj);
848-
849-
// FIXME:
850-
// I wanted to do something like:
851-
// size_t num_elem = args.size();
852-
// PythonList my_list(num_elem);
853-
// for (const char *elem : args)
854-
// my_list.append(PythonString(elem);
855-
//
856-
// and then pass my_list to the pfunc, but that crashes somewhere
857-
// deep in Python for reasons that aren't clear to me.
858848

859849
pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger)), SWIGBridge::ToSWIGWrapper(args_impl),
860850
SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp), cmd_retobj_arg.obj());

lldb/examples/python/parsed_cmd.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,51 @@
11
"""
22
This module implements a couple of utility classes to make writing
33
lldb parsed commands more Pythonic.
4-
The way to use it is to make a class for you command that inherits from ParsedCommandBase.
4+
The way to use it is to make a class for your command that inherits from ParsedCommandBase.
55
That will make an LLDBOVParser which you will use for your
66
option definition, and to fetch option values for the current invocation
77
of your command. Access to the OV parser is through:
88
99
ParsedCommandBase.get_parser()
1010
11-
Next, implement setup_command_definition in your new command class, and call:
11+
Next, implement setup_command_definition() in your new command class, and call:
1212
13-
self.get_parser().add_option
13+
self.get_parser().add_option()
1414
1515
to add all your options. The order doesn't matter for options, lldb will sort them
1616
alphabetically for you when it prints help.
1717
1818
Similarly you can define the arguments with:
1919
20-
self.get_parser.add_argument
20+
self.get_parser().add_argument()
2121
22-
at present, lldb doesn't do as much work as it should verifying arguments, it pretty
23-
much only checks that commands that take no arguments don't get passed arguments.
22+
At present, lldb doesn't do as much work as it should verifying arguments, it
23+
only checks that commands that take no arguments don't get passed arguments.
2424
2525
Then implement the execute function for your command as:
2626
27-
def __call__(self, debugger, args_array, exe_ctx, result):
27+
def __call__(self, debugger, args_list, exe_ctx, result):
28+
29+
The arguments will be a list of strings.
2830
29-
The arguments will be in a python array as strings.
31+
You can access the option values using the 'varname' string you passed in when defining the option.
3032
31-
You can access the option values using varname you passed in when defining the option.
3233
If you need to know whether a given option was set by the user or not, you can retrieve
3334
the option definition array with:
3435
3536
self.get_options_definition()
3637
37-
look up your element by varname and check the "_value_set" element.
38+
then look up your element by the 'varname' field, and check the "_value_set" element.
39+
FIXME: I should add a convenience method to do this.
3840
3941
There are example commands in the lldb testsuite at:
4042
4143
llvm-project/lldb/test/API/commands/command/script/add/test_commands.py
42-
43-
FIXME: I should make a convenient wrapper for that.
4444
"""
4545
import inspect
4646
import lldb
4747
import sys
48+
from abc import abstractmethod
4849

4950
class LLDBOVParser:
5051
def __init__(self):
@@ -59,12 +60,16 @@ def __init__(self):
5960
def to_bool(in_value):
6061
error = True
6162
value = False
63+
print(f"TYPE: {type(in_value)}")
64+
if type(in_value) != str or len(in_value) == 0:
65+
return (value, error)
66+
6267
low_in = in_value.lower()
63-
if low_in == "yes" or low_in == "true" or low_in == "1":
68+
if low_in == "y" or low_in == "yes" or low_in == "t" or low_in == "true" or low_in == "1":
6469
value = True
6570
error = False
6671

67-
if not value and low_in == "no" or low_in == "false" or low_in == "0":
72+
if not value and low_in == "n" or low_in == "no" or low_in == "f" or low_in == "false" or low_in == "0":
6873
value = False
6974
error = False
7075

@@ -75,6 +80,7 @@ def to_int(in_value):
7580
#FIXME: Not doing errors yet...
7681
return (int(in_value), False)
7782

83+
@staticmethod
7884
def to_unsigned(in_value):
7985
# FIXME: find an unsigned converter...
8086
# And handle errors.
@@ -102,7 +108,6 @@ def to_unsigned(in_value):
102108

103109
@classmethod
104110
def translate_value(cls, value_type, value):
105-
error = False
106111
try:
107112
return cls.translators[value_type](value)
108113
except KeyError:
@@ -176,7 +181,7 @@ def option_parsing_started(self):
176181
def set_enum_value(self, enum_values, input):
177182
candidates = []
178183
for candidate in enum_values:
179-
# The enum_values are a duple of value & help string.
184+
# The enum_values are a two element list of value & help string.
180185
value = candidate[0]
181186
if value.startswith(input):
182187
candidates.append(value)
@@ -294,9 +299,11 @@ def set_option_value(self, exe_ctx, opt_name, opt_value):
294299
return self.get_parser().set_option_value(exe_ctx, opt_name, opt_value)
295300

296301
# These are the two "pure virtual" methods:
302+
@abstractmethod
297303
def __call__(self, debugger, args_array, exe_ctx, result):
298304
raise NotImplementedError()
299305

306+
@abstractmethod
300307
def setup_command_definition(self):
301308
raise NotImplementedError()
302309

lldb/source/Commands/CommandObjectCommands.cpp

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,13 +1152,13 @@ class CommandObjectPythonFunction : public CommandObjectRaw {
11521152
/// This class implements a "raw" scripted command. lldb does no parsing of the
11531153
/// command line, instead passing the line unaltered (except for backtick
11541154
/// substitution).
1155-
class CommandObjectScriptingObject : public CommandObjectRaw {
1155+
class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
11561156
public:
1157-
CommandObjectScriptingObject(CommandInterpreter &interpreter,
1158-
std::string name,
1159-
StructuredData::GenericSP cmd_obj_sp,
1160-
ScriptedCommandSynchronicity synch,
1161-
CompletionType completion_type)
1157+
CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter,
1158+
std::string name,
1159+
StructuredData::GenericSP cmd_obj_sp,
1160+
ScriptedCommandSynchronicity synch,
1161+
CompletionType completion_type)
11621162
: CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
11631163
m_synchro(synch), m_fetched_help_short(false),
11641164
m_fetched_help_long(false), m_completion_type(completion_type) {
@@ -1169,7 +1169,7 @@ class CommandObjectScriptingObject : public CommandObjectRaw {
11691169
GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
11701170
}
11711171

1172-
~CommandObjectScriptingObject() override = default;
1172+
~CommandObjectScriptingObjectRaw() override = default;
11731173

11741174
void
11751175
HandleArgumentCompletion(CompletionRequest &request,
@@ -1304,32 +1304,30 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
13041304
void OptionParsingStarting(ExecutionContext *execution_context) override {
13051305
ScriptInterpreter *scripter =
13061306
m_interpreter.GetDebugger().GetScriptInterpreter();
1307-
if (!scripter) {
1307+
if (!scripter || !m_cmd_obj_sp)
13081308
return;
1309-
}
1310-
if (!m_cmd_obj_sp) {
1311-
return;
1312-
}
1309+
13131310
scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp);
1314-
};
1311+
}
13151312

13161313
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
13171314
if (!m_options_definition_up)
13181315
return {};
13191316
return llvm::ArrayRef(m_options_definition_up.get(), m_num_options);
13201317
}
13211318

1322-
static bool ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,
1323-
size_t counter, uint32_t &usage_mask, Status &error) {
1319+
static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,
1320+
size_t counter, uint32_t &usage_mask) {
13241321
// If the usage entry is not provided, we use LLDB_OPT_SET_ALL.
13251322
// If the usage mask is a UINT, the option belongs to that group.
13261323
// If the usage mask is a vector of UINT's, the option belongs to all the
13271324
// groups listed.
13281325
// If a subelement of the vector is a vector of two ints, then the option
13291326
// belongs to the inclusive range from the first to the second element.
1327+
Status error;
13301328
if (!obj_sp) {
13311329
usage_mask = LLDB_OPT_SET_ALL;
1332-
return true;
1330+
return error;
13331331
}
13341332

13351333
usage_mask = 0;
@@ -1342,17 +1340,17 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
13421340
if (value == 0) {
13431341
error.SetErrorStringWithFormatv(
13441342
"0 is not a valid group for option {0}", counter);
1345-
return false;
1343+
return error;
13461344
}
13471345
usage_mask = (1 << (value - 1));
1348-
return true;
1346+
return error;
13491347
}
13501348
// Otherwise it has to be an array:
13511349
StructuredData::Array *array_val = obj_sp->GetAsArray();
13521350
if (!array_val) {
13531351
error.SetErrorStringWithFormatv(
13541352
"required field is not a array for option {0}", counter);
1355-
return false;
1353+
return error;
13561354
}
13571355
// This is the array ForEach for accumulating a group usage mask from
13581356
// an array of string descriptions of groups.
@@ -1408,11 +1406,13 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
14081406
}
14091407
return true;
14101408
};
1411-
return array_val->ForEach(groups_accumulator);
1409+
array_val->ForEach(groups_accumulator);
1410+
return error;
14121411
}
14131412

14141413

1415-
Status SetOptionsFromArray(StructuredData::Array &options, Status &error) {
1414+
Status SetOptionsFromArray(StructuredData::Array &options) {
1415+
Status error;
14161416
m_num_options = options.GetSize();
14171417
m_options_definition_up.reset(new OptionDefinition[m_num_options]);
14181418
// We need to hand out pointers to contents of these vectors; we reserve
@@ -1447,8 +1447,8 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
14471447
// Usage Mask:
14481448
StructuredData::ObjectSP obj_sp = opt_dict->GetValueForKey("groups");
14491449
if (obj_sp) {
1450-
ParseUsageMaskFromArray(obj_sp, counter, option_def.usage_mask,
1451-
error);
1450+
error = ParseUsageMaskFromArray(obj_sp, counter,
1451+
option_def.usage_mask);
14521452
if (error.Fail())
14531453
return false;
14541454
}
@@ -1694,6 +1694,34 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
16941694
};
16951695

16961696
public:
1697+
static CommandObjectSP Create(CommandInterpreter &interpreter,
1698+
std::string name,
1699+
StructuredData::GenericSP cmd_obj_sp,
1700+
ScriptedCommandSynchronicity synch,
1701+
CommandReturnObject &result) {
1702+
CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed(
1703+
interpreter, name, cmd_obj_sp, synch));
1704+
1705+
CommandObjectScriptingObjectParsed *parsed_cmd
1706+
= static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get());
1707+
// Now check all the failure modes, and report if found.
1708+
Status opt_error = parsed_cmd->GetOptionsError();
1709+
Status arg_error = parsed_cmd->GetArgsError();
1710+
1711+
if (opt_error.Fail())
1712+
result.AppendErrorWithFormat("failed to parse option definitions: %s",
1713+
opt_error.AsCString());
1714+
if (arg_error.Fail())
1715+
result.AppendErrorWithFormat("%sfailed to parse argument definitions: %s",
1716+
opt_error.Fail() ? ", also " : "",
1717+
arg_error.AsCString());
1718+
1719+
if (!result.Succeeded())
1720+
return {};
1721+
1722+
return new_cmd_sp;
1723+
}
1724+
16971725
CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter,
16981726
std::string name,
16991727
StructuredData::GenericSP cmd_obj_sp,
@@ -1720,7 +1748,7 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
17201748
StructuredData::Array *options_array = options_object_sp->GetAsArray();
17211749
// but if it exists, it has to be an array.
17221750
if (options_array) {
1723-
m_options.SetOptionsFromArray(*(options_array), m_options_error);
1751+
m_options_error = m_options.SetOptionsFromArray(*(options_array));
17241752
// If we got an error don't bother with the arguments...
17251753
if (m_options_error.Fail())
17261754
return;
@@ -1804,8 +1832,8 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
18041832

18051833
// Usage Mask:
18061834
obj_sp = arg_dict->GetValueForKey("groups");
1807-
CommandOptions::ParseUsageMaskFromArray(obj_sp, counter,
1808-
arg_opt_set_association, m_args_error);
1835+
m_args_error = CommandOptions::ParseUsageMaskFromArray(obj_sp,
1836+
counter, arg_opt_set_association);
18091837
this_entry.emplace_back(arg_type, arg_repetition,
18101838
arg_opt_set_association);
18111839
elem_counter++;
@@ -1879,7 +1907,7 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
18791907

18801908

18811909
protected:
1882-
bool DoExecute(Args &args,
1910+
void DoExecute(Args &args,
18831911
CommandReturnObject &result) override {
18841912
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
18851913

@@ -1900,8 +1928,6 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
19001928
result.SetStatus(eReturnStatusSuccessFinishResult);
19011929
}
19021930
}
1903-
1904-
return result.Succeeded();
19051931
}
19061932

19071933
private:
@@ -2306,17 +2332,12 @@ class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
23062332
}
23072333

23082334
if (m_options.m_parsed_command) {
2309-
new_cmd_sp.reset(new CommandObjectScriptingObjectParsed(
2310-
m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity));
2311-
Status options_error
2312-
= static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get())->GetOptionsError();
2313-
if (options_error.Fail()) {
2314-
result.AppendErrorWithFormat("failed to parse option definitions: %s",
2315-
options_error.AsCString());
2316-
return false;
2317-
}
2335+
new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter,
2336+
m_cmd_name, cmd_obj_sp, m_synchronicity, result);
2337+
if (!result.Succeeded())
2338+
return;
23182339
} else
2319-
new_cmd_sp.reset(new CommandObjectScriptingObject(
2340+
new_cmd_sp.reset(new CommandObjectScriptingObjectRaw(
23202341
m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
23212342
m_completion_type));
23222343
}

0 commit comments

Comments
 (0)