1#!/usr/bin/env python 2 3# --------------------------------------------------------------------- 4# Be sure to add the python path that points to the LLDB shared library. 5# 6# # To use this in the embedded python interpreter using "lldb" just 7# import it with the full path using the "command script import" 8# command 9# (lldb) command script import /path/to/cmdtemplate.py 10# --------------------------------------------------------------------- 11 12import inspect 13import lldb 14import sys 15from lldb.plugins.parsed_cmd import ParsedCommand 16 17class FrameStatCommand(ParsedCommand): 18 program = "framestats" 19 20 @classmethod 21 def register_lldb_command(cls, debugger, module_name): 22 ParsedCommand.do_register_cmd(cls, debugger, module_name) 23 print( 24 'The "{0}" command has been installed, type "help {0}" or "{0} ' 25 '--help" for detailed help.'.format(cls.program) 26 ) 27 28 def get_flags(self): 29 return lldb.eCommandRequiresFrame | lldb.eCommandProcessMustBePaused 30 31 def setup_command_definition(self): 32 ov_parser = self.get_parser() 33 ov_parser.add_option( 34 "i", 35 "in-scope", 36 help = "in_scope_only = True", 37 value_type = lldb.eArgTypeBoolean, 38 dest = "bool_arg", 39 default = True, 40 ) 41 42 ov_parser.add_option( 43 "i", 44 "in-scope", 45 help = "in_scope_only = True", 46 value_type = lldb.eArgTypeBoolean, 47 dest = "inscope", 48 default=True, 49 ) 50 51 ov_parser.add_option( 52 "a", 53 "arguments", 54 help = "arguments = True", 55 value_type = lldb.eArgTypeBoolean, 56 dest = "arguments", 57 default = True, 58 ) 59 60 ov_parser.add_option( 61 "l", 62 "locals", 63 help = "locals = True", 64 value_type = lldb.eArgTypeBoolean, 65 dest = "locals", 66 default = True, 67 ) 68 69 ov_parser.add_option( 70 "s", 71 "statics", 72 help = "statics = True", 73 value_type = lldb.eArgTypeBoolean, 74 dest = "statics", 75 default = True, 76 ) 77 78 def get_repeat_command(self, args): 79 """As an example, make the command not auto-repeat:""" 80 return "" 81 82 def get_short_help(self): 83 return "Example command for use in debugging" 84 85 def get_long_help(self): 86 return ("This command is meant to be an example of how to make " 87 "an LLDB command that does something useful, follows " 88 "best practices, and exploits the SB API. " 89 "Specifically, this command computes the aggregate " 90 "and average size of the variables in the current " 91 "frame and allows you to tweak exactly which variables " 92 "are to be accounted in the computation.") 93 94 95 def __init__(self, debugger, unused): 96 super().__init__(debugger, unused) 97 98 def __call__(self, debugger, command, exe_ctx, result): 99 # Always get program state from the lldb.SBExecutionContext passed 100 # in as exe_ctx 101 frame = exe_ctx.GetFrame() 102 if not frame.IsValid(): 103 result.SetError("invalid frame") 104 return 105 106 ov_parser = self.get_parser() 107 variables_list = frame.GetVariables( 108 ov_parser.arguments, ov_parser.locals, ov_parser.statics, ov_parser.inscope 109 ) 110 variables_count = variables_list.GetSize() 111 if variables_count == 0: 112 print("no variables here", file=result) 113 return 114 total_size = 0 115 for i in range(0, variables_count): 116 variable = variables_list.GetValueAtIndex(i) 117 variable_type = variable.GetType() 118 total_size = total_size + variable_type.GetByteSize() 119 average_size = float(total_size) / variables_count 120 print( 121 "Your frame has %d variables. Their total size " 122 "is %d bytes. The average size is %f bytes" 123 % (variables_count, total_size, average_size), 124 file=result, 125 ) 126 # not returning anything is akin to returning success 127 128 129def __lldb_init_module(debugger, dict): 130 # Register all classes that have a register_lldb_command method 131 for _name, cls in inspect.getmembers(sys.modules[__name__]): 132 if inspect.isclass(cls) and callable( 133 getattr(cls, "register_lldb_command", None) 134 ): 135 cls.register_lldb_command(debugger, __name__) 136