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