199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest lldb Python event APIs.
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprechtfrom __future__ import print_function
699451b44SJordan Rupprecht
799451b44SJordan Rupprecht
899451b44SJordan Rupprechtimport re
999451b44SJordan Rupprechtimport lldb
1099451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
1199451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1299451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1399451b44SJordan Rupprecht
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprecht@skipIfLinux   # llvm.org/pr25924, sometimes generating SIGSEGV
1699451b44SJordan Rupprecht@skipIfDarwin
1799451b44SJordan Rupprechtclass EventAPITestCase(TestBase):
1899451b44SJordan Rupprecht
1999451b44SJordan Rupprecht    mydir = TestBase.compute_mydir(__file__)
2099451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
2199451b44SJordan Rupprecht
2299451b44SJordan Rupprecht    def setUp(self):
2399451b44SJordan Rupprecht        # Call super's setUp().
2499451b44SJordan Rupprecht        TestBase.setUp(self)
2599451b44SJordan Rupprecht        # Find the line number to of function 'c'.
2699451b44SJordan Rupprecht        self.line = line_number(
2799451b44SJordan Rupprecht            'main.c', '// Find the line number of function "c" here.')
2899451b44SJordan Rupprecht
2999451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
3099451b44SJordan Rupprecht    @expectedFailureAll(
3199451b44SJordan Rupprecht        oslist=["linux"],
3299451b44SJordan Rupprecht        bugnumber="llvm.org/pr23730 Flaky, fails ~1/10 cases")
3399451b44SJordan Rupprecht    @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373
3499451b44SJordan Rupprecht    @skipIfNetBSD
3599451b44SJordan Rupprecht    def test_listen_for_and_print_event(self):
3699451b44SJordan Rupprecht        """Exercise SBEvent API."""
3799451b44SJordan Rupprecht        self.build()
3899451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
3999451b44SJordan Rupprecht
4099451b44SJordan Rupprecht        self.dbg.SetAsync(True)
4199451b44SJordan Rupprecht
4299451b44SJordan Rupprecht        # Create a target by the debugger.
4399451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
4499451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
4599451b44SJordan Rupprecht
4699451b44SJordan Rupprecht        # Now create a breakpoint on main.c by name 'c'.
4799451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByName('c', 'a.out')
4899451b44SJordan Rupprecht
4999451b44SJordan Rupprecht        listener = lldb.SBListener("my listener")
5099451b44SJordan Rupprecht
5199451b44SJordan Rupprecht        # Now launch the process, and do not stop at the entry point.
5299451b44SJordan Rupprecht        error = lldb.SBError()
53*2ddba09eSJonas Devlieghere        flags = target.GetLaunchInfo().GetLaunchFlags()
5499451b44SJordan Rupprecht        process = target.Launch(listener,
5599451b44SJordan Rupprecht                                None,      # argv
5699451b44SJordan Rupprecht                                None,      # envp
5799451b44SJordan Rupprecht                                None,      # stdin_path
5899451b44SJordan Rupprecht                                None,      # stdout_path
5999451b44SJordan Rupprecht                                None,      # stderr_path
6099451b44SJordan Rupprecht                                None,      # working directory
61*2ddba09eSJonas Devlieghere                                flags,     # launch flags
6299451b44SJordan Rupprecht                                False,     # Stop at entry
6399451b44SJordan Rupprecht                                error)     # error
6499451b44SJordan Rupprecht
6599451b44SJordan Rupprecht        self.assertTrue(
6699451b44SJordan Rupprecht            process.GetState() == lldb.eStateStopped,
6799451b44SJordan Rupprecht            PROCESS_STOPPED)
6899451b44SJordan Rupprecht
6999451b44SJordan Rupprecht        # Create an empty event object.
7099451b44SJordan Rupprecht        event = lldb.SBEvent()
7199451b44SJordan Rupprecht
7299451b44SJordan Rupprecht        traceOn = self.TraceOn()
7399451b44SJordan Rupprecht        if traceOn:
7499451b44SJordan Rupprecht            lldbutil.print_stacktraces(process)
7599451b44SJordan Rupprecht
7699451b44SJordan Rupprecht        # Create MyListeningThread class to wait for any kind of event.
7799451b44SJordan Rupprecht        import threading
7899451b44SJordan Rupprecht
7999451b44SJordan Rupprecht        class MyListeningThread(threading.Thread):
8099451b44SJordan Rupprecht
8199451b44SJordan Rupprecht            def run(self):
8299451b44SJordan Rupprecht                count = 0
8399451b44SJordan Rupprecht                # Let's only try at most 4 times to retrieve any kind of event.
8499451b44SJordan Rupprecht                # After that, the thread exits.
8599451b44SJordan Rupprecht                while not count > 3:
8699451b44SJordan Rupprecht                    if traceOn:
8799451b44SJordan Rupprecht                        print("Try wait for event...")
8899451b44SJordan Rupprecht                    if listener.WaitForEvent(5, event):
8999451b44SJordan Rupprecht                        if traceOn:
9099451b44SJordan Rupprecht                            desc = lldbutil.get_description(event)
9199451b44SJordan Rupprecht                            print("Event description:", desc)
9299451b44SJordan Rupprecht                            print("Event data flavor:", event.GetDataFlavor())
9399451b44SJordan Rupprecht                            print(
9499451b44SJordan Rupprecht                                "Process state:",
9599451b44SJordan Rupprecht                                lldbutil.state_type_to_str(
9699451b44SJordan Rupprecht                                    process.GetState()))
9799451b44SJordan Rupprecht                            print()
9899451b44SJordan Rupprecht                    else:
9999451b44SJordan Rupprecht                        if traceOn:
10099451b44SJordan Rupprecht                            print("timeout occurred waiting for event...")
10199451b44SJordan Rupprecht                    count = count + 1
10299451b44SJordan Rupprecht                listener.Clear()
10399451b44SJordan Rupprecht                return
10499451b44SJordan Rupprecht
10599451b44SJordan Rupprecht        # Let's start the listening thread to retrieve the events.
10699451b44SJordan Rupprecht        my_thread = MyListeningThread()
10799451b44SJordan Rupprecht        my_thread.start()
10899451b44SJordan Rupprecht
10999451b44SJordan Rupprecht        # Use Python API to continue the process.  The listening thread should be
11099451b44SJordan Rupprecht        # able to receive the state changed events.
11199451b44SJordan Rupprecht        process.Continue()
11299451b44SJordan Rupprecht
11399451b44SJordan Rupprecht        # Use Python API to kill the process.  The listening thread should be
11499451b44SJordan Rupprecht        # able to receive the state changed event, too.
11599451b44SJordan Rupprecht        process.Kill()
11699451b44SJordan Rupprecht
11799451b44SJordan Rupprecht        # Wait until the 'MyListeningThread' terminates.
11899451b44SJordan Rupprecht        my_thread.join()
11999451b44SJordan Rupprecht
12099451b44SJordan Rupprecht        # Shouldn't we be testing against some kind of expectation here?
12199451b44SJordan Rupprecht
12299451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
12399451b44SJordan Rupprecht    @expectedFlakeyLinux("llvm.org/pr23730")  # Flaky, fails ~1/100 cases
12499451b44SJordan Rupprecht    @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373
12599451b44SJordan Rupprecht    @skipIfNetBSD
12699451b44SJordan Rupprecht    def test_wait_for_event(self):
12799451b44SJordan Rupprecht        """Exercise SBListener.WaitForEvent() API."""
12899451b44SJordan Rupprecht        self.build()
12999451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
13099451b44SJordan Rupprecht
13199451b44SJordan Rupprecht        self.dbg.SetAsync(True)
13299451b44SJordan Rupprecht
13399451b44SJordan Rupprecht        # Create a target by the debugger.
13499451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
13599451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
13699451b44SJordan Rupprecht
13799451b44SJordan Rupprecht        # Now create a breakpoint on main.c by name 'c'.
13899451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByName('c', 'a.out')
139b321b429SJonas Devlieghere        self.trace("breakpoint:", breakpoint)
14099451b44SJordan Rupprecht        self.assertTrue(breakpoint and
14199451b44SJordan Rupprecht                        breakpoint.GetNumLocations() == 1,
14299451b44SJordan Rupprecht                        VALID_BREAKPOINT)
14399451b44SJordan Rupprecht
14499451b44SJordan Rupprecht        # Get the debugger listener.
14599451b44SJordan Rupprecht        listener = self.dbg.GetListener()
14699451b44SJordan Rupprecht
14799451b44SJordan Rupprecht        # Now launch the process, and do not stop at entry point.
14899451b44SJordan Rupprecht        error = lldb.SBError()
149*2ddba09eSJonas Devlieghere        flags = target.GetLaunchInfo().GetLaunchFlags()
15099451b44SJordan Rupprecht        process = target.Launch(listener,
15199451b44SJordan Rupprecht                                None,      # argv
15299451b44SJordan Rupprecht                                None,      # envp
15399451b44SJordan Rupprecht                                None,      # stdin_path
15499451b44SJordan Rupprecht                                None,      # stdout_path
15599451b44SJordan Rupprecht                                None,      # stderr_path
15699451b44SJordan Rupprecht                                None,      # working directory
157*2ddba09eSJonas Devlieghere                                flags,     # launch flags
15899451b44SJordan Rupprecht                                False,     # Stop at entry
15999451b44SJordan Rupprecht                                error)     # error
16099451b44SJordan Rupprecht        self.assertTrue(error.Success() and process, PROCESS_IS_VALID)
16199451b44SJordan Rupprecht
16299451b44SJordan Rupprecht        # Create an empty event object.
16399451b44SJordan Rupprecht        event = lldb.SBEvent()
16499451b44SJordan Rupprecht        self.assertFalse(event, "Event should not be valid initially")
16599451b44SJordan Rupprecht
16699451b44SJordan Rupprecht        # Create MyListeningThread to wait for any kind of event.
16799451b44SJordan Rupprecht        import threading
16899451b44SJordan Rupprecht
16999451b44SJordan Rupprecht        class MyListeningThread(threading.Thread):
17099451b44SJordan Rupprecht
17199451b44SJordan Rupprecht            def run(self):
17299451b44SJordan Rupprecht                count = 0
17399451b44SJordan Rupprecht                # Let's only try at most 3 times to retrieve any kind of event.
17499451b44SJordan Rupprecht                while not count > 3:
17599451b44SJordan Rupprecht                    if listener.WaitForEvent(5, event):
176b321b429SJonas Devlieghere                        self.trace("Got a valid event:", event)
177b321b429SJonas Devlieghere                        self.trace("Event data flavor:", event.GetDataFlavor())
178b321b429SJonas Devlieghere                        self.trace("Event type:", lldbutil.state_type_to_str(event.GetType()))
17999451b44SJordan Rupprecht                        listener.Clear()
18099451b44SJordan Rupprecht                        return
18199451b44SJordan Rupprecht                    count = count + 1
18299451b44SJordan Rupprecht                    print("Timeout: listener.WaitForEvent")
18399451b44SJordan Rupprecht                listener.Clear()
18499451b44SJordan Rupprecht                return
18599451b44SJordan Rupprecht
18699451b44SJordan Rupprecht        # Use Python API to kill the process.  The listening thread should be
18799451b44SJordan Rupprecht        # able to receive a state changed event.
18899451b44SJordan Rupprecht        process.Kill()
18999451b44SJordan Rupprecht
19099451b44SJordan Rupprecht        # Let's start the listening thread to retrieve the event.
19199451b44SJordan Rupprecht        my_thread = MyListeningThread()
19299451b44SJordan Rupprecht        my_thread.start()
19399451b44SJordan Rupprecht
19499451b44SJordan Rupprecht        # Wait until the 'MyListeningThread' terminates.
19599451b44SJordan Rupprecht        my_thread.join()
19699451b44SJordan Rupprecht
19799451b44SJordan Rupprecht        self.assertTrue(event,
19899451b44SJordan Rupprecht                        "My listening thread successfully received an event")
19999451b44SJordan Rupprecht
20099451b44SJordan Rupprecht    @skipIfFreeBSD  # llvm.org/pr21325
20199451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
20299451b44SJordan Rupprecht    @expectedFailureAll(
20399451b44SJordan Rupprecht        oslist=["linux"],
20499451b44SJordan Rupprecht        bugnumber="llvm.org/pr23617 Flaky, fails ~1/10 cases")
20599451b44SJordan Rupprecht    @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373
20699451b44SJordan Rupprecht    @expectedFlakeyNetBSD
20799451b44SJordan Rupprecht    def test_add_listener_to_broadcaster(self):
20899451b44SJordan Rupprecht        """Exercise some SBBroadcaster APIs."""
20999451b44SJordan Rupprecht        self.build()
21099451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
21199451b44SJordan Rupprecht
21299451b44SJordan Rupprecht        self.dbg.SetAsync(True)
21399451b44SJordan Rupprecht
21499451b44SJordan Rupprecht        # Create a target by the debugger.
21599451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
21699451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
21799451b44SJordan Rupprecht
21899451b44SJordan Rupprecht        # Now create a breakpoint on main.c by name 'c'.
21999451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByName('c', 'a.out')
220b321b429SJonas Devlieghere        self.trace("breakpoint:", breakpoint)
22199451b44SJordan Rupprecht        self.assertTrue(breakpoint and
22299451b44SJordan Rupprecht                        breakpoint.GetNumLocations() == 1,
22399451b44SJordan Rupprecht                        VALID_BREAKPOINT)
22499451b44SJordan Rupprecht
22599451b44SJordan Rupprecht        listener = lldb.SBListener("my listener")
22699451b44SJordan Rupprecht
22799451b44SJordan Rupprecht        # Now launch the process, and do not stop at the entry point.
22899451b44SJordan Rupprecht        error = lldb.SBError()
229*2ddba09eSJonas Devlieghere        flags = target.GetLaunchInfo().GetLaunchFlags()
23099451b44SJordan Rupprecht        process = target.Launch(listener,
23199451b44SJordan Rupprecht                                None,      # argv
23299451b44SJordan Rupprecht                                None,      # envp
23399451b44SJordan Rupprecht                                None,      # stdin_path
23499451b44SJordan Rupprecht                                None,      # stdout_path
23599451b44SJordan Rupprecht                                None,      # stderr_path
23699451b44SJordan Rupprecht                                None,      # working directory
237*2ddba09eSJonas Devlieghere                                flags,     # launch flags
23899451b44SJordan Rupprecht                                False,     # Stop at entry
23999451b44SJordan Rupprecht                                error)     # error
24099451b44SJordan Rupprecht
24199451b44SJordan Rupprecht        # Create an empty event object.
24299451b44SJordan Rupprecht        event = lldb.SBEvent()
24399451b44SJordan Rupprecht        self.assertFalse(event, "Event should not be valid initially")
24499451b44SJordan Rupprecht
24599451b44SJordan Rupprecht        # The finite state machine for our custom listening thread, with an
24699451b44SJordan Rupprecht        # initial state of None, which means no event has been received.
24799451b44SJordan Rupprecht        # It changes to 'connected' after 'connected' event is received (for remote platforms)
24899451b44SJordan Rupprecht        # It changes to 'running' after 'running' event is received (should happen only if the
24999451b44SJordan Rupprecht        # currentstate is either 'None' or 'connected')
25099451b44SJordan Rupprecht        # It changes to 'stopped' if a 'stopped' event is received (should happen only if the
25199451b44SJordan Rupprecht        # current state is 'running'.)
25299451b44SJordan Rupprecht        self.state = None
25399451b44SJordan Rupprecht
25499451b44SJordan Rupprecht        # Create MyListeningThread to wait for state changed events.
25599451b44SJordan Rupprecht        # By design, a "running" event is expected following by a "stopped"
25699451b44SJordan Rupprecht        # event.
25799451b44SJordan Rupprecht        import threading
25899451b44SJordan Rupprecht
25999451b44SJordan Rupprecht        class MyListeningThread(threading.Thread):
26099451b44SJordan Rupprecht
26199451b44SJordan Rupprecht            def run(self):
262b321b429SJonas Devlieghere                self.trace("Running MyListeningThread:", self)
26399451b44SJordan Rupprecht
26499451b44SJordan Rupprecht                # Regular expression pattern for the event description.
26599451b44SJordan Rupprecht                pattern = re.compile("data = {.*, state = (.*)}$")
26699451b44SJordan Rupprecht
26799451b44SJordan Rupprecht                # Let's only try at most 6 times to retrieve our events.
26899451b44SJordan Rupprecht                count = 0
26999451b44SJordan Rupprecht                while True:
27099451b44SJordan Rupprecht                    if listener.WaitForEvent(5, event):
27199451b44SJordan Rupprecht                        desc = lldbutil.get_description(event)
272b321b429SJonas Devlieghere                        self.trace("Event description:", desc)
27399451b44SJordan Rupprecht                        match = pattern.search(desc)
27499451b44SJordan Rupprecht                        if not match:
27599451b44SJordan Rupprecht                            break
27699451b44SJordan Rupprecht                        if match.group(1) == 'connected':
27799451b44SJordan Rupprecht                            # When debugging remote targets with lldb-server, we
27899451b44SJordan Rupprecht                            # first get the 'connected' event.
27999451b44SJordan Rupprecht                            self.context.assertTrue(self.context.state is None)
28099451b44SJordan Rupprecht                            self.context.state = 'connected'
28199451b44SJordan Rupprecht                            continue
28299451b44SJordan Rupprecht                        elif match.group(1) == 'running':
28399451b44SJordan Rupprecht                            self.context.assertTrue(
28499451b44SJordan Rupprecht                                self.context.state is None or self.context.state == 'connected')
28599451b44SJordan Rupprecht                            self.context.state = 'running'
28699451b44SJordan Rupprecht                            continue
28799451b44SJordan Rupprecht                        elif match.group(1) == 'stopped':
28899451b44SJordan Rupprecht                            self.context.assertTrue(
28999451b44SJordan Rupprecht                                self.context.state == 'running')
29099451b44SJordan Rupprecht                            # Whoopee, both events have been received!
29199451b44SJordan Rupprecht                            self.context.state = 'stopped'
29299451b44SJordan Rupprecht                            break
29399451b44SJordan Rupprecht                        else:
29499451b44SJordan Rupprecht                            break
29599451b44SJordan Rupprecht                    print("Timeout: listener.WaitForEvent")
29699451b44SJordan Rupprecht                    count = count + 1
29799451b44SJordan Rupprecht                    if count > 6:
29899451b44SJordan Rupprecht                        break
29999451b44SJordan Rupprecht                listener.Clear()
30099451b44SJordan Rupprecht                return
30199451b44SJordan Rupprecht
30299451b44SJordan Rupprecht        # Use Python API to continue the process.  The listening thread should be
30399451b44SJordan Rupprecht        # able to receive the state changed events.
30499451b44SJordan Rupprecht        process.Continue()
30599451b44SJordan Rupprecht
30699451b44SJordan Rupprecht        # Start the listening thread to receive the "running" followed by the
30799451b44SJordan Rupprecht        # "stopped" events.
30899451b44SJordan Rupprecht        my_thread = MyListeningThread()
30999451b44SJordan Rupprecht        # Supply the enclosing context so that our listening thread can access
31099451b44SJordan Rupprecht        # the 'state' variable.
31199451b44SJordan Rupprecht        my_thread.context = self
31299451b44SJordan Rupprecht        my_thread.start()
31399451b44SJordan Rupprecht
31499451b44SJordan Rupprecht        # Wait until the 'MyListeningThread' terminates.
31599451b44SJordan Rupprecht        my_thread.join()
31699451b44SJordan Rupprecht
31799451b44SJordan Rupprecht        # The final judgement. :-)
31899451b44SJordan Rupprecht        self.assertTrue(self.state == 'stopped',
31999451b44SJordan Rupprecht                        "Both expected state changed events received")
320