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:
parent
38e0388107
commit
1d80af0b96
12 changed files with 1307 additions and 354 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue