blob: 15af61d56cad199693474f688aef366b8a8700c4 [file] [log] [blame]
Johnny Chenafd19042011-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 Chen2efc7c62011-03-28 22:48:25 +000014 Add LLDB.framework/Resources/Python and the test dir to the sys.path.
Johnny Chenafd19042011-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 Chen9aaceb12011-03-29 01:07:00 +000067def run_command(ci, cmd, res, echoInput=True, echoOutput=True):
68 if echoInput:
69 print "run command:", cmd
Johnny Chenafd19042011-03-28 22:40:32 +000070 ci.HandleCommand(cmd, res)
71 if res.Succeeded():
Johnny Chen9aaceb12011-03-29 01:07:00 +000072 if echoOutput:
73 print "run_command output:", res.GetOutput()
Johnny Chenafd19042011-03-28 22:40:32 +000074 else:
Johnny Chen9aaceb12011-03-29 01:07:00 +000075 if echoOutput:
76 print "run command failed!"
77 print "run_command error:", res.GetError()
Johnny Chenafd19042011-03-28 22:40:32 +000078
Johnny Chen337836b2011-03-30 18:47:54 +000079def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, symbols_to_disassemble):
Johnny Chen7df6fc42011-03-31 01:06:28 +000080 import lldb, atexit, re
81 from lldbutil import lldb_iter
Johnny Chenafd19042011-03-28 22:40:32 +000082
83 # Create the debugger instance now.
84 dbg = lldb.SBDebugger.Create()
85 if not dbg.IsValid():
86 raise Exception('Invalid debugger instance')
87
88 # Register an exit callback.
89 atexit.register(lambda: lldb.SBDebugger.Terminate())
90
91 # We want our debugger to be synchronous.
92 dbg.SetAsync(False)
93
94 # Get the command interpreter from the debugger.
95 ci = dbg.GetCommandInterpreter()
96 if not ci:
97 raise Exception('Could not get the command interpreter')
98
99 # And the associated result object.
100 res = lldb.SBCommandReturnObject()
101
102 # See if there any extra command(s) to execute before we issue the file command.
103 for cmd in lldb_commands:
104 run_command(ci, cmd, res)
105
Johnny Chen563ce6a2011-03-31 01:34:55 +0000106 # Now issue the file command.
107 run_command(ci, 'file %s' % exe, res)
108
Johnny Chen7df6fc42011-03-31 01:06:28 +0000109 # Create a target.
Johnny Chen563ce6a2011-03-31 01:34:55 +0000110 #target = dbg.CreateTarget(exe)
111 target = dbg.GetSelectedTarget()
Johnny Chen7df6fc42011-03-31 01:06:28 +0000112 stream = lldb.SBStream()
113
Johnny Chen563ce6a2011-03-31 01:34:55 +0000114 def IsCodeType(symbol):
115 """Check whether an SBSymbol represents code."""
116 return symbol.GetType() == lldb.eSymbolTypeCode
117
Johnny Chen7df6fc42011-03-31 01:06:28 +0000118 # Define a generator for the symbols to disassemble.
Johnny Chen563ce6a2011-03-31 01:34:55 +0000119 def symbol_iter(num, symbols, target):
Johnny Chen7df6fc42011-03-31 01:06:28 +0000120 # If we specify the symbols to disassemble, ignore symbol table dump.
121 if symbols:
122 for i in range(len(symbols)):
123 print "symbol:", symbols[i]
124 yield symbols[i]
125 else:
126 limited = True if num != -1 else False
127 if limited:
128 count = 0
129 stream = lldb.SBStream()
130 for m in lldb_iter(target, 'GetNumModules', 'GetModuleAtIndex'):
131 print "module:", m
132 for s in lldb_iter(m, 'GetNumSymbols', 'GetSymbolAtIndex'):
133 if limited and count >= num:
134 return
135 print "symbol:", s.GetName()
136 if IsCodeType(s):
137 if limited:
138 count = count + 1
Johnny Chen563ce6a2011-03-31 01:34:55 +0000139 print "returning symbol:", s.GetName()
Johnny Chen7df6fc42011-03-31 01:06:28 +0000140 yield s.GetName()
141 #print "start address:", s.GetStartAddress()
142 #print "end address:", s.GetEndAddress()
143 #s.GetDescription(stream)
144 #print "symbol description:", stream.GetData()
145 #stream.Clear()
146
Johnny Chen337836b2011-03-30 18:47:54 +0000147 # Disassembly time.
Johnny Chen563ce6a2011-03-31 01:34:55 +0000148 for symbol in symbol_iter(num_symbols, symbols_to_disassemble, target):
Johnny Chen337836b2011-03-30 18:47:54 +0000149 cmd = "disassemble %s '%s'" % (disassemble_options, symbol)
150 run_command(ci, cmd, res)
Johnny Chen9aaceb12011-03-29 01:07:00 +0000151
Johnny Chenafd19042011-03-28 22:40:32 +0000152
153def main():
154 # This is to set up the Python path to include the pexpect-2.4 dir.
155 # Remember to update this when/if things change.
156 scriptPath = sys.path[0]
157 sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4'))
158
159 parser = OptionParser(usage="""\
160Run lldb to disassemble all the available functions for an executable image.
161
162Usage: %prog [options]
163""")
164 parser.add_option('-C', '--lldb-command',
165 type='string', action='append', metavar='COMMAND',
166 default=[], dest='lldb_commands',
167 help='Command(s) lldb executes after starting up (can be empty)')
Johnny Chenafd19042011-03-28 22:40:32 +0000168 parser.add_option('-e', '--executable',
169 type='string', action='store',
170 dest='executable',
Johnny Chen9aaceb12011-03-29 01:07:00 +0000171 help="""Mandatory: the executable to do disassembly on.""")
172 parser.add_option('-o', '--options',
173 type='string', action='store',
174 dest='disassemble_options',
175 help="""Mandatory: the options passed to lldb's 'disassemble' command.""")
176 parser.add_option('-n', '--num-symbols',
Johnny Chen337836b2011-03-30 18:47:54 +0000177 type='int', action='store', default=-1,
Johnny Chen9aaceb12011-03-29 01:07:00 +0000178 dest='num_symbols',
179 help="""The number of symbols to disassemble, if specified.""")
Johnny Chen337836b2011-03-30 18:47:54 +0000180 parser.add_option('-s', '--symbol',
181 type='string', action='append', metavar='SYMBOL', default=[],
182 dest='symbols_to_disassemble',
183 help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""")
184
Johnny Chenafd19042011-03-28 22:40:32 +0000185 opts, args = parser.parse_args()
186
187 lldb_commands = opts.lldb_commands
Johnny Chenafd19042011-03-28 22:40:32 +0000188
Johnny Chen9aaceb12011-03-29 01:07:00 +0000189 if not opts.executable or not opts.disassemble_options:
Johnny Chenafd19042011-03-28 22:40:32 +0000190 parser.print_help()
191 sys.exit(1)
Johnny Chen9aaceb12011-03-29 01:07:00 +0000192
Johnny Chenafd19042011-03-28 22:40:32 +0000193 executable = opts.executable
Johnny Chen9aaceb12011-03-29 01:07:00 +0000194 disassemble_options = opts.disassemble_options
Johnny Chen337836b2011-03-30 18:47:54 +0000195 num_symbols = opts.num_symbols
196 symbols_to_disassemble = opts.symbols_to_disassemble
Johnny Chenafd19042011-03-28 22:40:32 +0000197
198 # We have parsed the options.
199 print "lldb commands:", lldb_commands
Johnny Chenafd19042011-03-28 22:40:32 +0000200 print "executable:", executable
Johnny Chen9aaceb12011-03-29 01:07:00 +0000201 print "disassemble options:", disassemble_options
202 print "num of symbols to disassemble:", num_symbols
Johnny Chen337836b2011-03-30 18:47:54 +0000203 print "symbols to disassemble:", symbols_to_disassemble
Johnny Chenafd19042011-03-28 22:40:32 +0000204
205 setupSysPath()
Johnny Chen337836b2011-03-30 18:47:54 +0000206 do_lldb_disassembly(lldb_commands, executable, disassemble_options, num_symbols, symbols_to_disassemble)
Johnny Chenafd19042011-03-28 22:40:32 +0000207
208if __name__ == '__main__':
209 main()