diff options
Diffstat (limited to 'plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java')
-rw-r--r-- | plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java | 245 |
1 files changed, 174 insertions, 71 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java index e01a4d26a..45c9aaca6 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java @@ -10,97 +10,200 @@ *******************************************************************************/ package org.eclipse.tm.internal.tcf.debug.ui.commands; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.commands.IDebugCommandRequest; -import org.eclipse.debug.core.commands.IEnabledStateRequest; import org.eclipse.debug.core.commands.IStepReturnHandler; import org.eclipse.tm.internal.tcf.debug.ui.Activator; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFModel; -import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode; -import org.eclipse.tm.internal.tcf.debug.ui.model.TCFRunnable; +import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeExecContext; +import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeStackFrame; import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IBreakpoints; import org.eclipse.tm.tcf.services.IRunControl; +import org.eclipse.tm.tcf.services.IRunControl.RunControlContext; -public class StepReturnCommand implements IStepReturnHandler { +public class StepReturnCommand extends StepCommand implements IStepReturnHandler { - private final TCFModel model; - - public StepReturnCommand(TCFModel model) { - this.model = model; - } - - public void canExecute(final IEnabledStateRequest monitor) { - new TCFRunnable(model.getDisplay(), monitor) { - public void run() { - Object[] elements = monitor.getElements(); - boolean res = false; - for (int i = 0; i < elements.length; i++) { - TCFNode node = null; - if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; - else node = model.getRootNode(); - while (node != null && !node.isDisposed()) { - if (!node.validateNode(this)) return; - IRunControl.RunControlContext ctx = node.getRunContext(); - if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OUT)) { - node = node.getParent(); - } - else { - if (node.isSuspended()) res = true; - node = null; + private static final long TIMEOUT = 10000; + + private static class StepStateMachine extends TCFModel.ContextAction implements IRunControl.RunControlListener { + + private final IDebugCommandRequest monitor; + private final Runnable done; + private final IRunControl rc = model.getLaunch().getService(IRunControl.class); + private final IBreakpoints bps = model.getLaunch().getService(IBreakpoints.class); + + private IRunControl.RunControlContext ctx; + private TCFNodeExecContext node; + private TCFNodeStackFrame frame; + private int step_cnt; + private Map<String,Object> bp; + private boolean started; + private boolean exited; + + StepStateMachine(TCFModel model, IDebugCommandRequest monitor, + IRunControl.RunControlContext ctx, Runnable done) { + super(model, ctx.getID()); + this.monitor = monitor; + this.ctx = ctx; + this.done = done; + } + + public void run() { + assert !exited; + if (!started) { + started = true; + rc.addListener(this); + node = (TCFNodeExecContext)model.getNode(ctx.getID()); + if (node == null) { + exit(new Exception("Invalid context ID")); + return; + } + if (!ctx.canResume(IRunControl.RM_STEP_OUT)) { + model.invokeLater(TIMEOUT, new Runnable() { + public void run() { + exit(new Exception("Time out")); } - } + }); } - monitor.setEnabled(res); - monitor.setStatus(Status.OK_STATUS); - done(); } - }; - } - - public boolean execute(final IDebugCommandRequest monitor) { - new TCFRunnable(model.getDisplay(), monitor) { - public void run() { - Object[] elements = monitor.getElements(); - Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>(); - for (int i = 0; i < elements.length; i++) { - TCFNode node = null; - if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; - else node = model.getRootNode(); - while (node != null && !node.isDisposed()) { - if (!node.validateNode(this)) return; - IRunControl.RunControlContext ctx = node.getRunContext(); - if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OUT)) { - node = node.getParent(); - } - else { - set.add(ctx); - node = null; - } + if (!node.validateNode(this)) return; + if (!node.isSuspended()) { + exit(new Exception("Context is not suspended")); + return; + } + if (ctx.canResume(IRunControl.RM_STEP_OUT)) { + if (step_cnt > 0) return; + ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + exit(error); } + }); + step_cnt++; + return; + } + if (frame == null) { + frame = node.getTopFrame(); + if (frame == null) { + exit(new Exception("Cannot get top stack frame")); + return; } - final Set<IToken> cmds = new HashSet<IToken>(); - for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) { - IRunControl.RunControlContext ctx = i.next(); - cmds.add(ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() { + } + if (!frame.validateNode(this)) return; + if (frame.getFrameNo() < 0) { + // Stepped out of selected function + exit(null); + } + else if (bps != null && ctx.canResume(IRunControl.RM_RESUME)) { + if (bp == null) { + BigInteger addr = frame.getReturnAddress(); + if (addr == null) { + exit(new Exception("Unknown stack frame return address")); + return; + } + bp = new HashMap<String,Object>(); + bp.put(IBreakpoints.PROP_ID, "Step" + System.currentTimeMillis()); + bp.put(IBreakpoints.PROP_LOCATION, addr.toString()); + bp.put(IBreakpoints.PROP_CONDITION, "$thread==\"" + ctx.getID() + "\""); + bp.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE); + bps.add(bp, new IBreakpoints.DoneCommand() { public void doneCommand(IToken token, Exception error) { - assert cmds.contains(token); - cmds.remove(token); - if (error != null) { - monitor.setStatus(new Status(IStatus.ERROR, - Activator.PLUGIN_ID, IStatus.OK, "Cannot step into", error)); - } - if (cmds.isEmpty()) done(); + if (error != null) exit(error); } - })); + }); } + ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (error != null) exit(error); + } + }); + } + else { + exit(new Exception("Step out is not supported")); + } + } + + private void exit(Throwable error) { + assert started; + if (exited) return; + if (bp != null) { + bps.remove(new String[]{ (String)bp.get(IBreakpoints.PROP_ID) }, new IBreakpoints.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + } + }); } - }; - return true; + rc.removeListener(this); + exited = true; + if (error != null) { + monitor.setStatus(new Status(IStatus.ERROR, + Activator.PLUGIN_ID, IStatus.OK, "Cannot step", error)); + } + done.run(); + done(); + } + + public void containerResumed(String[] context_ids) { + } + + public void containerSuspended(String context, String pc, + String reason, Map<String, Object> params, + String[] suspended_ids) { + for (String id : suspended_ids) { + if (!id.equals(context)) contextSuspended(id, null, null, null); + } + contextSuspended(context, pc, reason, params); + } + + public void contextAdded(RunControlContext[] contexts) { + } + + public void contextChanged(RunControlContext[] contexts) { + for (RunControlContext c : contexts) { + if (c.getID().equals(ctx.getID())) ctx = c; + } + } + + public void contextException(String context, String msg) { + if (context.equals(ctx.getID())) exit(new Exception(msg)); + } + + public void contextRemoved(String[] context_ids) { + for (String context : context_ids) { + if (context.equals(ctx.getID())) exit(null); + } + } + + public void contextResumed(String context) { + } + + public void contextSuspended(String context, String pc, String reason, + Map<String, Object> params) { + if (!context.equals(ctx.getID())) return; + exit(null); + } + } + + public StepReturnCommand(TCFModel model) { + super(model); + } + + @Override + protected boolean canExecute(IRunControl.RunControlContext ctx) { + if (ctx == null) return false; + if (ctx.canResume(IRunControl.RM_STEP_OUT)) return true; + if (ctx.canResume(IRunControl.RM_RESUME) && model.getLaunch().getService(IBreakpoints.class) != null) return true; + return false; + } + + @Override + protected void execute(final IDebugCommandRequest monitor, final IRunControl.RunControlContext ctx, + boolean src_step, final Runnable done) { + new StepStateMachine(model, monitor, ctx, done); } } |