""" Test defining commands using the lldb command definitions """ import inspect import sys import lldb from lldb.plugins.parsed_cmd import ParsedCommand class ReportingCmd(ParsedCommand): def __init__(self, debugger, unused): super().__init__(debugger, unused) def __call__(self, debugger, args_array, exe_ctx, result): opt_def = self.get_options_definition() if len(opt_def): result.AppendMessage("Options:\n") for long_option, elem in opt_def.items(): dest = elem["dest"] result.AppendMessage( f"{long_option} (set: {elem['_value_set']}): {object.__getattribute__(self.get_parser(), dest)}\n" ) else: result.AppendMessage("No options\n") num_args = args_array.GetSize() if num_args > 0: result.AppendMessage(f"{num_args} arguments:") for idx in range(0, num_args): result.AppendMessage( f"{idx}: {args_array.GetItemAtIndex(idx).GetStringValue(10000)}\n" ) # Use these to make sure that get_repeat_command sends the right # command. no_args_repeat = None one_arg_repeat = None two_arg_repeat = None class NoArgsCommand(ReportingCmd): program = "no-args" def __init__(self, debugger, unused): super().__init__(debugger, unused) @classmethod def register_lldb_command(cls, debugger, module_name): ParsedCommand.do_register_cmd(cls, debugger, module_name) def setup_command_definition(self): ov_parser = self.get_parser() ov_parser.add_option( "b", "bool-arg", "a boolean arg, defaults to True", value_type=lldb.eArgTypeBoolean, groups=[1, 2], dest="bool_arg", default=True, ) ov_parser.add_option( "s", "shlib-name", "A shared library name.", value_type=lldb.eArgTypeShlibName, groups=[1, [3, 4]], dest="shlib_name", default=None, ) ov_parser.add_option( "d", "disk-file-name", "An on disk filename", value_type=lldb.eArgTypeFilename, dest="disk_file_name", default=None, ) ov_parser.add_option( "l", "line-num", "A line number", value_type=lldb.eArgTypeLineNum, groups=3, dest="line_num", default=0, ) ov_parser.add_option( "e", "enum-option", "An enum, doesn't actually do anything", enum_values=[ ["foo", "does foo things"], ["bar", "does bar things"], ["baz", "does baz things"], ], groups=4, dest="enum_option", default="foo", ) def get_repeat_command(self, command): # No auto-repeat global no_args_repeat no_args_repeat = command return "" def get_short_help(self): return "Example command for use in debugging" def get_long_help(self): return self.help_string class OneArgCommandNoOptions(ReportingCmd): program = "one-arg-no-opt" def __init__(self, debugger, unused): super().__init__(debugger, unused) @classmethod def register_lldb_command(cls, debugger, module_name): ParsedCommand.do_register_cmd(cls, debugger, module_name) def setup_command_definition(self): ov_parser = self.get_parser() ov_parser.add_argument_set( [ov_parser.make_argument_element(lldb.eArgTypeSourceFile, "plain")] ) def get_repeat_command(self, command): # Repeat the current command global one_arg_repeat one_arg_repeat = command return None def get_short_help(self): return "Example command for use in debugging" def get_long_help(self): return self.help_string class TwoArgGroupsCommand(ReportingCmd): program = "two-args" def __init__(self, debugger, unused): super().__init__(debugger, unused) @classmethod def register_lldb_command(cls, debugger, module_name): ParsedCommand.do_register_cmd(cls, debugger, module_name) def setup_command_definition(self): ov_parser = self.get_parser() ov_parser.add_option( "l", "language", "language defaults to None", value_type=lldb.eArgTypeLanguage, groups=[1, 2], dest="language", default=None, ) ov_parser.add_option( "c", "log-channel", "log channel - defaults to lldb", value_type=lldb.eArgTypeLogChannel, groups=[1, 3], dest="log_channel", default="lldb", ) ov_parser.add_option( "p", "process-name", "A process name, defaults to None", value_type=lldb.eArgTypeProcessName, dest="proc_name", default=None, ) ov_parser.add_argument_set( [ ov_parser.make_argument_element( lldb.eArgTypeClassName, "plain", [1, 2] ), ov_parser.make_argument_element( lldb.eArgTypeOffset, "optional", [1, 2] ), ] ) ov_parser.add_argument_set( [ ov_parser.make_argument_element( lldb.eArgTypePythonClass, "plain", [3, 4] ), ov_parser.make_argument_element(lldb.eArgTypePid, "optional", [3, 4]), ] ) def get_repeat_command(self, command): global two_arg_repeat two_arg_repeat = command return command + " THIRD_ARG" def handle_option_argument_completion(self, long_option, cursor_pos): ov_parser = self.get_parser() value = ov_parser.dest_for_option(long_option)[0 : cursor_pos + 1] proc_value = ov_parser.proc_name if proc_value != None: new_str = value + proc_value ret_arr = {"completion": new_str, "mode": "partial"} return ret_arr ret_arr = {"values": [value + "nice", value + "not_nice", value + "mediocre"]} return ret_arr def handle_argument_completion(self, args, arg_pos, cursor_pos): ov_parser = self.get_parser() orig_arg = args[arg_pos][0:cursor_pos] if orig_arg == "correct_": ret_arr = {"completion": "correct_answer"} return ret_arr if ov_parser.was_set("process-name"): # No completions if proc_name was set. return True ret_arr = { "values": [orig_arg + "cool", orig_arg + "yuck"], "descriptions": ["good idea", "bad idea"], } return ret_arr def get_short_help(self): return "This is my short help string" def get_long_help(self): return self.help_string def __lldb_init_module(debugger, dict): # Register all classes that have a register_lldb_command method for _name, cls in inspect.getmembers(sys.modules[__name__]): if inspect.isclass(cls) and callable( getattr(cls, "register_lldb_command", None) ): cls.register_lldb_command(debugger, __name__)