summaryrefslogtreecommitdiffstats
path: root/lldb/examples
diff options
context:
space:
mode:
authorGreg Clayton <gclayton@apple.com>2013-06-19 21:50:28 +0000
committerGreg Clayton <gclayton@apple.com>2013-06-19 21:50:28 +0000
commitd8c3d4b1e9f8695a9c063615a324cb105c9ab780 (patch)
treecd14cf1ec62a3ee6215f7f1e8bab6cb0af9c9daf /lldb/examples
parent6d2cfb80ba239ed47d962d7dd2487c168082c531 (diff)
downloadbcm5719-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-xlldb/examples/python/types.py212
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
OpenPOWER on IntegriCloud