1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-19 15:05:36 +02:00

[233230] Support for RunToLine

This commit is contained in:
Marc Khouzam 2009-04-17 18:05:10 +00:00
parent 2a321cdc23
commit 3f6473cfed
9 changed files with 724 additions and 89 deletions

View file

@ -162,6 +162,11 @@
<adapter type="org.eclipse.debug.ui.contexts.ISuspendTrigger"/>
<adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory"/>
</factory>
<factory
class="org.eclipse.cdt.dsf.gdb.internal.ui.GdbRunToLineAdapterFactory"
adaptableType="org.eclipse.cdt.dsf.ui.viewmodel.IVMContext">
<adapter type="org.eclipse.debug.core.model.ISuspendResume"/>
</factory>
</extension>
<extension point="org.eclipse.debug.ui.memoryRenderings">

View file

@ -0,0 +1,68 @@
/*******************************************************************************
* Copyright (c) 2009 Wind River Systems 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.gdb.internal.ui.actions.GdbRunToLine;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.ISuspendResume;
/**
* @since 2.0
*/
public class GdbRunToLineAdapterFactory implements IAdapterFactory {
static class GdbSuspendResume implements ISuspendResume, IAdaptable {
private final GdbRunToLine fRunToLine;
GdbSuspendResume(IExecutionDMContext execCtx) {
fRunToLine = new GdbRunToLine(execCtx);
}
public Object getAdapter(Class adapter) {
if (adapter.isInstance(fRunToLine)) {
return fRunToLine;
}
return null;
}
public boolean canResume() { return false; }
public boolean canSuspend() { return false; }
public boolean isSuspended() { return false; }
public void resume() throws DebugException {}
public void suspend() throws DebugException {}
}
public Object getAdapter(Object adaptableObject, Class adapterType) {
if (ISuspendResume.class.equals(adapterType)) {
if (adaptableObject instanceof IDMVMContext) {
IExecutionDMContext execDmc = DMContexts.getAncestorOfType(
((IDMVMContext)adaptableObject).getDMContext(),
IExecutionDMContext.class);
// It only makes sense to RunToLine if we are dealing with a thread, not a container
if (execDmc != null && !(execDmc instanceof IContainerDMContext)) {
return new GdbSuspendResume(execDmc);
}
}
}
return null;
}
public Class[] getAdapterList() {
return new Class[] { ISuspendResume.class };
}
}

View file

@ -0,0 +1,135 @@
/*******************************************************************************
* Copyright (c) 2009 Wind River Systems 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.actions;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.cdt.debug.core.model.IRunToLine;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.ui.actions.IRunToLineTarget;
/**
* Implements the CDT's run to line interface. This interface is called by CDT's
* {@link IRunToLineTarget} implementation.
*
* @since 2.0
*/
public class GdbRunToLine implements IRunToLine {
private final IExecutionDMContext fContext;
public GdbRunToLine(IExecutionDMContext context) {
fContext = context;
}
public boolean canRunToLine(IFile file, int lineNumber) {
return canRunToLine();
}
public boolean canRunToLine(String fileName, int lineNumber) {
return canRunToLine();
}
private boolean canRunToLine() {
DsfSession session = DsfSession.getSession(fContext.getSessionId());
if (session != null && session.isActive()) {
try {
Query<Boolean> query = new Query<Boolean>() {
@Override
protected void execute(DataRequestMonitor<Boolean> rm) {
DsfServicesTracker tracker =
new DsfServicesTracker(GdbUIPlugin.getBundleContext(), fContext.getSessionId());
IRunControl runControl = tracker.getService(IRunControl.class);
if (runControl != null) {
runControl.canResume(fContext, rm);
} else {
rm.setData(false);
rm.done();
}
tracker.dispose();
}
};
session.getExecutor().execute(query);
return query.get();
} catch (RejectedExecutionException e) {
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
}
return false;
}
public void runToLine(IFile file, int lineNumber, boolean skipBreakpoints) throws DebugException {
runToLine(file.getLocation().makeAbsolute().toOSString(), lineNumber, skipBreakpoints);
}
public void runToLine(final String fileName, final int lineNumber, final boolean skipBreakpoints) throws DebugException {
DsfSession session = DsfSession.getSession(fContext.getSessionId());
if (session != null && session.isActive()) {
Throwable exception = null;
try {
Query<Object> query = new Query<Object>() {
@Override
protected void execute(final DataRequestMonitor<Object> rm) {
DsfServicesTracker tracker =
new DsfServicesTracker(GdbUIPlugin.getBundleContext(), fContext.getSessionId());
IMIRunControl miRunControl = tracker.getService(IMIRunControl.class);
if (miRunControl != null) {
miRunControl.runToLine(
fContext, fileName, Integer.toString(lineNumber), skipBreakpoints,
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
rm.setData(new Object());
rm.done();
};
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "MIRunControl service not available", null)); //$NON-NLS-1$
rm.done();
}
tracker.dispose();
}
};
session.getExecutor().execute(query);
query.get();
} catch (RejectedExecutionException e) {
exception = e;
} catch (InterruptedException e) {
exception = e;
} catch (ExecutionException e) {
exception = e;
}
if (exception != null) {
new DebugException(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Faild executing run to line", exception)); //$NON-NLS-1$
}
} else {
new DebugException(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Debug session is not active", null)); //$NON-NLS-1$
}
}
}

View file

@ -24,26 +24,60 @@ import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
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;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIStack;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakDelete;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakInsert;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue;
import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIInferiorExitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadExitEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
public class GDBRunControl extends MIRunControl {
private static class RunToLineActiveOperation {
private IMIExecutionDMContext fThreadContext;
private int fBpId;
private String fLocation;
private boolean fSkipBreakpoints;
public RunToLineActiveOperation(IMIExecutionDMContext threadContext,
int bpId, String location, boolean skipBreakpoints) {
fThreadContext = threadContext;
fBpId = bpId;
fLocation = location;
fSkipBreakpoints = skipBreakpoints;
}
public IMIExecutionDMContext getThreadContext() { return fThreadContext; }
public int getBreakointId() { return fBpId; }
public String getLocation() { return fLocation; }
public boolean shouldSkipBreakpoints() { return fSkipBreakpoints; }
}
private IGDBBackend fGdb;
private IMIProcesses fProcService;
// Record list of execution contexts
private IExecutionDMContext[] fOldExecutionCtxts;
private RunToLineActiveOperation fRunToLineActiveOperation = null;
public GDBRunControl(DsfSession session) {
super(session);
@ -65,6 +99,7 @@ public class GDBRunControl extends MIRunControl {
fProcService = getServicesTracker().getService(IMIProcesses.class);
register(new String[]{IRunControl.class.getName(),
IMIRunControl.class.getName(),
MIRunControl.class.getName(),
GDBRunControl.class.getName()}, new Hashtable<String,String>());
requestMonitor.done();
@ -210,4 +245,108 @@ public class GDBRunControl extends MIRunControl {
canResume(context, rm);
}
/** @since 2.0 */
@Override
public void runToLine(final IExecutionDMContext context, String fileName, String lineNo, final boolean skipBreakpoints, final DataRequestMonitor<MIInfo> rm){
// Later add support for Address and function.
assert context != null;
final IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
if (dmc == null){
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
rm.done();
return;
}
if (doCanResume(context)) {
final String location = fileName + ":" + lineNo; //$NON-NLS-1$
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(context, IBreakpointsTargetDMContext.class);
getConnection().queueCommand(
new MIBreakInsert(bpDmc, true, false, null, 0,
location, dmc.getThreadId()),
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), rm) {
@Override
public void handleSuccess() {
// We must set are RunToLineActiveOperation *before* we do the resume
// or else we may get the stopped event, before we have set this variable.
int bpId = getData().getMIBreakpoints()[0].getNumber();
fRunToLineActiveOperation = new RunToLineActiveOperation(dmc, bpId, location, skipBreakpoints);
resume(context, new RequestMonitor(getExecutor(), rm) {
@Override
public void handleFailure() {
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
IBreakpointsTargetDMContext.class);
int bpId = fRunToLineActiveOperation.getBreakointId();
getConnection().queueCommand(new MIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
super.handleFailure();
}
});
}
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED,
"Cannot resume given DMC.", null)); //$NON-NLS-1$
rm.done();
}
}
/**
* @nooverride This method is not intended to be re-implemented or extended by clients.
* @noreference This method is not intended to be referenced by clients.
*
* @since 2.0
*/
@DsfServiceEventHandler
public void eventDispatched(MIInferiorExitEvent e) {
if (fRunToLineActiveOperation != null) {
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
IBreakpointsTargetDMContext.class);
int bpId = fRunToLineActiveOperation.getBreakointId();
getConnection().queueCommand(new MIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
}
}
/** @since 2.0 */
@Override
@DsfServiceEventHandler
public void eventDispatched(final MIStoppedEvent e) {
if (fRunToLineActiveOperation != null) {
String location = e.getFrame().getFile() + ":" + e.getFrame().getLine(); //$NON-NLS-1$
if (location.equals(fRunToLineActiveOperation.getLocation())) {
// We stopped on our temporary breakpoint. All is well.
fRunToLineActiveOperation = null;
} else {
// Didn't stop at the right line yet
if (fRunToLineActiveOperation.shouldSkipBreakpoints() && e instanceof MIBreakpointHitEvent) {
getConnection().queueCommand(
new MIExecContinue(fRunToLineActiveOperation.getThreadContext()),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
// 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
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
IBreakpointsTargetDMContext.class);
int bpId = fRunToLineActiveOperation.getBreakointId();
getConnection().queueCommand(new MIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
}
}
}
super.eventDispatched(e);
}
}

View file

@ -23,6 +23,7 @@ import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
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;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
@ -30,9 +31,13 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommand
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIStack;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakDelete;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakInsert;
import org.eclipse.cdt.dsf.mi.service.command.commands.MICommand;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecReverseContinue;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecReverseNext;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecReverseNextInstruction;
@ -40,18 +45,46 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecReverseStep;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecReverseStepInstruction;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecUncall;
import org.eclipse.cdt.dsf.mi.service.command.commands.RawCommand;
import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIInferiorExitEvent;
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.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunControl {
private static class RunToLineActiveOperation {
private IMIExecutionDMContext fThreadContext;
private int fBpId;
private String fLocation;
private boolean fSkipBreakpoints;
public RunToLineActiveOperation(IMIExecutionDMContext threadContext,
int bpId, String location, boolean skipBreakpoints) {
fThreadContext = threadContext;
fBpId = bpId;
fLocation = location;
fSkipBreakpoints = skipBreakpoints;
}
public IMIExecutionDMContext getThreadContext() { return fThreadContext; }
public int getBreakointId() { return fBpId; }
public String getLocation() { return fLocation; }
public boolean shouldSkipBreakpoints() { return fSkipBreakpoints; }
}
private IGDBBackend fGdb;
private IMIProcesses fProcService;
private boolean fReverseSupported = true;
private boolean fReverseStepping = false;
private boolean fReverseModeEnabled = false;
private RunToLineActiveOperation fRunToLineActiveOperation = null;
public GDBRunControl_7_0(DsfSession session) {
super(session);
}
@ -76,7 +109,9 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro
fReverseSupported = false;
}
register(new String[]{IRunControl.class.getName(), MIRunControl.class.getName(),
register(new String[]{IRunControl.class.getName(),
IMIRunControl.class.getName(),
MIRunControl.class.getName(),
IReverseRunControl.class.getName()},
new Hashtable<String,String>());
requestMonitor.done();
@ -400,6 +435,111 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro
}
}
/** @since 2.0 */
@Override
public void runToLine(final IExecutionDMContext context, String fileName, String lineNo, final boolean skipBreakpoints, final DataRequestMonitor<MIInfo> rm){
// Later add support for Address and function.
assert context != null;
final IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
if (dmc == null){
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
rm.done();
return;
}
if (doCanResume(context)) {
final String location = fileName + ":" + lineNo; //$NON-NLS-1$
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(context, IBreakpointsTargetDMContext.class);
getConnection().queueCommand(
new MIBreakInsert(bpDmc, true, false, null, 0,
location, dmc.getThreadId()),
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), rm) {
@Override
public void handleSuccess() {
// We must set are RunToLineActiveOperation *before* we do the resume
// or else we may get the stopped event, before we have set this variable.
int bpId = getData().getMIBreakpoints()[0].getNumber();
fRunToLineActiveOperation = new RunToLineActiveOperation(dmc, bpId, location, skipBreakpoints);
resume(context, new RequestMonitor(getExecutor(), rm) {
@Override
public void handleFailure() {
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
IBreakpointsTargetDMContext.class);
int bpId = fRunToLineActiveOperation.getBreakointId();
getConnection().queueCommand(new MIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
super.handleFailure();
}
});
}
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED,
"Cannot resume given DMC.", null)); //$NON-NLS-1$
rm.done();
}
}
/**
* @nooverride This method is not intended to be re-implemented or extended by clients.
* @noreference This method is not intended to be referenced by clients.
*
* @since 2.0
*/
@DsfServiceEventHandler
public void eventDispatched(MIInferiorExitEvent e) {
if (fRunToLineActiveOperation != null) {
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
IBreakpointsTargetDMContext.class);
int bpId = fRunToLineActiveOperation.getBreakointId();
getConnection().queueCommand(new MIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
}
}
/** @since 2.0 */
@Override
@DsfServiceEventHandler
public void eventDispatched(final MIStoppedEvent e) {
if (fRunToLineActiveOperation != null) {
String location = e.getFrame().getFile() + ":" + e.getFrame().getLine(); //$NON-NLS-1$
if (location.equals(fRunToLineActiveOperation.getLocation())) {
// We stopped on our temporary breakpoint. All is well.
fRunToLineActiveOperation = null;
} else {
// Didn't stop at the right line yet
if (fRunToLineActiveOperation.shouldSkipBreakpoints() && e instanceof MIBreakpointHitEvent) {
getConnection().queueCommand(
new MIExecContinue(fRunToLineActiveOperation.getThreadContext()),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
// 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
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
IBreakpointsTargetDMContext.class);
int bpId = fRunToLineActiveOperation.getBreakointId();
getConnection().queueCommand(new MIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
}
}
}
super.eventDispatched(e);
}
/** @since 2.0 */
public void setReverseModeEnabled(boolean enabled) {
fReverseModeEnabled = enabled;

View file

@ -25,6 +25,7 @@ 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.IRunControl;
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.IThreadDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
@ -33,8 +34,11 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommand
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIStack;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakDelete;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakInsert;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecFinish;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecInterrupt;
@ -42,11 +46,11 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecNext;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecNextInstruction;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecStep;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecStepInstruction;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecUntil;
import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIErrorEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIInferiorExitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIRunningEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MISharedLibEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MISignalEvent;
@ -55,6 +59,7 @@ import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadCreatedEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadExitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointTriggerEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.AbstractDsfService;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
@ -75,7 +80,7 @@ import org.osgi.framework.BundleContext;
* sync with the service state.
* @since 1.1
*/
public class GDBRunControl_7_0_NS extends AbstractDsfService implements IRunControl, ICachingService
public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunControl, ICachingService
{
@Immutable
private static class ExecutionData implements IExecutionDMData {
@ -192,6 +197,26 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IRunCont
StateChangeReason fStateChangeReason;
}
private static class RunToLineActiveOperation {
private IMIExecutionDMContext fThreadContext;
private int fBpId;
private String fLocation;
private boolean fSkipBreakpoints;
public RunToLineActiveOperation(IMIExecutionDMContext threadContext,
int bpId, String location, boolean skipBreakpoints) {
fThreadContext = threadContext;
fBpId = bpId;
fLocation = location;
fSkipBreakpoints = skipBreakpoints;
}
public IMIExecutionDMContext getThreadContext() { return fThreadContext; }
public int getBreakointId() { return fBpId; }
public String getLocation() { return fLocation; }
public boolean shouldSkipBreakpoints() { return fSkipBreakpoints; }
}
///////////////////////////////////////////////////////////////////////////
// MIRunControlNS
///////////////////////////////////////////////////////////////////////////
@ -203,6 +228,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IRunCont
// ThreadStates indexed by the execution context
protected Map<IMIExecutionDMContext, MIThreadRunState> fThreadRunStates = new HashMap<IMIExecutionDMContext, MIThreadRunState>();
private RunToLineActiveOperation fRunToLineActiveOperation = null;
///////////////////////////////////////////////////////////////////////////
// Initialization and shutdown
///////////////////////////////////////////////////////////////////////////
@ -222,7 +249,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IRunCont
}
private void doInitialize(final RequestMonitor rm) {
register(new String[]{IRunControl.class.getName()}, new Hashtable<String,String>());
register(new String[]{IRunControl.class.getName(), IMIRunControl.class.getName()}, new Hashtable<String,String>());
fConnection = getServicesTracker().getService(ICommandControlService.class);
getSession().addServiceEventListener(this, null);
rm.done();
@ -539,13 +566,11 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IRunCont
// Run to line
// ------------------------------------------------------------------------
// Later add support for Address and function.
// skipBreakpoints is not used at the moment. Implement later
public void runToLine(IExecutionDMContext context, String fileName, String lineNo, boolean skipBreakpoints, final DataRequestMonitor<MIInfo> rm) {
public void runToLine(IExecutionDMContext context, String fileName, String lineNo, final boolean skipBreakpoints, final DataRequestMonitor<MIInfo> rm) {
assert context != null;
IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
final IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
if (dmc == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED,
"Given context: " + context + " is not an MI execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
@ -568,9 +593,44 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IRunCont
return;
}
threadState.fResumePending = true;
fConnection.queueCommand(new MIExecUntil(dmc, fileName + ":" + lineNo), //$NON-NLS-1$
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
final String location = fileName + ":" + lineNo; //$NON-NLS-1$
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(context, IBreakpointsTargetDMContext.class);
fConnection.queueCommand(
new MIBreakInsert(bpDmc, true, false, null, 0,
location, dmc.getThreadId()),
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), rm) {
@Override
public void handleSuccess() {
// We must set are RunToLineActiveOperation *before* we do the resume
// or else we may get the stopped event, before we have set this variable.
int bpId = getData().getMIBreakpoints()[0].getNumber();
// It would have been nice to use the address returned by the break-insert as our location,
// but that does not always work because sometimes the address is <MULTIPLE>
//
// Also, we could have used the breakpoint id to know if we hit the proper breakpoint,
// but that also doesn't always work because if there are many bp at that location,
// GDB will report hitting one of them but not all of them (although GDB does consider
// that all those bps did hit.)
fRunToLineActiveOperation = new RunToLineActiveOperation(dmc, bpId, location, skipBreakpoints);
resume(dmc, new RequestMonitor(getExecutor(), rm) {
@Override
public void handleFailure() {
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
IBreakpointsTargetDMContext.class);
int bpId = fRunToLineActiveOperation.getBreakointId();
fConnection.queueCommand(new MIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
super.handleFailure();
}
});
}
});
}
// ------------------------------------------------------------------------
@ -673,6 +733,37 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IRunCont
*/
@DsfServiceEventHandler
public void eventDispatched(final MIStoppedEvent e) {
if (fRunToLineActiveOperation != null) {
// First check if it is the right thread that stopped
IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
if (fRunToLineActiveOperation.getThreadContext().equals(threadDmc)) {
String location = e.getFrame().getFile() + ":" + e.getFrame().getLine(); //$NON-NLS-1$
if (location.equals(fRunToLineActiveOperation.getLocation())) {
// We stopped on our temporary breakpoint. All is well.
fRunToLineActiveOperation = null;
} else {
// The right thread stopped but not at the right place yet
if (fRunToLineActiveOperation.shouldSkipBreakpoints() && e instanceof MIBreakpointHitEvent) {
fConnection.queueCommand(
new MIExecContinue(fRunToLineActiveOperation.getThreadContext()),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
// Don't send the stop event since we are resuming again.
return;
} else {
// Stopped for any other reasons. Just remove our temporary one
// since we don't want it to hit later
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
IBreakpointsTargetDMContext.class);
int bpId = fRunToLineActiveOperation.getBreakointId();
fConnection.queueCommand(new MIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
}
}
}
}
getSession().dispatchEvent(new SuspendedEvent(e.getDMContext(), e), getProperties());
}
@ -761,6 +852,26 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IRunCont
fTerminated = true;
}
/**
* @nooverride This method is not intended to be re-implemented or extended by clients.
* @noreference This method is not intended to be referenced by clients.
*
* @since 2.0
*/
@DsfServiceEventHandler
public void eventDispatched(MIInferiorExitEvent e) {
if (fRunToLineActiveOperation != null) {
IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
IBreakpointsTargetDMContext.class);
int bpId = fRunToLineActiveOperation.getBreakointId();
fConnection.queueCommand(new MIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
}
}
public void flushCache(IDMContext context) {
}

View file

@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2009 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ericsson - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
/**
* This interface provides methods for RunControl that are not
* part of the standard DSF IRunControl
*
* @since 2.0
*/
public interface IMIRunControl extends IRunControl
{
/**
* Request to run the program up to the specified location.
* If skipBreakpoints is false, any other breakpoint will stop this
* command; while if skipBreakpoints is true, the operation will ignore
* other breakpoints and continue until the specified location.
*/
void runToLine(IExecutionDMContext context, String fileName, String lineNo,
boolean skipBreakpoints, DataRequestMonitor<MIInfo> rm);
}

View file

@ -20,7 +20,6 @@ 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.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
@ -73,7 +72,7 @@ import org.osgi.framework.BundleContext;
* events and track service state, to be perfectly in sync with the service
* state.
*/
public class MIRunControl extends AbstractDsfService implements IRunControl, ICachingService
public class MIRunControl extends AbstractDsfService implements IMIRunControl, ICachingService
{
private static class MIExecutionDMC extends AbstractDMContext implements IMIExecutionDMContext
{

View file

@ -242,87 +242,91 @@ public class MIRunControlEventProcessor_7_0
}
protected MIEvent<?> createEvent(String reason, MIExecAsyncOutput exec) {
String threadId = null;
String groupId = null;
MIResult[] results = exec.getMIResults();
for (int i = 0; i < results.length; i++) {
String var = results[i].getVariable();
MIValue val = results[i].getMIValue();
if (var.equals("thread-id")) { //$NON-NLS-1$
if (val instanceof MIConst) {
threadId = ((MIConst)val).getString();
}
} else if (var.equals("group-id")) { //$NON-NLS-1$
if (val instanceof MIConst) {
groupId = ((MIConst)val).getString();
}
}
}
IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class);
if (procService == null) {
return null;
}
IProcessDMContext procDmc = null;
IContainerDMContext containerDmc = null;
if (groupId == null) {
// MI does not currently provide the group-id in these events
if (threadId != null) {
containerDmc = procService.createContainerContextFromThreadId(fControlDmc, threadId);
procDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class);
}
} else {
// This code would only trigger if the groupId was provided by MI
procDmc = procService.createProcessContext(fControlDmc, groupId);
containerDmc = procService.createContainerContext(procDmc, groupId);
}
IExecutionDMContext execDmc = containerDmc;
if (threadId != null) {
IThreadDMContext threadDmc = procService.createThreadContext(procDmc, threadId);
execDmc = procService.createExecutionContext(containerDmc, threadDmc, threadId);
}
if (execDmc == null) {
// Badly formatted event
return null;
}
MIEvent<?> event = null;
if ("breakpoint-hit".equals(reason)) { //$NON-NLS-1$
event = MIBreakpointHitEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if (
"watchpoint-trigger".equals(reason) //$NON-NLS-1$
|| "read-watchpoint-trigger".equals(reason) //$NON-NLS-1$
|| "access-watchpoint-trigger".equals(reason)) { //$NON-NLS-1$
event = MIWatchpointTriggerEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("watchpoint-scope".equals(reason)) { //$NON-NLS-1$
event = MIWatchpointScopeEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("end-stepping-range".equals(reason)) { //$NON-NLS-1$
event = MISteppingRangeEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("signal-received".equals(reason)) { //$NON-NLS-1$
event = MISignalEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("location-reached".equals(reason)) { //$NON-NLS-1$
event = MILocationReachedEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("function-finished".equals(reason)) { //$NON-NLS-1$
event = MIFunctionFinishedEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$
if ("exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$
event = MIInferiorExitEvent.parse(fCommandControl.getContext(), exec.getToken(), exec.getMIResults());
} else if ("exited-signalled".equals(reason)) { //$NON-NLS-1$
event = MIInferiorSignalExitEvent.parse(fCommandControl.getContext(), exec.getToken(), exec.getMIResults());
} else if (STOPPED_REASON.equals(reason)) {
event = MIStoppedEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if (RUNNING_REASON.equals(reason)) {
// Retrieve the type of command from what we last stored
int type = MIRunningEvent.CONTINUE;
if (fLastRunningCmdType != null) {
type = fLastRunningCmdType;
fLastRunningCmdType = null;
} else {
String threadId = null;
String groupId = null;
MIResult[] results = exec.getMIResults();
for (int i = 0; i < results.length; i++) {
String var = results[i].getVariable();
MIValue val = results[i].getMIValue();
if (var.equals("thread-id")) { //$NON-NLS-1$
if (val instanceof MIConst) {
threadId = ((MIConst)val).getString();
}
} else if (var.equals("group-id")) { //$NON-NLS-1$
if (val instanceof MIConst) {
groupId = ((MIConst)val).getString();
}
}
}
IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class);
if (procService == null) {
return null;
}
IProcessDMContext procDmc = null;
IContainerDMContext containerDmc = null;
if (groupId == null) {
// MI does not currently provide the group-id in these events
if (threadId != null) {
containerDmc = procService.createContainerContextFromThreadId(fControlDmc, threadId);
procDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class);
}
} else {
// This code would only trigger if the groupId was provided by MI
procDmc = procService.createProcessContext(fControlDmc, groupId);
containerDmc = procService.createContainerContext(procDmc, groupId);
}
IExecutionDMContext execDmc = containerDmc;
if (threadId != null) {
IThreadDMContext threadDmc = procService.createThreadContext(procDmc, threadId);
execDmc = procService.createExecutionContext(containerDmc, threadDmc, threadId);
}
if (execDmc == null) {
// Badly formatted event
return null;
}
if ("breakpoint-hit".equals(reason)) { //$NON-NLS-1$
event = MIBreakpointHitEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if (
"watchpoint-trigger".equals(reason) //$NON-NLS-1$
|| "read-watchpoint-trigger".equals(reason) //$NON-NLS-1$
|| "access-watchpoint-trigger".equals(reason)) { //$NON-NLS-1$
event = MIWatchpointTriggerEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("watchpoint-scope".equals(reason)) { //$NON-NLS-1$
event = MIWatchpointScopeEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("end-stepping-range".equals(reason)) { //$NON-NLS-1$
event = MISteppingRangeEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("signal-received".equals(reason)) { //$NON-NLS-1$
event = MISignalEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("location-reached".equals(reason)) { //$NON-NLS-1$
event = MILocationReachedEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("function-finished".equals(reason)) { //$NON-NLS-1$
event = MIFunctionFinishedEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if (STOPPED_REASON.equals(reason)) {
event = MIStoppedEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if (RUNNING_REASON.equals(reason)) {
// Retrieve the type of command from what we last stored
int type = MIRunningEvent.CONTINUE;
if (fLastRunningCmdType != null) {
type = fLastRunningCmdType;
fLastRunningCmdType = null;
}
event = new MIRunningEvent(execDmc, exec.getToken(), type);
}
event = new MIRunningEvent(execDmc, exec.getToken(), type);
}
return event;
}