1#!/usr/bin/env python
2
3"""
4Run a program via lldb until it fails.
5The lldb executable is located via your PATH env variable, if not specified.
6"""
7
8import os
9import sys
10from optparse import OptionParser
11
12def is_exe(fpath):
13    """Check whether fpath is an executable."""
14    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
15
16def which(program):
17    """Find the full path to a program, or return None."""
18    fpath, fname = os.path.split(program)
19    if fpath:
20        if is_exe(program):
21            return program
22    else:
23        for path in os.environ["PATH"].split(os.pathsep):
24            exe_file = os.path.join(path, program)
25            if is_exe(exe_file):
26                return exe_file
27    return None
28
29def do_lldb_launch_loop(lldb_command, exe, exe_options):
30    from cStringIO import StringIO
31    import pexpect, time
32
33    prompt = "\(lldb\) "
34    lldb = pexpect.spawn(lldb_command)
35    # Turn on logging for what lldb sends back.
36    lldb.logfile_read = sys.stdout
37    lldb.expect(prompt)
38
39    # Now issue the file command.
40    #print "sending 'file %s' command..." % exe
41    lldb.sendline('file %s' % exe)
42    lldb.expect(prompt)
43
44    # Loop until it faults....
45    count = 0
46    #while True:
47    #    count = count + 1
48    for i in range(100):
49        count = i
50        #print "sending 'process launch -- %s' command... (iteration: %d)" % (exe_options, count)
51        lldb.sendline('process launch -- %s' % exe_options)
52        index = lldb.expect(['Process .* exited with status',
53                             'Process .* stopped',
54                             pexpect.TIMEOUT])
55        if index == 0:
56            # We'll try again later.
57            time.sleep(3)
58        elif index == 1:
59            # Perfect, our process had stopped; break out of the loop.
60            break;
61        elif index == 2:
62            # Something went wrong.
63            print "TIMEOUT occurred:", str(lldb)
64
65    # Give control of lldb shell to the user.
66    lldb.interact()
67
68def main():
69    # This is to set up the Python path to include the pexpect-2.4 dir.
70    # Remember to update this when/if things change.
71    scriptPath = sys.path[0]
72    sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4'))
73
74    parser = OptionParser(usage="""\
75%prog [options]
76Run a program via lldb until it fails.
77The lldb executable is located via your PATH env variable, if not specified.\
78""")
79    parser.add_option('-l', '--lldb-command',
80                      type='string', action='store', metavar='LLDB_COMMAND',
81                      default='lldb', dest='lldb_command',
82                      help='Full path to your lldb command')
83    parser.add_option('-e', '--executable',
84                      type='string', action='store',
85                      dest='exe',
86                      help="""(Mandatory) The executable to launch via lldb.""")
87    parser.add_option('-o', '--options',
88                      type='string', action='store',
89                      default = '', dest='exe_options',
90                      help="""The args/options passed to the launched program, if specified.""")
91
92    opts, args = parser.parse_args()
93
94    lldb_command = which(opts.lldb_command)
95
96    if not opts.exe:
97        parser.print_help()
98        sys.exit(1)
99    exe = opts.exe
100
101    exe_options = opts.exe_options
102
103    # We have parsed the options.
104    print "lldb command:", lldb_command
105    print "executable:", exe
106    print "executable options:", exe_options
107
108    do_lldb_launch_loop(lldb_command, exe, exe_options)
109
110if __name__ == '__main__':
111    main()
112