This revision was automatically updated to reflect the committed changes.
Closed by commit rGe655769c4a7b: Fix a bug in Launch when using an async 
debugger & remote platform. (authored by jingham).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112747/new/

https://reviews.llvm.org/D112747

Files:
  lldb/source/Target/Process.cpp
  lldb/test/API/functionalities/launch_stop_at_entry/Makefile
  lldb/test/API/functionalities/launch_stop_at_entry/TestStopAtEntry.py
  lldb/test/API/functionalities/launch_stop_at_entry/main.c

Index: lldb/test/API/functionalities/launch_stop_at_entry/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/launch_stop_at_entry/main.c
@@ -0,0 +1,5 @@
+int main(int argc, char **argv) {
+  /* We just want to make sure this ran, so
+     it doesn't actually need to do anything. */
+  return 0;
+}
Index: lldb/test/API/functionalities/launch_stop_at_entry/TestStopAtEntry.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/launch_stop_at_entry/TestStopAtEntry.py
@@ -0,0 +1,163 @@
+import lldb
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+from lldbgdbserverutils import get_debugserver_exe
+
+import os
+import platform
+import shutil
+import time
+import socket
+
+
+class TestStopAtEntry(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+    NO_DEBUG_INFO_TESTCASE = True
+
+    # The port used by debugserver.
+    PORT = 54637
+
+    # The number of attempts.
+    ATTEMPTS = 10
+
+    # Time given to the binary to launch and to debugserver to attach to it for
+    # every attempt. We'll wait a maximum of 10 times 2 seconds while the
+    # inferior will wait 10 times 10 seconds.
+    TIMEOUT = 2
+
+    def no_debugserver(self):
+        if get_debugserver_exe() is None:
+            return 'no debugserver'
+        return None
+
+    def port_not_available(self):
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        if s.connect_ex(('127.0.0.1', self.PORT)) == 0:
+            return '{} not available'.format(self.PORT)
+        return None
+
+    @skipUnlessDarwin
+    def test_stop_default_platform_sync(self):
+        self.do_test_stop_at_entry(True, False)
+
+    @skipUnlessDarwin
+    def test_stop_default_platform_async(self):
+        self.do_test_stop_at_entry(False, False)
+
+    @skipUnlessDarwin
+    @expectedFailureIfFn(no_debugserver)
+    @expectedFailureIfFn(port_not_available)
+    def test_stop_remote_platform_sync(self):
+        self.do_test_stop_at_entry(True, True)
+
+    @skipUnlessDarwin
+    @expectedFailureIfFn(no_debugserver)
+    @expectedFailureIfFn(port_not_available)
+    def test_stop_remote_platform_async(self):
+        self.do_test_stop_at_entry(False, True)
+
+    def do_test_stop_at_entry(self, synchronous, remote):        
+        """Test the normal launch path in either sync or async mode"""
+        self.build()
+
+        target = lldbutil.run_to_breakpoint_make_target(self)
+        launch_info = target.GetLaunchInfo()
+        launch_info.SetLaunchFlags(lldb.eLaunchFlagStopAtEntry)
+        old_async = self.dbg.GetAsync()
+        def cleanup ():
+            self.dbg.SetAsync(old_async)
+        self.addTearDownHook(cleanup)
+
+        if not synchronous:
+            self.dbg.SetAsync(True)
+            listener = lldb.SBListener("test-process-listener")
+            mask = listener.StartListeningForEventClass(self.dbg, lldb.SBProcess.GetBroadcasterClassName(), lldb.SBProcess.eBroadcastBitStateChanged)
+            self.assertEqual(mask, lldb.SBProcess.eBroadcastBitStateChanged, "Got right mask for listener")
+            launch_info.SetListener(listener)
+        else:
+            self.dbg.SetAsync(False)
+
+        if remote:
+            self.setup_remote_platform()
+
+        error = lldb.SBError()
+
+        process = target.Launch(launch_info, error)
+        self.assertTrue(error.Success(), "Launch failed: {0}".format(error.description))
+        # If we are asynchronous, we have to wait for the events:
+        if not synchronous:
+            listener = launch_info.GetListener()
+            event = lldb.SBEvent()
+            result = listener.WaitForEvent(30, event)
+            self.assertTrue(result, "Timed out waiting for event from process")
+            state = lldb.SBProcess.GetStateFromEvent(event)
+            self.assertEqual(state, lldb.eStateStopped, "Didn't get a stopped state after launch")
+
+        # Okay, we should be stopped.  Make sure we are indeed at the
+        # entry point.  I only know how to do this on darwin:
+        self.assertEqual(len(process.threads), 1, "Should only have one thread at entry")
+        thread = process.threads[0]
+        frame = thread.GetFrameAtIndex(0)
+        stop_func = frame.name
+        self.assertEqual(stop_func, "_dyld_start")
+
+        # Now make sure that we can resume the process and have it exit.
+        error = process.Continue()
+        self.assertTrue(error.Success(), "Error continuing: {0}".format(error.description))
+        # Fetch events till we get eStateExited:
+        if not synchronous:
+            # Get events till exited.
+            listener = launch_info.GetListener()
+            event = lldb.SBEvent()
+            # We get two running events in a row here???  That's a bug
+            # but not the one I'm testing for, so for now just fetch as
+            # many as were sent.
+            num_running = 0
+            state = lldb.eStateRunning
+            while state == lldb.eStateRunning:
+                num_running += 1
+                result = listener.WaitForEvent(30, event)
+                self.assertTrue(result, "Timed out waiting for running")
+                state = lldb.SBProcess.GetStateFromEvent(event)
+                if num_running == 1:
+                    self.assertEqual(state, lldb.eStateRunning, "Got running event")
+            # The last event we should get is the exited event
+            self.assertEqual(state, lldb.eStateExited, "Got running event")
+        else:
+            # Make sure that the process has indeed exited
+            state = process.GetState()
+            self.assertEqual(state, lldb.eStateExited);
+
+    def setup_remote_platform(self):
+        return
+        self.build()
+
+        exe = self.getBuildArtifact('a.out')
+        # Launch our test binary.
+
+        # Attach to it with debugserver.
+        debugserver = get_debugserver_exe()
+        debugserver_args = [
+            'localhost:{}'.format(self.PORT)
+        ]
+        self.spawnSubprocess(debugserver, debugserver_args)
+
+        # Select the platform.
+        self.expect('platform select remote-macosx', substrs=[sdk_dir])
+
+        # Connect to debugserver
+        interpreter = self.dbg.GetCommandInterpreter()
+        connected = False
+        for i in range(self.ATTEMPTS):
+            result = lldb.SBCommandReturnObject()
+            interpreter.HandleCommand('gdb-remote {}'.format(self.PORT),
+                                      result)
+            connected = result.Succeeded()
+            if connected:
+                break
+            time.sleep(self.TIMEOUT)
+
+        self.assertTrue(connected, "could not connect to debugserver")
Index: lldb/test/API/functionalities/launch_stop_at_entry/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/launch_stop_at_entry/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
Index: lldb/source/Target/Process.cpp
===================================================================
--- lldb/source/Target/Process.cpp
+++ lldb/source/Target/Process.cpp
@@ -2580,6 +2580,9 @@
           // stopped or crashed. Directly set the state.  This is done to
           // prevent a stop message with a bunch of spurious output on thread
           // status, as well as not pop a ProcessIOHandler.
+          // We are done with the launch hijack listener, and this stop should
+          // go to the public state listener:
+          RestoreProcessEvents();
           SetPublicState(state, false);
 
           if (PrivateStateThreadIsValid())
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to