diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 |
commit | 9e6d35490a6542f9c97607f93c2ef8ca8e03cbcc (patch) | |
tree | dd2a1ddf0476664c2b823409c36cbccd52662ca7 /utils/test/lldb-disasm.py | |
parent | 3bd2e91faeb9eeec1aae82c64a3253afff551cfd (diff) |
Notes
Diffstat (limited to 'utils/test/lldb-disasm.py')
-rwxr-xr-x | utils/test/lldb-disasm.py | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/utils/test/lldb-disasm.py b/utils/test/lldb-disasm.py new file mode 100755 index 0000000000000..7987c6b01c37f --- /dev/null +++ b/utils/test/lldb-disasm.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python + +""" +Run lldb to disassemble all the available functions for an executable image. + +""" + +import os +import re +import sys +from optparse import OptionParser + +def setupSysPath(): + """ + Add LLDB.framework/Resources/Python and the test dir to the sys.path. + """ + # Get the directory containing the current script. + scriptPath = sys.path[0] + if not scriptPath.endswith(os.path.join('utils', 'test')): + print "This script expects to reside in lldb's utils/test directory." + sys.exit(-1) + + # This is our base name component. + base = os.path.abspath(os.path.join(scriptPath, os.pardir, os.pardir)) + + # This is for the goodies in the test directory under base. + sys.path.append(os.path.join(base,'test')) + + # These are for xcode build directories. + xcode3_build_dir = ['build'] + xcode4_build_dir = ['build', 'lldb', 'Build', 'Products'] + dbg = ['Debug'] + rel = ['Release'] + bai = ['BuildAndIntegration'] + python_resource_dir = ['LLDB.framework', 'Resources', 'Python'] + + dbgPath = os.path.join(base, *(xcode3_build_dir + dbg + python_resource_dir)) + dbgPath2 = os.path.join(base, *(xcode4_build_dir + dbg + python_resource_dir)) + relPath = os.path.join(base, *(xcode3_build_dir + rel + python_resource_dir)) + relPath2 = os.path.join(base, *(xcode4_build_dir + rel + python_resource_dir)) + baiPath = os.path.join(base, *(xcode3_build_dir + bai + python_resource_dir)) + baiPath2 = os.path.join(base, *(xcode4_build_dir + bai + python_resource_dir)) + + lldbPath = None + if os.path.isfile(os.path.join(dbgPath, 'lldb.py')): + lldbPath = dbgPath + elif os.path.isfile(os.path.join(dbgPath2, 'lldb.py')): + lldbPath = dbgPath2 + elif os.path.isfile(os.path.join(relPath, 'lldb.py')): + lldbPath = relPath + elif os.path.isfile(os.path.join(relPath2, 'lldb.py')): + lldbPath = relPath2 + elif os.path.isfile(os.path.join(baiPath, 'lldb.py')): + lldbPath = baiPath + elif os.path.isfile(os.path.join(baiPath2, 'lldb.py')): + lldbPath = baiPath2 + + if not lldbPath: + print 'This script requires lldb.py to be in either ' + dbgPath + ',', + print relPath + ', or ' + baiPath + sys.exit(-1) + + # This is to locate the lldb.py module. Insert it right after sys.path[0]. + sys.path[1:1] = [lldbPath] + #print "sys.path:", sys.path + + +def run_command(ci, cmd, res, echo=True): + if echo: + print "run command:", cmd + ci.HandleCommand(cmd, res) + if res.Succeeded(): + if echo: + print "run_command output:", res.GetOutput() + else: + if echo: + print "run command failed!" + print "run_command error:", res.GetError() + +def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, + symbols_to_disassemble, + re_symbol_pattern, + quiet_disassembly): + import lldb, atexit, re + + # Create the debugger instance now. + dbg = lldb.SBDebugger.Create() + if not dbg: + raise Exception('Invalid debugger instance') + + # Register an exit callback. + atexit.register(lambda: lldb.SBDebugger.Terminate()) + + # We want our debugger to be synchronous. + dbg.SetAsync(False) + + # Get the command interpreter from the debugger. + ci = dbg.GetCommandInterpreter() + if not ci: + raise Exception('Could not get the command interpreter') + + # And the associated result object. + res = lldb.SBCommandReturnObject() + + # See if there any extra command(s) to execute before we issue the file command. + for cmd in lldb_commands: + run_command(ci, cmd, res, not quiet_disassembly) + + # Now issue the file command. + run_command(ci, 'file %s' % exe, res, not quiet_disassembly) + + # Create a target. + #target = dbg.CreateTarget(exe) + target = dbg.GetSelectedTarget() + stream = lldb.SBStream() + + def IsCodeType(symbol): + """Check whether an SBSymbol represents code.""" + return symbol.GetType() == lldb.eSymbolTypeCode + + # Define a generator for the symbols to disassemble. + def symbol_iter(num, symbols, re_symbol_pattern, target, verbose): + # If we specify the symbols to disassemble, ignore symbol table dump. + if symbols: + for i in range(len(symbols)): + if verbose: + print "symbol:", symbols[i] + yield symbols[i] + else: + limited = True if num != -1 else False + if limited: + count = 0 + if re_symbol_pattern: + pattern = re.compile(re_symbol_pattern) + stream = lldb.SBStream() + for m in target.module_iter(): + if verbose: + print "module:", m + for s in m: + if limited and count >= num: + return + # If a regexp symbol pattern is supplied, consult it. + if re_symbol_pattern: + # If the pattern does not match, look for the next symbol. + if not pattern.match(s.GetName()): + continue + + # If we come here, we're ready to disassemble the symbol. + if verbose: + print "symbol:", s.GetName() + if IsCodeType(s): + if limited: + count = count + 1 + if verbose: + print "returning symbol:", s.GetName() + yield s.GetName() + if verbose: + print "start address:", s.GetStartAddress() + print "end address:", s.GetEndAddress() + s.GetDescription(stream) + print "symbol description:", stream.GetData() + stream.Clear() + + # Disassembly time. + for symbol in symbol_iter(num_symbols, symbols_to_disassemble, re_symbol_pattern, target, not quiet_disassembly): + cmd = "disassemble %s '%s'" % (disassemble_options, symbol) + run_command(ci, cmd, res, not quiet_disassembly) + + +def main(): + # This is to set up the Python path to include the pexpect-2.4 dir. + # Remember to update this when/if things change. + scriptPath = sys.path[0] + sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4')) + + parser = OptionParser(usage="""\ +Run lldb to disassemble all the available functions for an executable image. + +Usage: %prog [options] +""") + parser.add_option('-C', '--lldb-command', + type='string', action='append', metavar='COMMAND', + default=[], dest='lldb_commands', + help='Command(s) lldb executes after starting up (can be empty)') + parser.add_option('-e', '--executable', + type='string', action='store', + dest='executable', + help="""Mandatory: the executable to do disassembly on.""") + parser.add_option('-o', '--options', + type='string', action='store', + dest='disassemble_options', + help="""Mandatory: the options passed to lldb's 'disassemble' command.""") + parser.add_option('-q', '--quiet-disassembly', + action='store_true', default=False, + dest='quiet_disassembly', + help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") + parser.add_option('-n', '--num-symbols', + type='int', action='store', default=-1, + dest='num_symbols', + help="""The number of symbols to disassemble, if specified.""") + parser.add_option('-p', '--symbol_pattern', + type='string', action='store', + dest='re_symbol_pattern', + help="""The regular expression of symbols to invoke lldb's 'disassemble' command.""") + parser.add_option('-s', '--symbol', + type='string', action='append', metavar='SYMBOL', default=[], + dest='symbols_to_disassemble', + help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") + + opts, args = parser.parse_args() + + lldb_commands = opts.lldb_commands + + if not opts.executable or not opts.disassemble_options: + parser.print_help() + sys.exit(1) + + executable = opts.executable + disassemble_options = opts.disassemble_options + quiet_disassembly = opts.quiet_disassembly + num_symbols = opts.num_symbols + symbols_to_disassemble = opts.symbols_to_disassemble + re_symbol_pattern = opts.re_symbol_pattern + + # We have parsed the options. + if not quiet_disassembly: + print "lldb commands:", lldb_commands + print "executable:", executable + print "disassemble options:", disassemble_options + print "quiet disassembly output:", quiet_disassembly + print "num of symbols to disassemble:", num_symbols + print "symbols to disassemble:", symbols_to_disassemble + print "regular expression of symbols to disassemble:", re_symbol_pattern + + setupSysPath() + do_lldb_disassembly(lldb_commands, executable, disassemble_options, + num_symbols, + symbols_to_disassemble, + re_symbol_pattern, + quiet_disassembly) + +if __name__ == '__main__': + main() |