xref: /llvm-project/lldb/test/API/python_api/event/TestEvents.py (revision 44d9692e6a657ec46e98e4912ac56417da67cfee)
199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest lldb Python event APIs.
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprechtimport re
699451b44SJordan Rupprechtimport lldb
799451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
899451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
999451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
10*44d9692eSjiminghamimport random
1199451b44SJordan Rupprecht
1299451b44SJordan Rupprecht@skipIfLinux  # llvm.org/pr25924, sometimes generating SIGSEGV
1399451b44SJordan Rupprechtclass EventAPITestCase(TestBase):
1499451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
1599451b44SJordan Rupprecht
1699451b44SJordan Rupprecht    def setUp(self):
1799451b44SJordan Rupprecht        # Call super's setUp().
1899451b44SJordan Rupprecht        TestBase.setUp(self)
1999451b44SJordan Rupprecht        # Find the line number to of function 'c'.
2099451b44SJordan Rupprecht        self.line = line_number(
212238dcc3SJonas Devlieghere            "main.c", '// Find the line number of function "c" here.'
222238dcc3SJonas Devlieghere        )
23*44d9692eSjimingham        random.seed()
2499451b44SJordan Rupprecht
2599451b44SJordan Rupprecht    @expectedFailureAll(
262238dcc3SJonas Devlieghere        oslist=["linux"], bugnumber="llvm.org/pr23730 Flaky, fails ~1/10 cases"
272238dcc3SJonas Devlieghere    )
2899451b44SJordan Rupprecht    @skipIfWindows  # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373
2999451b44SJordan Rupprecht    @skipIfNetBSD
3099451b44SJordan Rupprecht    def test_listen_for_and_print_event(self):
3199451b44SJordan Rupprecht        """Exercise SBEvent API."""
3299451b44SJordan Rupprecht        self.build()
3399451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
3499451b44SJordan Rupprecht
3599451b44SJordan Rupprecht        self.dbg.SetAsync(True)
3699451b44SJordan Rupprecht
3799451b44SJordan Rupprecht        # Create a target by the debugger.
3899451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
3999451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
4099451b44SJordan Rupprecht
4199451b44SJordan Rupprecht        # Now create a breakpoint on main.c by name 'c'.
422238dcc3SJonas Devlieghere        breakpoint = target.BreakpointCreateByName("c", "a.out")
4399451b44SJordan Rupprecht
4499451b44SJordan Rupprecht        listener = lldb.SBListener("my listener")
4599451b44SJordan Rupprecht
4699451b44SJordan Rupprecht        # Now launch the process, and do not stop at the entry point.
4799451b44SJordan Rupprecht        error = lldb.SBError()
482ddba09eSJonas Devlieghere        flags = target.GetLaunchInfo().GetLaunchFlags()
492238dcc3SJonas Devlieghere        process = target.Launch(
502238dcc3SJonas Devlieghere            listener,
5199451b44SJordan Rupprecht            None,  # argv
5299451b44SJordan Rupprecht            None,  # envp
5399451b44SJordan Rupprecht            None,  # stdin_path
5499451b44SJordan Rupprecht            None,  # stdout_path
5599451b44SJordan Rupprecht            None,  # stderr_path
5699451b44SJordan Rupprecht            None,  # working directory
572ddba09eSJonas Devlieghere            flags,  # launch flags
5899451b44SJordan Rupprecht            False,  # Stop at entry
592238dcc3SJonas Devlieghere            error,
602238dcc3SJonas Devlieghere        )  # error
6199451b44SJordan Rupprecht
622238dcc3SJonas Devlieghere        self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
6399451b44SJordan Rupprecht
6499451b44SJordan Rupprecht        # Create an empty event object.
6599451b44SJordan Rupprecht        event = lldb.SBEvent()
6699451b44SJordan Rupprecht
6799451b44SJordan Rupprecht        traceOn = self.TraceOn()
6899451b44SJordan Rupprecht        if traceOn:
6999451b44SJordan Rupprecht            lldbutil.print_stacktraces(process)
7099451b44SJordan Rupprecht
7199451b44SJordan Rupprecht        # Create MyListeningThread class to wait for any kind of event.
7299451b44SJordan Rupprecht        import threading
7399451b44SJordan Rupprecht
7499451b44SJordan Rupprecht        class MyListeningThread(threading.Thread):
7599451b44SJordan Rupprecht            def run(self):
7699451b44SJordan Rupprecht                count = 0
7799451b44SJordan Rupprecht                # Let's only try at most 4 times to retrieve any kind of event.
7899451b44SJordan Rupprecht                # After that, the thread exits.
7999451b44SJordan Rupprecht                while not count > 3:
8099451b44SJordan Rupprecht                    if traceOn:
8199451b44SJordan Rupprecht                        print("Try wait for event...")
8299451b44SJordan Rupprecht                    if listener.WaitForEvent(5, event):
8399451b44SJordan Rupprecht                        if traceOn:
8499451b44SJordan Rupprecht                            desc = lldbutil.get_description(event)
8599451b44SJordan Rupprecht                            print("Event description:", desc)
8699451b44SJordan Rupprecht                            print("Event data flavor:", event.GetDataFlavor())
8799451b44SJordan Rupprecht                            print(
8899451b44SJordan Rupprecht                                "Process state:",
892238dcc3SJonas Devlieghere                                lldbutil.state_type_to_str(process.GetState()),
902238dcc3SJonas Devlieghere                            )
9199451b44SJordan Rupprecht                            print()
9299451b44SJordan Rupprecht                    else:
9399451b44SJordan Rupprecht                        if traceOn:
9499451b44SJordan Rupprecht                            print("timeout occurred waiting for event...")
9599451b44SJordan Rupprecht                    count = count + 1
9699451b44SJordan Rupprecht                listener.Clear()
9799451b44SJordan Rupprecht                return
9899451b44SJordan Rupprecht
9999451b44SJordan Rupprecht        # Let's start the listening thread to retrieve the events.
10099451b44SJordan Rupprecht        my_thread = MyListeningThread()
10199451b44SJordan Rupprecht        my_thread.start()
10299451b44SJordan Rupprecht
10399451b44SJordan Rupprecht        # Use Python API to continue the process.  The listening thread should be
10499451b44SJordan Rupprecht        # able to receive the state changed events.
10599451b44SJordan Rupprecht        process.Continue()
10699451b44SJordan Rupprecht
10799451b44SJordan Rupprecht        # Use Python API to kill the process.  The listening thread should be
10899451b44SJordan Rupprecht        # able to receive the state changed event, too.
10999451b44SJordan Rupprecht        process.Kill()
11099451b44SJordan Rupprecht
11199451b44SJordan Rupprecht        # Wait until the 'MyListeningThread' terminates.
11299451b44SJordan Rupprecht        my_thread.join()
11399451b44SJordan Rupprecht
11499451b44SJordan Rupprecht        # Shouldn't we be testing against some kind of expectation here?
11599451b44SJordan Rupprecht
11699451b44SJordan Rupprecht    @expectedFlakeyLinux("llvm.org/pr23730")  # Flaky, fails ~1/100 cases
11799451b44SJordan Rupprecht    @skipIfWindows  # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373
11899451b44SJordan Rupprecht    @skipIfNetBSD
11999451b44SJordan Rupprecht    def test_wait_for_event(self):
12099451b44SJordan Rupprecht        """Exercise SBListener.WaitForEvent() API."""
12199451b44SJordan Rupprecht        self.build()
12299451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
12399451b44SJordan Rupprecht
12499451b44SJordan Rupprecht        self.dbg.SetAsync(True)
12599451b44SJordan Rupprecht
12699451b44SJordan Rupprecht        # Create a target by the debugger.
12799451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
12899451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
12999451b44SJordan Rupprecht
13099451b44SJordan Rupprecht        # Now create a breakpoint on main.c by name 'c'.
1312238dcc3SJonas Devlieghere        breakpoint = target.BreakpointCreateByName("c", "a.out")
132b321b429SJonas Devlieghere        self.trace("breakpoint:", breakpoint)
1332238dcc3SJonas Devlieghere        self.assertTrue(
1342238dcc3SJonas Devlieghere            breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT
1352238dcc3SJonas Devlieghere        )
13699451b44SJordan Rupprecht
13799451b44SJordan Rupprecht        # Get the debugger listener.
13899451b44SJordan Rupprecht        listener = self.dbg.GetListener()
13999451b44SJordan Rupprecht
14099451b44SJordan Rupprecht        # Now launch the process, and do not stop at entry point.
14199451b44SJordan Rupprecht        error = lldb.SBError()
1422ddba09eSJonas Devlieghere        flags = target.GetLaunchInfo().GetLaunchFlags()
1432238dcc3SJonas Devlieghere        process = target.Launch(
1442238dcc3SJonas Devlieghere            listener,
14599451b44SJordan Rupprecht            None,  # argv
14699451b44SJordan Rupprecht            None,  # envp
14799451b44SJordan Rupprecht            None,  # stdin_path
14899451b44SJordan Rupprecht            None,  # stdout_path
14999451b44SJordan Rupprecht            None,  # stderr_path
15099451b44SJordan Rupprecht            None,  # working directory
1512ddba09eSJonas Devlieghere            flags,  # launch flags
15299451b44SJordan Rupprecht            False,  # Stop at entry
1532238dcc3SJonas Devlieghere            error,
1542238dcc3SJonas Devlieghere        )  # error
15599451b44SJordan Rupprecht        self.assertTrue(error.Success() and process, PROCESS_IS_VALID)
15699451b44SJordan Rupprecht
15799451b44SJordan Rupprecht        # Create an empty event object.
15899451b44SJordan Rupprecht        event = lldb.SBEvent()
15999451b44SJordan Rupprecht        self.assertFalse(event, "Event should not be valid initially")
16099451b44SJordan Rupprecht
16199451b44SJordan Rupprecht        # Create MyListeningThread to wait for any kind of event.
16299451b44SJordan Rupprecht        import threading
16399451b44SJordan Rupprecht
16499451b44SJordan Rupprecht        class MyListeningThread(threading.Thread):
16599451b44SJordan Rupprecht            def run(self):
16699451b44SJordan Rupprecht                count = 0
16799451b44SJordan Rupprecht                # Let's only try at most 3 times to retrieve any kind of event.
16899451b44SJordan Rupprecht                while not count > 3:
16999451b44SJordan Rupprecht                    if listener.WaitForEvent(5, event):
1702a29c3f7SMed Ismail Bennani                        self.context.trace("Got a valid event:", event)
1712a29c3f7SMed Ismail Bennani                        self.context.trace("Event data flavor:", event.GetDataFlavor())
1722238dcc3SJonas Devlieghere                        self.context.trace(
1732238dcc3SJonas Devlieghere                            "Event type:", lldbutil.state_type_to_str(event.GetType())
1742238dcc3SJonas Devlieghere                        )
17599451b44SJordan Rupprecht                        listener.Clear()
17699451b44SJordan Rupprecht                        return
17799451b44SJordan Rupprecht                    count = count + 1
17899451b44SJordan Rupprecht                    print("Timeout: listener.WaitForEvent")
17999451b44SJordan Rupprecht                listener.Clear()
18099451b44SJordan Rupprecht                return
18199451b44SJordan Rupprecht
18299451b44SJordan Rupprecht        # Use Python API to kill the process.  The listening thread should be
18399451b44SJordan Rupprecht        # able to receive a state changed event.
18499451b44SJordan Rupprecht        process.Kill()
18599451b44SJordan Rupprecht
18699451b44SJordan Rupprecht        # Let's start the listening thread to retrieve the event.
18799451b44SJordan Rupprecht        my_thread = MyListeningThread()
1882a29c3f7SMed Ismail Bennani        my_thread.context = self
18999451b44SJordan Rupprecht        my_thread.start()
19099451b44SJordan Rupprecht
19199451b44SJordan Rupprecht        # Wait until the 'MyListeningThread' terminates.
19299451b44SJordan Rupprecht        my_thread.join()
19399451b44SJordan Rupprecht
1942238dcc3SJonas Devlieghere        self.assertTrue(event, "My listening thread successfully received an event")
19599451b44SJordan Rupprecht
19699451b44SJordan Rupprecht    @expectedFailureAll(
1972238dcc3SJonas Devlieghere        oslist=["linux"], bugnumber="llvm.org/pr23617 Flaky, fails ~1/10 cases"
1982238dcc3SJonas Devlieghere    )
19999451b44SJordan Rupprecht    @skipIfWindows  # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373
20099562332SMichał Górny    @expectedFailureNetBSD
20199451b44SJordan Rupprecht    def test_add_listener_to_broadcaster(self):
20299451b44SJordan Rupprecht        """Exercise some SBBroadcaster APIs."""
20399451b44SJordan Rupprecht        self.build()
20499451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
20599451b44SJordan Rupprecht
20699451b44SJordan Rupprecht        self.dbg.SetAsync(True)
20799451b44SJordan Rupprecht
20899451b44SJordan Rupprecht        # Create a target by the debugger.
20999451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
21099451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
21199451b44SJordan Rupprecht
21299451b44SJordan Rupprecht        # Now create a breakpoint on main.c by name 'c'.
2132238dcc3SJonas Devlieghere        breakpoint = target.BreakpointCreateByName("c", "a.out")
214b321b429SJonas Devlieghere        self.trace("breakpoint:", breakpoint)
2152238dcc3SJonas Devlieghere        self.assertTrue(
2162238dcc3SJonas Devlieghere            breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT
2172238dcc3SJonas Devlieghere        )
21899451b44SJordan Rupprecht
21999451b44SJordan Rupprecht        listener = lldb.SBListener("my listener")
22099451b44SJordan Rupprecht
22199451b44SJordan Rupprecht        # Now launch the process, and do not stop at the entry point.
22299451b44SJordan Rupprecht        error = lldb.SBError()
2232ddba09eSJonas Devlieghere        flags = target.GetLaunchInfo().GetLaunchFlags()
2242238dcc3SJonas Devlieghere        process = target.Launch(
2252238dcc3SJonas Devlieghere            listener,
22699451b44SJordan Rupprecht            None,  # argv
22799451b44SJordan Rupprecht            None,  # envp
22899451b44SJordan Rupprecht            None,  # stdin_path
22999451b44SJordan Rupprecht            None,  # stdout_path
23099451b44SJordan Rupprecht            None,  # stderr_path
23199451b44SJordan Rupprecht            None,  # working directory
2322ddba09eSJonas Devlieghere            flags,  # launch flags
23399451b44SJordan Rupprecht            False,  # Stop at entry
2342238dcc3SJonas Devlieghere            error,
2352238dcc3SJonas Devlieghere        )  # error
23699451b44SJordan Rupprecht
23799451b44SJordan Rupprecht        # Create an empty event object.
23899451b44SJordan Rupprecht        event = lldb.SBEvent()
23999451b44SJordan Rupprecht        self.assertFalse(event, "Event should not be valid initially")
24099451b44SJordan Rupprecht
24199451b44SJordan Rupprecht        # The finite state machine for our custom listening thread, with an
24299451b44SJordan Rupprecht        # initial state of None, which means no event has been received.
24399451b44SJordan Rupprecht        # It changes to 'connected' after 'connected' event is received (for remote platforms)
24499451b44SJordan Rupprecht        # It changes to 'running' after 'running' event is received (should happen only if the
24599451b44SJordan Rupprecht        # currentstate is either 'None' or 'connected')
24699451b44SJordan Rupprecht        # It changes to 'stopped' if a 'stopped' event is received (should happen only if the
24799451b44SJordan Rupprecht        # current state is 'running'.)
24899451b44SJordan Rupprecht        self.state = None
24999451b44SJordan Rupprecht
25099451b44SJordan Rupprecht        # Create MyListeningThread to wait for state changed events.
25199451b44SJordan Rupprecht        # By design, a "running" event is expected following by a "stopped"
25299451b44SJordan Rupprecht        # event.
25399451b44SJordan Rupprecht        import threading
25499451b44SJordan Rupprecht
25599451b44SJordan Rupprecht        class MyListeningThread(threading.Thread):
25699451b44SJordan Rupprecht            def run(self):
2572a29c3f7SMed Ismail Bennani                self.context.trace("Running MyListeningThread:", self)
25899451b44SJordan Rupprecht
25999451b44SJordan Rupprecht                # Regular expression pattern for the event description.
26099451b44SJordan Rupprecht                pattern = re.compile("data = {.*, state = (.*)}$")
26199451b44SJordan Rupprecht
26299451b44SJordan Rupprecht                # Let's only try at most 6 times to retrieve our events.
26399451b44SJordan Rupprecht                count = 0
26499451b44SJordan Rupprecht                while True:
26599451b44SJordan Rupprecht                    if listener.WaitForEvent(5, event):
26699451b44SJordan Rupprecht                        desc = lldbutil.get_description(event)
2672a29c3f7SMed Ismail Bennani                        self.context.trace("Event description:", desc)
26899451b44SJordan Rupprecht                        match = pattern.search(desc)
26999451b44SJordan Rupprecht                        if not match:
27099451b44SJordan Rupprecht                            break
2712238dcc3SJonas Devlieghere                        if match.group(1) == "connected":
27299451b44SJordan Rupprecht                            # When debugging remote targets with lldb-server, we
27399451b44SJordan Rupprecht                            # first get the 'connected' event.
27499451b44SJordan Rupprecht                            self.context.assertTrue(self.context.state is None)
2752238dcc3SJonas Devlieghere                            self.context.state = "connected"
27699451b44SJordan Rupprecht                            continue
2772238dcc3SJonas Devlieghere                        elif match.group(1) == "running":
27899451b44SJordan Rupprecht                            self.context.assertTrue(
2792238dcc3SJonas Devlieghere                                self.context.state is None
2802238dcc3SJonas Devlieghere                                or self.context.state == "connected"
2812238dcc3SJonas Devlieghere                            )
2822238dcc3SJonas Devlieghere                            self.context.state = "running"
28399451b44SJordan Rupprecht                            continue
2842238dcc3SJonas Devlieghere                        elif match.group(1) == "stopped":
2852238dcc3SJonas Devlieghere                            self.context.assertTrue(self.context.state == "running")
28699451b44SJordan Rupprecht                            # Whoopee, both events have been received!
2872238dcc3SJonas Devlieghere                            self.context.state = "stopped"
28899451b44SJordan Rupprecht                            break
28999451b44SJordan Rupprecht                        else:
29099451b44SJordan Rupprecht                            break
29199451b44SJordan Rupprecht                    print("Timeout: listener.WaitForEvent")
29299451b44SJordan Rupprecht                    count = count + 1
29399451b44SJordan Rupprecht                    if count > 6:
29499451b44SJordan Rupprecht                        break
29599451b44SJordan Rupprecht                listener.Clear()
29699451b44SJordan Rupprecht                return
29799451b44SJordan Rupprecht
29899451b44SJordan Rupprecht        # Use Python API to continue the process.  The listening thread should be
29999451b44SJordan Rupprecht        # able to receive the state changed events.
30099451b44SJordan Rupprecht        process.Continue()
30199451b44SJordan Rupprecht
30299451b44SJordan Rupprecht        # Start the listening thread to receive the "running" followed by the
30399451b44SJordan Rupprecht        # "stopped" events.
30499451b44SJordan Rupprecht        my_thread = MyListeningThread()
30599451b44SJordan Rupprecht        # Supply the enclosing context so that our listening thread can access
30699451b44SJordan Rupprecht        # the 'state' variable.
30799451b44SJordan Rupprecht        my_thread.context = self
30899451b44SJordan Rupprecht        my_thread.start()
30999451b44SJordan Rupprecht
31099451b44SJordan Rupprecht        # Wait until the 'MyListeningThread' terminates.
31199451b44SJordan Rupprecht        my_thread.join()
31299451b44SJordan Rupprecht
31399451b44SJordan Rupprecht        # The final judgement. :-)
3142238dcc3SJonas Devlieghere        self.assertEqual(
3152238dcc3SJonas Devlieghere            self.state, "stopped", "Both expected state changed events received"
3162238dcc3SJonas Devlieghere        )
3172e7aa2eeSJim Ingham
3182e7aa2eeSJim Ingham    def wait_for_next_event(self, expected_state, test_shadow=False):
3192e7aa2eeSJim Ingham        """Wait for an event from self.primary & self.shadow listener.
3202e7aa2eeSJim Ingham        If test_shadow is true, we also check that the shadow listener only
3212e7aa2eeSJim Ingham        receives events AFTER the primary listener does."""
322*44d9692eSjimingham        import stop_hook
3232e7aa2eeSJim Ingham        # Waiting on the shadow listener shouldn't have events yet because
3242e7aa2eeSJim Ingham        # we haven't fetched them for the primary listener yet:
3252e7aa2eeSJim Ingham        event = lldb.SBEvent()
3262e7aa2eeSJim Ingham
3272e7aa2eeSJim Ingham        if test_shadow:
3282e7aa2eeSJim Ingham            success = self.shadow_listener.WaitForEvent(1, event)
3292e7aa2eeSJim Ingham            self.assertFalse(success, "Shadow listener doesn't pull events")
3302e7aa2eeSJim Ingham
3312e7aa2eeSJim Ingham        # But there should be an event for the primary listener:
3322e7aa2eeSJim Ingham        success = self.primary_listener.WaitForEvent(5, event)
333*44d9692eSjimingham
3342e7aa2eeSJim Ingham        self.assertTrue(success, "Primary listener got the event")
3352e7aa2eeSJim Ingham
3362e7aa2eeSJim Ingham        state = lldb.SBProcess.GetStateFromEvent(event)
337*44d9692eSjimingham        primary_event_type = event.GetType()
3382e7aa2eeSJim Ingham        restart = False
3392e7aa2eeSJim Ingham        if state == lldb.eStateStopped:
3402e7aa2eeSJim Ingham            restart = lldb.SBProcess.GetRestartedFromEvent(event)
341*44d9692eSjimingham            # This counter is matching the stop hooks, which don't get run
342*44d9692eSjimingham            # for auto-restarting stops.
343*44d9692eSjimingham            if not restart:
344*44d9692eSjimingham                self.stop_counter += 1
345*44d9692eSjimingham                self.assertEqual(
346*44d9692eSjimingham                    stop_hook.StopHook.counter[self.instance],
347*44d9692eSjimingham                    self.stop_counter,
348*44d9692eSjimingham                    "matching stop hook",
349*44d9692eSjimingham                )
3502e7aa2eeSJim Ingham
35158611451SEisuke Kawashima        if expected_state is not None:
3526bf923d5SDavid Spickett            self.assertEqual(
3536bf923d5SDavid Spickett                state, expected_state, "Primary thread got the correct event"
3546bf923d5SDavid Spickett            )
3552e7aa2eeSJim Ingham
3562e7aa2eeSJim Ingham        # And after pulling that one there should be an equivalent event for the shadow
3572e7aa2eeSJim Ingham        # listener:
3582e7aa2eeSJim Ingham        success = self.shadow_listener.WaitForEvent(5, event)
3592e7aa2eeSJim Ingham        self.assertTrue(success, "Shadow listener got event too")
360*44d9692eSjimingham        shadow_event_type = event.GetType()
3616bf923d5SDavid Spickett        self.assertEqual(
362*44d9692eSjimingham            primary_event_type, shadow_event_type, "It was the same event type"
363*44d9692eSjimingham        )
364*44d9692eSjimingham        self.assertEqual(
365*44d9692eSjimingham            state, lldb.SBProcess.GetStateFromEvent(event), "It was the same state"
3666bf923d5SDavid Spickett        )
3676bf923d5SDavid Spickett        self.assertEqual(
3686bf923d5SDavid Spickett            restart,
3696bf923d5SDavid Spickett            lldb.SBProcess.GetRestartedFromEvent(event),
3706bf923d5SDavid Spickett            "It was the same restarted",
3716bf923d5SDavid Spickett        )
3722e7aa2eeSJim Ingham        return state, restart
3732e7aa2eeSJim Ingham
374d268ba38SJim Ingham    @expectedFlakeyLinux("llvm.org/pr23730")  # Flaky, fails ~1/100 cases
375d268ba38SJim Ingham    @skipIfWindows  # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373
376d268ba38SJim Ingham    @skipIfNetBSD
3772e7aa2eeSJim Ingham    def test_shadow_listener(self):
3782e7aa2eeSJim Ingham        self.build()
3792e7aa2eeSJim Ingham        exe = self.getBuildArtifact("a.out")
3802e7aa2eeSJim Ingham
3812e7aa2eeSJim Ingham        # Create a target by the debugger.
3822e7aa2eeSJim Ingham        target = self.dbg.CreateTarget(exe)
3832e7aa2eeSJim Ingham        self.assertTrue(target, VALID_TARGET)
3842e7aa2eeSJim Ingham
3852e7aa2eeSJim Ingham        # Now create a breakpoint on main.c by name 'c'.
3862e7aa2eeSJim Ingham        bkpt1 = target.BreakpointCreateByName("c", "a.out")
3872e7aa2eeSJim Ingham        self.trace("breakpoint:", bkpt1)
3889c246882SJordan Rupprecht        self.assertEqual(bkpt1.GetNumLocations(), 1, VALID_BREAKPOINT)
3892e7aa2eeSJim Ingham
3902e7aa2eeSJim Ingham        self.primary_listener = lldb.SBListener("my listener")
3912e7aa2eeSJim Ingham        self.shadow_listener = lldb.SBListener("shadow listener")
3922e7aa2eeSJim Ingham
3932e7aa2eeSJim Ingham        self.cur_thread = None
3942e7aa2eeSJim Ingham
3952e7aa2eeSJim Ingham        error = lldb.SBError()
3962e7aa2eeSJim Ingham        launch_info = target.GetLaunchInfo()
3972e7aa2eeSJim Ingham        launch_info.SetListener(self.primary_listener)
3982e7aa2eeSJim Ingham        launch_info.SetShadowListener(self.shadow_listener)
3992e7aa2eeSJim Ingham
4006bf923d5SDavid Spickett        self.runCmd(
4016bf923d5SDavid Spickett            "settings set target.process.extra-startup-command QSetLogging:bitmask=LOG_PROCESS|LOG_EXCEPTIONS|LOG_RNB_PACKETS|LOG_STEP;"
4026bf923d5SDavid Spickett        )
4032e7aa2eeSJim Ingham        self.dbg.SetAsync(True)
4042e7aa2eeSJim Ingham
405*44d9692eSjimingham        # Now make our stop hook - we want to ensure it stays up to date with
406*44d9692eSjimingham        # the events.  We can't get our hands on the stop-hook instance directly,
407*44d9692eSjimingham        # so we'll pass in an instance key, and use that to retrieve the data from
408*44d9692eSjimingham        # this instance of the stop hook:
409*44d9692eSjimingham        self.instance = f"Key{random.randint(0,10000)}"
410*44d9692eSjimingham        stop_hook_path = os.path.join(self.getSourceDir(), "stop_hook.py")
411*44d9692eSjimingham        self.runCmd(f"command script import {stop_hook_path}")
412*44d9692eSjimingham        import stop_hook
413*44d9692eSjimingham
414*44d9692eSjimingham        self.runCmd(
415*44d9692eSjimingham            f"target stop-hook add -P stop_hook.StopHook -k instance -v {self.instance}"
416*44d9692eSjimingham        )
417*44d9692eSjimingham        self.stop_counter = 0
418*44d9692eSjimingham
4192e7aa2eeSJim Ingham        self.process = target.Launch(launch_info, error)
4202e7aa2eeSJim Ingham        self.assertSuccess(error, "Process launched successfully")
4212e7aa2eeSJim Ingham
4222e7aa2eeSJim Ingham        # Keep fetching events from the primary to trigger the do on removal and
4232e7aa2eeSJim Ingham        # then from the shadow listener, and make sure they match:
4242e7aa2eeSJim Ingham
4252e7aa2eeSJim Ingham        # Events in the launch sequence might be platform dependent, so don't
4262e7aa2eeSJim Ingham        # expect any particular event till we get the stopped:
4272e7aa2eeSJim Ingham        state = lldb.eStateInvalid
428*44d9692eSjimingham
4292e7aa2eeSJim Ingham        while state != lldb.eStateStopped:
4302e7aa2eeSJim Ingham            state, restart = self.wait_for_next_event(None, False)
4312e7aa2eeSJim Ingham
4322e7aa2eeSJim Ingham        # Okay, we're now at a good stop, so try a next:
4332e7aa2eeSJim Ingham        self.cur_thread = self.process.threads[0]
4342e7aa2eeSJim Ingham
4352e7aa2eeSJim Ingham        # Make sure we're at our expected breakpoint:
4362e7aa2eeSJim Ingham        self.assertTrue(self.cur_thread.IsValid(), "Got a zeroth thread")
4372e7aa2eeSJim Ingham        self.assertEqual(self.cur_thread.stop_reason, lldb.eStopReasonBreakpoint)
4386bf923d5SDavid Spickett        self.assertEqual(
4396bf923d5SDavid Spickett            self.cur_thread.GetStopReasonDataCount(), 2, "Only one breakpoint/loc here"
4406bf923d5SDavid Spickett        )
4416bf923d5SDavid Spickett        self.assertEqual(
4426bf923d5SDavid Spickett            bkpt1.GetID(),
4436bf923d5SDavid Spickett            self.cur_thread.GetStopReasonDataAtIndex(0),
4446bf923d5SDavid Spickett            "Hit the right breakpoint",
4456bf923d5SDavid Spickett        )
4462e7aa2eeSJim Ingham
4472e7aa2eeSJim Ingham        self.cur_thread.StepOver()
4482e7aa2eeSJim Ingham        # We'll run the test for "shadow listener blocked by primary listener
4492e7aa2eeSJim Ingham        # for the first couple rounds, then we'll skip the 1 second pause...
4502e7aa2eeSJim Ingham        self.wait_for_next_event(lldb.eStateRunning, True)
4512e7aa2eeSJim Ingham        self.wait_for_next_event(lldb.eStateStopped, True)
4522e7aa2eeSJim Ingham
4532e7aa2eeSJim Ingham        # Next try an auto-continue breakpoint and make sure the shadow listener got
4542e7aa2eeSJim Ingham        # the resumed info as well.  Note that I'm not explicitly counting
4552e7aa2eeSJim Ingham        # running events here.  At the point when I wrote this lldb sometimes
4562e7aa2eeSJim Ingham        # emits two running events in a row.  Apparently the code to coalesce running
4572e7aa2eeSJim Ingham        # events isn't working.  But that's not what this test is testing, we're really
4582e7aa2eeSJim Ingham        # testing that the primary & shadow listeners hear the same thing and in the
4592e7aa2eeSJim Ingham        # right order.
4602e7aa2eeSJim Ingham
4612e7aa2eeSJim Ingham        main_spec = lldb.SBFileSpec("main.c")
4622e7aa2eeSJim Ingham        bkpt2 = target.BreakpointCreateBySourceRegex("b.2. returns %d", main_spec)
4639c246882SJordan Rupprecht        self.assertGreater(bkpt2.GetNumLocations(), 0, "BP2 worked")
4642e7aa2eeSJim Ingham        bkpt2.SetAutoContinue(True)
4652e7aa2eeSJim Ingham
4662e7aa2eeSJim Ingham        bkpt3 = target.BreakpointCreateBySourceRegex("a.3. returns %d", main_spec)
4679c246882SJordan Rupprecht        self.assertGreater(bkpt3.GetNumLocations(), 0, "BP3 worked")
4682e7aa2eeSJim Ingham
4692e7aa2eeSJim Ingham        state = lldb.eStateStopped
4702e7aa2eeSJim Ingham        restarted = False
4712e7aa2eeSJim Ingham
4722e7aa2eeSJim Ingham        # Put in a counter to make sure we don't spin forever if there is some
4732e7aa2eeSJim Ingham        # error in the logic.
4742e7aa2eeSJim Ingham        counter = 0
4752e7aa2eeSJim Ingham        while state != lldb.eStateExited:
4762e7aa2eeSJim Ingham            counter += 1
4776bf923d5SDavid Spickett            self.assertLess(
4786bf923d5SDavid Spickett                counter, 50, "Took more than 50 events to hit two breakpoints."
4796bf923d5SDavid Spickett            )
4802e7aa2eeSJim Ingham            if state == lldb.eStateStopped and not restarted:
4812e7aa2eeSJim Ingham                self.process.Continue()
482*44d9692eSjimingham
4832e7aa2eeSJim Ingham            state, restarted = self.wait_for_next_event(None, False)
484*44d9692eSjimingham
485*44d9692eSjimingham        # Now make sure we agree with the stop hook counter:
486*44d9692eSjimingham        self.assertEqual(self.stop_counter, stop_hook.StopHook.counter[self.instance])
487*44d9692eSjimingham        self.assertEqual(stop_hook.StopHook.non_stops[self.instance], 0, "No non stops")
488