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: 31e655769cSJim Ingham 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) 36e655769cSJim Ingham if s.connect_ex(('127.0.0.1', self.PORT)) == 0: 37e655769cSJim Ingham 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 52e655769cSJim Ingham @expectedFailureIfFn(no_debugserver) 53e655769cSJim Ingham @expectedFailureIfFn(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 59e655769cSJim Ingham @expectedFailureIfFn(no_debugserver) 60e655769cSJim Ingham @expectedFailureIfFn(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() 72e655769cSJim Ingham def cleanup (): 73e655769cSJim Ingham self.dbg.SetAsync(old_async) 74e655769cSJim Ingham self.addTearDownHook(cleanup) 75e655769cSJim Ingham 76e655769cSJim Ingham if not synchronous: 77e655769cSJim Ingham self.dbg.SetAsync(True) 78e655769cSJim Ingham listener = lldb.SBListener("test-process-listener") 79e655769cSJim Ingham mask = listener.StartListeningForEventClass(self.dbg, lldb.SBProcess.GetBroadcasterClassName(), lldb.SBProcess.eBroadcastBitStateChanged) 80e655769cSJim Ingham self.assertEqual(mask, lldb.SBProcess.eBroadcastBitStateChanged, "Got right mask for listener") 81e655769cSJim Ingham launch_info.SetListener(listener) 82e655769cSJim Ingham else: 83e655769cSJim Ingham self.dbg.SetAsync(False) 84e655769cSJim Ingham 85e655769cSJim Ingham if remote: 86e655769cSJim Ingham self.setup_remote_platform() 87e655769cSJim Ingham 88e655769cSJim Ingham error = lldb.SBError() 89e655769cSJim Ingham 90e655769cSJim Ingham process = target.Launch(launch_info, error) 91779bbbf2SDave Lee self.assertSuccess(error, "Launch failed") 92e655769cSJim Ingham # If we are asynchronous, we have to wait for the events: 93e655769cSJim Ingham if not synchronous: 94e655769cSJim Ingham listener = launch_info.GetListener() 95e655769cSJim Ingham event = lldb.SBEvent() 96e655769cSJim Ingham result = listener.WaitForEvent(30, event) 97e655769cSJim Ingham self.assertTrue(result, "Timed out waiting for event from process") 98e655769cSJim Ingham state = lldb.SBProcess.GetStateFromEvent(event) 99*ce825e46SJonas Devlieghere self.assertState(state, lldb.eStateStopped, "Didn't get a stopped state after launch") 100e655769cSJim Ingham 101e655769cSJim Ingham # Okay, we should be stopped. Make sure we are indeed at the 102e655769cSJim Ingham # entry point. I only know how to do this on darwin: 103e655769cSJim Ingham self.assertEqual(len(process.threads), 1, "Should only have one thread at entry") 104e655769cSJim Ingham thread = process.threads[0] 105e655769cSJim Ingham frame = thread.GetFrameAtIndex(0) 106e655769cSJim Ingham stop_func = frame.name 107e655769cSJim Ingham self.assertEqual(stop_func, "_dyld_start") 108e655769cSJim Ingham 109e655769cSJim Ingham # Now make sure that we can resume the process and have it exit. 110e655769cSJim Ingham error = process.Continue() 111779bbbf2SDave Lee self.assertSuccess(error, "Error continuing") 112e655769cSJim Ingham # Fetch events till we get eStateExited: 113e655769cSJim Ingham if not synchronous: 114e655769cSJim Ingham # Get events till exited. 115e655769cSJim Ingham listener = launch_info.GetListener() 116e655769cSJim Ingham event = lldb.SBEvent() 117e655769cSJim Ingham # We get two running events in a row here??? That's a bug 118e655769cSJim Ingham # but not the one I'm testing for, so for now just fetch as 119e655769cSJim Ingham # many as were sent. 120e655769cSJim Ingham num_running = 0 121e655769cSJim Ingham state = lldb.eStateRunning 122e655769cSJim Ingham while state == lldb.eStateRunning: 123e655769cSJim Ingham num_running += 1 124e655769cSJim Ingham result = listener.WaitForEvent(30, event) 125e655769cSJim Ingham self.assertTrue(result, "Timed out waiting for running") 126e655769cSJim Ingham state = lldb.SBProcess.GetStateFromEvent(event) 127e655769cSJim Ingham if num_running == 1: 128*ce825e46SJonas Devlieghere self.assertState(state, lldb.eStateRunning, "Got running event") 129e655769cSJim Ingham # The last event we should get is the exited event 130*ce825e46SJonas Devlieghere self.assertState(state, lldb.eStateExited, "Got exit event") 131e655769cSJim Ingham else: 132e655769cSJim Ingham # Make sure that the process has indeed exited 133e655769cSJim Ingham state = process.GetState() 134*ce825e46SJonas Devlieghere self.assertState(state, lldb.eStateExited); 135e655769cSJim Ingham 136e655769cSJim Ingham def setup_remote_platform(self): 137e655769cSJim Ingham return 138e655769cSJim Ingham self.build() 139e655769cSJim Ingham 140e655769cSJim Ingham exe = self.getBuildArtifact('a.out') 141e655769cSJim Ingham # Launch our test binary. 142e655769cSJim Ingham 143e655769cSJim Ingham # Attach to it with debugserver. 144e655769cSJim Ingham debugserver = get_debugserver_exe() 145e655769cSJim Ingham debugserver_args = [ 146e655769cSJim Ingham 'localhost:{}'.format(self.PORT) 147e655769cSJim Ingham ] 148e655769cSJim Ingham self.spawnSubprocess(debugserver, debugserver_args) 149e655769cSJim Ingham 150e655769cSJim Ingham # Select the platform. 151e655769cSJim Ingham self.expect('platform select remote-macosx', substrs=[sdk_dir]) 152e655769cSJim Ingham 153e655769cSJim Ingham # Connect to debugserver 154e655769cSJim Ingham interpreter = self.dbg.GetCommandInterpreter() 155e655769cSJim Ingham connected = False 156e655769cSJim Ingham for i in range(self.ATTEMPTS): 157e655769cSJim Ingham result = lldb.SBCommandReturnObject() 158e655769cSJim Ingham interpreter.HandleCommand('gdb-remote {}'.format(self.PORT), 159e655769cSJim Ingham result) 160e655769cSJim Ingham connected = result.Succeeded() 161e655769cSJim Ingham if connected: 162e655769cSJim Ingham break 163e655769cSJim Ingham time.sleep(self.TIMEOUT) 164e655769cSJim Ingham 165e655769cSJim Ingham self.assertTrue(connected, "could not connect to debugserver") 166