blob: 4bafc7c2901b34a5ecf8fdde26840afda65e4739 [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 Chen0e43f322011-03-31 01:06:28 +000079def IsCodeType(symbol):
80 """Check whether an SBSymbol represents code."""
81 return True
82
Johnny Chen318e7ba2011-03-30 18:47:54 +000083def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, symbols_to_disassemble):
Johnny Chen0e43f322011-03-31 01:06:28 +000084 import lldb, atexit, re
85 from lldbutil import lldb_iter
Johnny Chen5e28aa52011-03-28 22:40:32 +000086
87 # Create the debugger instance now.
88 dbg = lldb.SBDebugger.Create()
89 if not dbg.IsValid():
90 raise Exception('Invalid debugger instance')
91
92 # Register an exit callback.
93 atexit.register(lambda: lldb.SBDebugger.Terminate())
94
95 # We want our debugger to be synchronous.
96 dbg.SetAsync(False)
97
98 # Get the command interpreter from the debugger.
99 ci = dbg.GetCommandInterpreter()
100 if not ci:
101 raise Exception('Could not get the command interpreter')
102
103 # And the associated result object.
104 res = lldb.SBCommandReturnObject()
105
106 # See if there any extra command(s) to execute before we issue the file command.
107 for cmd in lldb_commands:
108 run_command(ci, cmd, res)
109
Johnny Chen0e43f322011-03-31 01:06:28 +0000110 # Create a target.
111 target = dbg.CreateTarget(exe)
112 stream = lldb.SBStream()
113
114 # Define a generator for the symbols to disassemble.
115 def symbol_iter_2(num, symbols, target):
116 # If we specify the symbols to disassemble, ignore symbol table dump.
117 if symbols:
118 for i in range(len(symbols)):
119 print "symbol:", symbols[i]
120 yield symbols[i]
121 else:
122 limited = True if num != -1 else False
123 if limited:
124 count = 0
125 stream = lldb.SBStream()
126 for m in lldb_iter(target, 'GetNumModules', 'GetModuleAtIndex'):
127 print "module:", m
128 for s in lldb_iter(m, 'GetNumSymbols', 'GetSymbolAtIndex'):
129 if limited and count >= num:
130 return
131 print "symbol:", s.GetName()
132 if IsCodeType(s):
133 if limited:
134 count = count + 1
135 yield s.GetName()
136 #print "start address:", s.GetStartAddress()
137 #print "end address:", s.GetEndAddress()
138 #s.GetDescription(stream)
139 #print "symbol description:", stream.GetData()
140 #stream.Clear()
141
Johnny Chen5e28aa52011-03-28 22:40:32 +0000142 # Now issue the file command.
143 run_command(ci, 'file %s' % exe, res)
144
145 # Send the 'image dump symtab' command.
Johnny Chen6454e152011-03-29 01:07:00 +0000146 run_command(ci, 'image dump symtab', res, echoOutput=False)
147
148 if not res.Succeeded():
149 print "Symbol table dump failed!"
150 sys.exit(-2)
151
152 # Do disassembly on the symbols.
153 # The following line from the 'image dump symtab' gives us a hint as to the
154 # starting char position of the symbol name.
155 # Index UserID DSX Type File Address/Value Load Address Size Flags Name
156 # ------- ------ --- ------------ ------------------ ------------------ ------------------ ---------- ----------------------------------
157 # [ 0] 0 Code 0x0000000000000820 0x0000000000000000 0x000e0008 sandbox_init_internal
158 symtab_dump = res.GetOutput()
159 symbol_pos = -1
160 code_type_pos = -1
161 code_type_end = -1
162
163 # Heuristics: the first 50 lines should give us the answer for symbol_pos and code_type_pos.
164 for line in symtab_dump.splitlines()[:50]:
165 print "line:", line
166 if re.match("^Index.*Name$", line):
167 symbol_pos = line.rfind('Name')
168 #print "symbol_pos:", symbol_pos
169 code_type_pos = line.find('Type')
170 code_type_end = code_type_pos + 4
171 #print "code_type_pos:", code_type_pos
172 break
173
Johnny Chen318e7ba2011-03-30 18:47:54 +0000174 # Define a generator for the symbols to disassemble.
175 def symbol_iter(num, symbols, symtab_dump):
176 # If we specify the symbols to disassemble, ignore symbol table dump.
177 if symbols:
178 for i in range(len(symbols)):
179 print "symbol:", symbols[i]
180 yield symbols[i]
181 else:
182 limited = True if num != -1 else False
Johnny Chen6454e152011-03-29 01:07:00 +0000183 if limited:
Johnny Chen318e7ba2011-03-30 18:47:54 +0000184 count = 0
185 for line in symtab_dump.splitlines():
186 if limited and count >= num:
187 return
188 if line[code_type_pos:code_type_end] == 'Code':
189 symbol = line[symbol_pos:]
190 print "symbol:", symbol
191 if limited:
192 count = count + 1
193 print "symbol count:", count
194 yield symbol
195
196 # Disassembly time.
197 for symbol in symbol_iter(num_symbols, symbols_to_disassemble, symtab_dump):
198 cmd = "disassemble %s '%s'" % (disassemble_options, symbol)
199 run_command(ci, cmd, res)
Johnny Chen6454e152011-03-29 01:07:00 +0000200
Johnny Chen5e28aa52011-03-28 22:40:32 +0000201
202def main():
203 # This is to set up the Python path to include the pexpect-2.4 dir.
204 # Remember to update this when/if things change.
205 scriptPath = sys.path[0]
206 sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4'))
207
208 parser = OptionParser(usage="""\
209Run lldb to disassemble all the available functions for an executable image.
210
211Usage: %prog [options]
212""")
213 parser.add_option('-C', '--lldb-command',
214 type='string', action='append', metavar='COMMAND',
215 default=[], dest='lldb_commands',
216 help='Command(s) lldb executes after starting up (can be empty)')
Johnny Chen5e28aa52011-03-28 22:40:32 +0000217 parser.add_option('-e', '--executable',
218 type='string', action='store',
219 dest='executable',
Johnny Chen6454e152011-03-29 01:07:00 +0000220 help="""Mandatory: the executable to do disassembly on.""")
221 parser.add_option('-o', '--options',
222 type='string', action='store',
223 dest='disassemble_options',
224 help="""Mandatory: the options passed to lldb's 'disassemble' command.""")
225 parser.add_option('-n', '--num-symbols',
Johnny Chen318e7ba2011-03-30 18:47:54 +0000226 type='int', action='store', default=-1,
Johnny Chen6454e152011-03-29 01:07:00 +0000227 dest='num_symbols',
228 help="""The number of symbols to disassemble, if specified.""")
Johnny Chen318e7ba2011-03-30 18:47:54 +0000229 parser.add_option('-s', '--symbol',
230 type='string', action='append', metavar='SYMBOL', default=[],
231 dest='symbols_to_disassemble',
232 help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""")
233
Johnny Chen5e28aa52011-03-28 22:40:32 +0000234 opts, args = parser.parse_args()
235
236 lldb_commands = opts.lldb_commands
Johnny Chen5e28aa52011-03-28 22:40:32 +0000237
Johnny Chen6454e152011-03-29 01:07:00 +0000238 if not opts.executable or not opts.disassemble_options:
Johnny Chen5e28aa52011-03-28 22:40:32 +0000239 parser.print_help()
240 sys.exit(1)
Johnny Chen6454e152011-03-29 01:07:00 +0000241
Johnny Chen5e28aa52011-03-28 22:40:32 +0000242 executable = opts.executable
Johnny Chen6454e152011-03-29 01:07:00 +0000243 disassemble_options = opts.disassemble_options
Johnny Chen318e7ba2011-03-30 18:47:54 +0000244 num_symbols = opts.num_symbols
245 symbols_to_disassemble = opts.symbols_to_disassemble
Johnny Chen5e28aa52011-03-28 22:40:32 +0000246
247 # We have parsed the options.
248 print "lldb commands:", lldb_commands
Johnny Chen5e28aa52011-03-28 22:40:32 +0000249 print "executable:", executable
Johnny Chen6454e152011-03-29 01:07:00 +0000250 print "disassemble options:", disassemble_options
251 print "num of symbols to disassemble:", num_symbols
Johnny Chen318e7ba2011-03-30 18:47:54 +0000252 print "symbols to disassemble:", symbols_to_disassemble
Johnny Chen5e28aa52011-03-28 22:40:32 +0000253
254 setupSysPath()
Johnny Chen318e7ba2011-03-30 18:47:54 +0000255 do_lldb_disassembly(lldb_commands, executable, disassemble_options, num_symbols, symbols_to_disassemble)
Johnny Chen5e28aa52011-03-28 22:40:32 +0000256
257if __name__ == '__main__':
258 main()