From 1d80af0b9662748a43101d54488e9c4a3d98b2d0 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Mon, 22 Feb 2010 21:30:56 +0000 Subject: [PATCH] [242943] Support for breakpoint operations while the program is running. JUnit tests included. --- .../dsf/gdb/service/GDBBreakpoints_7_0.java | 109 ++-- .../cdt/dsf/gdb/service/GDBRunControl.java | 10 +- .../dsf/gdb/service/GDBRunControl_7_0.java | 10 +- .../dsf/gdb/service/GDBRunControl_7_0_NS.java | 176 +++++- .../cdt/dsf/mi/service/IMIRunControl.java | 15 + .../cdt/dsf/mi/service/MIBreakpoints.java | 544 ++++++++++------ .../cdt/dsf/mi/service/MIRunControl.java | 145 ++++- .../command/commands/MIBreakInsert.java | 4 +- .../data/launch/src/BreakpointTestApp.cc | 12 +- .../cdt/tests/dsf/gdb/framework/SyncUtil.java | 37 +- .../dsf/gdb/tests/MIBreakpointsTest.java | 590 +++++++++++++++--- .../tests_6_8/MIBreakpointsTest_6_8.java | 9 +- 12 files changed, 1307 insertions(+), 354 deletions(-) diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_0.java index 59818fbc9a6..8072f56bae1 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_0.java @@ -17,11 +17,13 @@ import java.util.Map; import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Sequence.Step; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IBreakpoints; import org.eclipse.cdt.dsf.debug.service.command.ICommandControl; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.mi.service.IMIRunControl; import org.eclipse.cdt.dsf.mi.service.MIBreakpointDMData; import org.eclipse.cdt.dsf.mi.service.MIBreakpoints; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIPasscount; @@ -46,6 +48,7 @@ import org.eclipse.core.runtime.Status; public class GDBBreakpoints_7_0 extends MIBreakpoints { private ICommandControl fConnection; + private IMIRunControl fRunControl; public GDBBreakpoints_7_0(DsfSession session) { super(session); @@ -67,6 +70,7 @@ public class GDBBreakpoints_7_0 extends MIBreakpoints private void doInitialize(final RequestMonitor rm) { // Get the services references fConnection = getServicesTracker().getService(ICommandControl.class); + fRunControl = getServicesTracker().getService(IMIRunControl.class); // Register this service register(new String[] { IBreakpoints.class.getName(), @@ -91,78 +95,83 @@ public class GDBBreakpoints_7_0 extends MIBreakpoints * * @param context * @param breakpoint - * @param drm + * @param finalRm */ @Override - protected void addBreakpoint(final IBreakpointsTargetDMContext context, final Map attributes, final DataRequestMonitor drm) + protected void addBreakpoint(final IBreakpointsTargetDMContext context, final Map attributes, + final DataRequestMonitor finalRm) { // Select the context breakpoints map final Map contextBreakpoints = getBreakpointMap(context); if (contextBreakpoints == null) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); - drm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + finalRm.done(); return; } // Extract the relevant parameters (providing default values to avoid potential NPEs) - String location = formatLocation(attributes); + final String location = formatLocation(attributes); if (location.equals(NULL_STRING)) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); - drm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + finalRm.done(); return; } - Boolean enabled = (Boolean) getProperty(attributes, MIBreakpoints.IS_ENABLED, true); - Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false); - Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false); - String condition = (String) getProperty(attributes, MIBreakpoints.CONDITION, NULL_STRING); - Integer ignoreCount = (Integer) getProperty(attributes, MIBreakpoints.IGNORE_COUNT, 0); + final Boolean enabled = (Boolean) getProperty(attributes, MIBreakpoints.IS_ENABLED, true); + final Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false); + final Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false); + final String condition = (String) getProperty(attributes, MIBreakpoints.CONDITION, NULL_STRING); + final Integer ignoreCount = (Integer) getProperty(attributes, MIBreakpoints.IGNORE_COUNT, 0); String threadId = (String) getProperty(attributes, MIBreakpointDMData.THREAD_ID, "0"); //$NON-NLS-1$ - int tid = Integer.parseInt(threadId); + final int tid = Integer.parseInt(threadId); - // The DataRequestMonitor for the add request - DataRequestMonitor addBreakpointDRM = - new DataRequestMonitor(getExecutor(), drm) { - @Override - protected void handleSuccess() { + final Step insertBreakpointStep = new Step() { + @Override + public void execute(final RequestMonitor rm) { + // Execute the command + fConnection.queueCommand( + new MIBreakInsert(context, isTemporary, isHardware, condition, ignoreCount, location, tid, !enabled, false), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { - // With MI, an invalid location won't generate an error - if (getData().getMIBreakpoints().length == 0) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); - drm.done(); - return; - } + // With MI, an invalid location won't generate an error + if (getData().getMIBreakpoints().length == 0) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); + rm.done(); + return; + } - // Create a breakpoint object and store it in the map - final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]); - int reference = newBreakpoint.getNumber(); - if (reference == -1) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); - drm.done(); - return; - } - contextBreakpoints.put(reference, newBreakpoint); + // Create a breakpoint object and store it in the map + final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]); + int reference = newBreakpoint.getNumber(); + if (reference == -1) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); + rm.done(); + return; + } + contextBreakpoints.put(reference, newBreakpoint); - // Format the return value - MIBreakpointDMContext dmc = new MIBreakpointDMContext(GDBBreakpoints_7_0.this, new IDMContext[] { context }, reference); - drm.setData(dmc); + // Format the return value + MIBreakpointDMContext dmc = new MIBreakpointDMContext(GDBBreakpoints_7_0.this, new IDMContext[] { context }, reference); + finalRm.setData(dmc); - // Flag the event - getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties()); + // Flag the event + getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties()); - drm.done(); - } + rm.done(); + } - @Override - protected void handleError() { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); - drm.done(); - } - }; - - // Execute the command - fConnection.queueCommand( - new MIBreakInsert(context, isTemporary, isHardware, condition, ignoreCount, location, tid, !enabled, false), addBreakpointDRM); + @Override + protected void handleError() { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); + rm.done(); + } + }); + } + }; + + fRunControl.executeWithTargetAvailable(context, new Step[] { insertBreakpointStep }, finalRm); } /** diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java index 58251ae421e..02221edb063 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java @@ -362,8 +362,14 @@ public class GDBRunControl extends MIRunControl { // Don't send the stop event since we are resuming again. return; } else { - // Stopped at another breakpoint or not a breakpoint at all. Just remove our temporary one - // since we don't want it to hit later + // Stopped at another breakpoint that we should not skip. + // Or got an interrupt signal from a suspend command. + // Or got an interrupt signal because the user set/changed a breakpoint. This last case is tricky. + // We could let the run-to-line continue its job, however, I'm thinking that if the user creates + // a new breakpoint, she may want to force the program to stop, in a way to abort the run-to-line. + // So, let's cancel the run-to-line in this case. + // + // Just remove our temporary one since we don't want it to hit later IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(), IBreakpointsTargetDMContext.class); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0.java index 8958f0f5208..d80cb8de1d0 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0.java @@ -575,8 +575,14 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro // Don't send the stop event since we are resuming again. return; } else { - // Stopped at another breakpoint. Just remove our temporary one - // since we don't want it to hit later + // Stopped at another breakpoint that we should not skip. + // Or got an interrupt signal from a suspend command. + // Or got an interrupt signal because the user set/changed a breakpoint. This last case is tricky. + // We could let the run-to-line continue its job, however, I'm thinking that if the user creates + // a new breakpoint, she may want to force the program to stop, in a way to abort the run-to-line. + // So, let's cancel the run-to-line in this case. + // + // Just remove our temporary one since we don't want it to hit later IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(), IBreakpointsTargetDMContext.class); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java index 72d5e5fa637..045b4baedd3 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java @@ -15,15 +15,19 @@ package org.eclipse.cdt.dsf.gdb.service; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; +import java.util.Vector; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Immutable; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Sequence; +import org.eclipse.cdt.dsf.concurrent.Sequence.Step; import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.datamodel.IDMEvent; import org.eclipse.cdt.dsf.debug.service.ICachingService; +import org.eclipse.cdt.dsf.debug.service.IProcesses; import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; @@ -236,6 +240,15 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo private RunToLineActiveOperation fRunToLineActiveOperation = null; + /** + * A counter of MIRunning/MIStopped events that should be kept silent for the specified thread. + */ + private class DisableRunningAndStoppedEvents { + public IMIExecutionDMContext executionDmc = null; + public int count = 0; + }; + private DisableRunningAndStoppedEvents fDisableRunningAndStoppedEvents = new DisableRunningAndStoppedEvents(); + /////////////////////////////////////////////////////////////////////////// // Initialization and shutdown /////////////////////////////////////////////////////////////////////////// @@ -293,15 +306,14 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo return (threadState == null) ? false : !fTerminated && threadState.fSuspended; } - // Container case + // Container case. The container is considered suspended as long + // as one of its thread is suspended if (context instanceof IContainerDMContext) { - boolean isSuspended = false; for (IMIExecutionDMContext threadContext : fThreadRunStates.keySet()) { if (DMContexts.isAncestorOf(threadContext, context)) { - isSuspended |= isSuspended(threadContext); + if (isSuspended(threadContext)) return true; } } - return isSuspended; } // Default case @@ -792,6 +804,142 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo threadState.fStateChangeReason = reason; } + + /** + * @since 3.0 + */ + public void executeWithTargetAvailable(IDMContext ctx, Sequence.Step[] steps, RequestMonitor rm) { + Vector totalStepsVector = new Vector(); + totalStepsVector.add(new IsTargetAvailableStep(ctx)); + totalStepsVector.add(new MakeTargetAvailableStep()); + for (Step step : steps) { + totalStepsVector.add(step); + } + totalStepsVector.add(new RestoreTargetStateStep()); + + final Step[] totalSteps = totalStepsVector.toArray(new Step[totalStepsVector.size()]); + getExecutor().execute(new Sequence(getExecutor(), rm) { + @Override public Step[] getSteps() { return totalSteps; } + }); + } + + /* ****************************************************************************** + * Section to support making operations even when the target is unavailable. + * + * Although one would expect to be able to make commands all the time when + * in non-stop mode, it turns out that GDB has trouble with some commands + * like breakpoints. The safe way to do it is to make sure we have at least + * one thread suspended. + * + * Basically, we must make sure one container is suspended before making + * certain operations (currently breakpoints). If that is not the case, we must + * first suspend one thread, then perform the specified operations, + * and finally resume that thread.. + * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943 + * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273 + * + * ******************************************************************************/ + private IContainerDMContext fContainerDmcToSuspend = null; + private IMIExecutionDMContext fExecutionDmcToSuspend = null; + private boolean fTargetAvailable = false; + + /** + * @since 3.0 + */ + protected class IsTargetAvailableStep extends Sequence.Step { + final IDMContext fCtx; + + public IsTargetAvailableStep(IDMContext ctx) { + fCtx = ctx; + } + + @Override + public void execute(final RequestMonitor rm) { + IProcesses processControl = getServicesTracker().getService(IProcesses.class); + processControl.getProcessesBeingDebugged( + fCtx, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + assert getData() != null; + + if (getData().length == 0) { + // Happens at startup, starting with GDB 7.0 + // This means the target is available + fTargetAvailable = true; + } else { + fTargetAvailable = false; + // Choose the first process as the one to suspend if needed + fContainerDmcToSuspend = (IContainerDMContext)(getData()[0]); + for (IDMContext containerDmc : getData()) { + if (isSuspended((IContainerDMContext)containerDmc)) { + fTargetAvailable = true; + break; + } + } + } + rm.done(); + } + }); + } + }; + + /** + * @since 3.0 + */ + protected class MakeTargetAvailableStep extends Sequence.Step { + @Override + public void execute(final RequestMonitor rm) { + if (!fTargetAvailable) { + // Instead of suspending the entire process, let's find its first thread and use that + IProcesses processControl = getServicesTracker().getService(IProcesses.class); + processControl.getProcessesBeingDebugged( + fContainerDmcToSuspend, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + assert getData() != null; + assert getData().length > 0; + + fExecutionDmcToSuspend = (IMIExecutionDMContext)getData()[0]; + + // Don't broadcast the coming stopped/running events + assert fDisableRunningAndStoppedEvents.count == 0; + fDisableRunningAndStoppedEvents.count++; + fDisableRunningAndStoppedEvents.executionDmc = fExecutionDmcToSuspend; + + suspend(fExecutionDmcToSuspend, rm); + } + }); + } else { + rm.done(); + } + } + }; + + /** + * @since 3.0 + */ + protected class RestoreTargetStateStep extends Sequence.Step { + @Override + public void execute(final RequestMonitor rm) { + if (!fTargetAvailable) { + assert fDisableRunningAndStoppedEvents.count == 0 || fDisableRunningAndStoppedEvents.count == 1; + fDisableRunningAndStoppedEvents.count++; + fDisableRunningAndStoppedEvents.executionDmc = fExecutionDmcToSuspend; + + // Can't use the resume() call because we 'silently' stopped + // so resume() will not know we are actually stopped + fConnection.queueCommand( + new MIExecContinue(fExecutionDmcToSuspend), + new DataRequestMonitor(getExecutor(), rm)); + } else { + // We didn't suspend the thread, so we don't need to resume it + rm.done(); + } + } + }; + /////////////////////////////////////////////////////////////////////////// // Event handlers /////////////////////////////////////////////////////////////////////////// @@ -802,6 +950,14 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo */ @DsfServiceEventHandler public void eventDispatched(final MIRunningEvent e) { + if (fDisableRunningAndStoppedEvents.count > 0 && + fDisableRunningAndStoppedEvents.executionDmc.equals(e.getDMContext())) { + + fDisableRunningAndStoppedEvents.count--; + + // Don't broadcast the running event + return; + } getSession().dispatchEvent(new ResumedEvent(e.getDMContext(), e), getProperties()); } @@ -849,6 +1005,10 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo } else { // Stopped for any other reasons. Just remove our temporary one // since we don't want it to hit later + // + // Note that in Non-stop, we don't cancel a run-to-line when a new + // breakpoint is inserted. This is because the new breakpoint could + // be for another thread altogether and should not affect the current thread. IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(), IBreakpointsTargetDMContext.class); @@ -859,6 +1019,14 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo } } } + if (fDisableRunningAndStoppedEvents.count > 0 && + fDisableRunningAndStoppedEvents.executionDmc.equals(e.getDMContext())) { + + fDisableRunningAndStoppedEvents.count--; + + // Don't broadcast the stopped event + return; + } getSession().dispatchEvent(new SuspendedEvent(e.getDMContext(), e), getProperties()); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/IMIRunControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/IMIRunControl.java index 7ebc54cc971..0e550ee603f 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/IMIRunControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/IMIRunControl.java @@ -11,6 +11,8 @@ package org.eclipse.cdt.dsf.mi.service; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Sequence; +import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl; /** @@ -40,5 +42,18 @@ public interface IMIRunControl extends IRunControl */ void resumeAtLocation(IExecutionDMContext context, String location, RequestMonitor rm); + /** + * Request that the specified steps be executed by first ensuring the target is available + * to receive commands. Once the specified steps are executed, the target should be + * returned to its original availability. + * + * This can is of value for breakpoints commands; e.g., breakpoints need to be inserted + * even when the target is running, so this call would suspend the target, insert the + * breakpoint, and resume the target again. + * + * @since 3.0 + */ + public void executeWithTargetAvailable(IDMContext ctx, Sequence.Step[] stepsToExecute, RequestMonitor rm); + } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java index d407a9e7aed..2552792acbe 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java @@ -19,11 +19,17 @@ import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Immutable; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Sequence; +import org.eclipse.cdt.dsf.concurrent.Sequence.Step; import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IBreakpoints; +import org.eclipse.cdt.dsf.debug.service.IProcesses; +import org.eclipse.cdt.dsf.debug.service.IRunControl; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.cdt.dsf.debug.service.command.ICommandControl; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; @@ -88,7 +94,8 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints public static final String WRITE = PREFIX + ".write"; //$NON-NLS-1$ // Services - ICommandControl fConnection; + private ICommandControl fConnection; + private IMIRunControl fRunControl; // Service breakpoints tracking // The breakpoints are stored per context and keyed on the back-end breakpoint reference @@ -260,6 +267,7 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints // Get the services references fConnection = getServicesTracker().getService(ICommandControl.class); + fRunControl = getServicesTracker().getService(IMIRunControl.class); // Register for the useful events getSession().addServiceEventListener(this, null); @@ -522,82 +530,85 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints * * @param context * @param breakpoint - * @param drm + * @param finalRm * * @since 3.0 */ - protected void addBreakpoint(final IBreakpointsTargetDMContext context, final Map attributes, final DataRequestMonitor drm) + protected void addBreakpoint(final IBreakpointsTargetDMContext context, final Map attributes, final DataRequestMonitor finalRm) { // Select the context breakpoints map final Map contextBreakpoints = getBreakpointMap(context); if (contextBreakpoints == null) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); - drm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + finalRm.done(); return; } // Extract the relevant parameters (providing default values to avoid potential NPEs) - String location = formatLocation(attributes); + final String location = formatLocation(attributes); if (location.equals(NULL_STRING)) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); - drm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + finalRm.done(); return; } - Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false); - Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false); - final String condition = (String) getProperty(attributes, CONDITION, NULL_STRING); - Integer ignoreCount = (Integer) getProperty(attributes, IGNORE_COUNT, 0 ); - String threadId = (String) getProperty(attributes, MIBreakpointDMData.THREAD_ID, "0"); //$NON-NLS-1$ - int tid = Integer.parseInt(threadId); + final Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false); + final Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false); + final String condition = (String) getProperty(attributes, CONDITION, NULL_STRING); + final Integer ignoreCount = (Integer) getProperty(attributes, IGNORE_COUNT, 0 ); + final String threadId = (String) getProperty(attributes, MIBreakpointDMData.THREAD_ID, "0"); //$NON-NLS-1$ + final int tid = Integer.parseInt(threadId); - // The DataRequestMonitor for the add request - DataRequestMonitor addBreakpointDRM = - new DataRequestMonitor(getExecutor(), drm) { - @Override - protected void handleSuccess() { + final Step insertBreakpointStep = new Step() { + @Override + public void execute(final RequestMonitor rm) { + fConnection.queueCommand( + new MIBreakInsert(context, isTemporary, isHardware, condition, ignoreCount, location, tid), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { - // With MI, an invalid location won't generate an error - if (getData().getMIBreakpoints().length == 0) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); - drm.done(); - return; - } + // With MI, an invalid location won't generate an error + if (getData().getMIBreakpoints().length == 0) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); + rm.done(); + return; + } - // Create a breakpoint object and store it in the map - final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]); - int reference = newBreakpoint.getNumber(); - if (reference == -1) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); - drm.done(); - return; - } - contextBreakpoints.put(reference, newBreakpoint); + // Create a breakpoint object and store it in the map + final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]); + int reference = newBreakpoint.getNumber(); + if (reference == -1) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); + rm.done(); + return; + } + contextBreakpoints.put(reference, newBreakpoint); - // Format the return value - MIBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context }, reference); - drm.setData(dmc); + // Format the return value + MIBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context }, reference); + finalRm.setData(dmc); - // Flag the event - getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties()); + // Flag the event + getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties()); - // By default the breakpoint is enabled at creation - // If it wasn't supposed to be, then disable it right away - Map delta = new HashMap(); - delta.put(IS_ENABLED, getProperty(attributes, IS_ENABLED, true)); - modifyBreakpoint(dmc, delta, drm, false); - } + // By default the breakpoint is enabled at creation + // If it wasn't supposed to be, then disable it right away + Map delta = new HashMap(); + delta.put(IS_ENABLED, getProperty(attributes, IS_ENABLED, true)); + modifyBreakpoint(dmc, delta, rm, false); + } - @Override - protected void handleError() { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); - drm.done(); - } + @Override + protected void handleError() { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); + rm.done(); + } + }); + } }; - // Execute the command - fConnection.queueCommand( - new MIBreakInsert(context, isTemporary, isHardware, condition, ignoreCount, location, tid), addBreakpointDRM); + fRunControl.executeWithTargetAvailable(context, new Step[] { insertBreakpointStep }, finalRm); } /** @@ -696,12 +707,12 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints /* (non-Javadoc) * @see org.eclipse.cdt.dsf.debug.service.IBreakpoints#removeBreakpoint(org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext, org.eclipse.cdt.dsf.concurrent.RequestMonitor) */ - public void removeBreakpoint(final IBreakpointDMContext dmc, final RequestMonitor rm) { + public void removeBreakpoint(final IBreakpointDMContext dmc, final RequestMonitor finalRm) { // Validate the breakpoint context if (dmc == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); - rm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + finalRm.done(); return; } @@ -711,24 +722,24 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints breakpointCtx = (MIBreakpointDMContext) dmc; } else { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null)); - rm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null)); + finalRm.done(); return; } // Validate the target context - IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); + final IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); if (context == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null)); - rm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null)); + finalRm.done(); return; } // Pick the context breakpoints map final Map contextBreakpoints = getBreakpointMap(context); if (contextBreakpoints == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); - rm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + finalRm.done(); return; } @@ -736,24 +747,31 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints final int reference = breakpointCtx.getReference(); MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); if (breakpoint == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); - rm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + finalRm.done(); return; } - // Queue the command - fConnection.queueCommand( - new MIBreakDelete(context, new int[] { reference }), - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - getSession().dispatchEvent(new BreakpointRemovedEvent(dmc), getProperties()); - contextBreakpoints.remove(reference); - } - rm.done(); - } - }); + final Step deleteBreakpointStep = new Step() { + @Override + public void execute(final RequestMonitor rm) { + // Queue the command + fConnection.queueCommand( + new MIBreakDelete(context, new int[] { reference }), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + getSession().dispatchEvent(new BreakpointRemovedEvent(dmc), getProperties()); + contextBreakpoints.remove(reference); + } + rm.done(); + } + }); + } + }; + + fRunControl.executeWithTargetAvailable(context, new Step[] { deleteBreakpointStep }, finalRm); } // ------------------------------------------------------------------------- @@ -895,64 +913,71 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints * @param context * @param dmc * @param condition - * @param rm + * @param finalRm * * @since 3.0 */ protected void changeCondition(final IBreakpointsTargetDMContext context, - final int reference, final String condition, final RequestMonitor rm) + final int reference, final String condition, final RequestMonitor finalRm) { // Pick the context breakpoints map final Map contextBreakpoints = getBreakpointMap(context); if (contextBreakpoints == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); - rm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + finalRm.done(); return; } - // Queue the command - fConnection.queueCommand( - new MIBreakCondition(context, reference, condition), - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); - if (breakpoint == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); - rm.done(); - return; - } - breakpoint.setCondition(condition); - rm.done(); - } + final Step changeConditionStep = new Step() { + @Override + public void execute(final RequestMonitor rm) { + // Queue the command + fConnection.queueCommand( + new MIBreakCondition(context, reference, condition), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + breakpoint.setCondition(condition); + rm.done(); + } - // In case of error (new condition could not be installed for whatever reason), - // GDB "offers" different behaviours depending on its version: it can either keep - // the original condition (the right thing to do) or keep the invalid condition. - // Our sole option is to remove the condition in case of error and rely on the - // upper layer to re-install the right condition. - @Override - protected void handleError() { - MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); - if (breakpoint == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); - rm.done(); - return; - } - // Remove invalid condition from the back-end breakpoint - breakpoint.setCondition(NULL_STRING); - fConnection.queueCommand( - new MIBreakCondition(context, reference, NULL_STRING), - new DataRequestMonitor(getExecutor(), rm) { - @Override - // The report the initial problem - protected void handleCompleted() { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_CONDITION, null)); - rm.done(); - } - }); - } - }); + // In case of error (new condition could not be installed for whatever reason), + // GDB "offers" different behaviours depending on its version: it can either keep + // the original condition (the right thing to do) or keep the invalid condition. + // Our sole option is to remove the condition in case of error and rely on the + // upper layer to re-install the right condition. + @Override + protected void handleError() { + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + // Remove invalid condition from the back-end breakpoint + breakpoint.setCondition(NULL_STRING); + fConnection.queueCommand( + new MIBreakCondition(context, reference, NULL_STRING), + new DataRequestMonitor(getExecutor(), rm) { + @Override + // The report the initial problem + protected void handleCompleted() { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_CONDITION, null)); + rm.done(); + } + }); + } + }); + } + }; + + fRunControl.executeWithTargetAvailable(context, new Step[] { changeConditionStep }, finalRm); } @@ -962,37 +987,44 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints * @param context * @param reference * @param ignoreCount - * @param rm + * @param finalRm * * @since 3.0 */ - protected void changeIgnoreCount(IBreakpointsTargetDMContext context, - final int reference, final int ignoreCount, final RequestMonitor rm) + protected void changeIgnoreCount(final IBreakpointsTargetDMContext context, + final int reference, final int ignoreCount, final RequestMonitor finalRm) { // Pick the context breakpoints map final Map contextBreakpoints = getBreakpointMap(context); if (contextBreakpoints == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); - rm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + finalRm.done(); return; } - // Queue the command - fConnection.queueCommand( - new MIBreakAfter(context, reference, ignoreCount), - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); - if (breakpoint == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); - rm.done(); - return; - } - breakpoint.setIgnoreCount(ignoreCount); - rm.done(); - } - }); + final Step changeIgnoreCountStep = new Step() { + @Override + public void execute(final RequestMonitor rm) { + // Queue the command + fConnection.queueCommand( + new MIBreakAfter(context, reference, ignoreCount), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + breakpoint.setIgnoreCount(ignoreCount); + rm.done(); + } + }); + } + }; + + fRunControl.executeWithTargetAvailable(context, new Step[] { changeIgnoreCountStep }, finalRm); } /** @@ -1000,37 +1032,44 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints * * @param context * @param reference - * @param rm + * @param finalRm * * @since 3.0 */ - protected void enableBreakpoint(IBreakpointsTargetDMContext context, - final int reference, final RequestMonitor rm) + protected void enableBreakpoint(final IBreakpointsTargetDMContext context, + final int reference, final RequestMonitor finalRm) { // Pick the context breakpoints map final Map contextBreakpoints = getBreakpointMap(context); if (contextBreakpoints == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); - rm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + finalRm.done(); return; } - // Queue the command - fConnection.queueCommand( - new MIBreakEnable(context, new int[] { reference }), - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); - if (breakpoint == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); - rm.done(); - return; - } - breakpoint.setEnabled(true); - rm.done(); - } - }); + final Step enableBreakpointStep = new Step() { + @Override + public void execute(final RequestMonitor rm) { + // Queue the command + fConnection.queueCommand( + new MIBreakEnable(context, new int[] { reference }), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + breakpoint.setEnabled(true); + rm.done(); + } + }); + } + }; + + fRunControl.executeWithTargetAvailable(context, new Step[] { enableBreakpointStep }, finalRm); } /** @@ -1038,37 +1077,168 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints * * @param context * @param dmc - * @param rm + * @param finalRm * * @since 3.0 */ - protected void disableBreakpoint(IBreakpointsTargetDMContext context, - final int reference, final RequestMonitor rm) + protected void disableBreakpoint(final IBreakpointsTargetDMContext context, + final int reference, final RequestMonitor finalRm) { // Pick the context breakpoints map final Map contextBreakpoints = getBreakpointMap(context); if (contextBreakpoints == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); - rm.done(); + finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + finalRm.done(); return; } - // Queue the command - fConnection.queueCommand( - new MIBreakDisable(context, new int[] { reference }), - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); - if (breakpoint == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); - rm.done(); - return; - } - breakpoint.setEnabled(false); - rm.done(); - } - }); + final Step disableBreakpointStep = new Step() { + @Override + public void execute(final RequestMonitor rm) { + // Queue the command + fConnection.queueCommand( + new MIBreakDisable(context, new int[] { reference }), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + breakpoint.setEnabled(false); + rm.done(); + } + }); + } + }; + + fRunControl.executeWithTargetAvailable(context, new Step[] { disableBreakpointStep }, finalRm); } + /* ****************************************************************************** + * Section to support making breakpoint operations while the target is running. + * + * Basically, we must make sure we have one thread suspended before making + * a breakpoint operation. If we don't we must suspend a thread, do the + * breakpoint operation and then resume the thread. + * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943 + * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273 + * + * ******************************************************************************/ + /** The top level context describing our target **/ + private IDMContext fTargetDmc = null; + /** The container context used to determine if the target is suspended **/ + private IContainerDMContext fContainerDmc = null; + /** Must we suspend the target **/ + private boolean fMustSuspend = false; + + /** + * Returns the context of our target. It will be used to find the container we need + * to use to check to see if the target is suspended. + * @since 3.0 + */ + protected IDMContext getTargetDmc() { + return fTargetDmc; + } + + /** + * Returns the container context that should be used to determine if target is suspended. + * This container will also be the one suspended if needed. + * @since 3.0 + */ + protected IContainerDMContext getContainerDmc() { + return fContainerDmc; + } + + /** + * Returns whether the target must be suspended before performing the breakpoint operation + * @since 3.0 + */ + protected boolean getMustSuspended() { + return fMustSuspend; + } + + /** + * Returns whether the target must be suspended before performing the breakpoint operation + * @since 3.0 + */ + protected IExecutionDMContext getContextToSuspend() { + return fContainerDmc; + } + + /** + * Find the context for the container we should use to know + * if the target is already suspended. + * @since 3.0 + */ + protected class FindContainerDmcStep extends Sequence.Step { + @Override + public void execute(final RequestMonitor rm) { + IProcesses processControl = getServicesTracker().getService(IProcesses.class); + processControl.getProcessesBeingDebugged( + getTargetDmc(), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (getData() != null && getData().length != 0) { + fContainerDmc = (IContainerDMContext)(getData()[0]); + } + // else Not debugging any process yet, so no need to suspend target + rm.done(); + } + }); + } + }; + + + /** + * Check if the container returned by getContainerDmc() is suspended. + * If it is, we can do breakpoint operations. If it is not, we must first + * suspend it, and then we'll have to resume it. + * + * @since 3.0 + */ + protected class IsContainerSuspendedStep extends Sequence.Step { + @Override + public void execute(RequestMonitor rm) { + IRunControl runControl = getServicesTracker().getService(IRunControl.class); + fMustSuspend = !runControl.isSuspended(getContainerDmc()); + rm.done(); + } + }; + + /** + * If needed, suspend the target that is returned by getContextToSuspend(). + * @since 3.0 + */ + protected class SuspendTargetStep extends Sequence.Step { + @Override + public void execute(final RequestMonitor rm) { + if (getMustSuspended()) { + IRunControl runControl = getServicesTracker().getService(IRunControl.class); + runControl.suspend(getContextToSuspend(), rm); + } else { + rm.done(); + } + } + }; + + /** + * If needed, resume the thread that is returned by getThreadToSuspend(). + * @since 3.0 + */ + protected class ResumeThreadStep extends Sequence.Step { + @Override + public void execute(final RequestMonitor rm) { + if (getMustSuspended()) { + IRunControl runControl = getServicesTracker().getService(IRunControl.class); + runControl.resume(getContextToSuspend(), rm); + } else { + // We didn't suspend the thread, so we don't need to resume it + rm.done(); + } + } + }; } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java index 841420fb259..ffe38459957 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java @@ -11,15 +11,20 @@ *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service; +import java.util.Vector; + import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Immutable; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Sequence; +import org.eclipse.cdt.dsf.concurrent.Sequence.Step; import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.datamodel.IDMEvent; import org.eclipse.cdt.dsf.debug.service.ICachingService; +import org.eclipse.cdt.dsf.debug.service.IProcesses; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl; import org.eclipse.cdt.dsf.debug.service.command.CommandCache; @@ -271,6 +276,11 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I private StateChangeReason fStateChangeReason; private IExecutionDMContext fStateChangeTriggeringContext; + /** + * A counter of MIRunning/MIStopped events that should + * be kept silent. + */ + private int fDisableRunningAndStoppedEventsCount = 0; private static final int FAKE_THREAD_ID = 0; @@ -338,6 +348,12 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I */ @DsfServiceEventHandler public void eventDispatched(final MIRunningEvent e) { + if (fDisableRunningAndStoppedEventsCount > 0) { + fDisableRunningAndStoppedEventsCount--; + // We don't broadcast running events right now + return; + } + IDMEvent event = null; // Find the container context, which is used in multi-threaded debugging. IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class); @@ -357,7 +373,13 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I */ @DsfServiceEventHandler public void eventDispatched(final MIStoppedEvent e) { - IDMEvent event = null; + if (fDisableRunningAndStoppedEventsCount > 0) { + fDisableRunningAndStoppedEventsCount--; + // We don't broadcast stopped events right now + return; + } + + IDMEvent event = null; // Find the container context, which is used in multi-threaded debugging. IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class); if (containerDmc != null) { @@ -738,6 +760,127 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I rm.done(); } } + + /** + * @since 3.0 + */ + public void executeWithTargetAvailable(IDMContext ctx, Sequence.Step[] steps, RequestMonitor rm) { + Vector totalStepsVector = new Vector(); + totalStepsVector.add(new IsTargetAvailableStep(ctx)); + totalStepsVector.add(new MakeTargetAvailableStep()); + for (Step step : steps) { + totalStepsVector.add(step); + } + totalStepsVector.add(new RestoreTargetStateStep()); + + final Step[] totalSteps = totalStepsVector.toArray(new Step[totalStepsVector.size()]); + getExecutor().execute(new Sequence(getExecutor(), rm) { + @Override public Step[] getSteps() { return totalSteps; } + }); + } + + /* ****************************************************************************** + * Section to support making operations even when the target is unavailable. + * + * Basically, we must make sure the container is suspended before making + * certain operations (currently breakpoints). If we don't, we must first + * suspend the container, then perform the specified operations, + * and finally resume the container. + * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943 + * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273 + * + * ******************************************************************************/ + private IContainerDMContext fContainerDmc = null; + private boolean fTargetAvailable = false; + + /** + * Returns whether the target is available to perform operations + * @since 3.0 + */ + protected boolean isTargetAvailable() { + return fTargetAvailable; + } + + /** + * Returns whether the target must be suspended before performing the breakpoint operation + * @since 3.0 + */ + protected IExecutionDMContext getContextToSuspend() { + return fContainerDmc; + } + + /** + * @since 3.0 + */ + protected class IsTargetAvailableStep extends Sequence.Step { + final IDMContext fCtx; + + public IsTargetAvailableStep(IDMContext ctx) { + fCtx = ctx; + } + + @Override + public void execute(final RequestMonitor rm) { + IProcesses processControl = getServicesTracker().getService(IProcesses.class); + processControl.getProcessesBeingDebugged( + fCtx, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + assert getData() != null; + + if (getData().length == 0) { + // Happens at startup, starting with GDB 7.0 + // This means the target is available + fTargetAvailable = true; + } else { + fContainerDmc = (IContainerDMContext)(getData()[0]); + fTargetAvailable = isSuspended(fContainerDmc); + } + rm.done(); + } + }); + } + }; + + /** + * @since 3.0 + */ + protected class MakeTargetAvailableStep extends Sequence.Step { + @Override + public void execute(final RequestMonitor rm) { + if (!isTargetAvailable()) { + // Don't broadcast the coming stopped/running events + assert fDisableRunningAndStoppedEventsCount == 0; + fDisableRunningAndStoppedEventsCount++; + suspend(getContextToSuspend(), rm); + } else { + rm.done(); + } + } + }; + + /** + * @since 3.0 + */ + protected class RestoreTargetStateStep extends Sequence.Step { + @Override + public void execute(final RequestMonitor rm) { + if (!isTargetAvailable()) { + assert fDisableRunningAndStoppedEventsCount == 0 || fDisableRunningAndStoppedEventsCount == 1; + fDisableRunningAndStoppedEventsCount++; + + // Can't use the resume() call because we 'silently' stopped + // so resume() will not know we are actually stopped + fConnection.queueCommand( + new MIExecContinue(getContextToSuspend()), + new DataRequestMonitor(getExecutor(), rm)); + } else { + // We didn't suspend the container, so we don't need to resume it + rm.done(); + } + } + }; /** * {@inheritDoc} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIBreakInsert.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIBreakInsert.java index dd6f2b7d5be..b941093be92 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIBreakInsert.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIBreakInsert.java @@ -80,7 +80,7 @@ public class MIBreakInsert extends MICommand * @since 3.0 */ public MIBreakInsert(IBreakpointsTargetDMContext ctx, boolean isTemporary, boolean isHardware, - String condition, int ignoreCount, String line, int tid, boolean disabled, boolean isTracepoint) { + String condition, int ignoreCount, String location, int tid, boolean disabled, boolean isTracepoint) { super(ctx, "-break-insert"); //$NON-NLS-1$ // For a tracepoint, force certain parameters to what is allowed @@ -160,7 +160,7 @@ public class MIBreakInsert extends MICommand if (opts.length > 0) { setOptions(opts); } - setParameters(new Adjustable[]{ new PathAdjustable(line)}); + setParameters(new Adjustable[]{ new PathAdjustable(location)}); } @Override diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/BreakpointTestApp.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/BreakpointTestApp.cc index 5474e540718..3129248214b 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/BreakpointTestApp.cc +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/BreakpointTestApp.cc @@ -5,7 +5,7 @@ // Copyright : Ericsson AB // Description : Breakpoint test application //============================================================================ - +#include #include using namespace std; @@ -32,16 +32,20 @@ void setBlocks() void loop() { - int j; - - for (int i = 0; i < ARRAY_SIZE; i++) + int j = 10; + int i = 0; + for (i = 0; i < ARRAY_SIZE; i++) j = i; } int main() { + int a = 10; + zeroBlocks(1); loop(); setBlocks(); + sleep(1); + a++; return 0; } diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java index 5a946b65e23..6a161860241 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Ericsson and others. + * Copyright (c) 2007, 2010 Ericsson and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -44,6 +44,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecFinish; import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecNext; import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecStep; import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecUntil; +import org.eclipse.cdt.dsf.mi.service.command.events.MIRunningEvent; import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo; @@ -277,6 +278,40 @@ public class SyncUtil { return SyncResumeUntilStopped(fGdbContainerDmc); } + public static MIRunningEvent SyncResume(final IExecutionDMContext dmc) throws Throwable { + final ServiceEventWaitor eventWaitor = + new ServiceEventWaitor( + fSession, + MIRunningEvent.class); + + fRunControl.getExecutor().submit(new Runnable() { + public void run() { + // No need for a RequestMonitor since we will wait for the + // ServiceEvent telling us the program has been resumed + fCommandControl.queueCommand( + new MIExecContinue(dmc), + null); + } + }); + + // Wait for the execution to suspend after the step + return eventWaitor.waitForEvent(ServiceEventWaitor.WAIT_FOREVER); + } + + public static MIRunningEvent SyncResume() throws Throwable { + return SyncResume(fGdbContainerDmc); + } + + public static MIStoppedEvent SyncWaitForStop() throws Throwable { + final ServiceEventWaitor eventWaitor = + new ServiceEventWaitor( + fSession, + MIStoppedEvent.class); + + // Wait for the execution to suspend + return eventWaitor.waitForEvent(ServiceEventWaitor.WAIT_FOREVER); + } + public static MIStoppedEvent SyncRunToLocation(final String location) throws Throwable { // Set a temporary breakpoint and run to it. // Note that if there were other breakpoints set ahead of this one, diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIBreakpointsTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIBreakpointsTest.java index a109b0310ba..d6a077ee1a6 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIBreakpointsTest.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIBreakpointsTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2008 Ericsson and others. + * Copyright (c) 2007, 2010 Ericsson and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -105,7 +105,6 @@ public class MIBreakpointsTest extends BaseTestCase { final int WP_HIT = Events.WP_HIT.ordinal(); final int WP_OOS = Events.WP_OOS.ordinal(); private int[] fBreakpointEvents = new int[Events.values().length]; - private boolean fBreakpointEvent; private int fBreakpointEventCount; private int fBreakpointRef; @@ -132,7 +131,9 @@ public class MIBreakpointsTest extends BaseTestCase { private final int LINE_NUMBER_1 = 20; private final int LINE_NUMBER_2 = 21; private final int LINE_NUMBER_3 = 27; - private final int LINE_NUMBER_4 = 35; + private final int LINE_NUMBER_4 = 36; + private final int LINE_NUMBER_5 = 49; + private final int LINE_NUMBER_6 = 50; private final String FUNCTION = "zeroBlocks"; private final String SIGNED_FUNCTION = "zeroBlocks(int)"; private final String NO_CONDITION = ""; @@ -143,11 +144,14 @@ public class MIBreakpointsTest extends BaseTestCase { private final String CONDITION_1 = "i == 128"; private final String CONDITION_2 = "i == 64"; private final String CONDITION_3 = "j == 20"; + private final String CONDITION_4 = "a == 20"; + private final String CONDITION_5 = "a == 10"; private final int IGNORE_COUNT_1 = 128; private final int IGNORE_COUNT_2 = 20; private final String EXPRESSION_1 = "charBlock[20]"; private final String EXPRESSION_2 = "j"; + private final String EXPRESSION_3 = "a"; // Error messages final String UNKNOWN_EXECUTION_CONTEXT = "Unknown execution context"; @@ -221,10 +225,10 @@ public class MIBreakpointsTest extends BaseTestCase { @DsfServiceEventHandler public void eventDispatched(IBreakpointsAddedEvent e) { synchronized (lock) { + System.out.println("Got bp added event"); fBreakpointEvents[BP_ADDED]++; fBreakpointEventCount++; fBreakpointRef = ((MIBreakpointDMContext) e.getBreakpoints()[0]).getReference(); - fBreakpointEvent = true; lock.notifyAll(); } } @@ -232,10 +236,10 @@ public class MIBreakpointsTest extends BaseTestCase { @DsfServiceEventHandler public void eventDispatched(IBreakpointsUpdatedEvent e) { synchronized (lock) { + System.out.println("Got bp updated event"); fBreakpointEvents[BP_UPDATED]++; fBreakpointEventCount++; fBreakpointRef = ((MIBreakpointDMContext) e.getBreakpoints()[0]).getReference(); - fBreakpointEvent = true; lock.notifyAll(); } } @@ -243,10 +247,10 @@ public class MIBreakpointsTest extends BaseTestCase { @DsfServiceEventHandler public void eventDispatched(IBreakpointsRemovedEvent e) { synchronized (lock) { + System.out.println("Got bp removed event"); fBreakpointEvents[BP_REMOVED]++; fBreakpointEventCount++; fBreakpointRef = ((MIBreakpointDMContext) e.getBreakpoints()[0]).getReference(); - fBreakpointEvent = true; lock.notifyAll(); } } @@ -254,10 +258,10 @@ public class MIBreakpointsTest extends BaseTestCase { @DsfServiceEventHandler public void eventDispatched(MIBreakpointHitEvent e) { synchronized (lock) { + System.out.println("Got bp hit event"); fBreakpointEvents[BP_HIT]++; fBreakpointEventCount++; fBreakpointRef = e.getNumber(); - fBreakpointEvent = true; lock.notifyAll(); } } @@ -265,10 +269,10 @@ public class MIBreakpointsTest extends BaseTestCase { @DsfServiceEventHandler public void eventDispatched(MIWatchpointTriggerEvent e) { synchronized (lock) { + System.out.println("Got wp hit event"); fBreakpointEvents[WP_HIT]++; fBreakpointEventCount++; fBreakpointRef = e.getNumber(); - fBreakpointEvent = true; lock.notifyAll(); } } @@ -276,10 +280,10 @@ public class MIBreakpointsTest extends BaseTestCase { @DsfServiceEventHandler public void eventDispatched(MIWatchpointScopeEvent e) { synchronized (lock) { + System.out.println("Got wp scope event"); fBreakpointEvents[WP_OOS]++; fBreakpointEventCount++; fBreakpointRef = e.getNumber(); - fBreakpointEvent = true; lock.notifyAll(); } } @@ -290,7 +294,6 @@ public class MIBreakpointsTest extends BaseTestCase { for (int i = 0; i < fBreakpointEvents.length; i++) { fBreakpointEvents[i] = 0; } - fBreakpointEvent = false; fBreakpointEventCount = 0; } } @@ -306,15 +309,17 @@ public class MIBreakpointsTest extends BaseTestCase { // Suspends the thread until an event is flagged // NOTE: too simple for real life but good enough for this test suite - private void waitForBreakpointEvent() { + private void waitForBreakpointEvent(int count) { synchronized (lock) { - while (!fBreakpointEvent) { + // Make sure we don't wait forever, in case an event never + // arrives. The test will check if everything was received + int loopIndex = 0; + while (fBreakpointEventCount < count && loopIndex++ < 4) { try { - lock.wait(); + lock.wait(500); } catch (InterruptedException ex) { } } - fBreakpointEvent = false; } } @@ -742,7 +747,7 @@ public class MIBreakpointsTest extends BaseTestCase { IBreakpointDMContext ref = insertBreakpoint(fBreakpointsDmc, breakpoint); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -788,7 +793,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -837,7 +842,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -885,7 +890,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -932,7 +937,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -979,7 +984,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1025,7 +1030,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1054,7 +1059,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1111,7 +1116,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1134,7 +1139,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1172,6 +1177,47 @@ public class MIBreakpointsTest extends BaseTestCase { } } + // ------------------------------------------------------------------------ + // insertBreakpoint_WhileTargetRunning + // Set breakpoint while the target is running and make sure it eventually + // gets hit. + // ------------------------------------------------------------------------ + @Test + public void insertBreakpoint_WhileTargetRunning() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_5); + + // Run the program + SyncUtil.SyncResume(); + + // Install the breakpoint + MIBreakpointDMContext ref = (MIBreakpointDMContext) insertBreakpoint(fBreakpointsDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Wait for breakpoint to hit + MIStoppedEvent event = SyncUtil.SyncWaitForStop(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(2); + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 2); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint1.getNumber()); + clearEventCounters(); + + assertTrue("Did not stop because of breakpoint, but stopped because of: " + + event.getClass().getCanonicalName(), event instanceof MIBreakpointHitEvent); + assertTrue("Did not stop because of the correct breakpoint at line " + LINE_NUMBER_5, + ((MIBreakpointHitEvent)event).getNumber() == ref.getReference()); + } + /////////////////////////////////////////////////////////////////////////// // Add Watchpoint tests /////////////////////////////////////////////////////////////////////////// @@ -1195,7 +1241,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1241,7 +1287,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1288,7 +1334,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1315,6 +1361,65 @@ public class MIBreakpointsTest extends BaseTestCase { watchpoint1.equals(watchpoint2)); } + // ------------------------------------------------------------------------ + // insertWatchpoint_WhileTargetRunning + // Set a write watchpoint while the experiment is running. + // ------------------------------------------------------------------------ + @Ignore("Not supported because the frame where we stop does not contain the expression") + @Test + public void insertWatchpoint_WhileTargetRunning() throws Throwable { + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_3); + watchpoint.put(WRITE_TAG, true); + + // Run the program + SyncUtil.SyncResume(); + + // Install watchpoint + IBreakpointDMContext ref = insertBreakpoint(fBreakpointsDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Wait for breakpoint to hit + MIStoppedEvent event = SyncUtil.SyncWaitForStop(); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(2); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 2); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + clearEventCounters(); + + // Ensure that the watchpoint was correctly installed + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong expression)", + watchpoint1.getExpression().equals(EXPRESSION_1)); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong read state)", + !watchpoint1.isReadWatchpoint()); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong write state)", + watchpoint1.isWriteWatchpoint()); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong access state)", + !watchpoint1.isAccessWatchpoint()); + + // Ensure the BreakpointService holds only the right watchpoints + IBreakpointDMContext[] watchpoints = getBreakpoints(fBreakpointsDmc); + assertTrue("BreakpointService problem: expected " + 1 + " watchpoints(s), received " + + watchpoints.length, watchpoints.length == 1); + MIBreakpointDMData watchpoint2 = (MIBreakpointDMData) getBreakpoint(watchpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + watchpoint1.equals(watchpoint2)); + + assertTrue("Did not stop because of watchpoint, but stopped because of: " + + event.getClass().getCanonicalName(), event instanceof MIWatchpointTriggerEvent); + assertTrue("Did not stop because of the watchpoint", + ((MIWatchpointTriggerEvent)event).getNumber() == watchpoint1.getReference()); + } + /////////////////////////////////////////////////////////////////////////// // Remove Breakpoint tests /////////////////////////////////////////////////////////////////////////// @@ -1338,7 +1443,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1350,7 +1455,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_REMOVED event(s), received " @@ -1397,7 +1502,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1414,7 +1519,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_REMOVED event(s), received " @@ -1447,7 +1552,7 @@ public class MIBreakpointsTest extends BaseTestCase { MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1492,7 +1597,7 @@ public class MIBreakpointsTest extends BaseTestCase { // Ensure that right BreakpointEvents were received int expected = i + 1; - waitForBreakpointEvent(); + waitForBreakpointEvent(expected); assertTrue("BreakpointEvent problem: expected " + expected + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == expected); assertTrue("BreakpointEvent problem: expected " + expected + " BREAKPOINT_ADDED event(s), received " @@ -1519,7 +1624,7 @@ public class MIBreakpointsTest extends BaseTestCase { // Ensure that right BreakpointEvents were received int expected = i + 1; - waitForBreakpointEvent(); + waitForBreakpointEvent(expected); assertTrue("BreakpointEvent problem: expected " + expected + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == expected); assertTrue("BreakpointEvent problem: expected " + expected + " BREAKPOINT_REMOVED event(s), received " @@ -1537,6 +1642,54 @@ public class MIBreakpointsTest extends BaseTestCase { clearEventCounters(); } + // ------------------------------------------------------------------------ + // removeBreakpoint_WhileTargetRunning + // Remove breakpoint while the target is running and make sure it is does + // not get hit. + // ------------------------------------------------------------------------ + @Test + public void removeBreakpoint_WhileTargetRunning() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_5); + + // Install the breakpoint + MIBreakpointDMContext ref = (MIBreakpointDMContext) insertBreakpoint(fBreakpointsDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Install a second breakpoint + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_6); + + // Install the breakpoint + MIBreakpointDMContext ref1 = (MIBreakpointDMContext) insertBreakpoint(fBreakpointsDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Run the program + SyncUtil.SyncResume(); + + // Remove the first breakpoint + removeBreakpoint(ref); + assertTrue(fWait.getMessage(), fWait.isOK()); + + MIStoppedEvent event = SyncUtil.SyncWaitForStop(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(4); + assertTrue("BreakpointEvent problem: expected " + 4 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 4); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + clearEventCounters(); + + assertTrue("Did not stop on a breakpoint!", + event instanceof MIBreakpointHitEvent); + assertTrue("Did not stop because of the correct breakpoint at line " + LINE_NUMBER_5, + ((MIBreakpointHitEvent)event).getNumber() == ref1.getReference()); + } + /////////////////////////////////////////////////////////////////////////// // Breakpoint Update tests /////////////////////////////////////////////////////////////////////////// @@ -1588,7 +1741,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1602,7 +1755,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -1635,7 +1788,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1649,7 +1802,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -1682,7 +1835,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1696,7 +1849,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -1709,6 +1862,66 @@ public class MIBreakpointsTest extends BaseTestCase { breakpoint2.getCondition().equals(CONDITION_2)); } + // ------------------------------------------------------------------------ + // updateBreakpoint_ModifyCondition_WhileTargetRunning + // Change the condition of a breakpoint while the target is running and make sure + // it does get hit. + // ------------------------------------------------------------------------ + @Test + public void updateBreakpoint_ModifyCondition_WhileTargetRunning() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_5); + breakpoint.put(CONDITION_TAG, CONDITION_4); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fBreakpointsDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Prepare to update the condition + Map delta = new HashMap(); + delta.put(CONDITION_TAG, CONDITION_5); + + // Run the program + SyncUtil.SyncResume(); + //Update the condition + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + MIStoppedEvent event = SyncUtil.SyncWaitForStop(); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(2); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 2); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + clearEventCounters(); + + // Verify the state of the breakpoint + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", + breakpoint2.getCondition().equals(CONDITION_5)); + + assertTrue("Did not stop on our modified breakpoint!", + event instanceof MIBreakpointHitEvent); + assertTrue("Did not stop because of the correct breakpoint at line " + LINE_NUMBER_5, + ((MIBreakpointHitEvent)event).getNumber() == breakpoint2.getReference()); + } + // ------------------------------------------------------------------------ // updateWatchpoint_AddCondition // Set a watchpoint and then add a condition. @@ -1737,7 +1950,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1751,7 +1964,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -1793,7 +2006,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1807,7 +2020,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -1849,10 +2062,10 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); - assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + waitForBreakpointEvent(1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT events, received " + fBreakpointEventCount, fBreakpointEventCount == 1); - assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event, received " + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); clearEventCounters(); @@ -1863,7 +2076,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -1895,7 +2108,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1909,7 +2122,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -1942,7 +2155,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -1956,7 +2169,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -1989,7 +2202,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2003,7 +2216,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -2016,6 +2229,67 @@ public class MIBreakpointsTest extends BaseTestCase { breakpoint2.getIgnoreCount() == IGNORE_COUNT_2); } + // ------------------------------------------------------------------------ + // updateBreakpoint_ModifyCount_WhileTargetRunning + // Change the ignore count of a breakpoint while the target is running and make sure + // it does get hit. + // ------------------------------------------------------------------------ + @Test + public void updateBreakpoint_ModifyCount_WhileTargetRunning() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_5); + breakpoint.put(IGNORE_COUNT_TAG, IGNORE_COUNT_1); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fBreakpointsDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Prepare to update the count + Map delta = new HashMap(); + delta.put(IGNORE_COUNT_TAG, 0); + + // Run the program + SyncUtil.SyncResume(); + + //Update the count + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + MIStoppedEvent event = SyncUtil.SyncWaitForStop(); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(2); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 2); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + clearEventCounters(); + + // Verify the state of the breakpoint + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong count)", + breakpoint2.getIgnoreCount() == 0); + + assertTrue("Did not stop on our modified breakpoint!", + event instanceof MIBreakpointHitEvent); + assertTrue("Did not stop because of the correct breakpoint at line " + LINE_NUMBER_5, + ((MIBreakpointHitEvent)event).getNumber() == breakpoint2.getReference()); + } + // ------------------------------------------------------------------------ // updateBreakpoint_Disable // Set 2 breakpoints and disable the first one. @@ -2045,7 +2319,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(2); assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 2); assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT_ADDED event(s), received " @@ -2065,7 +2339,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -2082,7 +2356,7 @@ public class MIBreakpointsTest extends BaseTestCase { SyncUtil.SyncResumeUntilStopped(); // Ensure the BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " @@ -2092,6 +2366,66 @@ public class MIBreakpointsTest extends BaseTestCase { clearEventCounters(); } + // ------------------------------------------------------------------------ + // updateBreakpoint_Disable_WhileTargetRunning + // Disable a breakpoint while the target is running and make sure + // it does not get hit. + // ------------------------------------------------------------------------ + @Test + public void updateBreakpoint_Disable_WhileTargetRunning() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_5); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fBreakpointsDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Install a second breakpoint + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_6); + MIBreakpointDMContext ref1 = (MIBreakpointDMContext) insertBreakpoint(fBreakpointsDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(2); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 2); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 2); + clearEventCounters(); + + // Prepare to disable the breakpoint + Map delta = new HashMap(); + delta.put(IS_ENABLED_TAG, false); + + // Run the program + SyncUtil.SyncResume(); + + // Disable the breakpoint + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + MIStoppedEvent event = SyncUtil.SyncWaitForStop(); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(2); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 2); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + clearEventCounters(); + + assertTrue("Did not stop on a breakpoint!", + event instanceof MIBreakpointHitEvent); + assertTrue("Did not stop because of the correct breakpoint at line " + LINE_NUMBER_5, + ((MIBreakpointHitEvent)event).getNumber() == ref1.getReference()); + } + // ------------------------------------------------------------------------ // updateBreakpoint_Enable // In a loop, set 2 breakpoints and disable the first one. After hitting @@ -2122,7 +2456,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(2); assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 2); assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT_ADDED event(s), received " @@ -2142,7 +2476,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -2159,7 +2493,7 @@ public class MIBreakpointsTest extends BaseTestCase { SyncUtil.SyncResumeUntilStopped(); // Ensure the BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " @@ -2175,7 +2509,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -2192,7 +2526,7 @@ public class MIBreakpointsTest extends BaseTestCase { SyncUtil.SyncResumeUntilStopped(); // Ensure the BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " @@ -2202,6 +2536,62 @@ public class MIBreakpointsTest extends BaseTestCase { clearEventCounters(); } + // ------------------------------------------------------------------------ + // updateBreakpoint_Enable_WhileTargetRunning + // Enable a disabled breakpoint while the target is running and make sure + // it does get hit. + // ------------------------------------------------------------------------ + @Test + public void updateBreakpoint_Enable_WhileTargetRunning() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_5); + breakpoint.put(IS_ENABLED_TAG, false); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fBreakpointsDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Prepare to enable the breakpoint + Map delta = new HashMap(); + delta.put(IS_ENABLED_TAG, true); + + // Run the program + SyncUtil.SyncResume(); + + // Enable the breakpoint + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + MIStoppedEvent event = SyncUtil.SyncWaitForStop(); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(2); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 2); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + clearEventCounters(); + + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("Did not stop on our enabled breakpoint!", + event instanceof MIBreakpointHitEvent); + assertTrue("Did not stop because of the correct breakpoint at line " + LINE_NUMBER_5, + ((MIBreakpointHitEvent)event).getNumber() == breakpoint1.getReference()); + } /////////////////////////////////////////////////////////////////////////// // Breakpoint Hit tests /////////////////////////////////////////////////////////////////////////// @@ -2224,7 +2614,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2235,7 +2625,7 @@ public class MIBreakpointsTest extends BaseTestCase { SyncUtil.SyncResumeUntilStopped(); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2264,7 +2654,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2275,7 +2665,7 @@ public class MIBreakpointsTest extends BaseTestCase { SyncUtil.SyncResumeUntilStopped(); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2307,7 +2697,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2319,7 +2709,7 @@ public class MIBreakpointsTest extends BaseTestCase { IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2354,7 +2744,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2368,7 +2758,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -2380,7 +2770,7 @@ public class MIBreakpointsTest extends BaseTestCase { IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2416,7 +2806,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2428,7 +2818,7 @@ public class MIBreakpointsTest extends BaseTestCase { IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2463,7 +2853,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2477,7 +2867,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -2489,7 +2879,7 @@ public class MIBreakpointsTest extends BaseTestCase { IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2523,7 +2913,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2535,7 +2925,7 @@ public class MIBreakpointsTest extends BaseTestCase { IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2569,7 +2959,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2581,7 +2971,7 @@ public class MIBreakpointsTest extends BaseTestCase { IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2616,7 +3006,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2628,7 +3018,7 @@ public class MIBreakpointsTest extends BaseTestCase { IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2656,7 +3046,6 @@ public class MIBreakpointsTest extends BaseTestCase { if (fileName.contains(" ")) { //$NON-NLS-1$ fileName = "\"" + fileName + "\""; //$NON-NLS-1$//$NON-NLS-2$ } - SyncUtil.SyncAddBreakpoint(fileName + ":" + LINE_NUMBER_3, true); SyncUtil.SyncAddBreakpoint(fileName + ":" + LINE_NUMBER_4, true); SyncUtil.SyncResumeUntilStopped(); clearEventCounters(); @@ -2672,7 +3061,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2686,7 +3075,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -2698,7 +3087,7 @@ public class MIBreakpointsTest extends BaseTestCase { IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2709,8 +3098,9 @@ public class MIBreakpointsTest extends BaseTestCase { clearEventCounters(); // Verify that the condition is met - int j = evaluateExpression(frameDmc, "j").intValue(); - assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", j == IGNORE_COUNT_2); + int j = evaluateExpression(frameDmc, EXPRESSION_2).intValue(); + assertTrue("Watchpoint problem: " + EXPRESSION_2 +" was " + j + " instead of " + IGNORE_COUNT_2, + j == IGNORE_COUNT_2); } // ------------------------------------------------------------------------ @@ -2718,7 +3108,6 @@ public class MIBreakpointsTest extends BaseTestCase { // Set a write watchpoint, add a condition and go. // Ensure that the correct event is received. // ------------------------------------------------------------------------ - @Ignore @Test public void breakpointHit_watchpointUpdateCondition() throws Throwable { @@ -2727,7 +3116,6 @@ public class MIBreakpointsTest extends BaseTestCase { if (fileName.contains(" ")) { //$NON-NLS-1$ fileName = "\"" + fileName + "\""; //$NON-NLS-1$//$NON-NLS-2$ } - SyncUtil.SyncAddBreakpoint(fileName + ":" + LINE_NUMBER_3, true); SyncUtil.SyncAddBreakpoint(fileName + ":" + LINE_NUMBER_4, true); SyncUtil.SyncResumeUntilStopped(); clearEventCounters(); @@ -2743,7 +3131,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2757,7 +3145,7 @@ public class MIBreakpointsTest extends BaseTestCase { assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " @@ -2769,7 +3157,7 @@ public class MIBreakpointsTest extends BaseTestCase { IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); @@ -2780,8 +3168,9 @@ public class MIBreakpointsTest extends BaseTestCase { clearEventCounters(); // Verify that the condition is met - int j = evaluateExpression(frameDmc, "j").intValue(); - assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", j == IGNORE_COUNT_2); + int j = evaluateExpression(frameDmc, EXPRESSION_2).intValue(); + assertTrue("Watchpoint problem: " + EXPRESSION_2 +" was " + j + " instead of " + 20, + j == 20); } // ------------------------------------------------------------------------ @@ -2789,7 +3178,7 @@ public class MIBreakpointsTest extends BaseTestCase { // Set an access watchpoint and watch it go out of scope. // Ensure that the correct event is received. // ------------------------------------------------------------------------ - @Ignore + @Ignore("All GDBs seem to have a bug in this situation") @Test public void breakpointHit_WatchpointOutOfScope() throws Throwable { @@ -2798,8 +3187,7 @@ public class MIBreakpointsTest extends BaseTestCase { if (fileName.contains(" ")) { //$NON-NLS-1$ fileName = "\"" + fileName + "\""; //$NON-NLS-1$//$NON-NLS-2$ } - SyncUtil.SyncAddBreakpoint(fileName + ":" + LINE_NUMBER_1, true); - SyncUtil.SyncAddBreakpoint(fileName + ":" + LINE_NUMBER_3, true); + SyncUtil.SyncAddBreakpoint(fileName + ":" + LINE_NUMBER_4, true); SyncUtil.SyncResumeUntilStopped(); clearEventCounters(); @@ -2809,13 +3197,15 @@ public class MIBreakpointsTest extends BaseTestCase { watchpoint.put(EXPRESSION_TAG, EXPRESSION_2); watchpoint.put(READ_TAG, true); watchpoint.put(WRITE_TAG, true); + // Make sure watchpoint is not triggered by the expression actually changing + watchpoint.put(IGNORE_COUNT_TAG, 1000); // Install the watchpoint IBreakpointDMContext ref = insertBreakpoint(fBreakpointsDmc, watchpoint); assertTrue(fWait.getMessage(), fWait.isOK()); // Ensure that right BreakpointEvents were received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " @@ -2826,7 +3216,7 @@ public class MIBreakpointsTest extends BaseTestCase { SyncUtil.SyncResumeUntilStopped(); // Ensure the correct BreakpointEvent was received - waitForBreakpointEvent(); + waitForBreakpointEvent(1); MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + fBreakpointEventCount, fBreakpointEventCount == 1); diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/MIBreakpointsTest_6_8.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/MIBreakpointsTest_6_8.java index f24f4f2d80a..45c54518e16 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/MIBreakpointsTest_6_8.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/MIBreakpointsTest_6_8.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Ericsson and others. + * Copyright (c) 2009, 2010 Ericsson and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,6 +15,8 @@ import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner; import org.eclipse.cdt.tests.dsf.gdb.framework.BaseTestCase; import org.eclipse.cdt.tests.dsf.gdb.tests.MIBreakpointsTest; import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; import org.junit.runner.RunWith; @RunWith(BackgroundRunner.class) @@ -24,4 +26,9 @@ public class MIBreakpointsTest_6_8 extends MIBreakpointsTest { BaseTestCase.setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME, "gdb.6.8"); BaseTestCase.setLaunchAttribute(ATTR_DEBUG_SERVER_NAME, "gdbserver.6.8"); } + @Override + @Ignore("This GDB 6.8 only has a bug which ignores watchpoint conditions") + @Test + public void breakpointHit_watchpointUpdateCondition() throws Throwable { + } }