diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/BaseTestCase.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/BaseTestCase.java index f8c3b32ba14..ac625339ebb 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/BaseTestCase.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/BaseTestCase.java @@ -18,10 +18,12 @@ import java.util.Map; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.dsf.datamodel.IDMEvent; -import org.eclipse.cdt.dsf.debug.service.IBreakpointsExtension.IBreakpointHitDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent; import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; +import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent; import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; +import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession.SessionStartedListener; @@ -115,28 +117,46 @@ public class BaseTestCase { @DsfServiceEventHandler public void eventDispatched(IDMEvent event) { - if (event instanceof MIStoppedEvent) { - // We get this low-level event first. Record the MI event; various - // tests use it for context - synchronized(this) { - fInitialStoppedEvent = (MIStoppedEvent)event; - } - } - else if (event instanceof IBreakpointHitDMEvent) { - // We need to wait for a breakpoint event, not just a suspended event, - // this is because for remote tests, there is a suspended event when - // we connect, and then, there is the breakpoint event at main() - - // We get this higher level event shortly thereafter. We don't want - // to consider the session suspended until we get it. Set the event - // semaphore that will allow the test to proceed - synchronized (fTargetSuspendedSem) { - fTargetSuspended = true; - fTargetSuspendedSem.notify(); - } + // Wait for the program to have stopped on main. + // + // We have to jump through hoops to properly handle the remote + // case, because of differences between GDB <= 68 and GDB >= 7.0. + // + // With GDB >= 7.0, when connecting to the remote gdbserver, + // we get a first *stopped event at connection time. This is + // not the ISuspendedDMEvent event we want. We could instead + // listen for an IBreakpointHitDMEvent instead. + // However, with GDB <= 6.8, temporary breakpoints are not + // reported as breakpoint-hit, so we don't get an IBreakpointHitDMEvent + // for GDB <= 6.8. + // + // What I found to be able to know we have stopped at main, in all cases, + // is to look for an ISuspendedDMEvent and then confirming that it indicates + // in its frame that it stopped at "main". This will allow us to skip + // the first *stopped event for GDB >= 7.0 + if (event instanceof ISuspendedDMEvent) { + if (event instanceof IMIDMEvent) { + IMIDMEvent iMIEvent = (IMIDMEvent)event; - // no further need for this listener. Note fLaunch could be null if the test ran into a failure - fSession.removeServiceEventListener(this); + Object miEvent = iMIEvent.getMIEvent(); + if (miEvent instanceof MIStoppedEvent) { + // Store the corresponding MI *stopped event + fInitialStoppedEvent = (MIStoppedEvent)miEvent; + + // Check the content of the frame for "main" + MIFrame frame = fInitialStoppedEvent.getFrame(); + if (frame != null && "main".equals(frame.getFunction())) { + // Set the event semaphore that will allow the test to proceed + synchronized (fTargetSuspendedSem) { + fTargetSuspended = true; + fTargetSuspendedSem.notify(); + } + + // We found our event, no further need for this listener + fSession.removeServiceEventListener(this); + } + } + } } } }