1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 17:05:26 +02:00

[242943] Support for breakpoint operations while the program is running. JUnit tests included.

This commit is contained in:
Marc Khouzam 2010-02-22 21:30:56 +00:00
parent 38e0388107
commit 1d80af0b96
12 changed files with 1307 additions and 354 deletions

View file

@ -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<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> drm)
protected void addBreakpoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes,
final DataRequestMonitor<IBreakpointDMContext> finalRm)
{
// Select the context breakpoints map
final Map<Integer, MIBreakpointDMData> 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<MIBreakInsertInfo> addBreakpointDRM =
new DataRequestMonitor<MIBreakInsertInfo>(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<MIBreakInsertInfo>(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);
}
/**

View file

@ -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);

View file

@ -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);

View file

@ -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<Step> totalStepsVector = new Vector<Step>();
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<IDMContext[]>(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<IDMContext[]>(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<MIInfo>(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());
}

View file

@ -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);
}

View file

@ -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<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> drm)
protected void addBreakpoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> finalRm)
{
// Select the context breakpoints map
final Map<Integer, MIBreakpointDMData> 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<MIBreakInsertInfo> addBreakpointDRM =
new DataRequestMonitor<MIBreakInsertInfo>(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<MIBreakInsertInfo>(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<String,Object> delta = new HashMap<String,Object>();
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<String,Object> delta = new HashMap<String,Object>();
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<Integer,MIBreakpointDMData> 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<MIInfo>(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<MIInfo>(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<Integer, MIBreakpointDMData> 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<MIInfo>(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<MIInfo>(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<MIInfo>(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<MIInfo>(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<Integer, MIBreakpointDMData> 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<MIInfo>(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<MIInfo>(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<Integer, MIBreakpointDMData> 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<MIInfo>(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<MIInfo>(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<Integer, MIBreakpointDMData> 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<MIInfo>(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<MIInfo>(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<IDMContext[]>(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();
}
}
};
}

View file

@ -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<Step> totalStepsVector = new Vector<Step>();
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<IDMContext[]>(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<MIInfo>(getExecutor(), rm));
} else {
// We didn't suspend the container, so we don't need to resume it
rm.done();
}
}
};
/**
* {@inheritDoc}

View file

@ -80,7 +80,7 @@ public class MIBreakInsert extends MICommand<MIBreakInsertInfo>
* @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<MIBreakInsertInfo>
if (opts.length > 0) {
setOptions(opts);
}
setParameters(new Adjustable[]{ new PathAdjustable(line)});
setParameters(new Adjustable[]{ new PathAdjustable(location)});
}
@Override

View file

@ -5,7 +5,7 @@
// Copyright : Ericsson AB
// Description : Breakpoint test application
//============================================================================
#include <unistd.h>
#include <iostream>
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;
}

View file

@ -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<MIRunningEvent> eventWaitor =
new ServiceEventWaitor<MIRunningEvent>(
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<MIStoppedEvent> eventWaitor =
new ServiceEventWaitor<MIStoppedEvent>(
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,

View file

@ -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 {
}
}