blob: 9671ee5f4c19d20abced2f97a369be3f53a04799 [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
9import sys
10from optparse import OptionParser
11
12def setupSysPath():
13 """
Johnny Chen4044fdc2011-03-28 22:48:25 +000014 Add LLDB.framework/Resources/Python and the test dir to the sys.path.
Johnny Chen5e28aa52011-03-28 22:40:32 +000015 """
16 # Get the directory containing the current script.
17 scriptPath = sys.path[0]
18 if not scriptPath.endswith(os.path.join('utils', 'test')):
19 print "This script expects to reside in lldb's utils/test directory."
20 sys.exit(-1)
21
22 # This is our base name component.
23 base = os.path.abspath(os.path.join(scriptPath, os.pardir, os.pardir))
24
25 # This is for the goodies in the test directory under base.
26 sys.path.append(os.path.join(base,'test'))
27
28 # These are for xcode build directories.
29 xcode3_build_dir = ['build']
30 xcode4_build_dir = ['build', 'lldb', 'Build', 'Products']
31 dbg = ['Debug']
32 rel = ['Release']
33 bai = ['BuildAndIntegration']
34 python_resource_dir = ['LLDB.framework', 'Resources', 'Python']
35
36 dbgPath = os.path.join(base, *(xcode3_build_dir + dbg + python_resource_dir))
37 dbgPath2 = os.path.join(base, *(xcode4_build_dir + dbg + python_resource_dir))
38 relPath = os.path.join(base, *(xcode3_build_dir + rel + python_resource_dir))
39 relPath2 = os.path.join(base, *(xcode4_build_dir + rel + python_resource_dir))
40 baiPath = os.path.join(base, *(xcode3_build_dir + bai + python_resource_dir))
41 baiPath2 = os.path.join(base, *(xcode4_build_dir + bai + python_resource_dir))
42
43 lldbPath = None
44 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
45 lldbPath = dbgPath
46 elif os.path.isfile(os.path.join(dbgPath2, 'lldb.py')):
47 lldbPath = dbgPath2
48 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
49 lldbPath = relPath
50 elif os.path.isfile(os.path.join(relPath2, 'lldb.py')):
51 lldbPath = relPath2
52 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
53 lldbPath = baiPath
54 elif os.path.isfile(os.path.join(baiPath2, 'lldb.py')):
55 lldbPath = baiPath2
56
57 if not lldbPath:
58 print 'This script requires lldb.py to be in either ' + dbgPath + ',',
59 print relPath + ', or ' + baiPath
60 sys.exit(-1)
61
62 # This is to locate the lldb.py module. Insert it right after sys.path[0].
63 sys.path[1:1] = [lldbPath]
64 print "sys.path:", sys.path
65
66
Johnny Chen6454e152011-03-29 01:07:00 +000067def run_command(ci, cmd, res, echoInput=True, echoOutput=True):
68 if echoInput:
69 print "run command:", cmd
Johnny Chen5e28aa52011-03-28 22:40:32 +000070 ci.HandleCommand(cmd, res)
71 if res.Succeeded():
Johnny Chen6454e152011-03-29 01:07:00 +000072 if echoOutput:
73 print "run_command output:", res.GetOutput()
Johnny Chen5e28aa52011-03-28 22:40:32 +000074 else:
Johnny Chen6454e152011-03-29 01:07:00 +000075 if echoOutput:
76 print "run command failed!"
77 print "run_command error:", res.GetError()
Johnny Chen5e28aa52011-03-28 22:40:32 +000078
Johnny Chen901209d2011-08-18 22:04:27 +000079def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, symbols_to_disassemble, quiet_disassembly):
Johnny Chen0e43f322011-03-31 01:06:28 +000080 import lldb, atexit, re
Johnny Chen5e28aa52011-03-28 22:40:32 +000081
82 # Create the debugger instance now.
83 dbg = lldb.SBDebugger.Create()
Johnny Chen26fc16b2011-05-25 20:47:27 +000084 if not dbg:
Johnny Chen5e28aa52011-03-28 22:40:32 +000085 raise Exception('Invalid debugger instance')
86
87 # Register an exit callback.
88 atexit.register(lambda: lldb.SBDebugger.Terminate())
89
90 # We want our debugger to be synchronous.
91 dbg.SetAsync(False)
92
93 # Get the command interpreter from the debugger.
94 ci = dbg.GetCommandInterpreter()
95 if not ci:
96 raise Exception('Could not get the command interpreter')
97
98 # And the associated result object.
99 res = lldb.SBCommandReturnObject()
100
101 # See if there any extra command(s) to execute before we issue the file command.
102 for cmd in lldb_commands:
103 run_command(ci, cmd, res)
104
Johnny Chend16c1052011-03-31 01:34:55 +0000105 # Now issue the file command.
106 run_command(ci, 'file %s' % exe, res)
107
Johnny Chen0e43f322011-03-31 01:06:28 +0000108 # Create a target.
Johnny Chend16c1052011-03-31 01:34:55 +0000109 #target = dbg.CreateTarget(exe)
110 target = dbg.GetSelectedTarget()
Johnny Chen0e43f322011-03-31 01:06:28 +0000111 stream = lldb.SBStream()
112
Johnny Chend16c1052011-03-31 01:34:55 +0000113 def IsCodeType(symbol):
114 """Check whether an SBSymbol represents code."""
115 return symbol.GetType() == lldb.eSymbolTypeCode
116
Johnny Chen0e43f322011-03-31 01:06:28 +0000117 # Define a generator for the symbols to disassemble.
Johnny Chen901209d2011-08-18 22:04:27 +0000118 def symbol_iter(num, symbols, target, verbose):
Johnny Chen0e43f322011-03-31 01:06:28 +0000119 # If we specify the symbols to disassemble, ignore symbol table dump.
120 if symbols:
121 for i in range(len(symbols)):
122 print "symbol:", symbols[i]
123 yield symbols[i]
124 else:
125 limited = True if num != -1 else False
126 if limited:
127 count = 0
128 stream = lldb.SBStream()
Johnny Chen6cd4d1d2011-04-28 23:34:58 +0000129 for m in target.module_iter():
Johnny Chen0e43f322011-03-31 01:06:28 +0000130 print "module:", m
Johnny Chen6cd4d1d2011-04-28 23:34:58 +0000131 for s in m:
Johnny Chen0e43f322011-03-31 01:06:28 +0000132 if limited and count >= num:
133 return
134 print "symbol:", s.GetName()
135 if IsCodeType(s):
136 if limited:
137 count = count + 1
Johnny Chen901209d2011-08-18 22:04:27 +0000138 if verbose:
139 print "returning symbol:", s.GetName()
Johnny Chen0e43f322011-03-31 01:06:28 +0000140 yield s.GetName()
Johnny Chen901209d2011-08-18 22:04:27 +0000141 if verbose:
142 print "start address:", s.GetStartAddress()
143 print "end address:", s.GetEndAddress()
144 s.GetDescription(stream)
145 print "symbol description:", stream.GetData()
146 stream.Clear()
Johnny Chen0e43f322011-03-31 01:06:28 +0000147
Johnny Chen318e7ba2011-03-30 18:47:54 +0000148 # Disassembly time.
Johnny Chen901209d2011-08-18 22:04:27 +0000149 for symbol in symbol_iter(num_symbols, symbols_to_disassemble, target, not quiet_disassembly):
Johnny Chen318e7ba2011-03-30 18:47:54 +0000150 cmd = "disassemble %s '%s'" % (disassemble_options, symbol)
Johnny Chen901209d2011-08-18 22:04:27 +0000151 run_command(ci, cmd, res, True, not quiet_disassembly)
Johnny Chen6454e152011-03-29 01:07:00 +0000152
Johnny Chen5e28aa52011-03-28 22:40:32 +0000153
154def main():
155 # This is to set up the Python path to include the pexpect-2.4 dir.
156 # Remember to update this when/if things change.
157 scriptPath = sys.path[0]
158 sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4'))
159
160 parser = OptionParser(usage="""\
161Run lldb to disassemble all the available functions for an executable image.
162
163Usage: %prog [options]
164""")
165 parser.add_option('-C', '--lldb-command',
166 type='string', action='append', metavar='COMMAND',
167 default=[], dest='lldb_commands',
168 help='Command(s) lldb executes after starting up (can be empty)')
Johnny Chen5e28aa52011-03-28 22:40:32 +0000169 parser.add_option('-e', '--executable',
170 type='string', action='store',
171 dest='executable',
Johnny Chen6454e152011-03-29 01:07:00 +0000172 help="""Mandatory: the executable to do disassembly on.""")
173 parser.add_option('-o', '--options',
174 type='string', action='store',
175 dest='disassemble_options',
176 help="""Mandatory: the options passed to lldb's 'disassemble' command.""")
177 parser.add_option('-n', '--num-symbols',
Johnny Chen318e7ba2011-03-30 18:47:54 +0000178 type='int', action='store', default=-1,
Johnny Chen6454e152011-03-29 01:07:00 +0000179 dest='num_symbols',
180 help="""The number of symbols to disassemble, if specified.""")
Johnny Chen901209d2011-08-18 22:04:27 +0000181 parser.add_option('-q', '--quiet-disassembly',
182 action='store_true', default=False,
183 dest='quiet_disassembly',
184 help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""")
Johnny Chen318e7ba2011-03-30 18:47:54 +0000185 parser.add_option('-s', '--symbol',
186 type='string', action='append', metavar='SYMBOL', default=[],
187 dest='symbols_to_disassemble',
188 help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""")
189
Johnny Chen5e28aa52011-03-28 22:40:32 +0000190 opts, args = parser.parse_args()
191
192 lldb_commands = opts.lldb_commands
Johnny Chen5e28aa52011-03-28 22:40:32 +0000193
Johnny Chen6454e152011-03-29 01:07:00 +0000194 if not opts.executable or not opts.disassemble_options:
Johnny Chen5e28aa52011-03-28 22:40:32 +0000195 parser.print_help()
196 sys.exit(1)
Johnny Chen6454e152011-03-29 01:07:00 +0000197
Johnny Chen5e28aa52011-03-28 22:40:32 +0000198 executable = opts.executable
Johnny Chen6454e152011-03-29 01:07:00 +0000199 disassemble_options = opts.disassemble_options
Johnny Chen318e7ba2011-03-30 18:47:54 +0000200 num_symbols = opts.num_symbols
Johnny Chen901209d2011-08-18 22:04:27 +0000201 quiet_disassembly = opts.quiet_disassembly
Johnny Chen318e7ba2011-03-30 18:47:54 +0000202 symbols_to_disassemble = opts.symbols_to_disassemble
Johnny Chen5e28aa52011-03-28 22:40:32 +0000203
204 # We have parsed the options.
205 print "lldb commands:", lldb_commands
Johnny Chen5e28aa52011-03-28 22:40:32 +0000206 print "executable:", executable
Johnny Chen6454e152011-03-29 01:07:00 +0000207 print "disassemble options:", disassemble_options
208 print "num of symbols to disassemble:", num_symbols
Johnny Chen901209d2011-08-18 22:04:27 +0000209 print "quiet disassembly output:", quiet_disassembly
Johnny Chen318e7ba2011-03-30 18:47:54 +0000210 print "symbols to disassemble:", symbols_to_disassemble
Johnny Chen5e28aa52011-03-28 22:40:32 +0000211
212 setupSysPath()
Johnny Chen901209d2011-08-18 22:04:27 +0000213 do_lldb_disassembly(lldb_commands, executable, disassemble_options,
214 num_symbols,
215 symbols_to_disassemble,
216 quiet_disassembly)
Johnny Chen5e28aa52011-03-28 22:40:32 +0000217
218if __name__ == '__main__':
219 main()