diff options
author | Greg Clayton <gclayton@apple.com> | 2013-06-19 21:50:28 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2013-06-19 21:50:28 +0000 |
commit | d8c3d4b1e9f8695a9c063615a324cb105c9ab780 (patch) | |
tree | cd14cf1ec62a3ee6215f7f1e8bab6cb0af9c9daf /lldb/examples | |
parent | 6d2cfb80ba239ed47d962d7dd2487c168082c531 (diff) | |
download | bcm5719-llvm-d8c3d4b1e9f8695a9c063615a324cb105c9ab780.tar.gz bcm5719-llvm-d8c3d4b1e9f8695a9c063615a324cb105c9ab780.zip |
Implemented a types.py module that allows types to be inspected for padding.
The script was able to point out and save 40 bytes in each lldb_private::Section by being very careful where we need to have virtual destructors and also by re-ordering members.
llvm-svn: 184364
Diffstat (limited to 'lldb/examples')
-rwxr-xr-x | lldb/examples/python/types.py | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/lldb/examples/python/types.py b/lldb/examples/python/types.py new file mode 100755 index 00000000000..83ebbe6e4e1 --- /dev/null +++ b/lldb/examples/python/types.py @@ -0,0 +1,212 @@ +#!/usr/bin/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 +#---------------------------------------------------------------------- + +import commands +import platform +import os +import sys + +try: + # Just try for LLDB in case PYTHONPATH is already correctly setup + import lldb +except ImportError: + lldb_python_dirs = list() + # lldb is not in the PYTHONPATH, try some defaults for the current platform + platform_system = platform.system() + if platform_system == 'Darwin': + # On Darwin, try the currently selected Xcode directory + xcode_dir = commands.getoutput("xcode-select --print-path") + if xcode_dir: + lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python')) + lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + success = False + for lldb_python_dir in lldb_python_dirs: + if os.path.exists(lldb_python_dir): + if not (sys.path.__contains__(lldb_python_dir)): + sys.path.append(lldb_python_dir) + try: + import lldb + except ImportError: + pass + else: + print 'imported lldb from: "%s"' % (lldb_python_dir) + success = True + break + if not success: + print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" + sys.exit(1) + +import commands +import optparse +import shlex +import time + +def create_types_options(): + usage = "usage: %prog [options]" + description='''This command will help you verify that types in your program +are packed efficiently by showing all types and their sizes and showing the +padding bytes that waste space. +''' + parser = optparse.OptionParser(description=description, prog='framestats',usage=usage) + parser.add_option('-a', '--arch', type='string', dest='arch', help='The architecture to use when creating the debug target.', default=None) + parser.add_option('-p', '--platform', type='string', metavar='platform', dest='platform', help='specify one platform by name') + 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=[]) + 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=[]) + parser.add_option('-d', '--debug', action='store_true', dest='debug', help='Pause 10 seconds to wait for a debugger to attach.', default=False) + parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False) + return parser + +def verify_type (target, type): + print type + typename = type.GetName() + # print 'type: %s' % (typename) + (end_offset, padding) = verify_type_recursive (target, type, None, 0, 0, 0) + byte_size = type.GetByteSize() + # if end_offset < byte_size: + # last_member_padding = byte_size - end_offset + # print '%+4u <%u> padding' % (end_offset, last_member_padding) + # padding += last_member_padding + print 'Total byte size: %u' % (byte_size) + print 'Total pad bytes: %u' % (padding) + if padding > 0: + print 'Padding percentage: %2.2f %%' % ((float(padding) / float(byte_size)) * 100.0) + + +def verify_type_recursive (target, type, member_name, depth, base_offset, padding): + prev_end_offset = base_offset + typename = type.GetName() + byte_size = type.GetByteSize() + if member_name and member_name != typename: + print '%+4u <%3u> %s%s %s;' % (base_offset, type.GetByteSize(), ' ' * depth, typename, member_name) + else: + print '%+4u <%3u> %s%s' % (base_offset, type.GetByteSize(), ' ' * depth, typename) + + members = type.members + if members: + for member_idx, member in enumerate(members): + member_type = member.GetType() + member_canonical_type = member_type.GetCanonicalType() + member_type_class = member_canonical_type.GetTypeClass() + member_name = member.GetName() + member_offset = member.GetOffsetInBytes() + member_total_offset = member_offset + base_offset + member_byte_size = member_type.GetByteSize() + is_class_or_struct = False + if member_type_class == lldb.eTypeClassStruct or member_type_class == lldb.eTypeClassClass: + is_class_or_struct = True + if member_idx == 0 and member_offset == target.GetAddressByteSize() and type.IsPolymorphicClass(): + ptr_size = target.GetAddressByteSize() + print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1)) + prev_end_offset = ptr_size + else: + if prev_end_offset < member_total_offset: + member_padding = member_total_offset - prev_end_offset + padding = padding + member_padding + print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, member_padding, ' ' * (depth + 1)) + + if is_class_or_struct: + (prev_end_offset, padding) = verify_type_recursive (target, member_canonical_type, member_name, depth + 1, member_total_offset, padding) + else: + prev_end_offset = member_total_offset + member_byte_size + if member.IsBitfield(): + print '%+4u <%3u> %s%s:%u %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_type.GetName(), member.GetBitfieldSizeInBits(), member_name) + else: + print '%+4u <%3u> %s%s %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_type.GetName(), member_name) + + if prev_end_offset < byte_size: + last_member_padding = byte_size - prev_end_offset + print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, last_member_padding, ' ' * (depth + 1)) + padding += last_member_padding + else: + if type.IsPolymorphicClass(): + ptr_size = target.GetAddressByteSize() + print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1)) + prev_end_offset = ptr_size + prev_end_offset = base_offset + type.GetByteSize() + + return (prev_end_offset, padding) + +def types_command (debugger, command, result, dict): + # Use the Shell Lexer to properly parse up command options just like a + # shell would + command_args = shlex.split(command) + verify_types(debugger, command_args) + +def verify_types (debugger, command_args): + + parser = create_types_options() + try: + (options, args) = 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.SetStatus (lldb.eReturnStatusFailed) + return "option parsing failed" # returning a string is the same as returning an error whose description is the string + + if options.debug: + print 'Waiting for debugger to attach...' + for i in range(10): + time.sleep(1) + print '.' + + for path in args: + # in a command - the lldb.* convenience variables are not to be used + # and their values (if any) are undefined + # this is the best practice to access those objects from within a command + error = lldb.SBError() + target = debugger.CreateTarget (path, + options.arch, + options.platform, + True, + error) + if error.Fail(): + print error.GetCString() + continue + + print target + modules = list() + if len(options.modules) == 0: + # Append just the main executable if nothing was specified + module = target.modules[0] + if module: + modules.append(module) + else: + for module_name in options.modules: + module = lldb.target.module[module_name] + if module: + modules.append(module) + + if modules: + for module in modules: + print 'module: %s' % (module.file) + if options.typenames: + for typename in options.typenames: + print typename + types = module.FindTypes(typename) + if types.GetSize(): + for type in types: + verify_type (target, type) + else: + print 'error: no type matches "%s"' % (typename) + else: + types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct) + for type in types: + verify_type (target, type) + else: + print 'error: no modules' + +if __name__ == '__main__': + debugger = lldb.SBDebugger.Create() + verify_types (debugger, sys.argv[1:]) +elif getattr(lldb, 'debugger', None): + lldb.debugger.HandleCommand('command script add -f types.types_command types') + print '"types" command installed, use the "--help" option for detailed help'
\ No newline at end of file |