#!/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
#----------------------------------------------------------------------

from __future__ import print_function

import platform
import os
import re
import signal
import sys
import subprocess

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 = subprocess.check_output("xcode-select --print-path", shell=True)
        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 optparse
import shlex
import time


def regex_option_callback(option, opt_str, value, parser):
    if opt_str == "--std":
        value = '^std::'
    regex = re.compile(value)
    parser.values.skip_type_regexes.append(regex)


def create_types_options(for_lldb_command):
    if for_lldb_command:
        usage = "usage: %prog [options]"
        description = '''This command will help check for padding in between
base classes and members in structs and classes. It will summarize the types
and how much padding was found. If no types are specified with the --types TYPENAME
option, all structure and class types will be verified. If no modules are
specified with the --module option, only the target's main executable will be
searched.
'''
    else:
        usage = "usage: %prog [options] EXEPATH [EXEPATH ...]"
        description = '''This command will help check for padding in between
base classes and members in structures and classes. It will summarize the types
and how much padding was found. One or more paths to executable files must be
specified and targets will be created with these modules. If no types are
specified with the --types TYPENAME option, all structure and class types will
be verified in all specified modules.
'''
    parser = optparse.OptionParser(
        description=description,
        prog='framestats',
        usage=usage)
    if not for_lldb_command:
        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 the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
    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(
        '-d',
        '--debug',
        action='store_true',
        dest='debug',
        help='Pause 10 seconds to wait for a debugger to attach.',
        default=False)
    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(
        '-v',
        '--verbose',
        action='store_true',
        dest='verbose',
        help='Enable verbose logging and information.',
        default=False)
    parser.add_option(
        '-s',
        '--skip-type-regex',
        action="callback",
        callback=regex_option_callback,
        type='string',
        metavar='REGEX',
        dest='skip_type_regexes',
        help='Regular expressions that, if they match the current member typename, will cause the type to no be recursively displayed.',
        default=[])
    parser.add_option(
        '--std',
        action="callback",
        callback=regex_option_callback,
        metavar='REGEX',
        dest='skip_type_regexes',
        help="Don't' recurse into types in the std namespace.",
        default=[])
    return parser


def verify_type(target, options, type):
    print(type)
    typename = type.GetName()
    # print 'type: %s' % (typename)
    (end_offset, padding) = verify_type_recursive(
        target, options, 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))
    print()


def verify_type_recursive(
        target,
        options,
        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, byte_size, '    ' * depth, typename, member_name))
    else:
        print('%+4u {%3u} %s%s' % (base_offset, byte_size, '    ' * depth, typename))

    for type_regex in options.skip_type_regexes:
        match = type_regex.match(typename)
        if match:
            return (base_offset + byte_size, padding)

    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()
            member_is_class_or_struct = False
            if member_type_class == lldb.eTypeClassStruct or member_type_class == lldb.eTypeClassClass:
                member_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 member_is_class_or_struct:
                (prev_end_offset,
                 padding) = verify_type_recursive(target,
                                                  options,
                                                  member_canonical_type,
                                                  member_name,
                                                  depth + 1,
                                                  member_total_offset,
                                                  padding)
            else:
                prev_end_offset = member_total_offset + member_byte_size
                member_typename = member_type.GetName()
                if member.IsBitfield():
                    print('%+4u <%3u> %s%s:%u %s;' % (member_total_offset, member_byte_size, '    ' * (depth + 1), member_typename, member.GetBitfieldSizeInBits(), member_name))
                else:
                    print('%+4u <%3u> %s%s %s;' % (member_total_offset, member_byte_size, '    ' * (depth + 1), member_typename, 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 + byte_size

    return (prev_end_offset, padding)


def check_padding_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)
    parser = create_types_options(True)
    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)
        # returning a string is the same as returning an error whose
        # description is the string
        return "option parsing failed"
    verify_types(debugger.GetSelectedTarget(), options)


@lldb.command("parse_all_struct_class_types")
def parse_all_struct_class_types(debugger, command, result, dict):
    command_args = shlex.split(command)
    for f in command_args:
        error = lldb.SBError()
        target = debugger.CreateTarget(f, None, None, False, error)
        module = target.GetModuleAtIndex(0)
        print("Parsing all types in '%s'" % (module))
        types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct)
        for t in types:
            print(t)
        print("")


def verify_types(target, options):

    if not target:
        print('error: invalid target')
        return

    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:
                    types = module.FindTypes(typename)
                    if types.GetSize():
                        print('Found %u types matching "%s" in "%s"' % (len(types), typename, module.file))
                        for type in types:
                            verify_type(target, options, type)
                    else:
                        print('error: no type matches "%s" in "%s"' % (typename, module.file))
            else:
                types = module.GetTypes(
                    lldb.eTypeClassClass | lldb.eTypeClassStruct)
                print('Found %u types in "%s"' % (len(types), module.file))
                for type in types:
                    verify_type(target, options, type)
    else:
        print('error: no modules')

if __name__ == '__main__':
    debugger = lldb.SBDebugger.Create()
    parser = create_types_options(False)

    # try:
    (options, args) = parser.parse_args(sys.argv[1:])
    # except:
    #     print "error: option parsing failed"
    #     sys.exit(1)

    if options.debug:
        print("Waiting for debugger to attach to process %d" % os.getpid())
        os.kill(os.getpid(), signal.SIGSTOP)

    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
        verify_types(target, options)

elif getattr(lldb, 'debugger', None):
    lldb.debugger.HandleCommand(
        'command script add -f types.check_padding_command check_padding')
    print('"check_padding" command installed, use the "--help" option for detailed help')
