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