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.ov_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 35# Use these to make sure that get_repeat_command sends the right 36# command. 37no_args_repeat = None 38one_arg_repeat = None 39two_arg_repeat = None 40 41class NoArgsCommand(ReportingCmd): 42 program = "no-args" 43 44 def __init__(self, debugger, unused): 45 super().__init__(debugger, unused) 46 47 @classmethod 48 def register_lldb_command(cls, debugger, module_name): 49 ParsedCommand.do_register_cmd(cls, debugger, module_name) 50 51 def setup_command_definition(self): 52 self.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 self.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 self.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 self.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 self.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 self.ov_parser.add_argument_set( 130 [self.ov_parser.make_argument_element(lldb.eArgTypeSourceFile, "plain")] 131 ) 132 133 def get_repeat_command(self, command): 134 # Repeat the current command 135 global one_arg_repeat 136 one_arg_repeat = command 137 return None 138 139 def get_short_help(self): 140 return "Example command for use in debugging" 141 142 def get_long_help(self): 143 return self.help_string 144 145 146class TwoArgGroupsCommand(ReportingCmd): 147 program = "two-args" 148 149 def __init__(self, debugger, unused): 150 super().__init__(debugger, unused) 151 152 @classmethod 153 def register_lldb_command(cls, debugger, module_name): 154 ParsedCommand.do_register_cmd(cls, debugger, module_name) 155 156 def setup_command_definition(self): 157 self.ov_parser.add_option( 158 "l", 159 "language", 160 "language defaults to None", 161 value_type=lldb.eArgTypeLanguage, 162 groups=[1, 2], 163 dest="language", 164 default=None, 165 ) 166 167 self.ov_parser.add_option( 168 "c", 169 "log-channel", 170 "log channel - defaults to lldb", 171 value_type=lldb.eArgTypeLogChannel, 172 groups=[1, 3], 173 dest="log_channel", 174 default="lldb", 175 ) 176 177 self.ov_parser.add_option( 178 "p", 179 "process-name", 180 "A process name, defaults to None", 181 value_type=lldb.eArgTypeProcessName, 182 dest="proc_name", 183 default=None, 184 ) 185 186 self.ov_parser.add_argument_set( 187 [ 188 self.ov_parser.make_argument_element( 189 lldb.eArgTypeClassName, "plain", [1, 2] 190 ), 191 self.ov_parser.make_argument_element( 192 lldb.eArgTypeOffset, "optional", [1, 2] 193 ), 194 ] 195 ) 196 197 self.ov_parser.add_argument_set( 198 [ 199 self.ov_parser.make_argument_element( 200 lldb.eArgTypePythonClass, "plain", [3, 4] 201 ), 202 self.ov_parser.make_argument_element( 203 lldb.eArgTypePid, "optional", [3, 4] 204 ), 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 get_short_help(self): 214 return "This is my short help string" 215 216 def get_long_help(self): 217 return self.help_string 218 219 220def __lldb_init_module(debugger, dict): 221 # Register all classes that have a register_lldb_command method 222 for _name, cls in inspect.getmembers(sys.modules[__name__]): 223 if inspect.isclass(cls) and callable( 224 getattr(cls, "register_lldb_command", None) 225 ): 226 cls.register_lldb_command(debugger, __name__) 227