1*515bc8c1Sserge-sans-paille#!/usr/bin/env python
2d879a630SGreg Clayton
3ef115de6SGreg Clayton# ---------------------------------------------------------------------
4d879a630SGreg Clayton# Be sure to add the python path that points to the LLDB shared library.
5d879a630SGreg Clayton#
6e2841639SGreg Clayton# # To use this in the embedded python interpreter using "lldb" just
7e2841639SGreg Clayton# import it with the full path using the "command script import"
8e2841639SGreg Clayton# command
9e2841639SGreg Clayton#   (lldb) command script import /path/to/cmdtemplate.py
10ef115de6SGreg Clayton# ---------------------------------------------------------------------
11d879a630SGreg Clayton
12525cd59fSSerge Gueltonfrom __future__ import print_function
13525cd59fSSerge Guelton
14ef115de6SGreg Claytonimport inspect
15d879a630SGreg Claytonimport lldb
16d879a630SGreg Claytonimport optparse
17d879a630SGreg Claytonimport shlex
18ef115de6SGreg Claytonimport sys
19ef115de6SGreg Clayton
20d879a630SGreg Clayton
21dccb1db1SJim Inghamclass FrameStatCommand:
22ef115de6SGreg Clayton    program = 'framestats'
23ef115de6SGreg Clayton
24ef115de6SGreg Clayton    @classmethod
25ef115de6SGreg Clayton    def register_lldb_command(cls, debugger, module_name):
26ef115de6SGreg Clayton        parser = cls.create_options()
27ef115de6SGreg Clayton        cls.__doc__ = parser.format_help()
28ef115de6SGreg Clayton        # Add any commands contained in this module to LLDB
29ef115de6SGreg Clayton        command = 'command script add -c %s.%s %s' % (module_name,
30ef115de6SGreg Clayton                                                      cls.__name__,
31ef115de6SGreg Clayton                                                      cls.program)
32ef115de6SGreg Clayton        debugger.HandleCommand(command)
33ef115de6SGreg Clayton        print('The "{0}" command has been installed, type "help {0}" or "{0} '
34ef115de6SGreg Clayton              '--help" for detailed help.'.format(cls.program))
35ef115de6SGreg Clayton
36ef115de6SGreg Clayton    @classmethod
37ef115de6SGreg Clayton    def create_options(cls):
38b9c1b51eSKate Stone
39083fcdb4SEnrico Granata        usage = "usage: %prog [options]"
40ef115de6SGreg Clayton        description = ('This command is meant to be an example of how to make '
41ef115de6SGreg Clayton                       'an LLDB command that does something useful, follows '
42ef115de6SGreg Clayton                       'best practices, and exploits the SB API. '
43ef115de6SGreg Clayton                       'Specifically, this command computes the aggregate '
44ef115de6SGreg Clayton                       'and average size of the variables in the current '
45ef115de6SGreg Clayton                       'frame and allows you to tweak exactly which variables '
46ef115de6SGreg Clayton                       'are to be accounted in the computation.')
47dccb1db1SJim Ingham
48ef115de6SGreg Clayton        # Pass add_help_option = False, since this keeps the command in line
49ef115de6SGreg Clayton        #  with lldb commands, and we wire up "help command" to work by
50ef115de6SGreg Clayton        # providing the long & short help methods below.
51ef115de6SGreg Clayton        parser = optparse.OptionParser(
52b9c1b51eSKate Stone            description=description,
53ef115de6SGreg Clayton            prog=cls.program,
54dccb1db1SJim Ingham            usage=usage,
55dccb1db1SJim Ingham            add_help_option=False)
56dccb1db1SJim Ingham
57ef115de6SGreg Clayton        parser.add_option(
58b9c1b51eSKate Stone            '-i',
59b9c1b51eSKate Stone            '--in-scope',
60b9c1b51eSKate Stone            action='store_true',
61b9c1b51eSKate Stone            dest='inscope',
62b9c1b51eSKate Stone            help='in_scope_only = True',
63dccb1db1SJim Ingham            default=True)
64dccb1db1SJim Ingham
65ef115de6SGreg Clayton        parser.add_option(
66b9c1b51eSKate Stone            '-a',
67b9c1b51eSKate Stone            '--arguments',
68b9c1b51eSKate Stone            action='store_true',
69b9c1b51eSKate Stone            dest='arguments',
70b9c1b51eSKate Stone            help='arguments = True',
71dccb1db1SJim Ingham            default=True)
72dccb1db1SJim Ingham
73ef115de6SGreg Clayton        parser.add_option(
74b9c1b51eSKate Stone            '-l',
75b9c1b51eSKate Stone            '--locals',
76b9c1b51eSKate Stone            action='store_true',
77b9c1b51eSKate Stone            dest='locals',
78b9c1b51eSKate Stone            help='locals = True',
79dccb1db1SJim Ingham            default=True)
80dccb1db1SJim Ingham
81ef115de6SGreg Clayton        parser.add_option(
82b9c1b51eSKate Stone            '-s',
83b9c1b51eSKate Stone            '--statics',
84b9c1b51eSKate Stone            action='store_true',
85b9c1b51eSKate Stone            dest='statics',
86b9c1b51eSKate Stone            help='statics = True',
87dccb1db1SJim Ingham            default=True)
88f453907aSGreg Clayton
89ef115de6SGreg Clayton        return parser
90ef115de6SGreg Clayton
91dccb1db1SJim Ingham    def get_short_help(self):
92dccb1db1SJim Ingham        return "Example command for use in debugging"
93b9c1b51eSKate Stone
94dccb1db1SJim Ingham    def get_long_help(self):
95dccb1db1SJim Ingham        return self.help_string
96dccb1db1SJim Ingham
97dccb1db1SJim Ingham    def __init__(self, debugger, unused):
98ef115de6SGreg Clayton        self.parser = self.create_options()
99dccb1db1SJim Ingham        self.help_string = self.parser.format_help()
100dccb1db1SJim Ingham
101dccb1db1SJim Ingham    def __call__(self, debugger, command, exe_ctx, result):
102f453907aSGreg Clayton        # Use the Shell Lexer to properly parse up command options just like a
103f453907aSGreg Clayton        # shell would
104f453907aSGreg Clayton        command_args = shlex.split(command)
105dccb1db1SJim Ingham
106d879a630SGreg Clayton        try:
107dccb1db1SJim Ingham            (options, args) = self.parser.parse_args(command_args)
108d879a630SGreg Clayton        except:
109ef115de6SGreg Clayton            # if you don't handle exceptions, passing an incorrect argument to
110ef115de6SGreg Clayton            # the OptionParser will cause LLDB to exit (courtesy of OptParse
111ef115de6SGreg Clayton            # dealing with argument errors by throwing SystemExit)
112da504ff0SEnrico Granata            result.SetError("option parsing failed")
113da504ff0SEnrico Granata            return
114d879a630SGreg Clayton
115ef115de6SGreg Clayton        # Always get program state from the lldb.SBExecutionContext passed
116ef115de6SGreg Clayton        # in as exe_ctx
117dccb1db1SJim Ingham        frame = exe_ctx.GetFrame()
118083fcdb4SEnrico Granata        if not frame.IsValid():
119dccb1db1SJim Ingham            result.SetError("invalid frame")
120dccb1db1SJim Ingham            return
121dccb1db1SJim Ingham
122b9c1b51eSKate Stone        variables_list = frame.GetVariables(
123b9c1b51eSKate Stone            options.arguments,
124b9c1b51eSKate Stone            options.locals,
125b9c1b51eSKate Stone            options.statics,
126b9c1b51eSKate Stone            options.inscope)
127083fcdb4SEnrico Granata        variables_count = variables_list.GetSize()
128083fcdb4SEnrico Granata        if variables_count == 0:
129525cd59fSSerge Guelton            print("no variables here", file=result)
130083fcdb4SEnrico Granata            return
131083fcdb4SEnrico Granata        total_size = 0
132083fcdb4SEnrico Granata        for i in range(0, variables_count):
133083fcdb4SEnrico Granata            variable = variables_list.GetValueAtIndex(i)
134083fcdb4SEnrico Granata            variable_type = variable.GetType()
135083fcdb4SEnrico Granata            total_size = total_size + variable_type.GetByteSize()
136083fcdb4SEnrico Granata            average_size = float(total_size) / variables_count
137525cd59fSSerge Guelton            print("Your frame has %d variables. Their total size "
138525cd59fSSerge Guelton                             "is %d bytes. The average size is %f bytes" % (
139525cd59fSSerge Guelton                                    variables_count, total_size, average_size), file=result)
140da504ff0SEnrico Granata        # not returning anything is akin to returning success
141d879a630SGreg Clayton
142b9c1b51eSKate Stone
14387a59368SJim Inghamdef __lldb_init_module(debugger, dict):
144ef115de6SGreg Clayton    # Register all classes that have a register_lldb_command method
145ef115de6SGreg Clayton    for _name, cls in inspect.getmembers(sys.modules[__name__]):
146ef115de6SGreg Clayton        if inspect.isclass(cls) and callable(getattr(cls,
147ef115de6SGreg Clayton                                                     "register_lldb_command",
148ef115de6SGreg Clayton                                                     None)):
149ef115de6SGreg Clayton            cls.register_lldb_command(debugger, __name__)
150