xref: /llvm-project/lldb/examples/python/templates/parsed_cmd.py (revision 04b443e77845cd20ab5acc4356cee509316135dd)
1"""
2This module implements a couple of utility classes to make writing
3lldb parsed commands more Pythonic.
4The way to use it is to make a class for your command that inherits from ParsedCommandBase.
5That will make an LLDBOptionValueParser which you will use for your
6option definition, and to fetch option values for the current invocation
7of your command.  For concision, I'll call this the `OVParser`.
8Access to the `OVParser` is through:
9
10ParsedCommandBase.get_parser()
11
12Next, implement setup_command_definition() in your new command class, and call:
13
14  self.get_parser().add_option()
15
16to add all your options.  The order doesn't matter for options, lldb will sort them
17alphabetically for you when it prints help.
18
19Similarly you can define the arguments with:
20
21  self.get_parser().add_argument()
22
23At present, lldb doesn't do as much work as it should verifying arguments, it
24only checks that commands that take no arguments don't get passed arguments.
25
26Then implement the execute function for your command as:
27
28    def __call__(self, debugger, args_list, exe_ctx, result):
29
30The arguments will be a list of strings.
31
32You can access the option values using the 'dest' string you passed in when defining the option.
33And if you need to know whether a given option was set by the user or not, you can
34use the was_set API.
35
36So for instance, if you have an option whose "dest" is "my_option", then:
37
38    self.get_parser().my_option
39
40will fetch the value, and:
41
42    self.get_parser().was_set("my_option")
43
44will return True if the user set this option, and False if it was left at its default
45value.
46
47Custom Completions:
48
49You can also implement custom completers for your custom command, either for the
50arguments to your command or to the option values in your command.  If you use enum
51values or if your option/argument uses is one of the types we have completers for,
52you should not need to do this.  But if you have your own completeable types, or if
53you want completion of one option to be conditioned by other options on the command
54line, you can use this interface to take over the completion.
55
56You can choose to add a completion for the option values defined for your command,
57or for the arguments, separately.  For the option values, define:
58
59def handle_option_argument_completion(self, long_option, cursor_pos):
60
61The line to be completed will be parsed up to the option containint the cursor position,
62and the values will be set in the OptionValue parser object.  long_option will be
63the option name containing the cursor, and cursor_pos will be the position of the cursor
64in that option's value.  You can call the `OVParser` method: `dest_for_option(long_option)`
65to get the value for that option.  The other options that came before the cursor in the command
66line will also be set in the `OVParser` when the completion handler is called.
67
68For argument values, define:
69
70def handle_argument_completion(self, args, arg_pos, cursor_pos):
71
72Again, the command line will be parsed up to the cursor position, and all the options
73before the cursor pose will be set in the `OVParser`.  args is a python list of the
74arguments, arg_pos is the index of the argument with the cursor, and cursor_pos is
75the position of the cursor in the argument.
76
77In both cases, the return value determines the completion.
78
79Return False to mean "Not Handled" - in which case lldb will fall back on the
80standard completion machinery.
81
82Return True to mean "Handled with no completions".
83
84If there is a single unique completion, return a Python dictionary with two elements:
85
86return {"completion" : "completed_value", "mode" : <"partial", "complete">}
87
88If the mode is "partial", then the completion is to a common base, if it is "complete"
89then the argument is considered done - mostly meaning lldb will put a space after the
90completion string.  "complete" is the default if no "mode" is specified.
91
92If there are multiple completion options, then return:
93
94return {"values" : ["option1", "option2"]}
95
96Optionally, you can return a parallel array of "descriptions" which the completer will
97print alongside the options:
98
99return {"values" : ["option1", "option2"], "descriptions" : ["the first option", "the second option"]}
100
101The cmdtemplate example currently uses the parsed command infrastructure:
102
103llvm-project/lldb/examples/python/cmdtemplate.py
104
105There are also a few example commands in the lldb testsuite at:
106
107llvm-project/lldb/test/API/commands/command/script/add/test_commands.py
108"""
109import inspect
110import lldb
111import sys
112from abc import abstractmethod
113
114# Some methods to translate common value types.  Should return a
115# tuple of the value and an error value (True => error) if the
116# type can't be converted.  These are called internally when the
117# command line is parsed into the 'dest' properties, you should
118# not need to call them directly.
119# FIXME: Need a way to push the conversion error string back to lldb.
120def to_bool(in_value):
121    error = True
122    value = False
123    if type(in_value) != str or len(in_value) == 0:
124        return (value, error)
125
126    low_in = in_value.lower()
127    if low_in in ["y", "yes", "t", "true", "1"]:
128        value = True
129        error = False
130
131    if not value and low_in in ["n", "no", "f", "false", "0"]:
132        value = False
133        error = False
134
135    return (value, error)
136
137def to_int(in_value):
138    #FIXME: Not doing errors yet...
139    return (int(in_value), False)
140
141def to_unsigned(in_value):
142    # FIXME: find an unsigned converter...
143    # And handle errors.
144    return (int(in_value), False)
145
146translators = {
147    lldb.eArgTypeBoolean : to_bool,
148    lldb.eArgTypeBreakpointID : to_unsigned,
149    lldb.eArgTypeByteSize : to_unsigned,
150    lldb.eArgTypeCount : to_unsigned,
151    lldb.eArgTypeFrameIndex : to_unsigned,
152    lldb.eArgTypeIndex : to_unsigned,
153    lldb.eArgTypeLineNum : to_unsigned,
154    lldb.eArgTypeNumLines : to_unsigned,
155    lldb.eArgTypeNumberPerLine : to_unsigned,
156    lldb.eArgTypeOffset : to_int,
157    lldb.eArgTypeThreadIndex : to_unsigned,
158    lldb.eArgTypeUnsignedInteger : to_unsigned,
159    lldb.eArgTypeWatchpointID : to_unsigned,
160    lldb.eArgTypeColumnNum : to_unsigned,
161    lldb.eArgTypeRecognizerID : to_unsigned,
162    lldb.eArgTypeTargetID : to_unsigned,
163    lldb.eArgTypeStopHookID : to_unsigned
164}
165
166def translate_value(value_type, value):
167    try:
168        return translators[value_type](value)
169    except KeyError:
170        # If we don't have a translator, return the string value.
171        return (value, False)
172
173class LLDBOptionValueParser:
174    """
175    This class holds the option definitions for the command, and when
176    the command is run, you can ask the parser for the current values.  """
177
178    def __init__(self):
179        # This is a dictionary of dictionaries.  The key is the long option
180        # name, and the value is the rest of the definition.
181        self.options_dict = {}
182        self.args_array = []
183
184
185    # FIXME: would this be better done on the C++ side?
186    # The common completers are missing some useful ones.
187    # For instance there really should be a common Type completer
188    # And an "lldb command name" completer.
189    completion_table = {
190        lldb.eArgTypeAddressOrExpression : lldb.eVariablePathCompletion,
191        lldb.eArgTypeArchitecture : lldb.eArchitectureCompletion,
192        lldb.eArgTypeBreakpointID : lldb.eBreakpointCompletion,
193        lldb.eArgTypeBreakpointIDRange : lldb.eBreakpointCompletion,
194        lldb.eArgTypeBreakpointName : lldb.eBreakpointNameCompletion,
195        lldb.eArgTypeClassName : lldb.eSymbolCompletion,
196        lldb.eArgTypeDirectoryName : lldb.eDiskDirectoryCompletion,
197        lldb.eArgTypeExpression : lldb.eVariablePathCompletion,
198        lldb.eArgTypeExpressionPath : lldb.eVariablePathCompletion,
199        lldb.eArgTypeFilename : lldb.eDiskFileCompletion,
200        lldb.eArgTypeFrameIndex : lldb.eFrameIndexCompletion,
201        lldb.eArgTypeFunctionName : lldb.eSymbolCompletion,
202        lldb.eArgTypeFunctionOrSymbol : lldb.eSymbolCompletion,
203        lldb.eArgTypeLanguage : lldb.eTypeLanguageCompletion,
204        lldb.eArgTypePath : lldb.eDiskFileCompletion,
205        lldb.eArgTypePid : lldb.eProcessIDCompletion,
206        lldb.eArgTypeProcessName : lldb.eProcessNameCompletion,
207        lldb.eArgTypeRegisterName : lldb.eRegisterCompletion,
208        lldb.eArgTypeRunArgs : lldb.eDiskFileCompletion,
209        lldb.eArgTypeShlibName : lldb.eModuleCompletion,
210        lldb.eArgTypeSourceFile : lldb.eSourceFileCompletion,
211        lldb.eArgTypeSymbol : lldb.eSymbolCompletion,
212        lldb.eArgTypeThreadIndex : lldb.eThreadIndexCompletion,
213        lldb.eArgTypeVarName : lldb.eVariablePathCompletion,
214        lldb.eArgTypePlatform : lldb.ePlatformPluginCompletion,
215        lldb.eArgTypeWatchpointID : lldb.eWatchpointIDCompletion,
216        lldb.eArgTypeWatchpointIDRange : lldb.eWatchpointIDCompletion,
217        lldb.eArgTypeModuleUUID : lldb.eModuleUUIDCompletion,
218        lldb.eArgTypeStopHookID : lldb.eStopHookIDCompletion
219    }
220
221    @classmethod
222    def determine_completion(cls, arg_type):
223        return cls.completion_table.get(arg_type, lldb.eNoCompletion)
224
225    def add_argument_set(self, arguments):
226        self.args_array.append(arguments)
227
228    def get_option_element(self, long_name):
229        return self.options_dict.get(long_name, None)
230
231    def is_enum_opt(self, opt_name):
232        elem = self.get_option_element(opt_name)
233        if not elem:
234            return False
235        return "enum_values" in elem
236
237    def option_parsing_started(self):
238        """ This makes the ivars for all the "dest" values in the array and gives them
239            their default values.  You should not have to call this by hand, though if
240            you have some option that needs to do some work when a new command invocation
241            starts, you can override this to handle your special option.  """
242        for key, elem in self.options_dict.items():
243            elem['_value_set'] = False
244            try:
245                object.__setattr__(self, elem["dest"], elem["default"])
246            except AttributeError:
247                # It isn't an error not to have a "dest" variable name, you'll
248                # just have to manage this option's value on your own.
249                continue
250
251    def set_enum_value(self, enum_values, input):
252        """ This sets the value for an enum option, you should not have to call this
253        by hand.  """
254        candidates = []
255        for candidate in enum_values:
256            # The enum_values are a two element list of value & help string.
257            value = candidate[0]
258            if value.startswith(input):
259                candidates.append(value)
260
261        if len(candidates) == 1:
262            return (candidates[0], False)
263        else:
264            return (input, True)
265
266    def set_option_value(self, exe_ctx, opt_name, opt_value):
267        """ This sets a single option value.  This will handle most option
268        value types, but if you have an option that has some complex behavior,
269        you can override this to implement that behavior, and then pass the
270        rest of the options to the base class implementation. """
271        elem = self.get_option_element(opt_name)
272        if not elem:
273            return False
274
275        if "enum_values" in elem:
276            (value, error) = self.set_enum_value(elem["enum_values"], opt_value)
277        else:
278            (value, error)  = translate_value(elem["value_type"], opt_value)
279
280        if error:
281            return False
282
283        object.__setattr__(self, elem["dest"], value)
284        elem["_value_set"] = True
285        return True
286
287    def was_set(self, opt_name):
288        """Call this in the __call__ method of your command to determine
289        whether this option was set on the command line.  It is sometimes
290        useful to know whether an option has the default value because the
291        user set it explicitly (was_set -> True) or not.
292        You can also call this in a handle_completion method, but it will
293        currently only report true values for the options mentioned
294        BEFORE the cursor point in the command line.
295        """
296
297        elem = self.get_option_element(opt_name)
298        if not elem:
299            return False
300        try:
301            return elem["_value_set"]
302        except AttributeError:
303            return False
304
305    def dest_for_option(self, opt_name):
306        """This will return the value of the dest variable you defined for opt_name.
307        Mostly useful for handle_completion where you get passed the long option.
308        """
309        elem = self.get_option_element(opt_name)
310        if not elem:
311            return None
312        value = self.__dict__[elem["dest"]]
313        return value
314
315    def add_option(self, short_option, long_option, help, default,
316                   dest = None, required=False, groups = None,
317                   value_type=lldb.eArgTypeNone, completion_type=None,
318                   enum_values=None):
319        """
320        short_option: one character, must be unique, not required
321        long_option: no spaces, must be unique, required
322        help: a usage string for this option, will print in the command help
323        default: the initial value for this option (if it has a value)
324        dest: the name of the property that gives you access to the value for
325                 this value.  Defaults to the long option if not provided.
326        required: if true, this option must be provided or the command will error out
327        groups: Which "option groups" does this option belong to.  This can either be
328                a simple list (e.g. [1, 3, 4, 5]) or you can specify ranges by sublists:
329                so [1, [3,5]] is the same as [1, 3, 4, 5].
330        value_type: one of the lldb.eArgType enum values.  Some of the common arg
331                    types also have default completers, which will be applied automatically.
332        completion_type: currently these are values form the lldb.CompletionType enum.  If
333                         you need custom completions, implement handle_option_argument_completion.
334        enum_values: An array of duples: ["element_name", "element_help"].  If provided,
335                     only one of the enum elements is allowed.  The value will be the
336                     element_name for the chosen enum element as a string.
337        """
338        if not dest:
339            dest = long_option
340
341        if not completion_type:
342            completion_type = self.determine_completion(value_type)
343
344        dict = {"short_option" : short_option,
345                "required" : required,
346                "help" : help,
347                "value_type" : value_type,
348                "completion_type" : completion_type,
349                "dest" : dest,
350                "default" : default}
351
352        if enum_values:
353            dict["enum_values"] = enum_values
354        if groups:
355            dict["groups"] = groups
356
357        self.options_dict[long_option] = dict
358
359    def make_argument_element(self, arg_type, repeat = "optional", groups = None):
360        element = {"arg_type" : arg_type, "repeat" : repeat}
361        if groups:
362            element["groups"] = groups
363        return element
364
365class ParsedCommand:
366    def __init__(self, debugger, unused):
367        self.debugger = debugger
368        self.ov_parser = LLDBOptionValueParser()
369        self.setup_command_definition()
370
371    def get_options_definition(self):
372        return self.get_parser().options_dict
373
374    def get_flags(self):
375        return 0
376
377    def get_args_definition(self):
378        return self.get_parser().args_array
379
380    # The base class will handle calling these methods
381    # when appropriate.
382
383    def option_parsing_started(self):
384        self.get_parser().option_parsing_started()
385
386    def set_option_value(self, exe_ctx, opt_name, opt_value):
387        return self.get_parser().set_option_value(exe_ctx, opt_name, opt_value)
388
389    def get_parser(self):
390        """Returns the option value parser for this command.
391        When defining the command, use the parser to add
392        argument and option definitions to the command.
393        When you are in the command callback, the parser
394        gives you access to the options passes to this
395        invocation"""
396
397        return self.ov_parser
398
399    # These are the two "pure virtual" methods:
400    @abstractmethod
401    def __call__(self, debugger, args_array, exe_ctx, result):
402        """This is the command callback.  The option values are
403        provided by the 'dest' properties on the parser.
404
405        args_array: This is the list of arguments provided.
406        exe_ctx: Gives the SBExecutionContext on which the
407                 command should operate.
408        result:  Any results of the command should be
409                 written into this SBCommandReturnObject.
410        """
411        raise NotImplementedError()
412
413    @abstractmethod
414    def setup_command_definition(self):
415        """This will be called when your command is added to
416        the command interpreter.  Here is where you add your
417        options and argument definitions for the command."""
418        raise NotImplementedError()
419
420    @staticmethod
421    def do_register_cmd(cls, debugger, module_name):
422        """ Add any commands contained in this module to LLDB """
423        command = "command script add -o -p -c %s.%s %s" % (
424            module_name,
425            cls.__name__,
426            cls.program,
427        )
428        debugger.HandleCommand(command)
429        print(
430            'The "{0}" command has been installed, type "help {0}"'
431            'for detailed help.'.format(cls.program)
432        )
433