1""" 2This module implements a couple of utility classes to make writing 3lldb parsed commands more Pythonic. 4The way to use it is to make a class for your command that inherits from ParsedCommandBase. 5That will make an LLDBOptionValueParser which you will use for your 6option definition, and to fetch option values for the current invocation 7of your command. For concision, I'll call this the `OVParser`. 8Access to the `OVParser` is through: 9 10ParsedCommandBase.get_parser() 11 12Next, implement setup_command_definition() in your new command class, and call: 13 14 self.get_parser().add_option() 15 16to add all your options. The order doesn't matter for options, lldb will sort them 17alphabetically for you when it prints help. 18 19Similarly you can define the arguments with: 20 21 self.get_parser().add_argument() 22 23At present, lldb doesn't do as much work as it should verifying arguments, it 24only checks that commands that take no arguments don't get passed arguments. 25 26Then implement the execute function for your command as: 27 28 def __call__(self, debugger, args_list, exe_ctx, result): 29 30The arguments will be a list of strings. 31 32You can access the option values using the 'dest' string you passed in when defining the option. 33And if you need to know whether a given option was set by the user or not, you can 34use the was_set API. 35 36So for instance, if you have an option whose "dest" is "my_option", then: 37 38 self.get_parser().my_option 39 40will fetch the value, and: 41 42 self.get_parser().was_set("my_option") 43 44will return True if the user set this option, and False if it was left at its default 45value. 46 47Custom Completions: 48 49You can also implement custom completers for your custom command, either for the 50arguments to your command or to the option values in your command. If you use enum 51values or if your option/argument uses is one of the types we have completers for, 52you should not need to do this. But if you have your own completeable types, or if 53you want completion of one option to be conditioned by other options on the command 54line, you can use this interface to take over the completion. 55 56You can choose to add a completion for the option values defined for your command, 57or for the arguments, separately. For the option values, define: 58 59def handle_option_argument_completion(self, long_option, cursor_pos): 60 61The line to be completed will be parsed up to the option containint the cursor position, 62and the values will be set in the OptionValue parser object. long_option will be 63the option name containing the cursor, and cursor_pos will be the position of the cursor 64in that option's value. You can call the `OVParser` method: `dest_for_option(long_option)` 65to get the value for that option. The other options that came before the cursor in the command 66line will also be set in the `OVParser` when the completion handler is called. 67 68For argument values, define: 69 70def handle_argument_completion(self, args, arg_pos, cursor_pos): 71 72Again, the command line will be parsed up to the cursor position, and all the options 73before the cursor pose will be set in the `OVParser`. args is a python list of the 74arguments, arg_pos is the index of the argument with the cursor, and cursor_pos is 75the position of the cursor in the argument. 76 77In both cases, the return value determines the completion. 78 79Return False to mean "Not Handled" - in which case lldb will fall back on the 80standard completion machinery. 81 82Return True to mean "Handled with no completions". 83 84If there is a single unique completion, return a Python dictionary with two elements: 85 86return {"completion" : "completed_value", "mode" : <"partial", "complete">} 87 88If the mode is "partial", then the completion is to a common base, if it is "complete" 89then the argument is considered done - mostly meaning lldb will put a space after the 90completion string. "complete" is the default if no "mode" is specified. 91 92If there are multiple completion options, then return: 93 94return {"values" : ["option1", "option2"]} 95 96Optionally, you can return a parallel array of "descriptions" which the completer will 97print alongside the options: 98 99return {"values" : ["option1", "option2"], "descriptions" : ["the first option", "the second option"]} 100 101The cmdtemplate example currently uses the parsed command infrastructure: 102 103llvm-project/lldb/examples/python/cmdtemplate.py 104 105There are also a few example commands in the lldb testsuite at: 106 107llvm-project/lldb/test/API/commands/command/script/add/test_commands.py 108""" 109import inspect 110import lldb 111import sys 112from abc import abstractmethod 113 114# Some methods to translate common value types. Should return a 115# tuple of the value and an error value (True => error) if the 116# type can't be converted. These are called internally when the 117# command line is parsed into the 'dest' properties, you should 118# not need to call them directly. 119# FIXME: Need a way to push the conversion error string back to lldb. 120def to_bool(in_value): 121 error = True 122 value = False 123 if type(in_value) != str or len(in_value) == 0: 124 return (value, error) 125 126 low_in = in_value.lower() 127 if low_in in ["y", "yes", "t", "true", "1"]: 128 value = True 129 error = False 130 131 if not value and low_in in ["n", "no", "f", "false", "0"]: 132 value = False 133 error = False 134 135 return (value, error) 136 137def to_int(in_value): 138 #FIXME: Not doing errors yet... 139 return (int(in_value), False) 140 141def to_unsigned(in_value): 142 # FIXME: find an unsigned converter... 143 # And handle errors. 144 return (int(in_value), False) 145 146translators = { 147 lldb.eArgTypeBoolean : to_bool, 148 lldb.eArgTypeBreakpointID : to_unsigned, 149 lldb.eArgTypeByteSize : to_unsigned, 150 lldb.eArgTypeCount : to_unsigned, 151 lldb.eArgTypeFrameIndex : to_unsigned, 152 lldb.eArgTypeIndex : to_unsigned, 153 lldb.eArgTypeLineNum : to_unsigned, 154 lldb.eArgTypeNumLines : to_unsigned, 155 lldb.eArgTypeNumberPerLine : to_unsigned, 156 lldb.eArgTypeOffset : to_int, 157 lldb.eArgTypeThreadIndex : to_unsigned, 158 lldb.eArgTypeUnsignedInteger : to_unsigned, 159 lldb.eArgTypeWatchpointID : to_unsigned, 160 lldb.eArgTypeColumnNum : to_unsigned, 161 lldb.eArgTypeRecognizerID : to_unsigned, 162 lldb.eArgTypeTargetID : to_unsigned, 163 lldb.eArgTypeStopHookID : to_unsigned 164} 165 166def translate_value(value_type, value): 167 try: 168 return translators[value_type](value) 169 except KeyError: 170 # If we don't have a translator, return the string value. 171 return (value, False) 172 173class LLDBOptionValueParser: 174 """ 175 This class holds the option definitions for the command, and when 176 the command is run, you can ask the parser for the current values. """ 177 178 def __init__(self): 179 # This is a dictionary of dictionaries. The key is the long option 180 # name, and the value is the rest of the definition. 181 self.options_dict = {} 182 self.args_array = [] 183 184 185 # FIXME: would this be better done on the C++ side? 186 # The common completers are missing some useful ones. 187 # For instance there really should be a common Type completer 188 # And an "lldb command name" completer. 189 completion_table = { 190 lldb.eArgTypeAddressOrExpression : lldb.eVariablePathCompletion, 191 lldb.eArgTypeArchitecture : lldb.eArchitectureCompletion, 192 lldb.eArgTypeBreakpointID : lldb.eBreakpointCompletion, 193 lldb.eArgTypeBreakpointIDRange : lldb.eBreakpointCompletion, 194 lldb.eArgTypeBreakpointName : lldb.eBreakpointNameCompletion, 195 lldb.eArgTypeClassName : lldb.eSymbolCompletion, 196 lldb.eArgTypeDirectoryName : lldb.eDiskDirectoryCompletion, 197 lldb.eArgTypeExpression : lldb.eVariablePathCompletion, 198 lldb.eArgTypeExpressionPath : lldb.eVariablePathCompletion, 199 lldb.eArgTypeFilename : lldb.eDiskFileCompletion, 200 lldb.eArgTypeFrameIndex : lldb.eFrameIndexCompletion, 201 lldb.eArgTypeFunctionName : lldb.eSymbolCompletion, 202 lldb.eArgTypeFunctionOrSymbol : lldb.eSymbolCompletion, 203 lldb.eArgTypeLanguage : lldb.eTypeLanguageCompletion, 204 lldb.eArgTypePath : lldb.eDiskFileCompletion, 205 lldb.eArgTypePid : lldb.eProcessIDCompletion, 206 lldb.eArgTypeProcessName : lldb.eProcessNameCompletion, 207 lldb.eArgTypeRegisterName : lldb.eRegisterCompletion, 208 lldb.eArgTypeRunArgs : lldb.eDiskFileCompletion, 209 lldb.eArgTypeShlibName : lldb.eModuleCompletion, 210 lldb.eArgTypeSourceFile : lldb.eSourceFileCompletion, 211 lldb.eArgTypeSymbol : lldb.eSymbolCompletion, 212 lldb.eArgTypeThreadIndex : lldb.eThreadIndexCompletion, 213 lldb.eArgTypeVarName : lldb.eVariablePathCompletion, 214 lldb.eArgTypePlatform : lldb.ePlatformPluginCompletion, 215 lldb.eArgTypeWatchpointID : lldb.eWatchpointIDCompletion, 216 lldb.eArgTypeWatchpointIDRange : lldb.eWatchpointIDCompletion, 217 lldb.eArgTypeModuleUUID : lldb.eModuleUUIDCompletion, 218 lldb.eArgTypeStopHookID : lldb.eStopHookIDCompletion 219 } 220 221 @classmethod 222 def determine_completion(cls, arg_type): 223 return cls.completion_table.get(arg_type, lldb.eNoCompletion) 224 225 def add_argument_set(self, arguments): 226 self.args_array.append(arguments) 227 228 def get_option_element(self, long_name): 229 return self.options_dict.get(long_name, None) 230 231 def is_enum_opt(self, opt_name): 232 elem = self.get_option_element(opt_name) 233 if not elem: 234 return False 235 return "enum_values" in elem 236 237 def option_parsing_started(self): 238 """ This makes the ivars for all the "dest" values in the array and gives them 239 their default values. You should not have to call this by hand, though if 240 you have some option that needs to do some work when a new command invocation 241 starts, you can override this to handle your special option. """ 242 for key, elem in self.options_dict.items(): 243 elem['_value_set'] = False 244 try: 245 object.__setattr__(self, elem["dest"], elem["default"]) 246 except AttributeError: 247 # It isn't an error not to have a "dest" variable name, you'll 248 # just have to manage this option's value on your own. 249 continue 250 251 def set_enum_value(self, enum_values, input): 252 """ This sets the value for an enum option, you should not have to call this 253 by hand. """ 254 candidates = [] 255 for candidate in enum_values: 256 # The enum_values are a two element list of value & help string. 257 value = candidate[0] 258 if value.startswith(input): 259 candidates.append(value) 260 261 if len(candidates) == 1: 262 return (candidates[0], False) 263 else: 264 return (input, True) 265 266 def set_option_value(self, exe_ctx, opt_name, opt_value): 267 """ This sets a single option value. This will handle most option 268 value types, but if you have an option that has some complex behavior, 269 you can override this to implement that behavior, and then pass the 270 rest of the options to the base class implementation. """ 271 elem = self.get_option_element(opt_name) 272 if not elem: 273 return False 274 275 if "enum_values" in elem: 276 (value, error) = self.set_enum_value(elem["enum_values"], opt_value) 277 else: 278 (value, error) = translate_value(elem["value_type"], opt_value) 279 280 if error: 281 return False 282 283 object.__setattr__(self, elem["dest"], value) 284 elem["_value_set"] = True 285 return True 286 287 def was_set(self, opt_name): 288 """Call this in the __call__ method of your command to determine 289 whether this option was set on the command line. It is sometimes 290 useful to know whether an option has the default value because the 291 user set it explicitly (was_set -> True) or not. 292 You can also call this in a handle_completion method, but it will 293 currently only report true values for the options mentioned 294 BEFORE the cursor point in the command line. 295 """ 296 297 elem = self.get_option_element(opt_name) 298 if not elem: 299 return False 300 try: 301 return elem["_value_set"] 302 except AttributeError: 303 return False 304 305 def dest_for_option(self, opt_name): 306 """This will return the value of the dest variable you defined for opt_name. 307 Mostly useful for handle_completion where you get passed the long option. 308 """ 309 elem = self.get_option_element(opt_name) 310 if not elem: 311 return None 312 value = self.__dict__[elem["dest"]] 313 return value 314 315 def add_option(self, short_option, long_option, help, default, 316 dest = None, required=False, groups = None, 317 value_type=lldb.eArgTypeNone, completion_type=None, 318 enum_values=None): 319 """ 320 short_option: one character, must be unique, not required 321 long_option: no spaces, must be unique, required 322 help: a usage string for this option, will print in the command help 323 default: the initial value for this option (if it has a value) 324 dest: the name of the property that gives you access to the value for 325 this value. Defaults to the long option if not provided. 326 required: if true, this option must be provided or the command will error out 327 groups: Which "option groups" does this option belong to. This can either be 328 a simple list (e.g. [1, 3, 4, 5]) or you can specify ranges by sublists: 329 so [1, [3,5]] is the same as [1, 3, 4, 5]. 330 value_type: one of the lldb.eArgType enum values. Some of the common arg 331 types also have default completers, which will be applied automatically. 332 completion_type: currently these are values form the lldb.CompletionType enum. If 333 you need custom completions, implement handle_option_argument_completion. 334 enum_values: An array of duples: ["element_name", "element_help"]. If provided, 335 only one of the enum elements is allowed. The value will be the 336 element_name for the chosen enum element as a string. 337 """ 338 if not dest: 339 dest = long_option 340 341 if not completion_type: 342 completion_type = self.determine_completion(value_type) 343 344 dict = {"short_option" : short_option, 345 "required" : required, 346 "help" : help, 347 "value_type" : value_type, 348 "completion_type" : completion_type, 349 "dest" : dest, 350 "default" : default} 351 352 if enum_values: 353 dict["enum_values"] = enum_values 354 if groups: 355 dict["groups"] = groups 356 357 self.options_dict[long_option] = dict 358 359 def make_argument_element(self, arg_type, repeat = "optional", groups = None): 360 element = {"arg_type" : arg_type, "repeat" : repeat} 361 if groups: 362 element["groups"] = groups 363 return element 364 365class ParsedCommand: 366 def __init__(self, debugger, unused): 367 self.debugger = debugger 368 self.ov_parser = LLDBOptionValueParser() 369 self.setup_command_definition() 370 371 def get_options_definition(self): 372 return self.get_parser().options_dict 373 374 def get_flags(self): 375 return 0 376 377 def get_args_definition(self): 378 return self.get_parser().args_array 379 380 # The base class will handle calling these methods 381 # when appropriate. 382 383 def option_parsing_started(self): 384 self.get_parser().option_parsing_started() 385 386 def set_option_value(self, exe_ctx, opt_name, opt_value): 387 return self.get_parser().set_option_value(exe_ctx, opt_name, opt_value) 388 389 def get_parser(self): 390 """Returns the option value parser for this command. 391 When defining the command, use the parser to add 392 argument and option definitions to the command. 393 When you are in the command callback, the parser 394 gives you access to the options passes to this 395 invocation""" 396 397 return self.ov_parser 398 399 # These are the two "pure virtual" methods: 400 @abstractmethod 401 def __call__(self, debugger, args_array, exe_ctx, result): 402 """This is the command callback. The option values are 403 provided by the 'dest' properties on the parser. 404 405 args_array: This is the list of arguments provided. 406 exe_ctx: Gives the SBExecutionContext on which the 407 command should operate. 408 result: Any results of the command should be 409 written into this SBCommandReturnObject. 410 """ 411 raise NotImplementedError() 412 413 @abstractmethod 414 def setup_command_definition(self): 415 """This will be called when your command is added to 416 the command interpreter. Here is where you add your 417 options and argument definitions for the command.""" 418 raise NotImplementedError() 419 420 @staticmethod 421 def do_register_cmd(cls, debugger, module_name): 422 """ Add any commands contained in this module to LLDB """ 423 command = "command script add -o -p -c %s.%s %s" % ( 424 module_name, 425 cls.__name__, 426 cls.program, 427 ) 428 debugger.HandleCommand(command) 429 print( 430 'The "{0}" command has been installed, type "help {0}"' 431 'for detailed help.'.format(cls.program) 432 ) 433