diff options
Diffstat (limited to 'lldb/utils/test/lldb-disasm.py')
-rwxr-xr-x | lldb/utils/test/lldb-disasm.py | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/lldb/utils/test/lldb-disasm.py b/lldb/utils/test/lldb-disasm.py new file mode 100755 index 00000000000..339e8e7caba --- /dev/null +++ b/lldb/utils/test/lldb-disasm.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python + +""" +Run lldb to disassemble all the available functions for an executable image. + +""" + +from __future__ import print_function + +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 + ',', end=' ') + 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 + import atexit + import 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() |