1e655769cSJim Inghamimport lldb 2e655769cSJim Ingham 3e655769cSJim Inghamfrom lldbsuite.test.decorators import * 4e655769cSJim Inghamfrom lldbsuite.test.lldbtest import * 5e655769cSJim Inghamfrom lldbsuite.test import lldbutil 6e655769cSJim Inghamfrom lldbgdbserverutils import get_debugserver_exe 7e655769cSJim Ingham 8e655769cSJim Inghamimport os 9e655769cSJim Inghamimport platform 10e655769cSJim Inghamimport shutil 11e655769cSJim Inghamimport time 12e655769cSJim Inghamimport socket 13e655769cSJim Ingham 14e655769cSJim Ingham 15e655769cSJim Inghamclass TestStopAtEntry(TestBase): 16e655769cSJim Ingham NO_DEBUG_INFO_TESTCASE = True 17e655769cSJim Ingham 18e655769cSJim Ingham # The port used by debugserver. 19d1e9514aSJim Ingham PORT = 54638 20e655769cSJim Ingham 21e655769cSJim Ingham # The number of attempts. 22e655769cSJim Ingham ATTEMPTS = 10 23e655769cSJim Ingham 24e655769cSJim Ingham # Time given to the binary to launch and to debugserver to attach to it for 25e655769cSJim Ingham # every attempt. We'll wait a maximum of 10 times 2 seconds while the 26e655769cSJim Ingham # inferior will wait 10 times 10 seconds. 27e655769cSJim Ingham TIMEOUT = 2 28e655769cSJim Ingham 29e655769cSJim Ingham def no_debugserver(self): 30e655769cSJim Ingham if get_debugserver_exe() is None: 312238dcc3SJonas Devlieghere return "no debugserver" 32e655769cSJim Ingham return None 33e655769cSJim Ingham 34e655769cSJim Ingham def port_not_available(self): 35e655769cSJim Ingham s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 362238dcc3SJonas Devlieghere if s.connect_ex(("127.0.0.1", self.PORT)) == 0: 372238dcc3SJonas Devlieghere return "{} not available".format(self.PORT) 38e655769cSJim Ingham return None 39e655769cSJim Ingham 40e655769cSJim Ingham @skipUnlessDarwin 41065e3c9aSJonas Devlieghere @skipIfRemote 42e655769cSJim Ingham def test_stop_default_platform_sync(self): 43e655769cSJim Ingham self.do_test_stop_at_entry(True, False) 44e655769cSJim Ingham 45e655769cSJim Ingham @skipUnlessDarwin 46065e3c9aSJonas Devlieghere @skipIfRemote 47e655769cSJim Ingham def test_stop_default_platform_async(self): 48e655769cSJim Ingham self.do_test_stop_at_entry(False, False) 49e655769cSJim Ingham 50e655769cSJim Ingham @skipUnlessDarwin 51065e3c9aSJonas Devlieghere @skipIfRemote 52*0fc57866SJordan Rupprecht @skipTestIfFn(no_debugserver) 53*0fc57866SJordan Rupprecht @skipTestIfFn(port_not_available) 54e655769cSJim Ingham def test_stop_remote_platform_sync(self): 55e655769cSJim Ingham self.do_test_stop_at_entry(True, True) 56e655769cSJim Ingham 57e655769cSJim Ingham @skipUnlessDarwin 58065e3c9aSJonas Devlieghere @skipIfRemote 59*0fc57866SJordan Rupprecht @skipTestIfFn(no_debugserver) 60*0fc57866SJordan Rupprecht @skipTestIfFn(port_not_available) 61e655769cSJim Ingham def test_stop_remote_platform_async(self): 62e655769cSJim Ingham self.do_test_stop_at_entry(False, True) 63e655769cSJim Ingham 64e655769cSJim Ingham def do_test_stop_at_entry(self, synchronous, remote): 65e655769cSJim Ingham """Test the normal launch path in either sync or async mode""" 66e655769cSJim Ingham self.build() 67e655769cSJim Ingham 68e655769cSJim Ingham target = lldbutil.run_to_breakpoint_make_target(self) 69e655769cSJim Ingham launch_info = target.GetLaunchInfo() 70e655769cSJim Ingham launch_info.SetLaunchFlags(lldb.eLaunchFlagStopAtEntry) 71e655769cSJim Ingham old_async = self.dbg.GetAsync() 722238dcc3SJonas Devlieghere 73e655769cSJim Ingham def cleanup(): 74e655769cSJim Ingham self.dbg.SetAsync(old_async) 752238dcc3SJonas Devlieghere 76e655769cSJim Ingham self.addTearDownHook(cleanup) 77e655769cSJim Ingham 78e655769cSJim Ingham if not synchronous: 79e655769cSJim Ingham self.dbg.SetAsync(True) 80e655769cSJim Ingham listener = lldb.SBListener("test-process-listener") 812238dcc3SJonas Devlieghere mask = listener.StartListeningForEventClass( 822238dcc3SJonas Devlieghere self.dbg, 832238dcc3SJonas Devlieghere lldb.SBProcess.GetBroadcasterClassName(), 842238dcc3SJonas Devlieghere lldb.SBProcess.eBroadcastBitStateChanged, 852238dcc3SJonas Devlieghere ) 862238dcc3SJonas Devlieghere self.assertEqual( 872238dcc3SJonas Devlieghere mask, 882238dcc3SJonas Devlieghere lldb.SBProcess.eBroadcastBitStateChanged, 892238dcc3SJonas Devlieghere "Got right mask for listener", 902238dcc3SJonas Devlieghere ) 91e655769cSJim Ingham launch_info.SetListener(listener) 92e655769cSJim Ingham else: 93e655769cSJim Ingham self.dbg.SetAsync(False) 94e655769cSJim Ingham 95e655769cSJim Ingham if remote: 96e655769cSJim Ingham self.setup_remote_platform() 97e655769cSJim Ingham 98e655769cSJim Ingham error = lldb.SBError() 99e655769cSJim Ingham 100e655769cSJim Ingham process = target.Launch(launch_info, error) 101779bbbf2SDave Lee self.assertSuccess(error, "Launch failed") 102e655769cSJim Ingham # If we are asynchronous, we have to wait for the events: 103e655769cSJim Ingham if not synchronous: 104e655769cSJim Ingham listener = launch_info.GetListener() 105e655769cSJim Ingham event = lldb.SBEvent() 106e655769cSJim Ingham result = listener.WaitForEvent(30, event) 107e655769cSJim Ingham self.assertTrue(result, "Timed out waiting for event from process") 108e655769cSJim Ingham state = lldb.SBProcess.GetStateFromEvent(event) 1092238dcc3SJonas Devlieghere self.assertState( 1102238dcc3SJonas Devlieghere state, lldb.eStateStopped, "Didn't get a stopped state after launch" 1112238dcc3SJonas Devlieghere ) 112e655769cSJim Ingham 113e655769cSJim Ingham # Okay, we should be stopped. Make sure we are indeed at the 114e655769cSJim Ingham # entry point. I only know how to do this on darwin: 1152238dcc3SJonas Devlieghere self.assertEqual( 1162238dcc3SJonas Devlieghere len(process.threads), 1, "Should only have one thread at entry" 1172238dcc3SJonas Devlieghere ) 118e655769cSJim Ingham thread = process.threads[0] 119e655769cSJim Ingham frame = thread.GetFrameAtIndex(0) 120e655769cSJim Ingham stop_func = frame.name 121e655769cSJim Ingham self.assertEqual(stop_func, "_dyld_start") 122e655769cSJim Ingham 123e655769cSJim Ingham # Now make sure that we can resume the process and have it exit. 124e655769cSJim Ingham error = process.Continue() 125779bbbf2SDave Lee self.assertSuccess(error, "Error continuing") 126e655769cSJim Ingham # Fetch events till we get eStateExited: 127e655769cSJim Ingham if not synchronous: 128e655769cSJim Ingham # Get events till exited. 129e655769cSJim Ingham listener = launch_info.GetListener() 130e655769cSJim Ingham event = lldb.SBEvent() 131e655769cSJim Ingham # We get two running events in a row here??? That's a bug 132e655769cSJim Ingham # but not the one I'm testing for, so for now just fetch as 133e655769cSJim Ingham # many as were sent. 134e655769cSJim Ingham num_running = 0 135e655769cSJim Ingham state = lldb.eStateRunning 136e655769cSJim Ingham while state == lldb.eStateRunning: 137e655769cSJim Ingham num_running += 1 138e655769cSJim Ingham result = listener.WaitForEvent(30, event) 139e655769cSJim Ingham self.assertTrue(result, "Timed out waiting for running") 140e655769cSJim Ingham state = lldb.SBProcess.GetStateFromEvent(event) 141e655769cSJim Ingham if num_running == 1: 142ce825e46SJonas Devlieghere self.assertState(state, lldb.eStateRunning, "Got running event") 143e655769cSJim Ingham # The last event we should get is the exited event 144ce825e46SJonas Devlieghere self.assertState(state, lldb.eStateExited, "Got exit event") 145e655769cSJim Ingham else: 146e655769cSJim Ingham # Make sure that the process has indeed exited 147e655769cSJim Ingham state = process.GetState() 1482238dcc3SJonas Devlieghere self.assertState(state, lldb.eStateExited) 149e655769cSJim Ingham 150e655769cSJim Ingham def setup_remote_platform(self): 151e655769cSJim Ingham return 152e655769cSJim Ingham self.build() 153e655769cSJim Ingham 1542238dcc3SJonas Devlieghere exe = self.getBuildArtifact("a.out") 155e655769cSJim Ingham # Launch our test binary. 156e655769cSJim Ingham 157e655769cSJim Ingham # Attach to it with debugserver. 158e655769cSJim Ingham debugserver = get_debugserver_exe() 1592238dcc3SJonas Devlieghere debugserver_args = ["localhost:{}".format(self.PORT)] 160e655769cSJim Ingham self.spawnSubprocess(debugserver, debugserver_args) 161e655769cSJim Ingham 162e655769cSJim Ingham # Select the platform. 1632238dcc3SJonas Devlieghere self.expect("platform select remote-macosx", substrs=[sdk_dir]) 164e655769cSJim Ingham 165e655769cSJim Ingham # Connect to debugserver 166e655769cSJim Ingham interpreter = self.dbg.GetCommandInterpreter() 167e655769cSJim Ingham connected = False 168e655769cSJim Ingham for i in range(self.ATTEMPTS): 169e655769cSJim Ingham result = lldb.SBCommandReturnObject() 1702238dcc3SJonas Devlieghere interpreter.HandleCommand("gdb-remote {}".format(self.PORT), result) 171e655769cSJim Ingham connected = result.Succeeded() 172e655769cSJim Ingham if connected: 173e655769cSJim Ingham break 174e655769cSJim Ingham time.sleep(self.TIMEOUT) 175e655769cSJim Ingham 176e655769cSJim Ingham self.assertTrue(connected, "could not connect to debugserver") 177