Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2008-06-16 23:33:58 +0000
committereutarass2008-06-16 23:33:58 +0000
commitc4534274267e6b8a0aa2a7d0f0f5e9348d04909d (patch)
treea2e893e0f71998b8765e703687c01ff81302a496
parent870c5a56a7a83e7d1733a9b853d1d7d416c604ee (diff)
downloadorg.eclipse.tcf-c4534274267e6b8a0aa2a7d0f0f5e9348d04909d.tar.gz
org.eclipse.tcf-c4534274267e6b8a0aa2a7d0f0f5e9348d04909d.tar.xz
org.eclipse.tcf-c4534274267e6b8a0aa2a7d0f0f5e9348d04909d.zip
1. TCF agent Stack Trace service: fixed handling of PLT entries on Linux.
2. TCF agent Run Control service: fixed suspend reason reporting 3. TCF debugger: implemented source level step into command 4. Multiple fixes/improvement related to source level stepping 5. Better handling of TCF plugins activation/deactivation: start TCF event thread after plugin is fully activated, shutdown the thread when plugin is deactivated
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java36
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchLabelProvider.java7
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/BreakpointCommand.java5
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java127
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java287
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java354
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java245
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFSelfTest.java1
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java103
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java22
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java8
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java2
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java36
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java196
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java73
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java101
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java101
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java47
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java20
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java4
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java88
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFRunnable.java17
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java8
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java10
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java16
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/StackTraceProxy.java4
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/Activator.java28
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/EventQueue.java21
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java2
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IStackTrace.java9
30 files changed, 1422 insertions, 556 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java
index 50697c1dd..55817ebd0 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java
@@ -14,6 +14,7 @@ import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFAnnotationManager;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFModelManager;
+import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@@ -26,10 +27,8 @@ import org.osgi.framework.BundleListener;
*/
public class Activator extends AbstractUIPlugin {
- // The plug-in ID
public static final String PLUGIN_ID = "org.eclipse.tm.tcf.debug.ui";
- // The shared instance
private static Activator plugin;
private static TCFModelManager model_manager;
private static TCFAnnotationManager annotation_manager;
@@ -38,14 +37,18 @@ public class Activator extends AbstractUIPlugin {
public void bundleChanged(BundleEvent event) {
if (plugin != null && event.getBundle() == plugin.getBundle() &&
plugin.getBundle().getState() != Bundle.ACTIVE) {
- if (model_manager != null) {
- model_manager.dispose();
- model_manager = null;
- }
- if (annotation_manager != null) {
- annotation_manager.dispose();
- annotation_manager = null;
- }
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (model_manager != null) {
+ model_manager.dispose();
+ model_manager = null;
+ }
+ if (annotation_manager != null) {
+ annotation_manager.dispose();
+ annotation_manager = null;
+ }
+ }
+ });
}
}
};
@@ -64,6 +67,13 @@ public class Activator extends AbstractUIPlugin {
public void start(BundleContext context) throws Exception {
super.start(context);
context.addBundleListener(bundle_listener);
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (plugin == null) return;
+ model_manager = new TCFModelManager();
+ annotation_manager = new TCFAnnotationManager();
+ }
+ });
}
/*
@@ -90,9 +100,6 @@ public class Activator extends AbstractUIPlugin {
* @return the shared TCFModelManager instance
*/
public static TCFModelManager getModelManager() {
- if (plugin != null && model_manager == null && plugin.getBundle().getState() == Bundle.ACTIVE) {
- model_manager = new TCFModelManager();
- }
return model_manager;
}
@@ -102,9 +109,6 @@ public class Activator extends AbstractUIPlugin {
* @return the shared TCFAnnotationManager instance
*/
public static TCFAnnotationManager getAnnotationManager() {
- if (plugin != null && annotation_manager == null && plugin.getBundle().getState() == Bundle.ACTIVE) {
- annotation_manager = new TCFAnnotationManager();
- }
return annotation_manager;
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchLabelProvider.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchLabelProvider.java
index 3ffaf94b3..f7ec48a99 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchLabelProvider.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchLabelProvider.java
@@ -25,11 +25,14 @@ class TCFLaunchLabelProvider implements IElementLabelProvider {
result.setImageDescriptor(ImageCache.getImageDescriptor(ImageCache.IMG_TCF), 0);
String status = "";
if (launch.isConnecting()) status = "Connecting";
- else if (launch.isDisconnected()) status = "Disconnected";
+ else if (launch.isExited()) status = "Exited";
else if (launch.isTerminated()) status = "Terminated";
+ else if (launch.isDisconnected()) status = "Disconnected";
Throwable error = launch.getError();
if (error != null) {
- status += " - " + error;
+ String msg = error.getLocalizedMessage();
+ if (msg == null || msg.length() == 0) msg = error.getClass().getName();
+ status += " - " + msg;
result.setForeground(new RGB(255, 0, 0), 0);
}
if (status.length() > 0) status = " (" + status + ")";
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/BreakpointCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/BreakpointCommand.java
index fceba9f2d..a2b84a8c0 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/BreakpointCommand.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/BreakpointCommand.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.commands;
+import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
@@ -54,11 +55,11 @@ public class BreakpointCommand implements IToggleBreakpointsTargetExtension {
Protocol.invokeAndWait(new Runnable() {
public void run() {
try {
- String addr = node.getAddress();
+ BigInteger addr = node.getAddress();
if (addr == null) return;
Map<String,Object> m = new HashMap<String,Object>();
m.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
- m.put(IBreakpoints.PROP_LOCATION, addr);
+ m.put(IBreakpoints.PROP_LOCATION, addr.toString());
new TCFBreakpoint(ResourcesPlugin.getWorkspace().getRoot(), m);
}
catch (CoreException x) {
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java
new file mode 100644
index 000000000..07292e45d
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems, Inc. 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.tm.internal.tcf.debug.ui.commands;
+
+import java.util.HashSet;
+import java.util.Set;
+
+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.IStepOverHandler;
+import org.eclipse.jface.text.source.Annotation;
+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.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IRunControl;
+
+abstract class StepCommand implements IStepOverHandler {
+
+ protected final TCFModel model;
+
+ public StepCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ protected abstract boolean canExecute(IRunControl.RunControlContext ctx);
+
+ protected abstract void execute(IDebugCommandRequest monitor,
+ IRunControl.RunControlContext ctx, boolean src_step, Runnable done);
+
+ public final 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 (!canExecute(ctx)) {
+ node = node.getParent();
+ }
+ else {
+ if (node.isSuspended()) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public final boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ final 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 (!canExecute(ctx)) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ execute(monitor, this, set);
+ }
+ };
+ return true;
+ }
+
+ private void execute(final IDebugCommandRequest monitor, final TCFRunnable request,
+ final Set<IRunControl.RunControlContext> set) {
+ int i = 0;
+ final String[] ids = new String[set.size()];
+ for (IRunControl.RunControlContext ctx : set) ids[i++] = ctx.getID();
+ model.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ boolean src = false;
+ for (String id : ids) {
+ Annotation a = Activator.getAnnotationManager().findAnnotation(model, id);
+ if (a != null) src = true;
+ }
+ final boolean src_step = src;
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ final Set<Runnable> wait_list = new HashSet<Runnable>();
+ for (IRunControl.RunControlContext ctx : set) {
+ Runnable done = new Runnable() {
+ public void run() {
+ wait_list.remove(this);
+ if (wait_list.isEmpty()) request.done();
+ }
+ };
+ wait_list.add(done);
+ execute(monitor, ctx, src_step, done);
+ }
+ }
+ });
+ }
+ });
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java
index 279dac6dc..941100bf1 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java
@@ -10,97 +10,244 @@
*******************************************************************************/
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.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.IStepIntoHandler;
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.internal.tcf.debug.ui.model.TCFSourceRef;
import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.ILineNumbers;
import org.eclipse.tm.tcf.services.IRunControl;
+import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
-public class StepIntoCommand implements IStepIntoHandler {
+public class StepIntoCommand extends StepCommand implements IStepIntoHandler {
- private final TCFModel model;
-
- public StepIntoCommand(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_INTO)) {
- 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 boolean src_step;
+ private final Runnable done;
+ private final IRunControl rc = model.getLaunch().getService(IRunControl.class);
+
+ private IRunControl.RunControlContext ctx;
+ private TCFNodeExecContext node;
+ private TCFNodeStackFrame frame;
+ private TCFSourceRef line_info;
+ private BigInteger pc0;
+ private BigInteger pc1;
+ private int step_cnt;
+ private boolean started;
+ private boolean exited;
+
+ StepStateMachine(TCFModel model, IDebugCommandRequest monitor,
+ IRunControl.RunControlContext ctx,
+ boolean src_step, Runnable done) {
+ super(model, ctx.getID());
+ this.monitor = monitor;
+ this.ctx = ctx;
+ this.src_step = src_step;
+ 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(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO)) {
+ model.invokeLater(TIMEOUT, new Runnable() {
+ public void run() {
+ exit(new Exception("Time out"));
}
+ });
+ }
+ }
+ if (!node.validateNode(this)) return;
+ if (!node.isSuspended()) {
+ exit(new Exception("Context is not suspended"));
+ return;
+ }
+ if (ctx.canResume(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO)) {
+ if (step_cnt > 0) return;
+ ctx.resume(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ exit(error);
}
+ });
+ step_cnt++;
+ return;
+ }
+ if (!src_step) {
+ exit(new Exception("Step into is not supported"));
+ return;
+ }
+ if (frame == null) {
+ frame = node.getTopFrame();
+ if (frame == null) {
+ exit(new Exception("Cannot get top stack frame"));
+ return;
}
- 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_INTO)) {
- node = node.getParent();
+ if (frame.getFrameNo() >= 0 && !frame.validateNode(this)) return;
+ if (line_info == null) {
+ assert frame.getFrameNo() == 0;
+ line_info = frame.getLineInfo().getData();
+ if (line_info == null) {
+ exit(new Exception("Line info not available"));
+ return;
+ }
+ if (line_info.error != null) {
+ exit(line_info.error);
+ return;
+ }
+ ILineNumbers.CodeArea area = line_info.area;
+ if (area != null) {
+ if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
+ else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
+ if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
+ else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
+ }
+ }
+ if (frame.getFrameNo() != 0) {
+ // Stepped out of selected function
+ exit(null);
+ return;
+ }
+ if (step_cnt > 0) {
+ BigInteger pc = node.getAddress();
+ if (pc == null || pc0 == null || pc1 == null) {
+ exit(null);
+ return;
+ }
+ if (pc.compareTo(pc0) < 0 || pc.compareTo(pc1) >= 0) {
+ TCFSourceRef ref = frame.getLineInfo().getData();
+ if (ref != null && ref.area != null) {
+ if (isSameLine(line_info.area, ref.area)) {
+ line_info = ref;
+ ILineNumbers.CodeArea area = line_info.area;
+ if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
+ else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
+ if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
+ else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
}
else {
- set.add(ctx);
- node = null;
+ exit(null);
+ 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_INTO, 1, new IRunControl.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();
- }
- }));
- }
}
- };
- return true;
+ step_cnt++;
+ if (ctx.canResume(IRunControl.RM_STEP_INTO)) {
+ ctx.resume(IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ else {
+ exit(new Exception("Step into is not supported"));
+ }
+ }
+
+ private boolean isSameLine(ILineNumbers.CodeArea x, ILineNumbers.CodeArea y) {
+ if (x == null || y == null) return false;
+ if (x.start_line != y.start_line) return false;
+ if (x.directory != y.directory && (x.directory == null || !x.directory.equals(y.directory))) return false;
+ if (x.file != y.file && (x.file == null || !x.file.equals(y.file))) return false;
+ return true;
+ }
+
+ private void exit(Throwable error) {
+ assert started;
+ if (exited) return;
+ 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;
+ if (IRunControl.REASON_STEP.equals(reason)) {
+ Protocol.invokeLater(this);
+ }
+ else {
+ exit(null);
+ }
+ }
+ }
+
+ public StepIntoCommand(TCFModel model) {
+ super(model);
+ }
+
+ @Override
+ protected boolean canExecute(IRunControl.RunControlContext ctx) {
+ if (ctx == null) return false;
+ if (ctx.canResume(IRunControl.RM_STEP_INTO_LINE)) return true;
+ if (ctx.canResume(IRunControl.RM_STEP_INTO)) 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, src_step, done);
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java
index 7c22553e9..c71a48a73 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java
@@ -10,97 +10,311 @@
*******************************************************************************/
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.IStepOverHandler;
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.internal.tcf.debug.ui.model.TCFSourceRef;
import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IBreakpoints;
+import org.eclipse.tm.tcf.services.ILineNumbers;
import org.eclipse.tm.tcf.services.IRunControl;
+import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
-public class StepOverCommand implements IStepOverHandler {
-
- private final TCFModel model;
-
- public StepOverCommand(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_OVER)) {
- node = node.getParent();
- }
- else {
- if (node.isSuspended()) res = true;
- node = null;
+public class StepOverCommand extends StepCommand implements IStepOverHandler {
+
+ private static final long TIMEOUT = 10000;
+
+ private static class StepStateMachine extends TCFModel.ContextAction implements IRunControl.RunControlListener {
+
+ private final IDebugCommandRequest monitor;
+ private final boolean src_step;
+ 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 TCFSourceRef line_info;
+ private BigInteger pc0;
+ private BigInteger pc1;
+ private int step_cnt;
+ private Map<String,Object> bp;
+ private boolean started;
+ private boolean exited;
+
+ StepStateMachine(TCFModel model, IDebugCommandRequest monitor,
+ IRunControl.RunControlContext ctx,
+ boolean src_step, Runnable done) {
+ super(model, ctx.getID());
+ this.monitor = monitor;
+ this.ctx = ctx;
+ this.src_step = src_step;
+ 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(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER)) {
+ model.invokeLater(TIMEOUT, new Runnable() {
+ public void run() {
+ exit(new Exception("Time out"));
}
+ });
+ }
+ }
+ if (!node.validateNode(this)) return;
+ if (!node.isSuspended()) {
+ exit(new Exception("Context is not suspended"));
+ return;
+ }
+ if (ctx.canResume(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER)) {
+ if (step_cnt > 0) return;
+ ctx.resume(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER, 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;
}
- 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_OVER)) {
- node = node.getParent();
+ if (frame.getFrameNo() >= 0 && !frame.validateNode(this)) return;
+ if (src_step && line_info == null) {
+ assert frame.getFrameNo() == 0;
+ line_info = frame.getLineInfo().getData();
+ if (line_info == null) {
+ exit(new Exception("Line info not available"));
+ return;
+ }
+ if (line_info.error != null) {
+ exit(line_info.error);
+ return;
+ }
+ ILineNumbers.CodeArea area = line_info.area;
+ if (area != null) {
+ if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
+ else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
+ if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
+ else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
+ }
+ }
+ if (frame.getFrameNo() != 0) {
+ if (frame.getFrameNo() < 0) {
+ // Stepped out of selected function
+ exit(null);
+ }
+ else if (ctx.canResume(IRunControl.RM_STEP_OUT)) {
+ ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
}
- else {
- set.add(ctx);
- node = null;
+ });
+ }
+ else if (bps != null && ctx.canResume(IRunControl.RM_RESUME)) {
+ if (bp == null) {
+ BigInteger addr = frame.getAddress();
+ if (addr == null) {
+ exit(new Exception("Unknown PC 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) {
+ if (error != null) exit(error);
+ }
+ });
}
- }
- 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_OVER, 1, new IRunControl.DoneCommand() {
+ ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.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);
+ }
+ });
+ }
+ else {
+ exit(new Exception("Step over is not supported"));
+ }
+ return;
+ }
+ if (bp != null) {
+ bps.remove(new String[]{ (String)bp.get(IBreakpoints.PROP_ID) }, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ bp = null;
+ }
+ if (step_cnt > 0) {
+ BigInteger pc = node.getAddress();
+ if (pc == null || pc0 == null || pc1 == null) {
+ exit(null);
+ return;
+ }
+ if (pc.compareTo(pc0) < 0 || pc.compareTo(pc1) >= 0) {
+ TCFSourceRef ref = frame.getLineInfo().getData();
+ if (ref != null && ref.area != null) {
+ if (isSameLine(line_info.area, ref.area)) {
+ line_info = ref;
+ ILineNumbers.CodeArea area = line_info.area;
+ if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
+ else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
+ if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
+ else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
+ }
+ else {
+ exit(null);
+ return;
}
- }));
+ }
}
}
- };
- return true;
+ step_cnt++;
+ if (ctx.canResume(IRunControl.RM_STEP_OVER)) {
+ ctx.resume(IRunControl.RM_STEP_OVER, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ else if (ctx.canResume(IRunControl.RM_STEP_INTO)) {
+ ctx.resume(IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ else {
+ exit(new Exception("Step over 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) {
+ }
+ });
+ }
+ 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;
+ if (IRunControl.REASON_STEP.equals(reason) || isMyBreakpoint(pc, reason)) {
+ Protocol.invokeLater(this);
+ }
+ else {
+ exit(null);
+ }
+ }
+
+ private boolean isSameLine(ILineNumbers.CodeArea x, ILineNumbers.CodeArea y) {
+ if (x == null || y == null) return false;
+ if (x.start_line != y.start_line) return false;
+ if (x.directory != y.directory && (x.directory == null || !x.directory.equals(y.directory))) return false;
+ if (x.file != y.file && (x.file == null || !x.file.equals(y.file))) return false;
+ return true;
+ }
+
+ private boolean isMyBreakpoint(String pc, String reason) {
+ if (bp == null) return false;
+ if (pc == null) return false;
+ if (!IRunControl.REASON_BREAKPOINT.equals(reason)) return false;
+ BigInteger x = new BigInteger(pc);
+ BigInteger y = new BigInteger((String)bp.get(IBreakpoints.PROP_LOCATION));
+ return x.equals(y);
+ }
+ }
+
+ public StepOverCommand(TCFModel model) {
+ super(model);
+ }
+
+ @Override
+ protected boolean canExecute(IRunControl.RunControlContext ctx) {
+ if (ctx == null) return false;
+ if (ctx.canResume(IRunControl.RM_STEP_OVER_LINE)) return true;
+ if (ctx.canResume(IRunControl.RM_STEP_OVER)) return true;
+ if (ctx.canResume(IRunControl.RM_STEP_INTO) && 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, src_step, done);
}
}
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);
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFSelfTest.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFSelfTest.java
index 289a52f13..5c1d74b17 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFSelfTest.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFSelfTest.java
@@ -717,6 +717,7 @@ class TCFSelfTest {
}
if (get_state_cmds.isEmpty()) {
// No more pending commands
+ if (active_tests.get(this) == null) return;
doneStartingTestProcess();
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
index 592f06501..4ec3fbded 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
@@ -25,11 +25,9 @@ import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
import org.eclipse.tm.internal.tcf.debug.model.ITCFBreakpointListener;
import org.eclipse.tm.internal.tcf.debug.model.TCFBreakpoint;
import org.eclipse.tm.internal.tcf.debug.model.TCFBreakpointsStatus;
@@ -99,7 +97,7 @@ public class TCFAnnotationManager {
launch.getBreakpointsStatus().addListener(new ITCFBreakpointListener() {
public void breakpointStatusChanged(String id) {
- display.asyncExec(new Runnable() {
+ displayExec(new Runnable() {
public void run() {
if (active_launch != launch) return;
refreshBreakpointView();
@@ -108,7 +106,7 @@ public class TCFAnnotationManager {
}
public void breakpointRemoved(String id) {
- display.asyncExec(new Runnable() {
+ displayExec(new Runnable() {
public void run() {
if (active_launch != launch) return;
refreshBreakpointView();
@@ -120,19 +118,21 @@ public class TCFAnnotationManager {
public void onDisconnected(final TCFLaunch launch) {
assert Protocol.isDispatchThread();
- display.asyncExec(new Runnable() {
- public void run() {
- for (WorkbenchWindowInfo info : windows.values()) {
- for (Iterator<TCFAnnotation> i = info.annotations.iterator(); i.hasNext();) {
- TCFAnnotation a = i.next();
- if (a.model.getLaunch() == launch) {
- i.remove();
- a.dispose();
+ synchronized (Device.class) {
+ displayExec(new Runnable() {
+ public void run() {
+ for (WorkbenchWindowInfo info : windows.values()) {
+ for (Iterator<TCFAnnotation> i = info.annotations.iterator(); i.hasNext();) {
+ TCFAnnotation a = i.next();
+ if (a.model.getLaunch() == launch) {
+ i.remove();
+ a.dispose();
+ }
}
}
}
- }
- });
+ });
+ }
updateActiveLaunch();
}
};
@@ -177,47 +177,50 @@ public class TCFAnnotationManager {
private boolean disposed;
public TCFAnnotationManager() {
- assert Thread.currentThread() == display.getThread();
- Protocol.invokeLater(new Runnable() {
+ assert Protocol.isDispatchThread();
+ TCFLaunch.addListener(launch_listener);
+ displayExec(new Runnable() {
public void run() {
- TCFLaunch.addListener(launch_listener);
- }
- });
- for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
- window_listener.windowOpened(window);
- }
- PlatformUI.getWorkbench().addWindowListener(window_listener);
- IWorkbenchWindow w = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
- if (w != null) window_listener.windowActivated(w);
- display.addListener(SWT.Dispose, new Listener() {
- public void handleEvent(Event event) {
- dispose();
+ for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
+ window_listener.windowOpened(window);
+ }
+ PlatformUI.getWorkbench().addWindowListener(window_listener);
+ IWorkbenchWindow w = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (w != null) window_listener.windowActivated(w);
}
});
}
public void dispose() {
if (disposed) return;
- assert Thread.currentThread() == display.getThread();
+ assert Protocol.isDispatchThread();
disposed = true;
- Protocol.invokeLater(new Runnable() {
+ TCFLaunch.removeListener(launch_listener);
+ displayExec(new Runnable() {
public void run() {
- TCFLaunch.removeListener(launch_listener);
+ PlatformUI.getWorkbench().removeWindowListener(window_listener);
+ for (IWorkbenchWindow window : windows.keySet()) {
+ window.getSelectionService().removeSelectionListener(
+ IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
+ windows.get(window).dispose();
+ }
+ windows.clear();
}
});
- PlatformUI.getWorkbench().removeWindowListener(window_listener);
- for (IWorkbenchWindow window : windows.keySet()) {
- window.getSelectionService().removeSelectionListener(
- IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
- windows.get(window).dispose();
+ }
+
+ private void displayExec(Runnable r) {
+ synchronized (Device.class) {
+ if (!display.isDisposed()) {
+ display.asyncExec(r);
+ }
}
- windows.clear();
}
private void updateActiveLaunch() {
assert !disposed;
final int cnt = ++update_active_launch_cnt;
- display.asyncExec(new Runnable() {
+ displayExec(new Runnable() {
public void run() {
if (cnt != update_active_launch_cnt) return;
TCFLaunch launch = null;
@@ -247,7 +250,7 @@ public class TCFAnnotationManager {
private void refreshBreakpointView() {
assert !disposed;
final int cnt = ++refresh_breakpoint_view_cnt;
- display.asyncExec(new Runnable() {
+ displayExec(new Runnable() {
public void run() {
if (cnt != refresh_breakpoint_view_cnt) return;
for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
@@ -327,7 +330,21 @@ public class TCFAnnotationManager {
}
}
- void onContextResumed(final TCFModel model, String id) {
+ public Annotation findAnnotation(TCFModel model, String id) {
+ if (disposed) return null;
+ assert Thread.currentThread() == display.getThread();
+ for (WorkbenchWindowInfo info : windows.values()) {
+ for (Iterator<TCFAnnotation> i = info.annotations.iterator(); i.hasNext();) {
+ TCFAnnotation a = i.next();
+ if (a.model == model && a.exe_id.equals(id)) {
+ return a;
+ }
+ }
+ }
+ return null;
+ }
+
+ void onContextResumed(TCFModel model, String id) {
if (disposed) return;
assert Thread.currentThread() == display.getThread();
for (WorkbenchWindowInfo info : windows.values()) {
@@ -350,7 +367,7 @@ public class TCFAnnotationManager {
public void run() {
IRunControl.RunControlContext x = ((TCFNode)adaptable).getRunContext();
if (x != null && id.equals(x.getID())) {
- display.asyncExec(new Runnable() {
+ displayExec(new Runnable() {
public void run() {
IWorkbenchWindow w = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (w != null) {
@@ -365,7 +382,7 @@ public class TCFAnnotationManager {
}
}
- void onContextRemoved(final TCFModel model, String id) {
+ void onContextRemoved(TCFModel model, String id) {
if (disposed) return;
assert Thread.currentThread() == display.getThread();
for (WorkbenchWindowInfo info : windows.values()) {
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java
index 8a9b280b6..a9efd4cea 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java
@@ -75,6 +75,10 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> {
}
}
+ /**
+ * Set given data to the cache, mark cache as valid, cancel any pending data retrieval.
+ * @param data - up-to-date data to store in the cache, null means empty collection of nodes.
+ */
public void reset(Map<String,TCFNode> data) {
if (data != null) {
super.reset(data);
@@ -85,20 +89,38 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> {
}
}
+ /**
+ * Add a node to collection of children.
+ * @param n - a node.
+ */
void add(TCFNode n) {
node_pool.put(n.id, n);
if (isValid()) getData().put(n.id, n);
}
+ /** Return collection of all nodes, including current children as well as
+ * currently unused nodes from the pool.
+ * To get only current children use getData() method.
+ * @return Collection of nodes.
+ */
Collection<TCFNode> getNodes() {
return node_pool.values();
}
+ /**
+ * Return current number of children.
+ * The cache must be valid for the method to work.
+ * @return number of children.
+ */
int size() {
assert isValid();
return getData().size();
}
+ /**
+ * Return current children nodes as an array.
+ * @return array of nodes.
+ */
TCFNode[] toArray() {
assert isValid();
Map<String,TCFNode> data = getData();
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java
index e48da9201..17cb419e1 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java
@@ -126,10 +126,10 @@ public class TCFChildrenExecContext extends TCFChildren {
TCFNodeExecContext n = (TCFNodeExecContext)node.model.getNode(id);
if (n == null) {
n = new TCFNodeExecContext(node, id);
- node.makeModelDelta(IModelDelta.CONTENT);
+ node.addModelDelta(IModelDelta.CONTENT);
}
else {
- n.makeModelDelta(IModelDelta.STATE);
+ n.addModelDelta(IModelDelta.STATE);
}
add(n);
run_children.add(n);
@@ -142,10 +142,10 @@ public class TCFChildrenExecContext extends TCFChildren {
TCFNodeExecContext n = (TCFNodeExecContext)node.model.getNode(id);
if (n == null) {
n = new TCFNodeExecContext(node, id);
- node.makeModelDelta(IModelDelta.CONTENT);
+ node.addModelDelta(IModelDelta.CONTENT);
}
else {
- n.makeModelDelta(IModelDelta.STATE);
+ n.addModelDelta(IModelDelta.STATE);
}
add(n);
mem_children.add(n);
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java
index 92998f559..655b90369 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java
@@ -22,7 +22,7 @@ public class TCFChildrenRegisters extends TCFChildren {
private final TCFNode node;
TCFChildrenRegisters(TCFNode node) {
- super(node.model.getLaunch().getChannel());
+ super(node.model.getLaunch().getChannel(), 32);
this.node = node;
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java
index 071641cfa..3c42c7cb7 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java
@@ -11,6 +11,7 @@
package org.eclipse.tm.internal.tcf.debug.ui.model;
import java.util.HashMap;
+import java.util.Map;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.services.IStackTrace;
@@ -19,12 +20,12 @@ import org.eclipse.tm.tcf.services.IStackTrace;
public class TCFChildrenStackTrace extends TCFChildren {
private final TCFNodeExecContext node;
- private final TCFChildrenRegisters children_regs;
+
+ private String top_frame_id;
- TCFChildrenStackTrace(TCFNodeExecContext node, TCFChildrenRegisters children_regs) {
+ TCFChildrenStackTrace(TCFNodeExecContext node) {
super(node.model.getLaunch().getChannel(), 16);
this.node = node;
- this.children_regs = children_regs;
}
void onSourceMappingChange() {
@@ -43,20 +44,32 @@ public class TCFChildrenStackTrace extends TCFChildren {
void onResumed() {
reset(null);
}
+
+ TCFNodeStackFrame getTopFrame() {
+ return (TCFNodeStackFrame)node.model.getNode(top_frame_id);
+ }
@Override
+ public void set(IToken token, Throwable error, Map<String,TCFNode> data) {
+ for (TCFNode n : getNodes()) {
+ if (data == null || data.get(n.id) == null) ((TCFNodeStackFrame)n).setFrameNo(-1);
+ }
+ super.set(token, error, data);
+ }
+
+ @Override
protected boolean startDataRetrieval() {
final HashMap<String,TCFNode> data = new HashMap<String,TCFNode>();
if (!node.isSuspended()) {
set(null, null, data);
return true;
}
- String nm = node.id + "-TF";
- TCFNodeStackFrame n = (TCFNodeStackFrame)node.model.getNode(nm);
- if (n == null) n = new TCFNodeStackFrame(node, nm, children_regs);
- data.put(n.id, n);
IStackTrace st = node.model.getLaunch().getService(IStackTrace.class);
if (st == null) {
+ top_frame_id = node.id + "-TF";
+ TCFNodeStackFrame n = (TCFNodeStackFrame)node.model.getNode(top_frame_id);
+ if (n == null) n = new TCFNodeStackFrame(node, top_frame_id);
+ data.put(n.id, n);
set(null, null, data);
return true;
}
@@ -66,17 +79,14 @@ public class TCFChildrenStackTrace extends TCFChildren {
if (command == token && error == null) {
int cnt = contexts.length;
for (String id : contexts) {
+ cnt--;
TCFNodeStackFrame n = (TCFNodeStackFrame)node.model.getNode(id);
- if (n == null || n.getFrameNo() != cnt) {
- if (n != null) n.dispose();
- n = new TCFNodeStackFrame(node, id, cnt);
- }
- assert n.getFrameNo() != 0;
+ if (n == null) n = new TCFNodeStackFrame(node, id);
assert n.id.equals(id);
assert n.parent == node;
n.setFrameNo(cnt);
data.put(id, n);
- cnt--;
+ if (cnt == 0) top_frame_id = id;
}
}
set(token, error, data);
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
index 6445d105a..8f69833cc 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
@@ -12,6 +12,7 @@ package org.eclipse.tm.internal.tcf.debug.ui.model;
import java.util.Collection;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.Map;
import java.util.TreeSet;
@@ -38,13 +39,18 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.debug.ui.AbstractDebugView;
import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.IDebugView;
import org.eclipse.debug.ui.ISourcePresentation;
import org.eclipse.debug.ui.sourcelookup.CommonSourceNotFoundEditorInput;
import org.eclipse.debug.ui.sourcelookup.ISourceDisplay;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Display;
import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
@@ -65,7 +71,9 @@ import org.eclipse.tm.tcf.util.TCFDataCache;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
@@ -80,7 +88,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
private final Map<String,TCFNode> id2node = new HashMap<String,TCFNode>();
@SuppressWarnings("unchecked")
private final Map<Class,Object> commands = new HashMap<Class,Object>();
- private final TreeSet<FutureTask> queue = new TreeSet<FutureTask>();
+ private final TreeSet<FutureTask> future_task_queue = new TreeSet<FutureTask>();
private static final Map<ILaunchConfiguration,IEditorInput> editor_not_found =
new HashMap<ILaunchConfiguration,IEditorInput>();
@@ -90,7 +98,49 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
private int future_task_cnt;
- private int display_source_cnt;
+ private static int debug_view_selection_cnt;
+ private static int display_source_cnt;
+
+ private int context_action_cnt;
+ private final HashMap<String,LinkedList<Runnable>> context_action_queue =
+ new HashMap<String,LinkedList<Runnable>>();
+
+ public static abstract class ContextAction implements Runnable {
+
+ protected final TCFModel model;
+ protected final String context_id;
+
+ public ContextAction(TCFModel model, String context_id) {
+ assert Protocol.isDispatchThread();
+ assert context_id != null;
+ this.model = model;
+ this.context_id = context_id;
+ LinkedList<Runnable> l = model.context_action_queue.get(context_id);
+ if (l == null) {
+ l = new LinkedList<Runnable>();
+ model.context_action_queue.put(context_id, l);
+ }
+ l.add(this);
+ if (l.getFirst() == this) Protocol.invokeLater(this);
+ model.context_action_cnt++;
+ }
+
+ protected void done() {
+ assert Protocol.isDispatchThread();
+ model.context_action_cnt--;
+ LinkedList<Runnable> l = model.context_action_queue.get(context_id);
+ if (l == null) return; // context exited
+ assert l.getFirst() == this;
+ l.removeFirst();
+ if (!l.isEmpty()) {
+ assert model.context_action_cnt > 0;
+ Protocol.invokeLater(l.getFirst());
+ }
+ else if (model.context_action_cnt == 0) {
+ model.fireModelChanged();
+ }
+ }
+ }
private static class FutureTask implements Comparable<FutureTask>{
final int id;
@@ -117,19 +167,19 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
private final Thread future_task_dispatcher = new Thread() {
public void run() {
try {
- synchronized (queue) {
+ synchronized (future_task_queue) {
while (!disposed) {
- if (queue.isEmpty()) {
- queue.wait();
+ if (future_task_queue.isEmpty()) {
+ future_task_queue.wait();
}
else {
long time = System.currentTimeMillis();
- FutureTask t = queue.first();
+ FutureTask t = future_task_queue.first();
if (t.time > time) {
- queue.wait(t.time - time);
+ future_task_queue.wait(t.time - time);
}
else {
- queue.remove(t);
+ future_task_queue.remove(t);
Protocol.invokeLater(t.run);
}
}
@@ -171,13 +221,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
}
public void contextRemoved(final String[] context_ids) {
- for (String id : context_ids) {
- TCFNode node = getNode(id);
- if (node instanceof TCFNodeExecContext) {
- ((TCFNodeExecContext)node).onContextRemoved();
- }
- }
- fireModelChanged();
+ onContextRemoved(context_ids);
}
public void memoryChanged(String context_id, Number[] addr, long[] size) {
@@ -190,7 +234,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
};
private final IRunControl.RunControlListener run_listener = new IRunControl.RunControlListener() {
-
+
public void containerResumed(String[] context_ids) {
for (int i = 0; i < context_ids.length; i++) {
TCFNode node = getNode(context_ids[i]);
@@ -251,20 +295,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
}
public void contextRemoved(final String[] context_ids) {
- for (String id : context_ids) {
- TCFNode node = getNode(id);
- if (node instanceof TCFNodeExecContext) {
- ((TCFNodeExecContext)node).onContextRemoved();
- }
- }
- fireModelChanged();
- display.asyncExec(new Runnable() {
- public void run() {
- for (String id : context_ids) {
- Activator.getAnnotationManager().onContextRemoved(TCFModel.this, id);
- }
- }
- });
+ onContextRemoved(context_ids);
}
public void contextResumed(final String context) {
@@ -283,7 +314,9 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
public void contextSuspended(final String context, String pc, String reason, Map<String,Object> params) {
TCFNode node = getNode(context);
if (node instanceof TCFNodeExecContext) {
- ((TCFNodeExecContext)node).onContextSuspended(pc, reason, params);
+ final TCFNodeExecContext exe = (TCFNodeExecContext)node;
+ exe.onContextSuspended(pc, reason, params);
+ setDebugViewSelection(context);
}
fireModelChanged();
display.asyncExec(new Runnable() {
@@ -350,11 +383,12 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
void onDisconnected() {
assert Protocol.isDispatchThread();
- TCFNode[] a = id2node.values().toArray(new TCFNode[id2node.size()]);
- for (int i = 0; i < a.length; i++) {
- if (!a[i].isDisposed()) a[i].dispose();
+ if (launch_node != null) {
+ launchChanged();
+ launch_node.dispose();
+ launch_node = null;
}
- launchChanged();
+ assert id2node.size() == 0;
}
void onProxyInstalled(final TCFModelProxy p) {
@@ -372,6 +406,38 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
}
});
}
+
+ private void onContextRemoved(final String[] context_ids) {
+ boolean close_channel = false;
+ for (String id : context_ids) {
+ context_action_queue.remove(id);
+ TCFNode node = getNode(id);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextRemoved();
+ if (node.parent == launch_node) close_channel = true;
+ }
+ }
+ fireModelChanged();
+ if (close_channel) {
+ // Close end debug session if the last context is removed:
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (launch_node == null) return;
+ if (launch_node.isDisposed()) return;
+ if (!launch_node.validateNode(this)) return;
+ if (launch_node.getContextCount() != 0) return;
+ launch.onLastContextRemoved();
+ }
+ });
+ }
+ display.asyncExec(new Runnable() {
+ public void run() {
+ for (String id : context_ids) {
+ Activator.getAnnotationManager().onContextRemoved(TCFModel.this, id);
+ }
+ }
+ });
+ }
Collection<TCFModelProxy> getModelProxyList() {
return model_proxies.values();
@@ -379,15 +445,15 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
void launchChanged() {
if (launch_node != null) {
- launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ launch_node.addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
fireModelChanged();
}
}
void dispose() {
- synchronized (queue) {
+ synchronized (future_task_queue) {
disposed = true;
- queue.notify();
+ future_task_queue.notify();
}
try {
future_task_dispatcher.join();
@@ -413,6 +479,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
void fireModelChanged() {
assert Protocol.isDispatchThread();
+ if (context_action_cnt > 0) return;
for (TCFModelProxy p : model_proxies.values()) p.fireModelChanged();
}
@@ -436,12 +503,12 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
}
public void invokeLater(long delay, Runnable run) {
- synchronized (queue) {
- queue.add(new FutureTask(future_task_cnt++, System.currentTimeMillis() + delay, run));
- queue.notify();
+ synchronized (future_task_queue) {
+ future_task_queue.add(new FutureTask(future_task_cnt++, System.currentTimeMillis() + delay, run));
+ future_task_queue.notify();
}
}
-
+
public void update(IChildrenCountUpdate[] updates) {
for (int i = 0; i < updates.length; i++) {
Object o = updates[i].getElement();
@@ -498,6 +565,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
public void update(ILabelUpdate[] updates) {
for (int i = 0; i < updates.length; i++) {
Object o = updates[i].getElement();
+ // Launch label is provided by TCFLaunchLabelProvider class.
assert !(o instanceof TCFLaunch);
((TCFNode)o).update(updates[i]);
}
@@ -521,6 +589,50 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
return null;
}
+ public void setDebugViewSelection(final String node_id) {
+ final int cnt = ++debug_view_selection_cnt;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (cnt != debug_view_selection_cnt) return;
+ final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) return;
+ final IDebugView view = (IDebugView)window.getActivePage().findView(IDebugUIConstants.ID_DEBUG_VIEW);
+ if (view == null) return;
+ if (!((AbstractDebugView)view).isAvailable()) return;
+ invokeLater(300, new Runnable() {
+ public void run() {
+ TCFNode node = getNode(node_id);
+ if (node == null) return;
+ if (node.disposed) return;
+ if (!node.validateNode(this)) return;
+ if (node instanceof TCFNodeExecContext) {
+ TCFNode frame = ((TCFNodeExecContext)node).getTopFrame();
+ if (frame != null && !frame.disposed) {
+ if (!frame.validateNode(this)) return;
+ node = frame;
+ }
+ }
+ final TreeModelViewer viewer = (TreeModelViewer)view.getViewer();
+ for (TCFModelProxy proxy : model_proxies.values()) {
+ if (proxy.getProxyViewer() == viewer && !proxy.validateViewer(this)) return;
+ }
+ final TCFNode element = node;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (cnt != debug_view_selection_cnt) return;
+ if (element.parent != null && !viewer.getExpandedState(element.parent)) {
+ viewer.setExpandedState(element.parent, true);
+ }
+ ISelection selection = new StructuredSelection(element);
+ viewer.setSelection(selection);
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
/**
* Reveal source code associated with given model element.
*/
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java
index 7a4960b90..2491fa900 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java
@@ -19,7 +19,6 @@ import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchesListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
-import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.Protocol;
@@ -44,29 +43,38 @@ public class TCFModelManager {
private final ILaunchesListener debug_launch_listener = new ILaunchesListener() {
public void launchesAdded(final ILaunch[] launches) {
- }
-
- public void launchesChanged(final ILaunch[] launches) {
Protocol.invokeAndWait(new Runnable() {
public void run() {
for (int i = 0; i < launches.length; i++) {
if (launches[i] instanceof TCFLaunch) {
- TCFModel model = models.get(launches[i]);
- if (model != null) model.launchChanged();
+ TCFLaunch launch = (TCFLaunch)launches[i];
+ assert models.get(launch) == null;
+ TCFModel model = new TCFModel(display, launch);
+ models.put(launch, model);
+ assert launch.getChannel() == null;
}
}
}
});
}
+ public void launchesChanged(final ILaunch[] launches) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ for (ILaunch launch : launches) {
+ TCFModel model = models.get(launch);
+ if (model != null) model.launchChanged();
+ }
+ }
+ });
+ }
+
public void launchesRemoved(final ILaunch[] launches) {
Protocol.invokeAndWait(new Runnable() {
public void run() {
- for (int i = 0; i < launches.length; i++) {
- if (launches[i] instanceof TCFLaunch) {
- TCFModel model = models.remove(launches[i]);
- if (model != null) model.dispose();
- }
+ for (ILaunch launch : launches) {
+ TCFModel model = models.remove(launch);
+ if (model != null) model.dispose();
}
}
});
@@ -74,47 +82,32 @@ public class TCFModelManager {
};
public TCFModelManager() {
+ assert Protocol.isDispatchThread();
display = Display.getDefault();
DebugPlugin.getDefault().getLaunchManager().addLaunchListener(debug_launch_listener);
- Protocol.invokeAndWait(new Runnable() {
- public void run() {
- TCFLaunch.addListener(tcf_launch_listener);
- }
- });
+ TCFLaunch.addListener(tcf_launch_listener);
}
public void dispose() {
+ assert Protocol.isDispatchThread();
DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(debug_launch_listener);
- Protocol.invokeAndWait(new Runnable() {
- public void run() {
- TCFLaunch.removeListener(tcf_launch_listener);
- for (Iterator<TCFModel> i = models.values().iterator(); i.hasNext();) {
- TCFModel model = i.next();
- model.dispose();
- i.remove();
- }
- assert models.isEmpty();
- }
- });
+ TCFLaunch.removeListener(tcf_launch_listener);
+ for (Iterator<TCFModel> i = models.values().iterator(); i.hasNext();) {
+ TCFModel model = i.next();
+ model.dispose();
+ i.remove();
+ }
+ assert models.isEmpty();
}
public TCFModel getModel(TCFLaunch launch) {
assert Protocol.isDispatchThread();
- TCFModel model = models.get(launch);
- if (model == null) {
- model = new TCFModel(display, launch);
- models.put(launch, model);
- if (!launch.isConnecting()) {
- IChannel channel = launch.getChannel();
- if (channel != null && channel.getState() == IChannel.STATE_OPEN) {
- tcf_launch_listener.onConnected(launch);
- }
- }
- }
- return model;
+ return models.get(launch);
}
public TCFNode getRootNode(TCFLaunch launch) {
- return getModel(launch).getRootNode();
+ TCFModel model = getModel(launch);
+ if (model == null) return null;
+ return model.getRootNode();
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java
index ac5694bc1..3c2a19199 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.model;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -17,14 +18,47 @@ import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.tm.tcf.protocol.Protocol;
public class TCFModelProxy extends AbstractModelProxy implements IModelProxy {
private final TCFModel model;
- private final Map<TCFNode,ModelDelta> deltas = new HashMap<TCFNode,ModelDelta>();
+ private final Map<TCFNode,Integer> deltas = new HashMap<TCFNode,Integer>();
+ private final ArrayList<Runnable> wait_list = new ArrayList<Runnable>();
+
+ private boolean pending_deltas;
+ private boolean updating;
+
+ private final IViewerUpdateListener update_listener = new IViewerUpdateListener() {
+ public void viewerUpdatesComplete() {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ pending_deltas = false;
+ updating = false;
+ if (wait_list.isEmpty()) return;
+ Runnable[] arr = wait_list.toArray(new Runnable[wait_list.size()]);
+ for (Runnable r : arr) r.run();
+ wait_list.clear();
+ }
+ });
+ }
+ public void viewerUpdatesBegin() {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ updating = true;
+ }
+ });
+ }
+ public void updateStarted(IViewerUpdate update) {
+ }
+ public void updateComplete(IViewerUpdate update) {
+ }
+ };
TCFModelProxy(TCFModel model) {
this.model = model;
@@ -33,33 +67,68 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy {
public void installed(Viewer viewer) {
super.installed(viewer);
model.onProxyInstalled(this);
+ ((TreeModelViewer)viewer).addViewerUpdateListener(update_listener);
}
public void dispose() {
+ ((TreeModelViewer)getViewer()).removeViewerUpdateListener(update_listener);
model.onProxyDisposed(this);
super.dispose();
}
- ModelDelta getDelta(TCFNode node) {
- return deltas.get(node);
+ void addDelta(TCFNode node, int flags) {
+ Integer delta = deltas.get(node);
+ if (delta != null) {
+ deltas.put(node, Integer.valueOf(delta.intValue() | flags));
+ }
+ else {
+ deltas.put(node, Integer.valueOf(flags));
+ }
}
-
- void addDelta(TCFNode node, ModelDelta delta) {
- assert deltas.get(node) == null;
- assert delta.getElement() == node || delta.getElement() == model.getLaunch() && node == model.getRootNode();
- deltas.put(node, delta);
+
+ Viewer getProxyViewer() {
+ return getViewer();
+ }
+
+ boolean validateViewer(Runnable done) {
+ assert Protocol.isDispatchThread();
+ if (pending_deltas || updating) {
+ wait_list.add(done);
+ return false;
+ }
+ return true;
+ }
+
+ private ModelDelta makeDelta(ModelDelta root, Map<TCFNode,ModelDelta> map, TCFNode node, int flags) {
+ ModelDelta delta = map.get(node);
+ if (delta == null) {
+ if (node.parent == null) {
+ delta = root.addNode(model.getLaunch(), flags);
+ map.put(node, delta);
+ }
+ else {
+ delta = makeDelta(root, map, node.parent, 0).addNode(node, flags);
+ map.put(node, delta);
+ }
+ }
+ else if (flags != 0) {
+ delta.setFlags(delta.getFlags() | flags);
+ }
+ return delta;
}
void fireModelChanged() {
assert Protocol.isDispatchThread();
- ModelDelta delta = deltas.get(model.getRootNode());
- assert (delta == null) == deltas.isEmpty();
- if (delta != null) {
- deltas.clear();
- assert delta.getElement() == model.getLaunch();
- IModelDelta top = delta.getParentDelta();
- assert top.getElement() == DebugPlugin.getDefault().getLaunchManager();
- fireModelChanged(top);
+ if (deltas.isEmpty()) return;
+ ModelDelta root = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE);
+ Map<TCFNode,ModelDelta> map = new HashMap<TCFNode,ModelDelta>();
+ for (TCFNode node : deltas.keySet()) {
+ if (node.disposed) continue;
+ makeDelta(root, map, node, deltas.get(node).intValue());
}
+ deltas.clear();
+ if (map.isEmpty()) return;
+ fireModelChanged(root);
+ pending_deltas = true;
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java
index 10afd3ee6..e9125e834 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.model;
+import java.math.BigInteger;
import java.util.Collection;
import org.eclipse.core.runtime.PlatformObject;
@@ -25,7 +26,6 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.ui.sourcelookup.ISourceDisplay;
import org.eclipse.tm.internal.tcf.debug.ui.ImageCache;
import org.eclipse.tm.tcf.protocol.IChannel;
@@ -62,6 +62,8 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
*/
protected TCFNode(TCFNode parent, String id) {
assert Protocol.isDispatchThread();
+ assert parent != null;
+ assert id != null;
this.parent = parent;
this.id = id;
model = parent.model;
@@ -76,7 +78,7 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
assert !disposed;
if (parent != null) parent.dispose(id);
invalidateNode();
- model.removeNode(id);
+ if (id != null) model.removeNode(id);
disposed = true;
}
@@ -137,7 +139,7 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
* For executable contexts and stack frames address is current PC.
* @return
*/
- public String getAddress() {
+ public BigInteger getAddress() {
return null;
}
@@ -152,16 +154,17 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
final void update(final IChildrenCountUpdate result) {
new TCFRunnable(model.getDisplay(), result) {
public void run() {
- if (result.isCanceled()) return;
- IChannel channel = model.getLaunch().getChannel();
- if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
- if (!validateNode(this)) return;
- getData(result);
+ if (!result.isCanceled()) {
+ IChannel channel = model.getLaunch().getChannel();
+ if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ else {
+ result.setChildCount(0);
+ }
+ result.setStatus(Status.OK_STATUS);
}
- else {
- result.setChildCount(0);
- }
- result.setStatus(Status.OK_STATUS);
done();
}
};
@@ -174,13 +177,14 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
final void update(final IChildrenUpdate result) {
new TCFRunnable(model.getDisplay(), result) {
public void run() {
- if (result.isCanceled()) return;
- IChannel channel = model.getLaunch().getChannel();
- if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
- if (!validateNode(this)) return;
- getData(result);
+ if (!result.isCanceled()) {
+ IChannel channel = model.getLaunch().getChannel();
+ if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ result.setStatus(Status.OK_STATUS);
}
- result.setStatus(Status.OK_STATUS);
done();
}
};
@@ -193,16 +197,17 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
final void update(final IHasChildrenUpdate result) {
new TCFRunnable(model.getDisplay(), result) {
public void run() {
- if (result.isCanceled()) return;
- IChannel channel = model.getLaunch().getChannel();
- if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
- if (!validateNode(this)) return;
- getData(result);
- }
- else {
- result.setHasChilren(false);
+ if (!result.isCanceled()) {
+ IChannel channel = model.getLaunch().getChannel();
+ if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ else {
+ result.setHasChilren(false);
+ }
+ result.setStatus(Status.OK_STATUS);
}
- result.setStatus(Status.OK_STATUS);
done();
}
};
@@ -215,16 +220,17 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
final void update(final ILabelUpdate result) {
new TCFRunnable(model.getDisplay(), result) {
public void run() {
- if (result.isCanceled()) return;
- IChannel channel = model.getLaunch().getChannel();
- if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
- if (!validateNode(this)) return;
- getData(result);
- }
- else {
- result.setLabel("...", 0);
+ if (!result.isCanceled()) {
+ IChannel channel = model.getLaunch().getChannel();
+ if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ else {
+ result.setLabel("...", 0);
+ }
+ result.setStatus(Status.OK_STATUS);
}
- result.setStatus(Status.OK_STATUS);
done();
}
};
@@ -278,10 +284,10 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
* Create and post ModelDelta for changes in this node.
* @param flags - description of what has changed: IModelDelta.ADDED, IModelDelta.REMOVED, etc.
*/
- final void makeModelDelta(int flags) {
+ final void addModelDelta(int flags) {
for (TCFModelProxy p : model.getModelProxyList()) {
int f = flags & getRelevantModelDeltaFlags(p.getPresentationContext());
- if (f != 0) makeModelDelta(p, f);
+ if (f != 0) p.addDelta(this, f);
}
}
@@ -295,25 +301,6 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
return IModelDelta.CONTENT | IModelDelta.STATE;
}
- /**
- * Create and post ModelDelta for changes in this node, relevant for given presentation context.
- * @param p - target presentation context.
- * @param flags - description of what has changed: IModelDelta.ADDED, IModelDelta.REMOVED, etc.
- * @return - ModelDelta that describes node changes.
- */
- ModelDelta makeModelDelta(TCFModelProxy p, int flags) {
- ModelDelta delta = p.getDelta(this);
- if (delta == null) {
- ModelDelta parent_delta = parent.makeModelDelta(p, IModelDelta.NO_CHANGE);
- delta = parent_delta.addNode(this, flags);
- p.addDelta(this, delta);
- }
- else {
- delta.setFlags(delta.getFlags() | flags);
- }
- return delta;
- }
-
/*--------------------------------------------------------------------------------------*/
/* Node data retrieval state machine */
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java
index d7c3a2e93..8ec20b19e 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java
@@ -56,8 +56,8 @@ public class TCFNodeExecContext extends TCFNode {
TCFNodeExecContext(TCFNode parent, final String id) {
super(parent, id);
children_exec = new TCFChildrenExecContext(this);
+ children_stack = new TCFChildrenStackTrace(this);
children_regs = new TCFChildrenRegisters(this);
- children_stack = new TCFChildrenStackTrace(this, children_regs);
line_info_cache = new LinkedHashMap<BigInteger,TCFSourceRef>() {
@SuppressWarnings("unchecked")
protected boolean removeEldestEntry(Map.Entry eldest) {
@@ -190,7 +190,7 @@ public class TCFNodeExecContext extends TCFNode {
}
@Override
- public String getAddress() {
+ public BigInteger getAddress() {
assert Protocol.isDispatchThread();
if (!run_context.isValid()) return null;
IRunControl.RunControlContext ctx = run_context.getData();
@@ -198,7 +198,14 @@ public class TCFNodeExecContext extends TCFNode {
if (!state.isValid()) return null;
ContextState s = state.getData();
if (s == null) return null;
- return s.suspended_pc;
+ if (s.suspended_pc == null) return null;
+ return new BigInteger(s.suspended_pc);
+ }
+
+ public TCFNodeStackFrame getTopFrame() {
+ assert Protocol.isDispatchThread();
+ if (!children_stack.isValid()) return null;
+ return children_stack.getTopFrame();
}
@Override
@@ -300,7 +307,7 @@ public class TCFNodeExecContext extends TCFNode {
run_context.reset(context);
resumed_cnt++;
children_stack.onSourceMappingChange();
- makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
void onContextAdded(IMemory.MemoryContext context) {
@@ -311,14 +318,14 @@ public class TCFNodeExecContext extends TCFNode {
assert !disposed;
mem_context.reset(context);
resumed_cnt++;
- makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
void onContextRemoved() {
assert !disposed;
resumed_cnt++;
dispose();
- parent.makeModelDelta(IModelDelta.CONTENT);
+ parent.addModelDelta(IModelDelta.CONTENT);
}
void onContainerSuspended() {
@@ -330,7 +337,8 @@ public class TCFNodeExecContext extends TCFNode {
}
state.reset();
children_stack.onSuspended();
- makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ children_regs.onSuspended();
+ addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
void onContainerResumed() {
@@ -341,7 +349,7 @@ public class TCFNodeExecContext extends TCFNode {
if (!ctx.hasState()) return;
}
state.reset();
- makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
void onContextSuspended(String pc, String reason, Map<String,Object> params) {
@@ -352,14 +360,15 @@ public class TCFNodeExecContext extends TCFNode {
s.suspended_reason = reason;
state.reset(s);
children_stack.onSuspended();
+ children_regs.onSuspended();
resumed_cnt++;
- makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
void onContextResumed() {
assert !disposed;
state.reset(new ContextState());
- makeModelDelta(IModelDelta.STATE);
+ addModelDelta(IModelDelta.STATE);
final int cnt = ++resumed_cnt;
model.invokeLater(250, new Runnable() {
public void run() {
@@ -367,7 +376,7 @@ public class TCFNodeExecContext extends TCFNode {
if (disposed) return;
children_stack.onResumed();
if (!validateNode(this)) return;
- makeModelDelta(IModelDelta.CONTENT);
+ addModelDelta(IModelDelta.CONTENT);
if (parent instanceof TCFNodeExecContext) {
((TCFNodeExecContext)parent).onChildResumedOrSuspended();
}
@@ -378,7 +387,7 @@ public class TCFNodeExecContext extends TCFNode {
void onChildResumedOrSuspended() {
IRunControl.RunControlContext ctx = run_context.getData();
- if (ctx != null && ctx.isContainer()) makeModelDelta(IModelDelta.STATE);
+ if (ctx != null && ctx.isContainer()) addModelDelta(IModelDelta.STATE);
if (parent instanceof TCFNodeExecContext) ((TCFNodeExecContext)parent).onChildResumedOrSuspended();
}
@@ -391,7 +400,8 @@ public class TCFNodeExecContext extends TCFNode {
void onRegistersChanged() {
children_stack.onRegistersChanged();
- makeModelDelta(IModelDelta.CONTENT);
+ children_regs.onRegistersChanged();
+ addModelDelta(IModelDelta.CONTENT);
}
@Override
@@ -427,8 +437,8 @@ public class TCFNodeExecContext extends TCFNode {
children_exec.wait(done);
return false;
}
- children_regs.validate();
children_stack.validate();
+ children_regs.validate();
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && !ctx.hasState()) {
@@ -441,14 +451,15 @@ public class TCFNodeExecContext extends TCFNode {
}
}
- if (!children_regs.isValid()) {
- children_regs.wait(done);
- return false;
- }
if (!children_stack.isValid()) {
children_stack.wait(done);
return false;
}
+ if (!children_regs.isValid()) {
+ children_regs.wait(done);
+ return false;
+ }
+
return true;
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java
index 84cf9df0b..6afc906d0 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java
@@ -12,12 +12,9 @@ package org.eclipse.tm.internal.tcf.debug.ui.model;
import java.util.Arrays;
-import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.tm.tcf.services.IMemory;
import org.eclipse.tm.tcf.services.IRunControl;
@@ -74,19 +71,10 @@ public class TCFNodeLaunch extends TCFNode {
void onContextAdded(IMemory.MemoryContext context) {
children.onContextAdded(context);
}
-
- @Override
- ModelDelta makeModelDelta(TCFModelProxy p, int flags) {
- ModelDelta delta = p.getDelta(this);
- if (delta == null) {
- delta = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE);
- delta = delta.addNode(model.getLaunch(), -1, flags, -1);
- p.addDelta(this, delta);
- }
- else {
- delta.setFlags(delta.getFlags() | flags);
- }
- return delta;
+
+ int getContextCount() {
+ assert children.isValid();
+ return children.size();
}
@Override
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java
index e9b8cbc66..9b98d772b 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java
@@ -200,13 +200,13 @@ public class TCFNodeRegister extends TCFNode {
*/
void onSuspended() {
value.reset();
- makeModelDelta(IModelDelta.STATE);
+ addModelDelta(IModelDelta.STATE);
}
void onRegistersChanged() {
context.reset();
value.reset();
- makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
@Override
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java
index 91ba67499..141b8ad4d 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java
@@ -39,21 +39,24 @@ public class TCFNodeStackFrame extends TCFNode {
private final TCFDataCache<IStackTrace.StackTraceContext> stack_trace_context;
private final TCFDataCache<TCFSourceRef> line_info;
- private TCFNodeStackFrame(final TCFNodeExecContext parent, final String id, final int frame_no, TCFChildrenRegisters regs) {
+ TCFNodeStackFrame(final TCFNodeExecContext parent, final String id) {
super(parent, id);
- this.frame_no = frame_no;
- if (regs == null) regs = new TCFChildrenRegisters(this);
- this.children_regs = regs;
+ children_regs = new TCFChildrenRegisters(this);
IChannel channel = model.getLaunch().getChannel();
stack_trace_context = new TCFDataCache<IStackTrace.StackTraceContext>(channel) {
@Override
protected boolean startDataRetrieval() {
assert command == null;
- if (frame_no == 0) {
+ if (!isSuspended()) {
set(null, null, null);
return true;
}
IStackTrace st = model.getLaunch().getService(IStackTrace.class);
+ if (st == null) {
+ assert frame_no == 0;
+ set(null, null, null);
+ return true;
+ }
command = st.getContext(new String[]{ id }, new IStackTrace.DoneGetContext() {
public void doneGetContext(IToken token, Exception error, IStackTrace.StackTraceContext[] context) {
set(token, error, context == null || context.length == 0 ? null : context[0]);
@@ -66,18 +69,11 @@ public class TCFNodeStackFrame extends TCFNode {
line_info = new TCFDataCache<TCFSourceRef>(channel) {
@Override
protected boolean startDataRetrieval() {
- BigInteger n = null;
- if (frame_no == 0) {
- if (!parent.validateNode(this)) return false;
- }
- else {
- if (!stack_trace_context.validate()) {
- stack_trace_context.wait(this);
- return false;
- }
+ if (!stack_trace_context.validate()) {
+ stack_trace_context.wait(this);
+ return false;
}
- String s = getAddress();
- if (s != null) n = new BigInteger(s);
+ BigInteger n = getAddress();
if (n == null) {
set(null, null, null);
return true;
@@ -117,37 +113,28 @@ public class TCFNodeStackFrame extends TCFNode {
};
}
- TCFNodeStackFrame(TCFNodeExecContext parent, String id, TCFChildrenRegisters children_regs) {
- this(parent, id, 0, children_regs);
- }
-
- TCFNodeStackFrame(TCFNodeExecContext parent, String id, int frame_no) {
- this(parent, id, frame_no, null);
- }
-
- int getFrameNo() {
+ public int getFrameNo() {
assert Protocol.isDispatchThread();
return frame_no;
}
void setFrameNo(int frame_no) {
- assert this.frame_no != 0 && frame_no != 0;
this.frame_no = frame_no;
}
- TCFDataCache<TCFSourceRef> getLineInfo() {
+ public TCFDataCache<TCFSourceRef> getLineInfo() {
return line_info;
}
@Override
void dispose() {
- if (frame_no != 0) children_regs.dispose();
+ children_regs.dispose();
super.dispose();
}
@Override
void dispose(String id) {
- if (frame_no != 0) children_regs.dispose(id);
+ children_regs.dispose(id);
}
@Override
@@ -171,14 +158,27 @@ public class TCFNodeStackFrame extends TCFNode {
}
@Override
- public String getAddress() {
+ public BigInteger getAddress() {
assert Protocol.isDispatchThread();
+ if (!stack_trace_context.isValid()) return null;
+ IStackTrace.StackTraceContext ctx = stack_trace_context.getData();
+ if (ctx != null) {
+ Number n = ctx.getInstructionAddress();
+ if (n instanceof BigInteger) return (BigInteger)n;
+ if (n != null) return new BigInteger(n.toString());
+ }
if (frame_no == 0) return parent.getAddress();
+ return null;
+ }
+
+ public BigInteger getReturnAddress() {
+ assert Protocol.isDispatchThread();
if (!stack_trace_context.isValid()) return null;
IStackTrace.StackTraceContext ctx = stack_trace_context.getData();
if (ctx != null) {
- Number addr = ctx.getReturnAddress();
- if (addr != null) return addr.toString();
+ Number n = ctx.getReturnAddress();
+ if (n instanceof BigInteger) return (BigInteger)n;
+ if (n != null) return new BigInteger(n.toString());
}
return null;
}
@@ -186,6 +186,10 @@ public class TCFNodeStackFrame extends TCFNode {
@Override
protected void getData(IChildrenCountUpdate result) {
if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ if (frame_no == 0) {
+ parent.getData(result);
+ return;
+ }
result.setChildCount(children_regs.size());
}
else {
@@ -197,6 +201,10 @@ public class TCFNodeStackFrame extends TCFNode {
protected void getData(IChildrenUpdate result) {
TCFNode[] arr = null;
if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ if (frame_no == 0) {
+ parent.getData(result);
+ return;
+ }
arr = children_regs.toArray();
}
else {
@@ -219,6 +227,10 @@ public class TCFNodeStackFrame extends TCFNode {
@Override
protected void getData(IHasChildrenUpdate result) {
if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ if (frame_no == 0) {
+ parent.getData(result);
+ return;
+ }
result.setHasChilren(children_regs.size() > 0);
}
else {
@@ -231,7 +243,7 @@ public class TCFNodeStackFrame extends TCFNode {
result.setImageDescriptor(ImageCache.getImageDescriptor(getImageName()), 0);
Throwable error = stack_trace_context.getError();
if (error == null) error = line_info.getError();
- if (error != null) {
+ if (error != null && isSuspended()) {
result.setForeground(new RGB(255, 0, 0), 0);
result.setLabel(error.getClass().getName() + ": " + error.getMessage(), 0);
}
@@ -265,19 +277,19 @@ public class TCFNodeStackFrame extends TCFNode {
void onSourceMappingChange() {
line_info.reset();
- makeModelDelta(IModelDelta.STATE);
+ addModelDelta(IModelDelta.STATE);
}
void onSuspended() {
stack_trace_context.reset();
line_info.reset();
children_regs.onSuspended();
- makeModelDelta(IModelDelta.STATE);
+ addModelDelta(IModelDelta.STATE);
}
void onRegistersChanged() {
children_regs.onRegistersChanged();
- makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
@Override
@@ -291,12 +303,12 @@ public class TCFNodeStackFrame extends TCFNode {
public boolean validateNode(Runnable done) {
if (frame_no == 0 && !parent.validateNode(done)) return false;
stack_trace_context.validate();
- children_regs.validate();
+ if (frame_no != 0) children_regs.validate();
if (!stack_trace_context.isValid()) {
stack_trace_context.wait(done);
return false;
}
- if (!children_regs.isValid()) {
+ if (frame_no != 0 && !children_regs.isValid()) {
children_regs.wait(done);
return false;
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFRunnable.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFRunnable.java
index b9e387a92..cbfbba5fd 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFRunnable.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFRunnable.java
@@ -20,8 +20,6 @@ public abstract class TCFRunnable implements Runnable {
private final IRequest monitor;
private final Display display;
- private boolean canceled;
-
public TCFRunnable() {
monitor = null;
display = null;
@@ -33,17 +31,6 @@ public abstract class TCFRunnable implements Runnable {
Protocol.invokeLater(this);
}
- public void cancel() {
- canceled = true;
- if (display == null) return;
- display.asyncExec(new Runnable() {
- public void run() {
- monitor.cancel();
- monitor.done();
- }
- });
- }
-
public void done() {
if (display == null) return;
display.asyncExec(new Runnable() {
@@ -52,8 +39,4 @@ public abstract class TCFRunnable implements Runnable {
}
});
}
-
- public boolean isCanceled() {
- return canceled;
- }
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java
index e8e213406..19cbdf74d 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java
@@ -17,8 +17,8 @@ import org.eclipse.tm.tcf.services.ILineNumbers;
/**
* Objects of this class represent a mapping between an address and source code area.
*/
-class TCFSourceRef {
- BigInteger address;
- ILineNumbers.CodeArea area;
- Throwable error;
+public class TCFSourceRef {
+ public BigInteger address;
+ public ILineNumbers.CodeArea area;
+ public Throwable error;
}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java
index 3fd7701c3..d3c290c19 100644
--- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java
@@ -62,6 +62,7 @@ public class TCFLaunch extends Launch {
private boolean connecting;
private boolean disconnected;
private boolean shutdown;
+ private boolean last_context_exited;
private ProcessContext process;
public TCFLaunch(ILaunchConfiguration launchConfiguration, String mode) {
@@ -238,6 +239,11 @@ public class TCFLaunch extends Launch {
public boolean isConnecting() {
return connecting;
}
+
+ public void onLastContextRemoved() {
+ last_context_exited = true;
+ channel.close();
+ }
public IPeer getPeer() {
assert Protocol.isDispatchThread();
@@ -310,6 +316,10 @@ public class TCFLaunch extends Launch {
return res[0];
}
+ public boolean isExited() {
+ return last_context_exited;
+ }
+
public void disconnect() throws DebugException {
Protocol.invokeAndWait(new Runnable() {
public void run() {
diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java
index 75c0117fa..20e263a6d 100644
--- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java
+++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/local/LocatorService.java
@@ -27,6 +27,7 @@ import org.eclipse.tm.internal.tcf.core.RemotePeer;
import org.eclipse.tm.tcf.Activator;
import org.eclipse.tm.tcf.core.AbstractChannel;
import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IEventQueue;
import org.eclipse.tm.tcf.protocol.IPeer;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.protocol.JSON;
@@ -51,15 +52,18 @@ public class LocatorService implements ILocator {
private Thread output_thread = new Thread() {
public void run() {
- for (;;) {
- Protocol.invokeAndWait(new Runnable() {
- public void run() {
- sendPeerInfoRequest();
- }
- });
+ while (true) {
try {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ sendPeerInfoRequest();
+ }
+ });
sleep(5 * 1000);
}
+ catch (IllegalStateException x) {
+ break;
+ }
catch (InterruptedException x) {
break;
}
diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/StackTraceProxy.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/StackTraceProxy.java
index e59aa731f..994bc6699 100644
--- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/StackTraceProxy.java
+++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/StackTraceProxy.java
@@ -63,6 +63,10 @@ public class StackTraceProxy implements IStackTrace {
return (Number)props.get(PROP_RETURN_ADDRESS);
}
+ public Number getInstructionAddress() {
+ return (Number)props.get(PROP_INSTRUCTION_ADDRESS);
+ }
+
public Map<String, Object> getProperties() {
return props;
}
diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/Activator.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/Activator.java
index d1df1ce56..69ddd599f 100644
--- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/Activator.java
+++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/Activator.java
@@ -20,6 +20,8 @@ import org.eclipse.core.runtime.Status;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
/**
@@ -27,11 +29,20 @@ import org.osgi.framework.BundleContext;
*/
public class Activator extends Plugin {
- // The plug-in ID
public static final String PLUGIN_ID = "org.eclipse.tm.tcf";
- // The shared instance
private static Activator plugin;
+ private static final EventQueue queue = new EventQueue();
+ private static final BundleListener bundle_listener = new BundleListener() {
+ private boolean started = false;
+ public void bundleChanged(BundleEvent event) {
+ if (plugin != null && !started && event.getBundle() == plugin.getBundle() &&
+ plugin.getBundle().getState() == Bundle.ACTIVE) {
+ queue.start();
+ started = true;
+ }
+ }
+ };
public Activator() {
plugin = this;
@@ -40,14 +51,19 @@ public class Activator extends Plugin {
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
- EventQueue e = new EventQueue();
- Protocol.setEventQueue(e);
- runTCFStartup();
- e.start();
+ Protocol.setEventQueue(queue);
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ runTCFStartup();
+ }
+ });
+ context.addBundleListener(bundle_listener);
}
@Override
public void stop(BundleContext context) throws Exception {
+ context.removeBundleListener(bundle_listener);
+ queue.shutdown();
plugin = null;
super.stop(context);
}
diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/EventQueue.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/EventQueue.java
index 61bb453cd..df0a7c679 100644
--- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/EventQueue.java
+++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/EventQueue.java
@@ -29,6 +29,7 @@ class EventQueue implements IEventQueue, Runnable {
private final LinkedList<Runnable> queue = new LinkedList<Runnable>();
private final Thread thread;
private boolean waiting;
+ private boolean shutdown;
private int job_cnt;
EventQueue() {
@@ -64,6 +65,22 @@ class EventQueue implements IEventQueue, Runnable {
void start() {
thread.start();
}
+
+ void shutdown() {
+ try {
+ synchronized (this) {
+ shutdown = true;
+ if (waiting) {
+ waiting = false;
+ notifyAll();
+ }
+ }
+ thread.join();
+ }
+ catch (Exception e) {
+ Activator.log("Failed to shutdown TCF event dispatch thread", e);
+ }
+ }
private void error(Throwable x) {
if (debug) x.printStackTrace();
@@ -76,6 +93,7 @@ class EventQueue implements IEventQueue, Runnable {
Runnable r = null;
synchronized (this) {
while (queue.isEmpty()) {
+ if (shutdown) return;
waiting = true;
wait();
}
@@ -91,6 +109,7 @@ class EventQueue implements IEventQueue, Runnable {
public synchronized void invokeLater(final Runnable r) {
assert r != null;
+ if (shutdown) throw new IllegalStateException("TCF event dispatch is shutdown");
queue.add(r);
if (waiting) {
waiting = false;
@@ -101,7 +120,7 @@ class EventQueue implements IEventQueue, Runnable {
public boolean isDispatchThread() {
return Thread.currentThread() == thread;
}
-
+
public synchronized int getCongestion() {
int l0 = job_cnt / 10 - 100;
int l1 = queue.size() / 10 - 100;
diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java
index 4eeadb16d..b6c4af42d 100644
--- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java
+++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/AbstractChannel.java
@@ -459,7 +459,7 @@ public abstract class AbstractChannel implements IChannel {
}
else {
IChannel.IEventListener[] next = new IChannel.IEventListener[list.length - 1];
- System.arraycopy(list, 0, next, 0, i - 1);
+ System.arraycopy(list, 0, next, 0, i);
System.arraycopy(list, i + 1, next, i, next.length - i);
event_listeners.put(service.getName(), next);
}
diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IStackTrace.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IStackTrace.java
index 6c86f9458..cba5b560c 100644
--- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IStackTrace.java
+++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IStackTrace.java
@@ -30,6 +30,7 @@ public interface IStackTrace extends IService {
PROP_NAME = "Name",
PROP_FRAME_ADDRESS = "FP",
PROP_RETURN_ADDRESS = "RP",
+ PROP_INSTRUCTION_ADDRESS = "IP",
PROP_ARGUMENTS_COUNT = "ArgsCnt",
PROP_ARGUMENTS_ADDRESS = "ArgsAddr";
@@ -121,6 +122,14 @@ public interface IStackTrace extends IService {
Number getReturnAddress();
/**
+ * Get address of the next instruction to be executed in this stack frame.
+ * For top frame it is same as PC register value.
+ * For other frames it is same as return address of the next frame.
+ * @return instruction address or null if not a stack frame.
+ */
+ Number getInstructionAddress();
+
+ /**
* Get number of function arguments for this frame.
* @return function arguments count.
*/

Back to the top