#!/usr/bin/env python # --------------------------------------------------------------------- # Be sure to add the python path that points to the LLDB shared library. # # # To use this in the embedded python interpreter using "lldb" just # import it with the full path using the "command script import" # command # (lldb) command script import /path/to/cmdtemplate.py # --------------------------------------------------------------------- import inspect import lldb import optparse import shlex import sys class FrameStatCommand: program = "framestats" @classmethod def register_lldb_command(cls, debugger, module_name): parser = cls.create_options() cls.__doc__ = parser.format_help() # Add any commands contained in this module to LLDB command = "command script add -o -c %s.%s %s" % ( module_name, cls.__name__, cls.program, ) debugger.HandleCommand(command) print( 'The "{0}" command has been installed, type "help {0}" or "{0} ' '--help" for detailed help.'.format(cls.program) ) @classmethod def create_options(cls): usage = "usage: %prog [options]" description = ( "This command is meant to be an example of how to make " "an LLDB command that does something useful, follows " "best practices, and exploits the SB API. " "Specifically, this command computes the aggregate " "and average size of the variables in the current " "frame and allows you to tweak exactly which variables " "are to be accounted in the computation." ) # Pass add_help_option = False, since this keeps the command in line # with lldb commands, and we wire up "help command" to work by # providing the long & short help methods below. parser = optparse.OptionParser( description=description, prog=cls.program, usage=usage, add_help_option=False, ) parser.add_option( "-i", "--in-scope", action="store_true", dest="inscope", help="in_scope_only = True", default=True, ) parser.add_option( "-a", "--arguments", action="store_true", dest="arguments", help="arguments = True", default=True, ) parser.add_option( "-l", "--locals", action="store_true", dest="locals", help="locals = True", default=True, ) parser.add_option( "-s", "--statics", action="store_true", dest="statics", help="statics = True", default=True, ) return parser def get_short_help(self): return "Example command for use in debugging" def get_long_help(self): return self.help_string def __init__(self, debugger, unused): self.parser = self.create_options() self.help_string = self.parser.format_help() def __call__(self, debugger, command, exe_ctx, result): # Use the Shell Lexer to properly parse up command options just like a # shell would command_args = shlex.split(command) try: (options, args) = self.parser.parse_args(command_args) except: # if you don't handle exceptions, passing an incorrect argument to # the OptionParser will cause LLDB to exit (courtesy of OptParse # dealing with argument errors by throwing SystemExit) result.SetError("option parsing failed") return # Always get program state from the lldb.SBExecutionContext passed # in as exe_ctx frame = exe_ctx.GetFrame() if not frame.IsValid(): result.SetError("invalid frame") return variables_list = frame.GetVariables( options.arguments, options.locals, options.statics, options.inscope ) variables_count = variables_list.GetSize() if variables_count == 0: print("no variables here", file=result) return total_size = 0 for i in range(0, variables_count): variable = variables_list.GetValueAtIndex(i) variable_type = variable.GetType() total_size = total_size + variable_type.GetByteSize() average_size = float(total_size) / variables_count print( "Your frame has %d variables. Their total size " "is %d bytes. The average size is %f bytes" % (variables_count, total_size, average_size), file=result, ) # not returning anything is akin to returning success 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__)