1#!/usr/bin/env python 2 3""" 4Run lldb to disassemble all the available functions for an executable image. 5 6""" 7 8import os 9import re 10import sys 11from optparse import OptionParser 12 13def setupSysPath(): 14 """ 15 Add LLDB.framework/Resources/Python and the test dir to the sys.path. 16 """ 17 # Get the directory containing the current script. 18 scriptPath = sys.path[0] 19 if not scriptPath.endswith(os.path.join('utils', 'test')): 20 print "This script expects to reside in lldb's utils/test directory." 21 sys.exit(-1) 22 23 # This is our base name component. 24 base = os.path.abspath(os.path.join(scriptPath, os.pardir, os.pardir)) 25 26 # This is for the goodies in the test directory under base. 27 sys.path.append(os.path.join(base,'test')) 28 29 # These are for xcode build directories. 30 xcode3_build_dir = ['build'] 31 xcode4_build_dir = ['build', 'lldb', 'Build', 'Products'] 32 dbg = ['Debug'] 33 rel = ['Release'] 34 bai = ['BuildAndIntegration'] 35 python_resource_dir = ['LLDB.framework', 'Resources', 'Python'] 36 37 dbgPath = os.path.join(base, *(xcode3_build_dir + dbg + python_resource_dir)) 38 dbgPath2 = os.path.join(base, *(xcode4_build_dir + dbg + python_resource_dir)) 39 relPath = os.path.join(base, *(xcode3_build_dir + rel + python_resource_dir)) 40 relPath2 = os.path.join(base, *(xcode4_build_dir + rel + python_resource_dir)) 41 baiPath = os.path.join(base, *(xcode3_build_dir + bai + python_resource_dir)) 42 baiPath2 = os.path.join(base, *(xcode4_build_dir + bai + python_resource_dir)) 43 44 lldbPath = None 45 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')): 46 lldbPath = dbgPath 47 elif os.path.isfile(os.path.join(dbgPath2, 'lldb.py')): 48 lldbPath = dbgPath2 49 elif os.path.isfile(os.path.join(relPath, 'lldb.py')): 50 lldbPath = relPath 51 elif os.path.isfile(os.path.join(relPath2, 'lldb.py')): 52 lldbPath = relPath2 53 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')): 54 lldbPath = baiPath 55 elif os.path.isfile(os.path.join(baiPath2, 'lldb.py')): 56 lldbPath = baiPath2 57 58 if not lldbPath: 59 print 'This script requires lldb.py to be in either ' + dbgPath + ',', 60 print relPath + ', or ' + baiPath 61 sys.exit(-1) 62 63 # This is to locate the lldb.py module. Insert it right after sys.path[0]. 64 sys.path[1:1] = [lldbPath] 65 #print "sys.path:", sys.path 66 67 68def run_command(ci, cmd, res, echo=True): 69 if echo: 70 print "run command:", cmd 71 ci.HandleCommand(cmd, res) 72 if res.Succeeded(): 73 if echo: 74 print "run_command output:", res.GetOutput() 75 else: 76 if echo: 77 print "run command failed!" 78 print "run_command error:", res.GetError() 79 80def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, 81 symbols_to_disassemble, 82 re_symbol_pattern, 83 quiet_disassembly): 84 import lldb, atexit, re 85 86 # Create the debugger instance now. 87 dbg = lldb.SBDebugger.Create() 88 if not dbg: 89 raise Exception('Invalid debugger instance') 90 91 # Register an exit callback. 92 atexit.register(lambda: lldb.SBDebugger.Terminate()) 93 94 # We want our debugger to be synchronous. 95 dbg.SetAsync(False) 96 97 # Get the command interpreter from the debugger. 98 ci = dbg.GetCommandInterpreter() 99 if not ci: 100 raise Exception('Could not get the command interpreter') 101 102 # And the associated result object. 103 res = lldb.SBCommandReturnObject() 104 105 # See if there any extra command(s) to execute before we issue the file command. 106 for cmd in lldb_commands: 107 run_command(ci, cmd, res, not quiet_disassembly) 108 109 # Now issue the file command. 110 run_command(ci, 'file %s' % exe, res, not quiet_disassembly) 111 112 # Create a target. 113 #target = dbg.CreateTarget(exe) 114 target = dbg.GetSelectedTarget() 115 stream = lldb.SBStream() 116 117 def IsCodeType(symbol): 118 """Check whether an SBSymbol represents code.""" 119 return symbol.GetType() == lldb.eSymbolTypeCode 120 121 # Define a generator for the symbols to disassemble. 122 def symbol_iter(num, symbols, re_symbol_pattern, target, verbose): 123 # If we specify the symbols to disassemble, ignore symbol table dump. 124 if symbols: 125 for i in range(len(symbols)): 126 if verbose: 127 print "symbol:", symbols[i] 128 yield symbols[i] 129 else: 130 limited = True if num != -1 else False 131 if limited: 132 count = 0 133 if re_symbol_pattern: 134 pattern = re.compile(re_symbol_pattern) 135 stream = lldb.SBStream() 136 for m in target.module_iter(): 137 if verbose: 138 print "module:", m 139 for s in m: 140 if limited and count >= num: 141 return 142 # If a regexp symbol pattern is supplied, consult it. 143 if re_symbol_pattern: 144 # If the pattern does not match, look for the next symbol. 145 if not pattern.match(s.GetName()): 146 continue 147 148 # If we come here, we're ready to disassemble the symbol. 149 if verbose: 150 print "symbol:", s.GetName() 151 if IsCodeType(s): 152 if limited: 153 count = count + 1 154 if verbose: 155 print "returning symbol:", s.GetName() 156 yield s.GetName() 157 if verbose: 158 print "start address:", s.GetStartAddress() 159 print "end address:", s.GetEndAddress() 160 s.GetDescription(stream) 161 print "symbol description:", stream.GetData() 162 stream.Clear() 163 164 # Disassembly time. 165 for symbol in symbol_iter(num_symbols, symbols_to_disassemble, re_symbol_pattern, target, not quiet_disassembly): 166 cmd = "disassemble %s '%s'" % (disassemble_options, symbol) 167 run_command(ci, cmd, res, not quiet_disassembly) 168 169 170def main(): 171 # This is to set up the Python path to include the pexpect-2.4 dir. 172 # Remember to update this when/if things change. 173 scriptPath = sys.path[0] 174 sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4')) 175 176 parser = OptionParser(usage="""\ 177Run lldb to disassemble all the available functions for an executable image. 178 179Usage: %prog [options] 180""") 181 parser.add_option('-C', '--lldb-command', 182 type='string', action='append', metavar='COMMAND', 183 default=[], dest='lldb_commands', 184 help='Command(s) lldb executes after starting up (can be empty)') 185 parser.add_option('-e', '--executable', 186 type='string', action='store', 187 dest='executable', 188 help="""Mandatory: the executable to do disassembly on.""") 189 parser.add_option('-o', '--options', 190 type='string', action='store', 191 dest='disassemble_options', 192 help="""Mandatory: the options passed to lldb's 'disassemble' command.""") 193 parser.add_option('-q', '--quiet-disassembly', 194 action='store_true', default=False, 195 dest='quiet_disassembly', 196 help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") 197 parser.add_option('-n', '--num-symbols', 198 type='int', action='store', default=-1, 199 dest='num_symbols', 200 help="""The number of symbols to disassemble, if specified.""") 201 parser.add_option('-p', '--symbol_pattern', 202 type='string', action='store', 203 dest='re_symbol_pattern', 204 help="""The regular expression of symbols to invoke lldb's 'disassemble' command.""") 205 parser.add_option('-s', '--symbol', 206 type='string', action='append', metavar='SYMBOL', default=[], 207 dest='symbols_to_disassemble', 208 help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") 209 210 opts, args = parser.parse_args() 211 212 lldb_commands = opts.lldb_commands 213 214 if not opts.executable or not opts.disassemble_options: 215 parser.print_help() 216 sys.exit(1) 217 218 executable = opts.executable 219 disassemble_options = opts.disassemble_options 220 quiet_disassembly = opts.quiet_disassembly 221 num_symbols = opts.num_symbols 222 symbols_to_disassemble = opts.symbols_to_disassemble 223 re_symbol_pattern = opts.re_symbol_pattern 224 225 # We have parsed the options. 226 if not quiet_disassembly: 227 print "lldb commands:", lldb_commands 228 print "executable:", executable 229 print "disassemble options:", disassemble_options 230 print "quiet disassembly output:", quiet_disassembly 231 print "num of symbols to disassemble:", num_symbols 232 print "symbols to disassemble:", symbols_to_disassemble 233 print "regular expression of symbols to disassemble:", re_symbol_pattern 234 235 setupSysPath() 236 do_lldb_disassembly(lldb_commands, executable, disassemble_options, 237 num_symbols, 238 symbols_to_disassemble, 239 re_symbol_pattern, 240 quiet_disassembly) 241 242if __name__ == '__main__': 243 main() 244