types.py revision e4513b950e0e31783bff8ecece8723eb1d18901b
177e67a51acb825d79d25be687c085833713d5205Greg Clayton#!/usr/bin/python
277e67a51acb825d79d25be687c085833713d5205Greg Clayton
377e67a51acb825d79d25be687c085833713d5205Greg Clayton#----------------------------------------------------------------------
477e67a51acb825d79d25be687c085833713d5205Greg Clayton# Be sure to add the python path that points to the LLDB shared library.
577e67a51acb825d79d25be687c085833713d5205Greg Clayton#
677e67a51acb825d79d25be687c085833713d5205Greg Clayton# # To use this in the embedded python interpreter using "lldb" just
777e67a51acb825d79d25be687c085833713d5205Greg Clayton# import it with the full path using the "command script import"
877e67a51acb825d79d25be687c085833713d5205Greg Clayton# command
977e67a51acb825d79d25be687c085833713d5205Greg Clayton#   (lldb) command script import /path/to/cmdtemplate.py
1077e67a51acb825d79d25be687c085833713d5205Greg Clayton#----------------------------------------------------------------------
1177e67a51acb825d79d25be687c085833713d5205Greg Clayton
1277e67a51acb825d79d25be687c085833713d5205Greg Claytonimport commands
1377e67a51acb825d79d25be687c085833713d5205Greg Claytonimport platform
1477e67a51acb825d79d25be687c085833713d5205Greg Claytonimport os
1577e67a51acb825d79d25be687c085833713d5205Greg Claytonimport sys
1677e67a51acb825d79d25be687c085833713d5205Greg Clayton
1777e67a51acb825d79d25be687c085833713d5205Greg Claytontry:
1877e67a51acb825d79d25be687c085833713d5205Greg Clayton    # Just try for LLDB in case PYTHONPATH is already correctly setup
1977e67a51acb825d79d25be687c085833713d5205Greg Clayton    import lldb
2077e67a51acb825d79d25be687c085833713d5205Greg Claytonexcept ImportError:
2177e67a51acb825d79d25be687c085833713d5205Greg Clayton    lldb_python_dirs = list()
2277e67a51acb825d79d25be687c085833713d5205Greg Clayton    # lldb is not in the PYTHONPATH, try some defaults for the current platform
2377e67a51acb825d79d25be687c085833713d5205Greg Clayton    platform_system = platform.system()
2477e67a51acb825d79d25be687c085833713d5205Greg Clayton    if platform_system == 'Darwin':
2577e67a51acb825d79d25be687c085833713d5205Greg Clayton        # On Darwin, try the currently selected Xcode directory
2677e67a51acb825d79d25be687c085833713d5205Greg Clayton        xcode_dir = commands.getoutput("xcode-select --print-path")
2777e67a51acb825d79d25be687c085833713d5205Greg Clayton        if xcode_dir:
2877e67a51acb825d79d25be687c085833713d5205Greg Clayton            lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python'))
2977e67a51acb825d79d25be687c085833713d5205Greg Clayton            lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
3077e67a51acb825d79d25be687c085833713d5205Greg Clayton        lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
3177e67a51acb825d79d25be687c085833713d5205Greg Clayton    success = False
3277e67a51acb825d79d25be687c085833713d5205Greg Clayton    for lldb_python_dir in lldb_python_dirs:
3377e67a51acb825d79d25be687c085833713d5205Greg Clayton        if os.path.exists(lldb_python_dir):
3477e67a51acb825d79d25be687c085833713d5205Greg Clayton            if not (sys.path.__contains__(lldb_python_dir)):
3577e67a51acb825d79d25be687c085833713d5205Greg Clayton                sys.path.append(lldb_python_dir)
3677e67a51acb825d79d25be687c085833713d5205Greg Clayton                try:
3777e67a51acb825d79d25be687c085833713d5205Greg Clayton                    import lldb
3877e67a51acb825d79d25be687c085833713d5205Greg Clayton                except ImportError:
3977e67a51acb825d79d25be687c085833713d5205Greg Clayton                    pass
4077e67a51acb825d79d25be687c085833713d5205Greg Clayton                else:
4177e67a51acb825d79d25be687c085833713d5205Greg Clayton                    print 'imported lldb from: "%s"' % (lldb_python_dir)
4277e67a51acb825d79d25be687c085833713d5205Greg Clayton                    success = True
4377e67a51acb825d79d25be687c085833713d5205Greg Clayton                    break
4477e67a51acb825d79d25be687c085833713d5205Greg Clayton    if not success:
4577e67a51acb825d79d25be687c085833713d5205Greg Clayton        print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
4677e67a51acb825d79d25be687c085833713d5205Greg Clayton        sys.exit(1)
4777e67a51acb825d79d25be687c085833713d5205Greg Clayton
4877e67a51acb825d79d25be687c085833713d5205Greg Claytonimport commands
4977e67a51acb825d79d25be687c085833713d5205Greg Claytonimport optparse
5077e67a51acb825d79d25be687c085833713d5205Greg Claytonimport shlex
5177e67a51acb825d79d25be687c085833713d5205Greg Claytonimport time
5277e67a51acb825d79d25be687c085833713d5205Greg Clayton
5377e67a51acb825d79d25be687c085833713d5205Greg Claytondef create_types_options():
5477e67a51acb825d79d25be687c085833713d5205Greg Clayton    usage = "usage: %prog [options]"
5577e67a51acb825d79d25be687c085833713d5205Greg Clayton    description='''This command will help you verify that types in your program
5677e67a51acb825d79d25be687c085833713d5205Greg Claytonare packed efficiently by showing all types and their sizes and showing the
5777e67a51acb825d79d25be687c085833713d5205Greg Claytonpadding bytes that waste space.
5877e67a51acb825d79d25be687c085833713d5205Greg Clayton'''
5977e67a51acb825d79d25be687c085833713d5205Greg Clayton    parser = optparse.OptionParser(description=description, prog='framestats',usage=usage)
6077e67a51acb825d79d25be687c085833713d5205Greg Clayton    parser.add_option('-a', '--arch', type='string', dest='arch', help='The architecture to use when creating the debug target.', default=None)
6177e67a51acb825d79d25be687c085833713d5205Greg Clayton    parser.add_option('-p', '--platform', type='string', metavar='platform', dest='platform', help='specify one platform by name')
6277e67a51acb825d79d25be687c085833713d5205Greg Clayton    parser.add_option('-m', '--module', action='append', type='string', metavar='MODULE', dest='modules', help='Specify one or more modules which will be used to verify the types.', default=[])
6377e67a51acb825d79d25be687c085833713d5205Greg Clayton    parser.add_option('-t', '--type', action='append', type='string', metavar='TYPENAME', dest='typenames', help='Specify one or more type names which should be verified. If no type names are specified, all class and struct types will be verified.', default=[])
6477e67a51acb825d79d25be687c085833713d5205Greg Clayton    parser.add_option('-d', '--debug', action='store_true', dest='debug', help='Pause 10 seconds to wait for a debugger to attach.', default=False)
6577e67a51acb825d79d25be687c085833713d5205Greg Clayton    parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False)
6677e67a51acb825d79d25be687c085833713d5205Greg Clayton    return parser
6777e67a51acb825d79d25be687c085833713d5205Greg Clayton
6877e67a51acb825d79d25be687c085833713d5205Greg Claytondef verify_type (target, type):
6977e67a51acb825d79d25be687c085833713d5205Greg Clayton    print type
7077e67a51acb825d79d25be687c085833713d5205Greg Clayton    typename = type.GetName()
7177e67a51acb825d79d25be687c085833713d5205Greg Clayton    # print 'type: %s' % (typename)
7277e67a51acb825d79d25be687c085833713d5205Greg Clayton    (end_offset, padding) = verify_type_recursive (target, type, None, 0, 0, 0)
7377e67a51acb825d79d25be687c085833713d5205Greg Clayton    byte_size = type.GetByteSize()
7477e67a51acb825d79d25be687c085833713d5205Greg Clayton    # if end_offset < byte_size:
7577e67a51acb825d79d25be687c085833713d5205Greg Clayton    #     last_member_padding = byte_size - end_offset
7677e67a51acb825d79d25be687c085833713d5205Greg Clayton    #     print '%+4u <%u> padding' % (end_offset, last_member_padding)
7777e67a51acb825d79d25be687c085833713d5205Greg Clayton    #     padding += last_member_padding
7877e67a51acb825d79d25be687c085833713d5205Greg Clayton    print 'Total byte size: %u' % (byte_size)
7977e67a51acb825d79d25be687c085833713d5205Greg Clayton    print 'Total pad bytes: %u' % (padding)
8077e67a51acb825d79d25be687c085833713d5205Greg Clayton    if padding > 0:
8177e67a51acb825d79d25be687c085833713d5205Greg Clayton        print 'Padding percentage: %2.2f %%' % ((float(padding) / float(byte_size)) * 100.0)
82e4513b950e0e31783bff8ecece8723eb1d18901bGreg Clayton    print
8377e67a51acb825d79d25be687c085833713d5205Greg Clayton
8477e67a51acb825d79d25be687c085833713d5205Greg Claytondef verify_type_recursive (target, type, member_name, depth, base_offset, padding):
8577e67a51acb825d79d25be687c085833713d5205Greg Clayton    prev_end_offset = base_offset
8677e67a51acb825d79d25be687c085833713d5205Greg Clayton    typename = type.GetName()
8777e67a51acb825d79d25be687c085833713d5205Greg Clayton    byte_size = type.GetByteSize()
8877e67a51acb825d79d25be687c085833713d5205Greg Clayton    if member_name and member_name != typename:
8977e67a51acb825d79d25be687c085833713d5205Greg Clayton        print '%+4u <%3u> %s%s %s;' % (base_offset, type.GetByteSize(), '    ' * depth, typename, member_name)
9077e67a51acb825d79d25be687c085833713d5205Greg Clayton    else:
9177e67a51acb825d79d25be687c085833713d5205Greg Clayton        print '%+4u <%3u> %s%s' % (base_offset, type.GetByteSize(), '    ' * depth, typename)
9277e67a51acb825d79d25be687c085833713d5205Greg Clayton
9377e67a51acb825d79d25be687c085833713d5205Greg Clayton    members = type.members
9477e67a51acb825d79d25be687c085833713d5205Greg Clayton    if members:
9577e67a51acb825d79d25be687c085833713d5205Greg Clayton        for member_idx, member in enumerate(members):
9677e67a51acb825d79d25be687c085833713d5205Greg Clayton            member_type = member.GetType()
9777e67a51acb825d79d25be687c085833713d5205Greg Clayton            member_canonical_type = member_type.GetCanonicalType()
9877e67a51acb825d79d25be687c085833713d5205Greg Clayton            member_type_class = member_canonical_type.GetTypeClass()
9977e67a51acb825d79d25be687c085833713d5205Greg Clayton            member_name = member.GetName()
10077e67a51acb825d79d25be687c085833713d5205Greg Clayton            member_offset = member.GetOffsetInBytes()
10177e67a51acb825d79d25be687c085833713d5205Greg Clayton            member_total_offset = member_offset + base_offset
10277e67a51acb825d79d25be687c085833713d5205Greg Clayton            member_byte_size = member_type.GetByteSize()
10377e67a51acb825d79d25be687c085833713d5205Greg Clayton            is_class_or_struct = False
10477e67a51acb825d79d25be687c085833713d5205Greg Clayton            if member_type_class == lldb.eTypeClassStruct or member_type_class == lldb.eTypeClassClass:
10577e67a51acb825d79d25be687c085833713d5205Greg Clayton                is_class_or_struct = True
10677e67a51acb825d79d25be687c085833713d5205Greg Clayton            if member_idx == 0 and member_offset == target.GetAddressByteSize() and type.IsPolymorphicClass():
10777e67a51acb825d79d25be687c085833713d5205Greg Clayton                ptr_size = target.GetAddressByteSize()
10877e67a51acb825d79d25be687c085833713d5205Greg Clayton                print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, '    ' * (depth + 1))
10977e67a51acb825d79d25be687c085833713d5205Greg Clayton                prev_end_offset = ptr_size
11077e67a51acb825d79d25be687c085833713d5205Greg Clayton            else:
11177e67a51acb825d79d25be687c085833713d5205Greg Clayton                if prev_end_offset < member_total_offset:
11277e67a51acb825d79d25be687c085833713d5205Greg Clayton                    member_padding = member_total_offset - prev_end_offset
11377e67a51acb825d79d25be687c085833713d5205Greg Clayton                    padding = padding + member_padding
11477e67a51acb825d79d25be687c085833713d5205Greg Clayton                    print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, member_padding, '    ' * (depth + 1))
11577e67a51acb825d79d25be687c085833713d5205Greg Clayton
11677e67a51acb825d79d25be687c085833713d5205Greg Clayton            if is_class_or_struct:
11777e67a51acb825d79d25be687c085833713d5205Greg Clayton                (prev_end_offset, padding) = verify_type_recursive (target, member_canonical_type, member_name, depth + 1, member_total_offset, padding)
11877e67a51acb825d79d25be687c085833713d5205Greg Clayton            else:
11977e67a51acb825d79d25be687c085833713d5205Greg Clayton                prev_end_offset = member_total_offset + member_byte_size
12077e67a51acb825d79d25be687c085833713d5205Greg Clayton                if member.IsBitfield():
12177e67a51acb825d79d25be687c085833713d5205Greg Clayton                    print '%+4u <%3u> %s%s:%u %s;' % (member_total_offset, member_byte_size, '    ' * (depth + 1), member_type.GetName(), member.GetBitfieldSizeInBits(), member_name)
12277e67a51acb825d79d25be687c085833713d5205Greg Clayton                else:
12377e67a51acb825d79d25be687c085833713d5205Greg Clayton                    print '%+4u <%3u> %s%s %s;' % (member_total_offset, member_byte_size, '    ' * (depth + 1), member_type.GetName(), member_name)
12477e67a51acb825d79d25be687c085833713d5205Greg Clayton
12577e67a51acb825d79d25be687c085833713d5205Greg Clayton        if prev_end_offset < byte_size:
12677e67a51acb825d79d25be687c085833713d5205Greg Clayton            last_member_padding = byte_size - prev_end_offset
12777e67a51acb825d79d25be687c085833713d5205Greg Clayton            print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, last_member_padding, '    ' * (depth + 1))
12877e67a51acb825d79d25be687c085833713d5205Greg Clayton            padding += last_member_padding
12977e67a51acb825d79d25be687c085833713d5205Greg Clayton    else:
13077e67a51acb825d79d25be687c085833713d5205Greg Clayton        if type.IsPolymorphicClass():
13177e67a51acb825d79d25be687c085833713d5205Greg Clayton            ptr_size = target.GetAddressByteSize()
13277e67a51acb825d79d25be687c085833713d5205Greg Clayton            print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, '    ' * (depth + 1))
13377e67a51acb825d79d25be687c085833713d5205Greg Clayton            prev_end_offset = ptr_size
13477e67a51acb825d79d25be687c085833713d5205Greg Clayton        prev_end_offset = base_offset + type.GetByteSize()
13577e67a51acb825d79d25be687c085833713d5205Greg Clayton
13677e67a51acb825d79d25be687c085833713d5205Greg Clayton    return (prev_end_offset, padding)
13777e67a51acb825d79d25be687c085833713d5205Greg Clayton
13877e67a51acb825d79d25be687c085833713d5205Greg Claytondef types_command (debugger, command, result, dict):
13977e67a51acb825d79d25be687c085833713d5205Greg Clayton    # Use the Shell Lexer to properly parse up command options just like a
14077e67a51acb825d79d25be687c085833713d5205Greg Clayton    # shell would
14177e67a51acb825d79d25be687c085833713d5205Greg Clayton    command_args = shlex.split(command)
14277e67a51acb825d79d25be687c085833713d5205Greg Clayton    verify_types(debugger, command_args)
14377e67a51acb825d79d25be687c085833713d5205Greg Clayton
14477e67a51acb825d79d25be687c085833713d5205Greg Claytondef verify_types (debugger, command_args):
14577e67a51acb825d79d25be687c085833713d5205Greg Clayton
14677e67a51acb825d79d25be687c085833713d5205Greg Clayton    parser = create_types_options()
14777e67a51acb825d79d25be687c085833713d5205Greg Clayton    try:
14877e67a51acb825d79d25be687c085833713d5205Greg Clayton        (options, args) = parser.parse_args(command_args)
14977e67a51acb825d79d25be687c085833713d5205Greg Clayton    except:
15077e67a51acb825d79d25be687c085833713d5205Greg Clayton        # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
15177e67a51acb825d79d25be687c085833713d5205Greg Clayton        # (courtesy of OptParse dealing with argument errors by throwing SystemExit)
15277e67a51acb825d79d25be687c085833713d5205Greg Clayton        result.SetStatus (lldb.eReturnStatusFailed)
15377e67a51acb825d79d25be687c085833713d5205Greg Clayton        return "option parsing failed" # returning a string is the same as returning an error whose description is the string
15477e67a51acb825d79d25be687c085833713d5205Greg Clayton
15577e67a51acb825d79d25be687c085833713d5205Greg Clayton    if options.debug:
15677e67a51acb825d79d25be687c085833713d5205Greg Clayton        print 'Waiting for debugger to attach...'
15777e67a51acb825d79d25be687c085833713d5205Greg Clayton        for i in range(10):
15877e67a51acb825d79d25be687c085833713d5205Greg Clayton            time.sleep(1)
15977e67a51acb825d79d25be687c085833713d5205Greg Clayton            print '.'
16077e67a51acb825d79d25be687c085833713d5205Greg Clayton
16177e67a51acb825d79d25be687c085833713d5205Greg Clayton    for path in args:
16277e67a51acb825d79d25be687c085833713d5205Greg Clayton    # in a command - the lldb.* convenience variables are not to be used
16377e67a51acb825d79d25be687c085833713d5205Greg Clayton    # and their values (if any) are undefined
16477e67a51acb825d79d25be687c085833713d5205Greg Clayton    # this is the best practice to access those objects from within a command
16577e67a51acb825d79d25be687c085833713d5205Greg Clayton        error = lldb.SBError()
16677e67a51acb825d79d25be687c085833713d5205Greg Clayton        target = debugger.CreateTarget (path,
16777e67a51acb825d79d25be687c085833713d5205Greg Clayton                                        options.arch,
16877e67a51acb825d79d25be687c085833713d5205Greg Clayton                                        options.platform,
16977e67a51acb825d79d25be687c085833713d5205Greg Clayton                                        True,
17077e67a51acb825d79d25be687c085833713d5205Greg Clayton                                        error)
17177e67a51acb825d79d25be687c085833713d5205Greg Clayton        if error.Fail():
17277e67a51acb825d79d25be687c085833713d5205Greg Clayton            print error.GetCString()
17377e67a51acb825d79d25be687c085833713d5205Greg Clayton            continue
17477e67a51acb825d79d25be687c085833713d5205Greg Clayton
17577e67a51acb825d79d25be687c085833713d5205Greg Clayton        modules = list()
17677e67a51acb825d79d25be687c085833713d5205Greg Clayton        if len(options.modules) == 0:
17777e67a51acb825d79d25be687c085833713d5205Greg Clayton            # Append just the main executable if nothing was specified
17877e67a51acb825d79d25be687c085833713d5205Greg Clayton            module = target.modules[0]
17977e67a51acb825d79d25be687c085833713d5205Greg Clayton            if module:
18077e67a51acb825d79d25be687c085833713d5205Greg Clayton                modules.append(module)
18177e67a51acb825d79d25be687c085833713d5205Greg Clayton        else:
18277e67a51acb825d79d25be687c085833713d5205Greg Clayton            for module_name in options.modules:
18377e67a51acb825d79d25be687c085833713d5205Greg Clayton                module = lldb.target.module[module_name]
18477e67a51acb825d79d25be687c085833713d5205Greg Clayton                if module:
18577e67a51acb825d79d25be687c085833713d5205Greg Clayton                    modules.append(module)
18677e67a51acb825d79d25be687c085833713d5205Greg Clayton
18777e67a51acb825d79d25be687c085833713d5205Greg Clayton        if modules:
18877e67a51acb825d79d25be687c085833713d5205Greg Clayton            for module in modules:
18977e67a51acb825d79d25be687c085833713d5205Greg Clayton                print 'module: %s' % (module.file)
19077e67a51acb825d79d25be687c085833713d5205Greg Clayton                if options.typenames:
19177e67a51acb825d79d25be687c085833713d5205Greg Clayton                    for typename in options.typenames:
19277e67a51acb825d79d25be687c085833713d5205Greg Clayton                        types = module.FindTypes(typename)
19377e67a51acb825d79d25be687c085833713d5205Greg Clayton                        if types.GetSize():
194e4513b950e0e31783bff8ecece8723eb1d18901bGreg Clayton                            print 'Found %u types matching "%s" in "%s"' % (len(types), typename, module.file)
19577e67a51acb825d79d25be687c085833713d5205Greg Clayton                            for type in types:
19677e67a51acb825d79d25be687c085833713d5205Greg Clayton                                verify_type (target, type)
19777e67a51acb825d79d25be687c085833713d5205Greg Clayton                        else:
198e4513b950e0e31783bff8ecece8723eb1d18901bGreg Clayton                            print 'error: no type matches "%s" in "%s"' % (typename, module.file)
19977e67a51acb825d79d25be687c085833713d5205Greg Clayton                else:
20077e67a51acb825d79d25be687c085833713d5205Greg Clayton                    types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct)
201e4513b950e0e31783bff8ecece8723eb1d18901bGreg Clayton                    print 'Found %u types in "%s"' % (len(types), module.file)
20277e67a51acb825d79d25be687c085833713d5205Greg Clayton                    for type in types:
20377e67a51acb825d79d25be687c085833713d5205Greg Clayton                        verify_type (target, type)
20477e67a51acb825d79d25be687c085833713d5205Greg Clayton        else:
20577e67a51acb825d79d25be687c085833713d5205Greg Clayton            print 'error: no modules'
20677e67a51acb825d79d25be687c085833713d5205Greg Clayton
20777e67a51acb825d79d25be687c085833713d5205Greg Claytonif __name__ == '__main__':
20877e67a51acb825d79d25be687c085833713d5205Greg Clayton    debugger = lldb.SBDebugger.Create()
20977e67a51acb825d79d25be687c085833713d5205Greg Clayton    verify_types (debugger, sys.argv[1:])
21077e67a51acb825d79d25be687c085833713d5205Greg Claytonelif getattr(lldb, 'debugger', None):
21177e67a51acb825d79d25be687c085833713d5205Greg Clayton    lldb.debugger.HandleCommand('command script add -f types.types_command types')
21277e67a51acb825d79d25be687c085833713d5205Greg Clayton    print '"types" command installed, use the "--help" option for detailed help'