blob: 7987c6b01c37fc45876d3c815ae2e00a1ba119f9 [file] [log] [blame]
Johnny Chen5e28aa52011-03-28 22:40:32 +00001#!/usr/bin/env python
2
3"""
4Run lldb to disassemble all the available functions for an executable image.
5
6"""
7
8import os
Johnny Chen293683b2011-08-18 22:46:50 +00009import re
Johnny Chen5e28aa52011-03-28 22:40:32 +000010import sys
11from optparse import OptionParser
12
13def setupSysPath():
14 """
Johnny Chen4044fdc2011-03-28 22:48:25 +000015 Add LLDB.framework/Resources/Python and the test dir to the sys.path.
Johnny Chen5e28aa52011-03-28 22:40:32 +000016 """
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]
Johnny Chen758f2882011-08-19 20:51:15 +000065 #print "sys.path:", sys.path
Johnny Chen5e28aa52011-03-28 22:40:32 +000066
67
Johnny Chen758f2882011-08-19 20:51:15 +000068def run_command(ci, cmd, res, echo=True):
69 if echo:
Johnny Chen6454e152011-03-29 01:07:00 +000070 print "run command:", cmd
Johnny Chen5e28aa52011-03-28 22:40:32 +000071 ci.HandleCommand(cmd, res)
72 if res.Succeeded():
Johnny Chen758f2882011-08-19 20:51:15 +000073 if echo:
Johnny Chen6454e152011-03-29 01:07:00 +000074 print "run_command output:", res.GetOutput()
Johnny Chen5e28aa52011-03-28 22:40:32 +000075 else:
Johnny Chen758f2882011-08-19 20:51:15 +000076 if echo:
Johnny Chen6454e152011-03-29 01:07:00 +000077 print "run command failed!"
78 print "run_command error:", res.GetError()
Johnny Chen5e28aa52011-03-28 22:40:32 +000079
Johnny Chen293683b2011-08-18 22:46:50 +000080def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols,
81 symbols_to_disassemble,
82 re_symbol_pattern,
83 quiet_disassembly):
Johnny Chen0e43f322011-03-31 01:06:28 +000084 import lldb, atexit, re
Johnny Chen5e28aa52011-03-28 22:40:32 +000085
86 # Create the debugger instance now.
87 dbg = lldb.SBDebugger.Create()
Johnny Chen26fc16b2011-05-25 20:47:27 +000088 if not dbg:
Johnny Chen5e28aa52011-03-28 22:40:32 +000089 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:
Johnny Chen758f2882011-08-19 20:51:15 +0000107 run_command(ci, cmd, res, not quiet_disassembly)
Johnny Chen5e28aa52011-03-28 22:40:32 +0000108
Johnny Chend16c1052011-03-31 01:34:55 +0000109 # Now issue the file command.
Johnny Chen758f2882011-08-19 20:51:15 +0000110 run_command(ci, 'file %s' % exe, res, not quiet_disassembly)
Johnny Chend16c1052011-03-31 01:34:55 +0000111
Johnny Chen0e43f322011-03-31 01:06:28 +0000112 # Create a target.
Johnny Chend16c1052011-03-31 01:34:55 +0000113 #target = dbg.CreateTarget(exe)
114 target = dbg.GetSelectedTarget()
Johnny Chen0e43f322011-03-31 01:06:28 +0000115 stream = lldb.SBStream()
116
Johnny Chend16c1052011-03-31 01:34:55 +0000117 def IsCodeType(symbol):
118 """Check whether an SBSymbol represents code."""
119 return symbol.GetType() == lldb.eSymbolTypeCode
120
Johnny Chen0e43f322011-03-31 01:06:28 +0000121 # Define a generator for the symbols to disassemble.
Johnny Chen293683b2011-08-18 22:46:50 +0000122 def symbol_iter(num, symbols, re_symbol_pattern, target, verbose):
Johnny Chen0e43f322011-03-31 01:06:28 +0000123 # If we specify the symbols to disassemble, ignore symbol table dump.
124 if symbols:
125 for i in range(len(symbols)):
Johnny Chen758f2882011-08-19 20:51:15 +0000126 if verbose:
127 print "symbol:", symbols[i]
Johnny Chen0e43f322011-03-31 01:06:28 +0000128 yield symbols[i]
129 else:
130 limited = True if num != -1 else False
131 if limited:
132 count = 0
Johnny Chen4c35b712011-08-19 17:28:25 +0000133 if re_symbol_pattern:
134 pattern = re.compile(re_symbol_pattern)
Johnny Chen0e43f322011-03-31 01:06:28 +0000135 stream = lldb.SBStream()
Johnny Chen6cd4d1d2011-04-28 23:34:58 +0000136 for m in target.module_iter():
Johnny Chen758f2882011-08-19 20:51:15 +0000137 if verbose:
138 print "module:", m
Johnny Chen6cd4d1d2011-04-28 23:34:58 +0000139 for s in m:
Johnny Chen0e43f322011-03-31 01:06:28 +0000140 if limited and count >= num:
141 return
Johnny Chen293683b2011-08-18 22:46:50 +0000142 # 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.
Johnny Chen758f2882011-08-19 20:51:15 +0000149 if verbose:
150 print "symbol:", s.GetName()
Johnny Chen0e43f322011-03-31 01:06:28 +0000151 if IsCodeType(s):
152 if limited:
153 count = count + 1
Johnny Chen901209d2011-08-18 22:04:27 +0000154 if verbose:
155 print "returning symbol:", s.GetName()
Johnny Chen0e43f322011-03-31 01:06:28 +0000156 yield s.GetName()
Johnny Chen901209d2011-08-18 22:04:27 +0000157 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()
Johnny Chen0e43f322011-03-31 01:06:28 +0000163
Johnny Chen318e7ba2011-03-30 18:47:54 +0000164 # Disassembly time.
Johnny Chen293683b2011-08-18 22:46:50 +0000165 for symbol in symbol_iter(num_symbols, symbols_to_disassemble, re_symbol_pattern, target, not quiet_disassembly):
Johnny Chen318e7ba2011-03-30 18:47:54 +0000166 cmd = "disassemble %s '%s'" % (disassemble_options, symbol)
Johnny Chen758f2882011-08-19 20:51:15 +0000167 run_command(ci, cmd, res, not quiet_disassembly)
Johnny Chen6454e152011-03-29 01:07:00 +0000168
Johnny Chen5e28aa52011-03-28 22:40:32 +0000169
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)')
Johnny Chen5e28aa52011-03-28 22:40:32 +0000185 parser.add_option('-e', '--executable',
186 type='string', action='store',
187 dest='executable',
Johnny Chen6454e152011-03-29 01:07:00 +0000188 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.""")
Johnny Chen901209d2011-08-18 22:04:27 +0000193 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.""")
Johnny Chen293683b2011-08-18 22:46:50 +0000197 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.""")
Johnny Chen318e7ba2011-03-30 18:47:54 +0000205 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
Johnny Chen5e28aa52011-03-28 22:40:32 +0000210 opts, args = parser.parse_args()
211
212 lldb_commands = opts.lldb_commands
Johnny Chen5e28aa52011-03-28 22:40:32 +0000213
Johnny Chen6454e152011-03-29 01:07:00 +0000214 if not opts.executable or not opts.disassemble_options:
Johnny Chen5e28aa52011-03-28 22:40:32 +0000215 parser.print_help()
216 sys.exit(1)
Johnny Chen6454e152011-03-29 01:07:00 +0000217
Johnny Chen5e28aa52011-03-28 22:40:32 +0000218 executable = opts.executable
Johnny Chen6454e152011-03-29 01:07:00 +0000219 disassemble_options = opts.disassemble_options
Johnny Chen901209d2011-08-18 22:04:27 +0000220 quiet_disassembly = opts.quiet_disassembly
Johnny Chen293683b2011-08-18 22:46:50 +0000221 num_symbols = opts.num_symbols
Johnny Chen318e7ba2011-03-30 18:47:54 +0000222 symbols_to_disassemble = opts.symbols_to_disassemble
Johnny Chen293683b2011-08-18 22:46:50 +0000223 re_symbol_pattern = opts.re_symbol_pattern
Johnny Chen5e28aa52011-03-28 22:40:32 +0000224
225 # We have parsed the options.
Johnny Chen758f2882011-08-19 20:51:15 +0000226 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
Johnny Chen5e28aa52011-03-28 22:40:32 +0000234
235 setupSysPath()
Johnny Chen901209d2011-08-18 22:04:27 +0000236 do_lldb_disassembly(lldb_commands, executable, disassemble_options,
237 num_symbols,
238 symbols_to_disassemble,
Johnny Chen293683b2011-08-18 22:46:50 +0000239 re_symbol_pattern,
Johnny Chen901209d2011-08-18 22:04:27 +0000240 quiet_disassembly)
Johnny Chen5e28aa52011-03-28 22:40:32 +0000241
242if __name__ == '__main__':
243 main()