264 lines · python
1"""2Test defining commands using the lldb command definitions3"""4import inspect5import sys6import lldb7from lldb.plugins.parsed_cmd import ParsedCommand8 9 10class ReportingCmd(ParsedCommand):11 def __init__(self, debugger, unused):12 super().__init__(debugger, unused)13 14 def __call__(self, debugger, args_array, exe_ctx, result):15 opt_def = self.get_options_definition()16 if len(opt_def):17 result.AppendMessage("Options:\n")18 for long_option, elem in opt_def.items():19 if "value_type" in elem:20 print(f"Looking at {long_option} - {elem}")21 dest = elem["dest"]22 result.AppendMessage(23 f"{long_option} (set: {elem['_value_set']}): {object.__getattribute__(self.get_parser(), dest)}\n"24 )25 else:26 result.AppendMessage(27 f"{long_option} (set: {elem['_value_set']}): flag value\n"28 )29 else:30 result.AppendMessage("No options\n")31 32 num_args = args_array.GetSize()33 if num_args > 0:34 result.AppendMessage(f"{num_args} arguments:")35 for idx in range(0, num_args):36 result.AppendMessage(37 f"{idx}: {args_array.GetItemAtIndex(idx).GetStringValue(10000)}\n"38 )39 40# Use these to make sure that get_repeat_command sends the right41# command.42no_args_repeat = None43one_arg_repeat = None44two_arg_repeat = None45 46class NoArgsCommand(ReportingCmd):47 program = "no-args"48 49 def __init__(self, debugger, unused):50 super().__init__(debugger, unused)51 52 @classmethod53 def register_lldb_command(cls, debugger, module_name):54 ParsedCommand.do_register_cmd(cls, debugger, module_name)55 56 def setup_command_definition(self):57 ov_parser = self.get_parser()58 ov_parser.add_option(59 "b",60 "bool-arg",61 "a boolean arg, defaults to True",62 value_type=lldb.eArgTypeBoolean,63 groups=[1, 2],64 dest="bool_arg",65 default=True,66 )67 68 ov_parser.add_option(69 "s",70 "shlib-name",71 "A shared library name.",72 value_type=lldb.eArgTypeShlibName,73 groups=[1, [3, 4]],74 dest="shlib_name",75 default=None,76 )77 78 ov_parser.add_option(79 "d",80 "disk-file-name",81 "An on disk filename",82 value_type=lldb.eArgTypeFilename,83 dest="disk_file_name",84 default=None,85 )86 87 ov_parser.add_option("f", "flag-value", "This is a flag value")88 89 ov_parser.add_option(90 "l",91 "line-num",92 "A line number",93 value_type=lldb.eArgTypeLineNum,94 groups=3,95 dest="line_num",96 default=0,97 )98 99 ov_parser.add_option(100 "e",101 "enum-option",102 "An enum, doesn't actually do anything",103 enum_values=[104 ["foo", "does foo things"],105 ["bar", "does bar things"],106 ["baz", "does baz things"],107 ],108 groups=4,109 dest="enum_option",110 default="foo",111 )112 113 def get_repeat_command(self, command):114 # No auto-repeat115 global no_args_repeat116 no_args_repeat = command117 return ""118 119 def get_short_help(self):120 return "Example command for use in debugging"121 122 def get_long_help(self):123 return self.help_string124 125 126class OneArgCommandNoOptions(ReportingCmd):127 program = "one-arg-no-opt"128 129 def __init__(self, debugger, unused):130 super().__init__(debugger, unused)131 132 @classmethod133 def register_lldb_command(cls, debugger, module_name):134 ParsedCommand.do_register_cmd(cls, debugger, module_name)135 136 def setup_command_definition(self):137 ov_parser = self.get_parser()138 ov_parser.add_argument_set(139 [ov_parser.make_argument_element(lldb.eArgTypeSourceFile, "plain")]140 )141 142 def get_repeat_command(self, command):143 # Repeat the current command144 global one_arg_repeat145 one_arg_repeat = command146 return None147 148 def get_short_help(self):149 return "Example command for use in debugging"150 151 def get_long_help(self):152 return self.help_string153 154 155class TwoArgGroupsCommand(ReportingCmd):156 program = "two-args"157 158 def __init__(self, debugger, unused):159 super().__init__(debugger, unused)160 161 @classmethod162 def register_lldb_command(cls, debugger, module_name):163 ParsedCommand.do_register_cmd(cls, debugger, module_name)164 165 def setup_command_definition(self):166 ov_parser = self.get_parser()167 ov_parser.add_option(168 "l",169 "language",170 "language defaults to None",171 value_type=lldb.eArgTypeLanguage,172 groups=[1, 2],173 dest="language",174 default=None,175 )176 177 ov_parser.add_option(178 "c",179 "log-channel",180 "log channel - defaults to lldb",181 value_type=lldb.eArgTypeLogChannel,182 groups=[1, 3],183 dest="log_channel",184 default="lldb",185 )186 187 ov_parser.add_option(188 "p",189 "process-name",190 "A process name, defaults to None",191 value_type=lldb.eArgTypeProcessName,192 dest="proc_name",193 default=None,194 )195 196 ov_parser.add_argument_set(197 [198 ov_parser.make_argument_element(199 lldb.eArgTypeClassName, "plain", [1, 2]200 ),201 ov_parser.make_argument_element(202 lldb.eArgTypeOffset, "optional", [1, 2]203 ),204 ]205 )206 207 ov_parser.add_argument_set(208 [209 ov_parser.make_argument_element(210 lldb.eArgTypePythonClass, "plain", [3, 4]211 ),212 ov_parser.make_argument_element(lldb.eArgTypePid, "optional", [3, 4]),213 ]214 )215 216 def get_repeat_command(self, command):217 global two_arg_repeat218 two_arg_repeat = command219 return command + " THIRD_ARG"220 221 def handle_option_argument_completion(self, long_option, cursor_pos):222 ov_parser = self.get_parser()223 value = ov_parser.dest_for_option(long_option)[0 : cursor_pos + 1]224 proc_value = ov_parser.proc_name225 if proc_value != None:226 new_str = value + proc_value227 ret_arr = {"completion": new_str, "mode": "partial"}228 return ret_arr229 230 ret_arr = {"values": [value + "nice", value + "not_nice", value + "mediocre"]}231 return ret_arr232 233 def handle_argument_completion(self, args, arg_pos, cursor_pos):234 ov_parser = self.get_parser()235 orig_arg = args[arg_pos][0:cursor_pos]236 if orig_arg == "correct_":237 ret_arr = {"completion": "correct_answer"}238 return ret_arr239 240 if ov_parser.was_set("process-name"):241 # No completions if proc_name was set.242 return True243 244 ret_arr = {245 "values": [orig_arg + "cool", orig_arg + "yuck"],246 "descriptions": ["good idea", "bad idea"],247 }248 return ret_arr249 250 def get_short_help(self):251 return "This is my short help string"252 253 def get_long_help(self):254 return self.help_string255 256 257def __lldb_init_module(debugger, dict):258 # Register all classes that have a register_lldb_command method259 for _name, cls in inspect.getmembers(sys.modules[__name__]):260 if inspect.isclass(cls) and callable(261 getattr(cls, "register_lldb_command", None)262 ):263 cls.register_lldb_command(debugger, __name__)264