================ @@ -0,0 +1,420 @@ +# Writing Custom Commands + +### Create a new command using a Python function + +Python functions can be used to create new LLDB command interpreter commands, +which will work like all the natively defined lldb commands. This provides a +very flexible and easy way to extend LLDB to meet your debugging requirements. + +To write a python function that implements a new LLDB command define the +function to take five arguments as follows: + +```python3 +def command_function(debugger, command, exe_ctx, result, internal_dict): + # Your code goes here +``` + +The meaning of the arguments is given in the table below. + +If you provide a Python docstring in your command function LLDB will use it +when providing "long help" for your command, as in: + +```python3 +def command_function(debugger, command, result, internal_dict): + """This command takes a lot of options and does many fancy things""" + # Your code goes here +``` + +though providing help can also be done programmatically (see below). + +Prior to lldb 3.5.2 (April 2015), LLDB Python command definitions didn't take the SBExecutionContext +argument. So you may still see commands where the command definition is: + +```python3 +def command_function(debugger, command, result, internal_dict): + # Your code goes here +``` + +Using this form is strongly discouraged because it can only operate on the "currently selected" +target, process, thread, frame. The command will behave as expected when run +directly on the command line. But if the command is used in a stop-hook, breakpoint +callback, etc. where the response to the callback determines whether we will select +this or that particular process/frame/thread, the global "currently selected" +entity is not necessarily the one the callback is meant to handle. In that case, this +command definition form can't do the right thing. + +| Argument | Type | Description | +|----------|------|-------------| +| `debugger` | `lldb.SBDebugger` | The current debugger object. | +| `command` | `python string` | A python string containing all arguments for your command. If you need to chop up the arguments try using the `shlex` module's `shlex.split(command)` to properly extract the arguments. | +| `exe_ctx` | `lldb.SBExecutionContext` | An execution context object carrying around information on the inferior process' context in which the command is expected to act *Optional since lldb 3.5.2, unavailable before* | +| `result` | `lldb.SBCommandReturnObject` | A return object which encapsulates success/failure information for the command and output text that needs to be printed as a result of the command. The plain Python "print" command also works but text won't go in the result by default (it is useful as a temporary logging facility). | +| `internal_dict` | `python dict object` | The dictionary for the current embedded script session which contains all variables and functions. | + +### Create a new command using a Python class + +Since lldb 3.7, Python commands can also be implemented by means of a class +which should implement the following interface: + +```python3 +class CommandObjectType: + def __init__(self, debugger, internal_dict): + # this call should initialize the command with respect to the command interpreter for the passed-in debugger + + def __call__(self, debugger, command, exe_ctx, result): + # this is the actual bulk of the command, akin to Python command functions + + def get_short_help(self): + # this call should return the short help text for this command[1] + + def get_long_help(self): + # this call should return the long help text for this command[1] + + def get_flags(self): + # this will be called when the command is added to the command interpreter, + # and should return a flag field made from or-ing together the appropriate + # elements of the lldb.CommandFlags enum to specify the requirements of this command. + # The CommandInterpreter will make sure all these requirements are met, and will + # return the standard lldb error if they are not.[1] + + def get_repeat_command(self, command): + # The auto-repeat command is what will get executed when the user types just + # a return at the next prompt after this command is run. Even if your command + # was run because it was specified as a repeat command, that invocation will still + # get asked for IT'S repeat command, so you can chain a series of repeats, for instance + # to implement a pager. + + # The command argument is the command that is about to be executed. + + # If this call returns None, then the ordinary repeat mechanism will be used + # If this call returns an empty string, then auto-repeat is disabled + # If this call returns any other string, that will be the repeat command [1] +``` + +[1] This method is optional. + +As a convenience, you can treat the result object as a Python file object, and +say + +```python3 +print("my command does lots of cool stuff", file=result) +``` + +`SBCommandReturnObject` and `SBStream` both support this file-like behavior by +providing `write()` and `flush()` calls at the Python layer. + +### Parsed Commands + +The commands that are added using this class definition are what lldb calls +"raw" commands. The command interpreter doesn't attempt to parse the command, +doesn't handle option values, neither generating help for them, or their +completion. Raw commands are useful when the arguments passed to the command +are unstructured, and having to protect them against lldb command parsing would +be onerous. For instance, "expr" is a raw command. + +You can also add scripted commands that implement the "parsed command", where +the options and their types are specified, as well as the argument and argument +types. These commands look and act like the majority of lldb commands, and you +can also add custom completions for the options and/or the arguments if you have +special needs. + +The easiest way to do this is to derive your new command from the lldb.ParsedCommand +class. That responds in the same way to the help & repeat command interfaces, and +provides some convenience methods, and most importantly an LLDBOptionValueParser, +accessed through lldb.ParsedCommand.get_parser(). The parser is used to set +your command definitions, and to retrieve option values in the `__call__` method. + +To set up the command definition, implement the ParsedCommand abstract method: + +```python3 +def setup_command_definition(self): +``` + +This is called when your command is added to lldb. In this method you add the +options and their types, the option help strings, etc. to the command using the API: + +```python3 +def add_option(self, short_option, long_option, help, default, + dest = None, required=False, groups = None, + value_type=lldb.eArgTypeNone, completion_type=None, + enum_values=None): + """ + short_option: one character, must be unique, not required + long_option: no spaces, must be unique, required + help: a usage string for this option, will print in the command help + default: the initial value for this option (if it has a value) + dest: the name of the property that gives you access to the value for + this value. Defaults to the long option if not provided. + required: if true, this option must be provided or the command will error out + groups: Which "option groups" does this option belong to. This can either be + a simple list (e.g. [1, 3, 4, 5]) or you can specify ranges by sublists: + so [1, [3,5]] is the same as [1, 3, 4, 5]. + value_type: one of the lldb.eArgType enum values. Some of the common arg + types also have default completers, which will be applied automatically. + completion_type: currently these are values form the lldb.CompletionType enum. If + you need custom completions, implement handle_option_argument_completion. + enum_values: An array of duples: ["element_name", "element_help"]. If provided, + only one of the enum elements is allowed. The value will be the + element_name for the chosen enum element as a string. + """ +``` + +Similarly, you can add argument types to the command: + +```python3 +def make_argument_element(self, arg_type, repeat = "optional", groups = None): + """ + arg_type: The argument type, one of the lldb.eArgType enum values. + repeat: Choose from the following options: + "plain" - one value + "optional" - zero or more values + "plus" - one or more values + groups: As with add_option. + """ +``` + +Then implement the body of the command by defining: + +```python3 +def __call__(self, debugger, args_array, exe_ctx, result): + """This is the command callback. The option values are + provided by the 'dest' properties on the parser. + + args_array: This is the list of arguments provided. + exe_ctx: Gives the SBExecutionContext on which the + command should operate. + result: Any results of the command should be + written into this SBCommandReturnObject. + """ +``` + +This differs from the "raw" command's `__call__` in that the arguments are already +parsed into the args_array, and the option values are set in the parser, and +can be accessed using their property name. The LLDBOptionValueParser class has +a couple of other handy methods: + +```python3 +def was_set(self, long_option_name): +``` + +returns `True` if the option was specified on the command line. + +```python +def dest_for_option(self, long_option_name): +""" +This will return the value of the dest variable you defined for opt_name. +Mostly useful for handle_completion where you get passed the long option. +""" +``` + +### Completion + +lldb will handle completing your option names, and all your enum values +automatically. If your option or argument types have associated built-in completers, +then lldb will also handle that completion for you. But if you have a need for +custom completions, either in your arguments or option values, you can handle +completion by hand as well. To handle completion of option value arguments, +your lldb.ParsedCommand subclass should implement: + +```python3 +def handle_option_argument_completion(self, long_option, cursor_pos): +""" +long_option: The long option name of the option whose value you are + asked to complete. +cursor_pos: The cursor position in the value for that option - which +you can get from the option parser. +""" +``` + +And to handle the completion of arguments: + +```python3 +def handle_argument_completion(self, args, arg_pos, cursor_pos): +""" +args: A list of the arguments to the command +arg_pos: An index into the args list of the argument with the cursor +cursor_pos: The cursor position in the arg specified by arg_pos +""" +``` + +When either of these API's is called, the command line will have been parsed up to +the word containing the cursor, and any option values set in that part of the command +string are available from the option value parser. That's useful for instance +if you have a --shared-library option that would constrain the completions for, +say, a symbol name option or argument. + +The return value specifies what the completion options are. You have four +choices: + +- `True`: the completion was handled with no completions. + +- `False`: the completion was not handled, forward it to the regular +completion machinery. + +- A dictionary with the key: "completion": there is one candidate, +whose value is the value of the "completion" key. Optionally you can pass a +"mode" key whose value is either "partial" or "complete". Return partial if +the "completion" string is a prefix for all the completed value. + +For instance, if the string you are completing is "Test" and the available completions are: +"Test1", "Test11" and "Test111", you should return the dictionary: + +```python3 +return {"completion": "Test1", "mode" : "partial"} +``` + +and then lldb will add the "1" at the cursor and advance it after the added string, +waiting for more completions. But if "Test1" is the only completion, return: + +```python3 +{"completion": "Test1", "mode": "complete"} +``` + +and lldb will add "1 " at the cursor, indicating the command string is complete. + +The default is "complete", you don't need to specify a "mode" in that case. + +- A dictionary with the key: "values" whose value is a list of candidate completion +strings. The command interpreter will present those strings as the available choices. +You can optionally include a "descriptions" key, whose value is a parallel array +of description strings, and the completion will show the description next to +each completion. + +## Loading Commands + +One other handy convenience when defining lldb command-line commands is the +command "command script import" which will import a module specified by file +path, so you don't have to change your PYTHONPATH for temporary scripts. It +also has another convenience that if your new script module has a function of +the form: + +```python +def __lldb_init_module(debugger, internal_dict): ---------------- kastiglione wrote:
What do you think of documenting the `lldb.command` decorator? For python commands, I use it instead of `__lldb_init_module`. ```python3 import lldb @lldb.command() def goodstuff(debugger, command, ctx, result, _): """command help string" # command implementation ``` this creates a command using the same name as the function, and using the optional docstring as the command's help. https://github.com/llvm/llvm-project/pull/158331 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits