blob: a1b1ed70a7edcb306c6a14a6a93903b6c566b4df [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 Chen6454e152011-03-29 01:07:00 +000079def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols):
80 import lldb, lldbutil, atexit, re
Johnny Chen5e28aa52011-03-28 22:40:32 +000081
82 # Create the debugger instance now.
83 dbg = lldb.SBDebugger.Create()
84 if not dbg.IsValid():
85 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
105 # Now issue the file command.
106 run_command(ci, 'file %s' % exe, res)
107
108 # Send the 'image dump symtab' command.
Johnny Chen6454e152011-03-29 01:07:00 +0000109 run_command(ci, 'image dump symtab', res, echoOutput=False)
110
111 if not res.Succeeded():
112 print "Symbol table dump failed!"
113 sys.exit(-2)
114
115 # Do disassembly on the symbols.
116 # The following line from the 'image dump symtab' gives us a hint as to the
117 # starting char position of the symbol name.
118 # Index UserID DSX Type File Address/Value Load Address Size Flags Name
119 # ------- ------ --- ------------ ------------------ ------------------ ------------------ ---------- ----------------------------------
120 # [ 0] 0 Code 0x0000000000000820 0x0000000000000000 0x000e0008 sandbox_init_internal
121 symtab_dump = res.GetOutput()
122 symbol_pos = -1
123 code_type_pos = -1
124 code_type_end = -1
125
126 # Heuristics: the first 50 lines should give us the answer for symbol_pos and code_type_pos.
127 for line in symtab_dump.splitlines()[:50]:
128 print "line:", line
129 if re.match("^Index.*Name$", line):
130 symbol_pos = line.rfind('Name')
131 #print "symbol_pos:", symbol_pos
132 code_type_pos = line.find('Type')
133 code_type_end = code_type_pos + 4
134 #print "code_type_pos:", code_type_pos
135 break
136
137 # Disassembly time.
138 limited = True if num_symbols != -1 else False
139 if limited:
140 count = 0
141 for line in symtab_dump.splitlines():
142 if line[code_type_pos:code_type_end] == 'Code':
143 symbol = line[symbol_pos:]
144 #print "symbol:", symbol
145 cmd = "disassemble %s '%s'" % (disassemble_options, symbol)
146 run_command(ci, cmd, res)
147 if limited:
148 count = count + 1
149 print "number of symbols disassembled:", count
150 if count >= num_symbols:
151 break
152
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',
178 type='int', action='store',
179 dest='num_symbols',
180 help="""The number of symbols to disassemble, if specified.""")
Johnny Chen5e28aa52011-03-28 22:40:32 +0000181
182 opts, args = parser.parse_args()
183
184 lldb_commands = opts.lldb_commands
Johnny Chen5e28aa52011-03-28 22:40:32 +0000185
Johnny Chen6454e152011-03-29 01:07:00 +0000186 if not opts.executable or not opts.disassemble_options:
Johnny Chen5e28aa52011-03-28 22:40:32 +0000187 parser.print_help()
188 sys.exit(1)
Johnny Chen6454e152011-03-29 01:07:00 +0000189
Johnny Chen5e28aa52011-03-28 22:40:32 +0000190 executable = opts.executable
Johnny Chen6454e152011-03-29 01:07:00 +0000191 disassemble_options = opts.disassemble_options
192
193 if opts.num_symbols:
194 num_symbols = opts.num_symbols
195 else:
196 num_symbols = -1
Johnny Chen5e28aa52011-03-28 22:40:32 +0000197
198 # We have parsed the options.
199 print "lldb commands:", lldb_commands
Johnny Chen5e28aa52011-03-28 22:40:32 +0000200 print "executable:", executable
Johnny Chen6454e152011-03-29 01:07:00 +0000201 print "disassemble options:", disassemble_options
202 print "num of symbols to disassemble:", num_symbols
Johnny Chen5e28aa52011-03-28 22:40:32 +0000203
204 setupSysPath()
Johnny Chen6454e152011-03-29 01:07:00 +0000205 do_lldb_disassembly(lldb_commands, executable, disassemble_options, num_symbols)
Johnny Chen5e28aa52011-03-28 22:40:32 +0000206
207if __name__ == '__main__':
208 main()