#!/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 # --------------------------------------------------------------------- from __future__ import print_function 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 -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__)