]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - utils/test/lldb-disasm.py
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / utils / test / lldb-disasm.py
1 #!/usr/bin/env python
2
3 """
4 Run lldb to disassemble all the available functions for an executable image.
5
6 """
7
8 import os
9 import re
10 import sys
11 from optparse import OptionParser
12
13
14 def setupSysPath():
15     """
16     Add LLDB.framework/Resources/Python and the test dir to the sys.path.
17     """
18     # Get the directory containing the current script.
19     scriptPath = sys.path[0]
20     if not scriptPath.endswith(os.path.join('utils', 'test')):
21         print "This script expects to reside in lldb's utils/test directory."
22         sys.exit(-1)
23
24     # This is our base name component.
25     base = os.path.abspath(os.path.join(scriptPath, os.pardir, os.pardir))
26
27     # This is for the goodies in the test directory under base.
28     sys.path.append(os.path.join(base, 'test'))
29
30     # These are for xcode build directories.
31     xcode3_build_dir = ['build']
32     xcode4_build_dir = ['build', 'lldb', 'Build', 'Products']
33     dbg = ['Debug']
34     rel = ['Release']
35     bai = ['BuildAndIntegration']
36     python_resource_dir = ['LLDB.framework', 'Resources', 'Python']
37
38     dbgPath = os.path.join(
39         base, *(xcode3_build_dir + dbg + python_resource_dir))
40     dbgPath2 = os.path.join(
41         base, *(xcode4_build_dir + dbg + python_resource_dir))
42     relPath = os.path.join(
43         base, *(xcode3_build_dir + rel + python_resource_dir))
44     relPath2 = os.path.join(
45         base, *(xcode4_build_dir + rel + python_resource_dir))
46     baiPath = os.path.join(
47         base, *(xcode3_build_dir + bai + python_resource_dir))
48     baiPath2 = os.path.join(
49         base, *(xcode4_build_dir + bai + python_resource_dir))
50
51     lldbPath = None
52     if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
53         lldbPath = dbgPath
54     elif os.path.isfile(os.path.join(dbgPath2, 'lldb.py')):
55         lldbPath = dbgPath2
56     elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
57         lldbPath = relPath
58     elif os.path.isfile(os.path.join(relPath2, 'lldb.py')):
59         lldbPath = relPath2
60     elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
61         lldbPath = baiPath
62     elif os.path.isfile(os.path.join(baiPath2, 'lldb.py')):
63         lldbPath = baiPath2
64
65     if not lldbPath:
66         print 'This script requires lldb.py to be in either ' + dbgPath + ',',
67         print relPath + ', or ' + baiPath
68         sys.exit(-1)
69
70     # This is to locate the lldb.py module.  Insert it right after sys.path[0].
71     sys.path[1:1] = [lldbPath]
72     # print "sys.path:", sys.path
73
74
75 def run_command(ci, cmd, res, echo=True):
76     if echo:
77         print "run command:", cmd
78     ci.HandleCommand(cmd, res)
79     if res.Succeeded():
80         if echo:
81             print "run_command output:", res.GetOutput()
82     else:
83         if echo:
84             print "run command failed!"
85             print "run_command error:", res.GetError()
86
87
88 def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols,
89                         symbols_to_disassemble,
90                         re_symbol_pattern,
91                         quiet_disassembly):
92     import lldb
93     import atexit
94     import re
95
96     # Create the debugger instance now.
97     dbg = lldb.SBDebugger.Create()
98     if not dbg:
99         raise Exception('Invalid debugger instance')
100
101     # Register an exit callback.
102     atexit.register(lambda: lldb.SBDebugger.Terminate())
103
104     # We want our debugger to be synchronous.
105     dbg.SetAsync(False)
106
107     # Get the command interpreter from the debugger.
108     ci = dbg.GetCommandInterpreter()
109     if not ci:
110         raise Exception('Could not get the command interpreter')
111
112     # And the associated result object.
113     res = lldb.SBCommandReturnObject()
114
115     # See if there any extra command(s) to execute before we issue the file
116     # command.
117     for cmd in lldb_commands:
118         run_command(ci, cmd, res, not quiet_disassembly)
119
120     # Now issue the file command.
121     run_command(ci, 'file %s' % exe, res, not quiet_disassembly)
122
123     # Create a target.
124     #target = dbg.CreateTarget(exe)
125     target = dbg.GetSelectedTarget()
126     stream = lldb.SBStream()
127
128     def IsCodeType(symbol):
129         """Check whether an SBSymbol represents code."""
130         return symbol.GetType() == lldb.eSymbolTypeCode
131
132     # Define a generator for the symbols to disassemble.
133     def symbol_iter(num, symbols, re_symbol_pattern, target, verbose):
134         # If we specify the symbols to disassemble, ignore symbol table dump.
135         if symbols:
136             for i in range(len(symbols)):
137                 if verbose:
138                     print "symbol:", symbols[i]
139                 yield symbols[i]
140         else:
141             limited = True if num != -1 else False
142             if limited:
143                 count = 0
144             if re_symbol_pattern:
145                 pattern = re.compile(re_symbol_pattern)
146             stream = lldb.SBStream()
147             for m in target.module_iter():
148                 if verbose:
149                     print "module:", m
150                 for s in m:
151                     if limited and count >= num:
152                         return
153                     # If a regexp symbol pattern is supplied, consult it.
154                     if re_symbol_pattern:
155                         # If the pattern does not match, look for the next
156                         # symbol.
157                         if not pattern.match(s.GetName()):
158                             continue
159
160                     # If we come here, we're ready to disassemble the symbol.
161                     if verbose:
162                         print "symbol:", s.GetName()
163                     if IsCodeType(s):
164                         if limited:
165                             count = count + 1
166                             if verbose:
167                                 print "returning symbol:", s.GetName()
168                         yield s.GetName()
169                     if verbose:
170                         print "start address:", s.GetStartAddress()
171                         print "end address:", s.GetEndAddress()
172                         s.GetDescription(stream)
173                         print "symbol description:", stream.GetData()
174                         stream.Clear()
175
176     # Disassembly time.
177     for symbol in symbol_iter(
178             num_symbols,
179             symbols_to_disassemble,
180             re_symbol_pattern,
181             target,
182             not quiet_disassembly):
183         cmd = "disassemble %s '%s'" % (disassemble_options, symbol)
184         run_command(ci, cmd, res, not quiet_disassembly)
185
186
187 def main():
188     # This is to set up the Python path to include the pexpect-2.4 dir.
189     # Remember to update this when/if things change.
190     scriptPath = sys.path[0]
191     sys.path.append(
192         os.path.join(
193             scriptPath,
194             os.pardir,
195             os.pardir,
196             'test',
197             'pexpect-2.4'))
198
199     parser = OptionParser(usage="""\
200 Run lldb to disassemble all the available functions for an executable image.
201
202 Usage: %prog [options]
203 """)
204     parser.add_option(
205         '-C',
206         '--lldb-command',
207         type='string',
208         action='append',
209         metavar='COMMAND',
210         default=[],
211         dest='lldb_commands',
212         help='Command(s) lldb executes after starting up (can be empty)')
213     parser.add_option(
214         '-e',
215         '--executable',
216         type='string',
217         action='store',
218         dest='executable',
219         help="""Mandatory: the executable to do disassembly on.""")
220     parser.add_option(
221         '-o',
222         '--options',
223         type='string',
224         action='store',
225         dest='disassemble_options',
226         help="""Mandatory: the options passed to lldb's 'disassemble' command.""")
227     parser.add_option(
228         '-q',
229         '--quiet-disassembly',
230         action='store_true',
231         default=False,
232         dest='quiet_disassembly',
233         help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""")
234     parser.add_option(
235         '-n',
236         '--num-symbols',
237         type='int',
238         action='store',
239         default=-1,
240         dest='num_symbols',
241         help="""The number of symbols to disassemble, if specified.""")
242     parser.add_option(
243         '-p',
244         '--symbol_pattern',
245         type='string',
246         action='store',
247         dest='re_symbol_pattern',
248         help="""The regular expression of symbols to invoke lldb's 'disassemble' command.""")
249     parser.add_option(
250         '-s',
251         '--symbol',
252         type='string',
253         action='append',
254         metavar='SYMBOL',
255         default=[],
256         dest='symbols_to_disassemble',
257         help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""")
258
259     opts, args = parser.parse_args()
260
261     lldb_commands = opts.lldb_commands
262
263     if not opts.executable or not opts.disassemble_options:
264         parser.print_help()
265         sys.exit(1)
266
267     executable = opts.executable
268     disassemble_options = opts.disassemble_options
269     quiet_disassembly = opts.quiet_disassembly
270     num_symbols = opts.num_symbols
271     symbols_to_disassemble = opts.symbols_to_disassemble
272     re_symbol_pattern = opts.re_symbol_pattern
273
274     # We have parsed the options.
275     if not quiet_disassembly:
276         print "lldb commands:", lldb_commands
277         print "executable:", executable
278         print "disassemble options:", disassemble_options
279         print "quiet disassembly output:", quiet_disassembly
280         print "num of symbols to disassemble:", num_symbols
281         print "symbols to disassemble:", symbols_to_disassemble
282         print "regular expression of symbols to disassemble:", re_symbol_pattern
283
284     setupSysPath()
285     do_lldb_disassembly(lldb_commands, executable, disassemble_options,
286                         num_symbols,
287                         symbols_to_disassemble,
288                         re_symbol_pattern,
289                         quiet_disassembly)
290
291 if __name__ == '__main__':
292     main()