1#!/usr/bin/python
2
3#----------------------------------------------------------------------
4# Be sure to add the python path that points to the LLDB shared library.
5# On MacOSX csh, tcsh:
6#   setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
7# On MacOSX sh, bash:
8#   export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
9#----------------------------------------------------------------------
10
11import commands
12import optparse
13import os
14import platform
15import resource
16import sys
17import time
18
19#----------------------------------------------------------------------
20# Code that auto imports LLDB
21#----------------------------------------------------------------------
22try:
23    # Just try for LLDB in case PYTHONPATH is already correctly setup
24    import lldb
25except ImportError:
26    lldb_python_dirs = list()
27    # lldb is not in the PYTHONPATH, try some defaults for the current platform
28    platform_system = platform.system()
29    if platform_system == 'Darwin':
30        # On Darwin, try the currently selected Xcode directory
31        xcode_dir = commands.getoutput("xcode-select --print-path")
32        if xcode_dir:
33            lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python'))
34            lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
35        lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
36    success = False
37    for lldb_python_dir in lldb_python_dirs:
38        if os.path.exists(lldb_python_dir):
39            if not (sys.path.__contains__(lldb_python_dir)):
40                sys.path.append(lldb_python_dir)
41                try:
42                    import lldb
43                except ImportError:
44                    pass
45                else:
46                    print 'imported lldb from: "%s"' % (lldb_python_dir)
47                    success = True
48                    break
49    if not success:
50        print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
51        sys.exit(1)
52
53
54class Timer:
55    def __enter__(self):
56        self.start = time.clock()
57        return self
58
59    def __exit__(self, *args):
60        self.end = time.clock()
61        self.interval = self.end - self.start
62
63class TestCase:
64    """Class that aids in running performance tests."""
65    def __init__(self):
66        self.verbose = False
67        self.debugger = lldb.SBDebugger.Create()
68        self.target = None
69        self.process = None
70        self.thread = None
71        self.launch_info = None
72        self.listener = self.debugger.GetListener()
73
74    def Setup(self, args):
75        self.launch_info = lldb.SBLaunchInfo(args)
76
77    def Run (self, args):
78        assert False, "performance.TestCase.Run() must be subclassed"
79
80    def Launch(self):
81        if self.target:
82            error = lldb.SBError()
83            self.process = self.target.Launch (self.launch_info, error);
84            if not error.Success():
85                print "error: %s" % error.GetCString()
86            if self.process:
87                self.process.GetBroadcaster().AddListener(self.listener, lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt);
88                return True
89        return False
90
91    def WaitForNextProcessEvent (self):
92        event = None
93        if self.process:
94            while event is None:
95                process_event = lldb.SBEvent()
96                if self.listener.WaitForEvent (lldb.UINT32_MAX, process_event):
97                    state = lldb.SBProcess.GetStateFromEvent (process_event)
98                    if self.verbose:
99                        print "event = %s" % (lldb.SBDebugger.StateAsCString(state))
100                    if lldb.SBProcess.GetRestartedFromEvent(process_event):
101                        continue
102                    if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or  state == lldb.eStateUnloaded or state == lldb.eStateExited:
103                       event = process_event
104                    elif state == lldb.eStateConnected or state == lldb.eStateAttaching or state == lldb.eStateLaunching or state == lldb.eStateRunning or state == lldb.eStateStepping or state == lldb.eStateSuspended:
105                         continue
106                    elif state == lldb.eStateStopped:
107                        event = process_event
108                        call_test_step = True
109                        fatal = False
110                        selected_thread = False
111                        for thread in self.process:
112                            frame = thread.GetFrameAtIndex(0)
113                            select_thread = False
114                            stop_reason = thread.GetStopReason();
115                            if self.verbose:
116                                print "tid = %#x pc = %#x " % (thread.GetThreadID(),frame.GetPC()),
117                            if stop_reason == lldb.eStopReasonNone:
118                                if self.verbose:
119                                    print "none"
120                            elif stop_reason == lldb.eStopReasonTrace:
121                                select_thread = True
122                                if self.verbose:
123                                    print "trace"
124                            elif stop_reason == lldb.eStopReasonPlanComplete:
125                                select_thread = True
126                                if self.verbose:
127                                    print "plan complete"
128                            elif stop_reason == lldb.eStopReasonThreadExiting:
129                                if self.verbose:
130                                    print "thread exiting"
131                            elif stop_reason == lldb.eStopReasonExec:
132                                if self.verbose:
133                                    print "exec"
134                            elif stop_reason == lldb.eStopReasonInvalid:
135                                if self.verbose:
136                                    print "invalid"
137                            elif stop_reason == lldb.eStopReasonException:
138                                select_thread = True
139                                if self.verbose:
140                                    print "exception"
141                                fatal = True
142                            elif stop_reason == lldb.eStopReasonBreakpoint:
143                                select_thread = True
144                                if self.verbose:
145                                    print "breakpoint id = %d.%d" % (thread.GetStopReasonDataAtIndex(0),thread.GetStopReasonDataAtIndex(1))
146                            elif stop_reason == lldb.eStopReasonWatchpoint:
147                                select_thread = True
148                                if self.verbose:
149                                    print "watchpoint id = %d" % (thread.GetStopReasonDataAtIndex(0))
150                            elif stop_reason == lldb.eStopReasonSignal:
151                                select_thread = True
152                                if self.verbose:
153                                    print "signal %d" % (thread.GetStopReasonDataAtIndex(0))
154
155                            if select_thread and not selected_thread:
156                                self.thread = thread;
157                                selected_thread = self.process.SetSelectedThread(thread);
158                        if fatal:
159                            # if self.verbose:
160                            #     Xcode.RunCommand(self.debugger,"bt all",true);
161                            sys.exit(1);
162        return event
163
164
165class TesterTestCase(TestCase):
166
167    def Run (self, args):
168        self.Setup(args)
169        self.verbose = True
170        self.target = self.debugger.CreateTarget(args[0])
171        if self.target:
172            if self.Launch():
173                print resource.getrusage (resource.RUSAGE_SELF)
174                with Timer() as breakpoint_timer:
175                    self.target.BreakpointCreateByName("main")
176                    self.target.BreakpointCreateByName("malloc")
177                print('Breakpoint took %.03f sec.' % breakpoint_timer.interval)
178                print resource.getrusage (resource.RUSAGE_SELF)
179                event = self.WaitForNextProcessEvent()
180                self.process.Continue()
181                event = self.WaitForNextProcessEvent()
182                self.process.Continue()
183                event = self.WaitForNextProcessEvent()
184                self.process.Continue()
185                event = self.WaitForNextProcessEvent()
186                self.process.Continue()
187            else:
188                print "error: failed to launch process"
189        else:
190            print "error: failed to create target with '%s'" % (args[0])
191
192if __name__ == '__main__':
193    lldb.SBDebugger.Initialize()
194    test = TesterTestCase()
195    test.Run (sys.argv[1:])
196    lldb.SBDebugger.Terminate()
197