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'