mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-06 07:45:50 +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.CountingRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
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.DMContexts;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
|
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
|
||||||
import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
|
import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
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.MIBreakpointDMData;
|
||||||
import org.eclipse.cdt.dsf.mi.service.MIBreakpoints;
|
import org.eclipse.cdt.dsf.mi.service.MIBreakpoints;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIPasscount;
|
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
|
public class GDBBreakpoints_7_0 extends MIBreakpoints
|
||||||
{
|
{
|
||||||
private ICommandControl fConnection;
|
private ICommandControl fConnection;
|
||||||
|
private IMIRunControl fRunControl;
|
||||||
|
|
||||||
public GDBBreakpoints_7_0(DsfSession session) {
|
public GDBBreakpoints_7_0(DsfSession session) {
|
||||||
super(session);
|
super(session);
|
||||||
|
@ -67,6 +70,7 @@ public class GDBBreakpoints_7_0 extends MIBreakpoints
|
||||||
private void doInitialize(final RequestMonitor rm) {
|
private void doInitialize(final RequestMonitor rm) {
|
||||||
// Get the services references
|
// Get the services references
|
||||||
fConnection = getServicesTracker().getService(ICommandControl.class);
|
fConnection = getServicesTracker().getService(ICommandControl.class);
|
||||||
|
fRunControl = getServicesTracker().getService(IMIRunControl.class);
|
||||||
|
|
||||||
// Register this service
|
// Register this service
|
||||||
register(new String[] { IBreakpoints.class.getName(),
|
register(new String[] { IBreakpoints.class.getName(),
|
||||||
|
@ -91,78 +95,83 @@ public class GDBBreakpoints_7_0 extends MIBreakpoints
|
||||||
*
|
*
|
||||||
* @param context
|
* @param context
|
||||||
* @param breakpoint
|
* @param breakpoint
|
||||||
* @param drm
|
* @param finalRm
|
||||||
*/
|
*/
|
||||||
@Override
|
@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
|
// Select the context breakpoints map
|
||||||
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
||||||
if (contextBreakpoints == null) {
|
if (contextBreakpoints == null) {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
||||||
drm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the relevant parameters (providing default values to avoid potential NPEs)
|
// 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)) {
|
if (location.equals(NULL_STRING)) {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
||||||
drm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Boolean enabled = (Boolean) getProperty(attributes, MIBreakpoints.IS_ENABLED, true);
|
final Boolean enabled = (Boolean) getProperty(attributes, MIBreakpoints.IS_ENABLED, true);
|
||||||
Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false);
|
final Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false);
|
||||||
Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false);
|
final Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false);
|
||||||
String condition = (String) getProperty(attributes, MIBreakpoints.CONDITION, NULL_STRING);
|
final String condition = (String) getProperty(attributes, MIBreakpoints.CONDITION, NULL_STRING);
|
||||||
Integer ignoreCount = (Integer) getProperty(attributes, MIBreakpoints.IGNORE_COUNT, 0);
|
final Integer ignoreCount = (Integer) getProperty(attributes, MIBreakpoints.IGNORE_COUNT, 0);
|
||||||
String threadId = (String) getProperty(attributes, MIBreakpointDMData.THREAD_ID, "0"); //$NON-NLS-1$
|
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
|
final Step insertBreakpointStep = new Step() {
|
||||||
DataRequestMonitor<MIBreakInsertInfo> addBreakpointDRM =
|
@Override
|
||||||
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), drm) {
|
public void execute(final RequestMonitor rm) {
|
||||||
@Override
|
// Execute the command
|
||||||
protected void handleSuccess() {
|
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
|
// With MI, an invalid location won't generate an error
|
||||||
if (getData().getMIBreakpoints().length == 0) {
|
if (getData().getMIBreakpoints().length == 0) {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
||||||
drm.done();
|
rm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a breakpoint object and store it in the map
|
// Create a breakpoint object and store it in the map
|
||||||
final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]);
|
final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]);
|
||||||
int reference = newBreakpoint.getNumber();
|
int reference = newBreakpoint.getNumber();
|
||||||
if (reference == -1) {
|
if (reference == -1) {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
||||||
drm.done();
|
rm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
contextBreakpoints.put(reference, newBreakpoint);
|
contextBreakpoints.put(reference, newBreakpoint);
|
||||||
|
|
||||||
// Format the return value
|
// Format the return value
|
||||||
MIBreakpointDMContext dmc = new MIBreakpointDMContext(GDBBreakpoints_7_0.this, new IDMContext[] { context }, reference);
|
MIBreakpointDMContext dmc = new MIBreakpointDMContext(GDBBreakpoints_7_0.this, new IDMContext[] { context }, reference);
|
||||||
drm.setData(dmc);
|
finalRm.setData(dmc);
|
||||||
|
|
||||||
// Flag the event
|
// Flag the event
|
||||||
getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties());
|
getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties());
|
||||||
|
|
||||||
drm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleError() {
|
protected void handleError() {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
||||||
drm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
}
|
||||||
// Execute the command
|
};
|
||||||
fConnection.queueCommand(
|
|
||||||
new MIBreakInsert(context, isTemporary, isHardware, condition, ignoreCount, location, tid, !enabled, false), addBreakpointDRM);
|
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.
|
// Don't send the stop event since we are resuming again.
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Stopped at another breakpoint or not a breakpoint at all. Just remove our temporary one
|
// Stopped at another breakpoint that we should not skip.
|
||||||
// since we don't want it to hit later
|
// 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 bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
|
||||||
IBreakpointsTargetDMContext.class);
|
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.
|
// Don't send the stop event since we are resuming again.
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Stopped at another breakpoint. Just remove our temporary one
|
// Stopped at another breakpoint that we should not skip.
|
||||||
// since we don't want it to hit later
|
// 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 bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
|
||||||
IBreakpointsTargetDMContext.class);
|
IBreakpointsTargetDMContext.class);
|
||||||
|
|
||||||
|
|
|
@ -15,15 +15,19 @@ package org.eclipse.cdt.dsf.gdb.service;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.Immutable;
|
import org.eclipse.cdt.dsf.concurrent.Immutable;
|
||||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
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.AbstractDMEvent;
|
||||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
|
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
|
||||||
import org.eclipse.cdt.dsf.debug.service.ICachingService;
|
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.IRunControl;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
|
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;
|
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
|
// Initialization and shutdown
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -293,15 +306,14 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
|
||||||
return (threadState == null) ? false : !fTerminated && threadState.fSuspended;
|
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) {
|
if (context instanceof IContainerDMContext) {
|
||||||
boolean isSuspended = false;
|
|
||||||
for (IMIExecutionDMContext threadContext : fThreadRunStates.keySet()) {
|
for (IMIExecutionDMContext threadContext : fThreadRunStates.keySet()) {
|
||||||
if (DMContexts.isAncestorOf(threadContext, context)) {
|
if (DMContexts.isAncestorOf(threadContext, context)) {
|
||||||
isSuspended |= isSuspended(threadContext);
|
if (isSuspended(threadContext)) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isSuspended;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default case
|
// Default case
|
||||||
|
@ -792,6 +804,142 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
|
||||||
threadState.fStateChangeReason = reason;
|
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
|
// Event handlers
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -802,6 +950,14 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
|
||||||
*/
|
*/
|
||||||
@DsfServiceEventHandler
|
@DsfServiceEventHandler
|
||||||
public void eventDispatched(final MIRunningEvent e) {
|
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());
|
getSession().dispatchEvent(new ResumedEvent(e.getDMContext(), e), getProperties());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,6 +1005,10 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
|
||||||
} else {
|
} else {
|
||||||
// Stopped for any other reasons. Just remove our temporary one
|
// Stopped for any other reasons. Just remove our temporary one
|
||||||
// since we don't want it to hit later
|
// 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 bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
|
||||||
IBreakpointsTargetDMContext.class);
|
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());
|
getSession().dispatchEvent(new SuspendedEvent(e.getDMContext(), e), getProperties());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
package org.eclipse.cdt.dsf.mi.service;
|
package org.eclipse.cdt.dsf.mi.service;
|
||||||
|
|
||||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
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;
|
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);
|
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.DataRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.Immutable;
|
import org.eclipse.cdt.dsf.concurrent.Immutable;
|
||||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
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.AbstractDMContext;
|
||||||
import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
|
import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
|
||||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
|
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.ICommandControl;
|
||||||
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
|
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
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$
|
public static final String WRITE = PREFIX + ".write"; //$NON-NLS-1$
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
ICommandControl fConnection;
|
private ICommandControl fConnection;
|
||||||
|
private IMIRunControl fRunControl;
|
||||||
|
|
||||||
// Service breakpoints tracking
|
// Service breakpoints tracking
|
||||||
// The breakpoints are stored per context and keyed on the back-end breakpoint reference
|
// 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
|
// Get the services references
|
||||||
fConnection = getServicesTracker().getService(ICommandControl.class);
|
fConnection = getServicesTracker().getService(ICommandControl.class);
|
||||||
|
fRunControl = getServicesTracker().getService(IMIRunControl.class);
|
||||||
|
|
||||||
// Register for the useful events
|
// Register for the useful events
|
||||||
getSession().addServiceEventListener(this, null);
|
getSession().addServiceEventListener(this, null);
|
||||||
|
@ -522,82 +530,85 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints
|
||||||
*
|
*
|
||||||
* @param context
|
* @param context
|
||||||
* @param breakpoint
|
* @param breakpoint
|
||||||
* @param drm
|
* @param finalRm
|
||||||
*
|
*
|
||||||
* @since 3.0
|
* @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
|
// Select the context breakpoints map
|
||||||
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
||||||
if (contextBreakpoints == null) {
|
if (contextBreakpoints == null) {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
||||||
drm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the relevant parameters (providing default values to avoid potential NPEs)
|
// 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)) {
|
if (location.equals(NULL_STRING)) {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
||||||
drm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false);
|
final Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false);
|
||||||
Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false);
|
final Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false);
|
||||||
final String condition = (String) getProperty(attributes, CONDITION, NULL_STRING);
|
final String condition = (String) getProperty(attributes, CONDITION, NULL_STRING);
|
||||||
Integer ignoreCount = (Integer) getProperty(attributes, IGNORE_COUNT, 0 );
|
final Integer ignoreCount = (Integer) getProperty(attributes, IGNORE_COUNT, 0 );
|
||||||
String threadId = (String) getProperty(attributes, MIBreakpointDMData.THREAD_ID, "0"); //$NON-NLS-1$
|
final 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
|
final Step insertBreakpointStep = new Step() {
|
||||||
DataRequestMonitor<MIBreakInsertInfo> addBreakpointDRM =
|
@Override
|
||||||
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), drm) {
|
public void execute(final RequestMonitor rm) {
|
||||||
@Override
|
fConnection.queueCommand(
|
||||||
protected void handleSuccess() {
|
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
|
// With MI, an invalid location won't generate an error
|
||||||
if (getData().getMIBreakpoints().length == 0) {
|
if (getData().getMIBreakpoints().length == 0) {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
||||||
drm.done();
|
rm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a breakpoint object and store it in the map
|
// Create a breakpoint object and store it in the map
|
||||||
final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]);
|
final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]);
|
||||||
int reference = newBreakpoint.getNumber();
|
int reference = newBreakpoint.getNumber();
|
||||||
if (reference == -1) {
|
if (reference == -1) {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
||||||
drm.done();
|
rm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
contextBreakpoints.put(reference, newBreakpoint);
|
contextBreakpoints.put(reference, newBreakpoint);
|
||||||
|
|
||||||
// Format the return value
|
// Format the return value
|
||||||
MIBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context }, reference);
|
MIBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context }, reference);
|
||||||
drm.setData(dmc);
|
finalRm.setData(dmc);
|
||||||
|
|
||||||
// Flag the event
|
// Flag the event
|
||||||
getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties());
|
getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties());
|
||||||
|
|
||||||
// By default the breakpoint is enabled at creation
|
// By default the breakpoint is enabled at creation
|
||||||
// If it wasn't supposed to be, then disable it right away
|
// If it wasn't supposed to be, then disable it right away
|
||||||
Map<String,Object> delta = new HashMap<String,Object>();
|
Map<String,Object> delta = new HashMap<String,Object>();
|
||||||
delta.put(IS_ENABLED, getProperty(attributes, IS_ENABLED, true));
|
delta.put(IS_ENABLED, getProperty(attributes, IS_ENABLED, true));
|
||||||
modifyBreakpoint(dmc, delta, drm, false);
|
modifyBreakpoint(dmc, delta, rm, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleError() {
|
protected void handleError() {
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null));
|
||||||
drm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute the command
|
fRunControl.executeWithTargetAvailable(context, new Step[] { insertBreakpointStep }, finalRm);
|
||||||
fConnection.queueCommand(
|
|
||||||
new MIBreakInsert(context, isTemporary, isHardware, condition, ignoreCount, location, tid), addBreakpointDRM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -696,12 +707,12 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints
|
||||||
/* (non-Javadoc)
|
/* (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)
|
* @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
|
// Validate the breakpoint context
|
||||||
if (dmc == null) {
|
if (dmc == null) {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
||||||
rm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,24 +722,24 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints
|
||||||
breakpointCtx = (MIBreakpointDMContext) dmc;
|
breakpointCtx = (MIBreakpointDMContext) dmc;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null));
|
||||||
rm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the target context
|
// Validate the target context
|
||||||
IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class);
|
final IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class);
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null));
|
||||||
rm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick the context breakpoints map
|
// Pick the context breakpoints map
|
||||||
final Map<Integer,MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
final Map<Integer,MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
||||||
if (contextBreakpoints == null) {
|
if (contextBreakpoints == null) {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
||||||
rm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,24 +747,31 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints
|
||||||
final int reference = breakpointCtx.getReference();
|
final int reference = breakpointCtx.getReference();
|
||||||
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
||||||
if (breakpoint == null) {
|
if (breakpoint == null) {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
||||||
rm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue the command
|
final Step deleteBreakpointStep = new Step() {
|
||||||
fConnection.queueCommand(
|
@Override
|
||||||
new MIBreakDelete(context, new int[] { reference }),
|
public void execute(final RequestMonitor rm) {
|
||||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
// Queue the command
|
||||||
@Override
|
fConnection.queueCommand(
|
||||||
protected void handleCompleted() {
|
new MIBreakDelete(context, new int[] { reference }),
|
||||||
if (isSuccess()) {
|
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||||
getSession().dispatchEvent(new BreakpointRemovedEvent(dmc), getProperties());
|
@Override
|
||||||
contextBreakpoints.remove(reference);
|
protected void handleCompleted() {
|
||||||
}
|
if (isSuccess()) {
|
||||||
rm.done();
|
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 context
|
||||||
* @param dmc
|
* @param dmc
|
||||||
* @param condition
|
* @param condition
|
||||||
* @param rm
|
* @param finalRm
|
||||||
*
|
*
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
protected void changeCondition(final IBreakpointsTargetDMContext context,
|
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
|
// Pick the context breakpoints map
|
||||||
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
||||||
if (contextBreakpoints == null) {
|
if (contextBreakpoints == null) {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
||||||
rm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue the command
|
final Step changeConditionStep = new Step() {
|
||||||
fConnection.queueCommand(
|
@Override
|
||||||
new MIBreakCondition(context, reference, condition),
|
public void execute(final RequestMonitor rm) {
|
||||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
// Queue the command
|
||||||
@Override
|
fConnection.queueCommand(
|
||||||
protected void handleSuccess() {
|
new MIBreakCondition(context, reference, condition),
|
||||||
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||||
if (breakpoint == null) {
|
@Override
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
protected void handleSuccess() {
|
||||||
rm.done();
|
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
||||||
return;
|
if (breakpoint == null) {
|
||||||
}
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
||||||
breakpoint.setCondition(condition);
|
rm.done();
|
||||||
rm.done();
|
return;
|
||||||
}
|
}
|
||||||
|
breakpoint.setCondition(condition);
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
|
||||||
// In case of error (new condition could not be installed for whatever reason),
|
// 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
|
// 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.
|
// 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
|
// Our sole option is to remove the condition in case of error and rely on the
|
||||||
// upper layer to re-install the right condition.
|
// upper layer to re-install the right condition.
|
||||||
@Override
|
@Override
|
||||||
protected void handleError() {
|
protected void handleError() {
|
||||||
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
||||||
if (breakpoint == null) {
|
if (breakpoint == null) {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
||||||
rm.done();
|
rm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Remove invalid condition from the back-end breakpoint
|
// Remove invalid condition from the back-end breakpoint
|
||||||
breakpoint.setCondition(NULL_STRING);
|
breakpoint.setCondition(NULL_STRING);
|
||||||
fConnection.queueCommand(
|
fConnection.queueCommand(
|
||||||
new MIBreakCondition(context, reference, NULL_STRING),
|
new MIBreakCondition(context, reference, NULL_STRING),
|
||||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||||
@Override
|
@Override
|
||||||
// The report the initial problem
|
// The report the initial problem
|
||||||
protected void handleCompleted() {
|
protected void handleCompleted() {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_CONDITION, null));
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_CONDITION, null));
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fRunControl.executeWithTargetAvailable(context, new Step[] { changeConditionStep }, finalRm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -962,37 +987,44 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints
|
||||||
* @param context
|
* @param context
|
||||||
* @param reference
|
* @param reference
|
||||||
* @param ignoreCount
|
* @param ignoreCount
|
||||||
* @param rm
|
* @param finalRm
|
||||||
*
|
*
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
protected void changeIgnoreCount(IBreakpointsTargetDMContext context,
|
protected void changeIgnoreCount(final IBreakpointsTargetDMContext context,
|
||||||
final int reference, final int ignoreCount, final RequestMonitor rm)
|
final int reference, final int ignoreCount, final RequestMonitor finalRm)
|
||||||
{
|
{
|
||||||
// Pick the context breakpoints map
|
// Pick the context breakpoints map
|
||||||
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
||||||
if (contextBreakpoints == null) {
|
if (contextBreakpoints == null) {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
||||||
rm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue the command
|
final Step changeIgnoreCountStep = new Step() {
|
||||||
fConnection.queueCommand(
|
@Override
|
||||||
new MIBreakAfter(context, reference, ignoreCount),
|
public void execute(final RequestMonitor rm) {
|
||||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
// Queue the command
|
||||||
@Override
|
fConnection.queueCommand(
|
||||||
protected void handleSuccess() {
|
new MIBreakAfter(context, reference, ignoreCount),
|
||||||
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||||
if (breakpoint == null) {
|
@Override
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
protected void handleSuccess() {
|
||||||
rm.done();
|
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
||||||
return;
|
if (breakpoint == null) {
|
||||||
}
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
||||||
breakpoint.setIgnoreCount(ignoreCount);
|
rm.done();
|
||||||
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 context
|
||||||
* @param reference
|
* @param reference
|
||||||
* @param rm
|
* @param finalRm
|
||||||
*
|
*
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
protected void enableBreakpoint(IBreakpointsTargetDMContext context,
|
protected void enableBreakpoint(final IBreakpointsTargetDMContext context,
|
||||||
final int reference, final RequestMonitor rm)
|
final int reference, final RequestMonitor finalRm)
|
||||||
{
|
{
|
||||||
// Pick the context breakpoints map
|
// Pick the context breakpoints map
|
||||||
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
||||||
if (contextBreakpoints == null) {
|
if (contextBreakpoints == null) {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
||||||
rm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue the command
|
final Step enableBreakpointStep = new Step() {
|
||||||
fConnection.queueCommand(
|
@Override
|
||||||
new MIBreakEnable(context, new int[] { reference }),
|
public void execute(final RequestMonitor rm) {
|
||||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
// Queue the command
|
||||||
@Override
|
fConnection.queueCommand(
|
||||||
protected void handleSuccess() {
|
new MIBreakEnable(context, new int[] { reference }),
|
||||||
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||||
if (breakpoint == null) {
|
@Override
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
protected void handleSuccess() {
|
||||||
rm.done();
|
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
||||||
return;
|
if (breakpoint == null) {
|
||||||
}
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
||||||
breakpoint.setEnabled(true);
|
rm.done();
|
||||||
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 context
|
||||||
* @param dmc
|
* @param dmc
|
||||||
* @param rm
|
* @param finalRm
|
||||||
*
|
*
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
protected void disableBreakpoint(IBreakpointsTargetDMContext context,
|
protected void disableBreakpoint(final IBreakpointsTargetDMContext context,
|
||||||
final int reference, final RequestMonitor rm)
|
final int reference, final RequestMonitor finalRm)
|
||||||
{
|
{
|
||||||
// Pick the context breakpoints map
|
// Pick the context breakpoints map
|
||||||
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
|
||||||
if (contextBreakpoints == null) {
|
if (contextBreakpoints == null) {
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
|
||||||
rm.done();
|
finalRm.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue the command
|
final Step disableBreakpointStep = new Step() {
|
||||||
fConnection.queueCommand(
|
@Override
|
||||||
new MIBreakDisable(context, new int[] { reference }),
|
public void execute(final RequestMonitor rm) {
|
||||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
// Queue the command
|
||||||
@Override
|
fConnection.queueCommand(
|
||||||
protected void handleSuccess() {
|
new MIBreakDisable(context, new int[] { reference }),
|
||||||
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||||
if (breakpoint == null) {
|
@Override
|
||||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
protected void handleSuccess() {
|
||||||
rm.done();
|
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
|
||||||
return;
|
if (breakpoint == null) {
|
||||||
}
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
|
||||||
breakpoint.setEnabled(false);
|
rm.done();
|
||||||
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;
|
package org.eclipse.cdt.dsf.mi.service;
|
||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.Immutable;
|
import org.eclipse.cdt.dsf.concurrent.Immutable;
|
||||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
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.AbstractDMContext;
|
||||||
import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
|
import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
|
||||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
|
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
|
||||||
import org.eclipse.cdt.dsf.debug.service.ICachingService;
|
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.IStack.IFrameDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
|
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
|
||||||
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
|
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 StateChangeReason fStateChangeReason;
|
||||||
private IExecutionDMContext fStateChangeTriggeringContext;
|
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;
|
private static final int FAKE_THREAD_ID = 0;
|
||||||
|
|
||||||
|
@ -338,6 +348,12 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
|
||||||
*/
|
*/
|
||||||
@DsfServiceEventHandler
|
@DsfServiceEventHandler
|
||||||
public void eventDispatched(final MIRunningEvent e) {
|
public void eventDispatched(final MIRunningEvent e) {
|
||||||
|
if (fDisableRunningAndStoppedEventsCount > 0) {
|
||||||
|
fDisableRunningAndStoppedEventsCount--;
|
||||||
|
// We don't broadcast running events right now
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IDMEvent<?> event = null;
|
IDMEvent<?> event = null;
|
||||||
// Find the container context, which is used in multi-threaded debugging.
|
// Find the container context, which is used in multi-threaded debugging.
|
||||||
IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class);
|
IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class);
|
||||||
|
@ -357,7 +373,13 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
|
||||||
*/
|
*/
|
||||||
@DsfServiceEventHandler
|
@DsfServiceEventHandler
|
||||||
public void eventDispatched(final MIStoppedEvent e) {
|
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.
|
// Find the container context, which is used in multi-threaded debugging.
|
||||||
IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class);
|
IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class);
|
||||||
if (containerDmc != null) {
|
if (containerDmc != null) {
|
||||||
|
@ -738,6 +760,127 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
|
||||||
rm.done();
|
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}
|
* {@inheritDoc}
|
||||||
|
|
|
@ -80,7 +80,7 @@ public class MIBreakInsert extends MICommand<MIBreakInsertInfo>
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public MIBreakInsert(IBreakpointsTargetDMContext ctx, boolean isTemporary, boolean isHardware,
|
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$
|
super(ctx, "-break-insert"); //$NON-NLS-1$
|
||||||
|
|
||||||
// For a tracepoint, force certain parameters to what is allowed
|
// For a tracepoint, force certain parameters to what is allowed
|
||||||
|
@ -160,7 +160,7 @@ public class MIBreakInsert extends MICommand<MIBreakInsertInfo>
|
||||||
if (opts.length > 0) {
|
if (opts.length > 0) {
|
||||||
setOptions(opts);
|
setOptions(opts);
|
||||||
}
|
}
|
||||||
setParameters(new Adjustable[]{ new PathAdjustable(line)});
|
setParameters(new Adjustable[]{ new PathAdjustable(location)});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// Copyright : Ericsson AB
|
// Copyright : Ericsson AB
|
||||||
// Description : Breakpoint test application
|
// Description : Breakpoint test application
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
#include <unistd.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -32,16 +32,20 @@ void setBlocks()
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
int j;
|
int j = 10;
|
||||||
|
int i = 0;
|
||||||
for (int i = 0; i < ARRAY_SIZE; i++)
|
for (i = 0; i < ARRAY_SIZE; i++)
|
||||||
j = i;
|
j = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
int a = 10;
|
||||||
|
|
||||||
zeroBlocks(1);
|
zeroBlocks(1);
|
||||||
loop();
|
loop();
|
||||||
setBlocks();
|
setBlocks();
|
||||||
|
sleep(1);
|
||||||
|
a++;
|
||||||
return 0;
|
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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* 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.MIExecNext;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecStep;
|
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.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.events.MIStoppedEvent;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
|
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo;
|
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo;
|
||||||
|
@ -277,6 +278,40 @@ public class SyncUtil {
|
||||||
return SyncResumeUntilStopped(fGdbContainerDmc);
|
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 {
|
public static MIStoppedEvent SyncRunToLocation(final String location) throws Throwable {
|
||||||
// Set a temporary breakpoint and run to it.
|
// Set a temporary breakpoint and run to it.
|
||||||
// Note that if there were other breakpoints set ahead of this one,
|
// 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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* 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.framework.BaseTestCase;
|
||||||
import org.eclipse.cdt.tests.dsf.gdb.tests.MIBreakpointsTest;
|
import org.eclipse.cdt.tests.dsf.gdb.tests.MIBreakpointsTest;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
@RunWith(BackgroundRunner.class)
|
@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(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME, "gdb.6.8");
|
||||||
BaseTestCase.setLaunchAttribute(ATTR_DEBUG_SERVER_NAME, "gdbserver.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