Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2008-07-09 16:45:34 +0000
committereutarass2008-07-09 16:45:34 +0000
commit67ad4de442d3a8d76c1ecfe777122cb0457017e0 (patch)
tree87be9df227fe2273ab29351bcbb701b1a10fc97a /plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal
parent7ed998ec71c68d95c0da3e678e403f9e7cf5a298 (diff)
downloadorg.eclipse.tcf-67ad4de442d3a8d76c1ecfe777122cb0457017e0.tar.gz
org.eclipse.tcf-67ad4de442d3a8d76c1ecfe777122cb0457017e0.tar.xz
org.eclipse.tcf-67ad4de442d3a8d76c1ecfe777122cb0457017e0.zip
1. Added Protocol.invokeLater() method that dispatches an event with given delay
2. Moved source level stepping and related logic to non-UI plug-in, made it reusable. 3. Added source level stepping support into DSF integration.
Diffstat (limited to 'plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal')
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFAction.java45
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepInto.java224
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOut.java170
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOver.java290
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFContextState.java22
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java71
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java24
7 files changed, 840 insertions, 6 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFAction.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFAction.java
new file mode 100644
index 000000000..7e298146f
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFAction.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 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.actions;
+
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.tcf.protocol.Protocol;
+
+/**
+ * TCFAction class represents user request to perform some action(s) on
+ * a remote context, for example, step over line command.
+ * Such action might require multiple data exchanges with remote target.
+ * Actions for a particular context should be executed sequentially -
+ * it does not make sense to execute two step commands concurrently.
+ * If user requests actions faster then they are executed,
+ * actions are placed into a FIFO queue.
+ *
+ * Clients are expected to implement run() method to perform the action job.
+ * When the job is done, client code should call done() method.
+ */
+public abstract class TCFAction implements Runnable {
+
+ protected final TCFLaunch launch;
+ protected final String context_id;
+
+ public TCFAction(TCFLaunch launch, String context_id) {
+ assert Protocol.isDispatchThread();
+ assert context_id != null;
+ this.launch = launch;
+ this.context_id = context_id;
+ launch.addContextAction(this, context_id);
+ }
+
+ protected void done() {
+ assert Protocol.isDispatchThread();
+ launch.removeContextAction(this, context_id);
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepInto.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepInto.java
new file mode 100644
index 000000000..b2595ae0b
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepInto.java
@@ -0,0 +1,224 @@
+package org.eclipse.tm.internal.tcf.debug.actions;
+
+import java.math.BigInteger;
+import java.util.Map;
+
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.internal.tcf.debug.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.IStackTrace;
+import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.util.TCFDataCache;
+
+public abstract class TCFActionStepInto extends TCFAction implements IRunControl.RunControlListener {
+
+ private static final long TIMEOUT = 10000;
+
+ private final boolean src_step;
+ private final IRunControl rc = launch.getService(IRunControl.class);
+
+ private IRunControl.RunControlContext ctx;
+ private TCFDataCache<TCFContextState> state;
+ private TCFDataCache<TCFSourceRef> line_info;
+ private TCFSourceRef source_ref;
+ private BigInteger pc0;
+ private BigInteger pc1;
+ private int step_cnt;
+
+ protected boolean exited;
+
+ public TCFActionStepInto(TCFLaunch launch, IRunControl.RunControlContext ctx, boolean src_step) {
+ super(launch, ctx.getID());
+ this.ctx = ctx;
+ this.src_step = src_step;
+ }
+
+ protected abstract TCFDataCache<TCFContextState> getContextState();
+ protected abstract TCFDataCache<TCFSourceRef> getLineInfo();
+ protected abstract TCFDataCache<?> getStackTrace();
+ protected abstract TCFDataCache<IStackTrace.StackTraceContext> getStackFrame();
+ protected abstract int getStackFrameIndex();
+
+ public void run() {
+ if (exited) return;
+ if (state == null) {
+ rc.addListener(this);
+ state = getContextState();
+ if (state == null) {
+ exit(new Exception("Invalid context ID"));
+ return;
+ }
+ if (!ctx.canResume(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO)) {
+ Protocol.invokeLater(TIMEOUT, new Runnable() {
+ public void run() {
+ exit(new Exception("Time out"));
+ }
+ });
+ }
+ }
+ if (!state.validate()) {
+ state.wait(this);
+ return;
+ }
+ if (!state.getData().is_suspended) {
+ 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;
+ }
+ TCFDataCache<?> stack_trace = getStackTrace();
+ if (!stack_trace.validate()) {
+ stack_trace.wait(this);
+ return;
+ }
+ if (source_ref == null) {
+ line_info = getLineInfo();
+ if (!line_info.validate()) {
+ line_info.wait(this);
+ return;
+ }
+ source_ref = line_info.getData();
+ if (source_ref == null) {
+ exit(new Exception("Line info not available"));
+ return;
+ }
+ if (source_ref.error != null) {
+ exit(source_ref.error);
+ return;
+ }
+ ILineNumbers.CodeArea area = source_ref.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 (getStackFrameIndex() != 0) {
+ // Stepped out of selected function
+ exit(null);
+ return;
+ }
+ if (step_cnt > 0) {
+ TCFDataCache<IStackTrace.StackTraceContext> frame = getStackFrame();
+ if (!frame.validate()) {
+ frame.wait(this);
+ return;
+ }
+ Number addr = frame.getData().getInstructionAddress();
+ BigInteger pc = addr instanceof BigInteger ? (BigInteger)addr : new BigInteger(addr.toString());
+ if (pc == null || pc0 == null || pc1 == null) {
+ exit(null);
+ return;
+ }
+ if (pc.compareTo(pc0) < 0 || pc.compareTo(pc1) >= 0) {
+ if (!line_info.validate()) {
+ line_info.wait(this);
+ return;
+ }
+ TCFSourceRef ref = line_info.getData();
+ if (ref != null && ref.area != null) {
+ if (isSameLine(source_ref.area, ref.area)) {
+ source_ref = ref;
+ ILineNumbers.CodeArea area = source_ref.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;
+ }
+ }
+ }
+ }
+ 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;
+ }
+
+ protected void exit(Throwable error) {
+ if (exited) return;
+ rc.removeListener(this);
+ exited = true;
+ 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);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOut.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOut.java
new file mode 100644
index 000000000..b6e64a286
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOut.java
@@ -0,0 +1,170 @@
+package org.eclipse.tm.internal.tcf.debug.actions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+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.IRunControl;
+import org.eclipse.tm.tcf.services.IStackTrace;
+import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.util.TCFDataCache;
+
+public abstract class TCFActionStepOut extends TCFAction implements IRunControl.RunControlListener {
+
+ private static final long TIMEOUT = 10000;
+
+ private final IRunControl rc = launch.getService(IRunControl.class);
+ private final IBreakpoints bps = launch.getService(IBreakpoints.class);
+
+ private IRunControl.RunControlContext ctx;
+ private TCFDataCache<TCFContextState> state;
+ private int step_cnt;
+ private Map<String,Object> bp;
+
+ protected boolean exited;
+
+ public TCFActionStepOut(TCFLaunch launch, IRunControl.RunControlContext ctx) {
+ super(launch, ctx.getID());
+ this.ctx = ctx;
+ }
+
+ protected abstract TCFDataCache<TCFContextState> getContextState();
+ protected abstract TCFDataCache<?> getStackTrace();
+ protected abstract TCFDataCache<IStackTrace.StackTraceContext> getStackFrame();
+ protected abstract int getStackFrameIndex();
+
+ public void run() {
+ if (exited) return;
+ if (state == null) {
+ rc.addListener(this);
+ state = getContextState();
+ if (state == null) {
+ exit(new Exception("Invalid context ID"));
+ return;
+ }
+ if (!ctx.canResume(IRunControl.RM_STEP_OUT)) {
+ Protocol.invokeLater(TIMEOUT, new Runnable() {
+ public void run() {
+ exit(new Exception("Time out"));
+ }
+ });
+ }
+ }
+ if (!state.validate()) {
+ state.wait(this);
+ return;
+ }
+ if (!state.getData().is_suspended) {
+ 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;
+ }
+ TCFDataCache<?> stack_trace = getStackTrace();
+ if (!stack_trace.validate()) {
+ stack_trace.wait(this);
+ return;
+ }
+ if (getStackFrameIndex() < 0) {
+ // Stepped out of selected function
+ exit(null);
+ }
+ else if (bps != null && ctx.canResume(IRunControl.RM_RESUME)) {
+ if (bp == null) {
+ TCFDataCache<IStackTrace.StackTraceContext> frame = getStackFrame();
+ if (!frame.validate()) {
+ frame.wait(this);
+ return;
+ }
+ Number addr = frame.getData().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) {
+ 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"));
+ }
+ }
+
+ protected void exit(Throwable error) {
+ 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;
+ 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);
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOver.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOver.java
new file mode 100644
index 000000000..f262faa2b
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOver.java
@@ -0,0 +1,290 @@
+package org.eclipse.tm.internal.tcf.debug.actions;
+
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.internal.tcf.debug.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.IStackTrace;
+import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.util.TCFDataCache;
+
+public abstract class TCFActionStepOver extends TCFAction implements IRunControl.RunControlListener {
+
+ private static final long TIMEOUT = 10000;
+
+ private final boolean src_step;
+ private final IRunControl rc = launch.getService(IRunControl.class);
+ private final IBreakpoints bps = launch.getService(IBreakpoints.class);
+
+ private IRunControl.RunControlContext ctx;
+ private TCFDataCache<TCFContextState> state;
+ private TCFDataCache<TCFSourceRef> line_info;
+ private TCFSourceRef source_ref;
+ private BigInteger pc0;
+ private BigInteger pc1;
+ private int step_cnt;
+ private Map<String,Object> bp;
+
+ protected boolean exited;
+
+ public TCFActionStepOver(TCFLaunch launch, IRunControl.RunControlContext ctx, boolean src_step) {
+ super(launch, ctx.getID());
+ this.ctx = ctx;
+ this.src_step = src_step;
+ }
+
+ protected abstract TCFDataCache<TCFContextState> getContextState();
+ protected abstract TCFDataCache<TCFSourceRef> getLineInfo();
+ protected abstract TCFDataCache<?> getStackTrace();
+ protected abstract TCFDataCache<IStackTrace.StackTraceContext> getStackFrame();
+ protected abstract int getStackFrameIndex();
+
+ public void run() {
+ if (exited) return;
+ if (state == null) {
+ rc.addListener(this);
+ state = getContextState();
+ if (state == null) {
+ exit(new Exception("Invalid context ID"));
+ return;
+ }
+ if (!ctx.canResume(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER)) {
+ Protocol.invokeLater(TIMEOUT, new Runnable() {
+ public void run() {
+ exit(new Exception("Time out"));
+ }
+ });
+ }
+ }
+ if (!state.validate()) {
+ state.wait(this);
+ return;
+ }
+ if (!state.getData().is_suspended) {
+ 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;
+ }
+ TCFDataCache<?> stack_trace = getStackTrace();
+ if (!stack_trace.validate()) {
+ stack_trace.wait(this);
+ return;
+ }
+ if (src_step && source_ref == null) {
+ line_info = getLineInfo();
+ if (!line_info.validate()) {
+ line_info.wait(this);
+ return;
+ }
+ source_ref = line_info.getData();
+ if (source_ref == null) {
+ exit(new Exception("Line info not available"));
+ return;
+ }
+ if (source_ref.error != null) {
+ exit(source_ref.error);
+ return;
+ }
+ ILineNumbers.CodeArea area = source_ref.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 (getStackFrameIndex() != 0) {
+ if (getStackFrameIndex() < 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 if (bps != null && ctx.canResume(IRunControl.RM_RESUME)) {
+ if (bp == null) {
+ TCFDataCache<IStackTrace.StackTraceContext> frame = getStackFrame();
+ if (!frame.validate()) {
+ frame.wait(this);
+ return;
+ }
+ Number addr = frame.getData().getInstructionAddress();
+ 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);
+ }
+ });
+ }
+ 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 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) {
+ if (pc0 == null || pc1 == null || state.getData().suspend_pc == null) {
+ exit(null);
+ return;
+ }
+ assert src_step;
+ BigInteger pc = new BigInteger(state.getData().suspend_pc);
+ if (pc.compareTo(pc0) < 0 || pc.compareTo(pc1) >= 0) {
+ if (!line_info.validate()) {
+ line_info.wait(this);
+ return;
+ }
+ TCFSourceRef ref = line_info.getData();
+ if (ref != null && ref.area != null) {
+ if (isSameLine(source_ref.area, ref.area)) {
+ source_ref = ref;
+ ILineNumbers.CodeArea area = source_ref.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;
+ }
+ }
+ }
+ }
+ 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"));
+ }
+ }
+
+ protected void exit(Throwable error) {
+ 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;
+ 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);
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFContextState.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFContextState.java
new file mode 100644
index 000000000..3a9dd15a8
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFContextState.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 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.model;
+
+import java.util.Map;
+
+public class TCFContextState {
+ public boolean is_suspended;
+ public boolean is_terminated;
+
+ public String suspend_pc;
+ public String suspend_reason;
+ public Map<String,Object> suspend_params;
+}
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 f1c62b3ab..2a355d386 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
@@ -14,6 +14,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -23,6 +24,7 @@ import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.Launch;
import org.eclipse.tm.internal.tcf.debug.Activator;
+import org.eclipse.tm.internal.tcf.debug.actions.TCFAction;
import org.eclipse.tm.internal.tcf.debug.launch.TCFLaunchDelegate;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IPeer;
@@ -41,6 +43,9 @@ public class TCFLaunch extends Launch {
public void onDisconnected(TCFLaunch launch);
+ public void onContextActionsStart(TCFLaunch launch);
+
+ public void onContextActionsDone(TCFLaunch launch);
}
private static final Collection<Listener> listeners = new ArrayList<Listener>();
@@ -55,6 +60,10 @@ public class TCFLaunch extends Launch {
private boolean last_context_exited;
private ProcessContext process;
+ private int context_action_cnt;
+ private final HashMap<String,LinkedList<Runnable>> context_action_queue =
+ new HashMap<String,LinkedList<Runnable>>();
+
public TCFLaunch(ILaunchConfiguration launchConfiguration, String mode) {
super(launchConfiguration, mode, null);
}
@@ -261,13 +270,18 @@ public class TCFLaunch extends Launch {
}
public void disconnect() throws DebugException {
- Protocol.invokeLater(new Runnable() {
- public void run() {
- if (channel != null && channel.getState() != IChannel.STATE_CLOSED) {
- channel.close();
+ try {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (channel != null && channel.getState() != IChannel.STATE_CLOSED) {
+ channel.close();
+ }
}
- }
- });
+ });
+ }
+ catch (IllegalStateException x) {
+ disconnected = true;
+ }
}
public boolean canTerminate() {
@@ -307,4 +321,49 @@ public class TCFLaunch extends Launch {
});
assert channel.getState() == IChannel.STATE_OPENNING;
}
+
+ public void addContextAction(TCFAction action, String context_id) {
+ assert Protocol.isDispatchThread();
+ LinkedList<Runnable> list = context_action_queue.get(context_id);
+ if (list == null) {
+ list = new LinkedList<Runnable>();
+ context_action_queue.put(context_id, list);
+ }
+ list.add(action);
+ context_action_cnt++;
+ if (context_action_cnt == 1) {
+ for (Listener l : listeners) l.onContextActionsStart(this);
+ }
+ if (list.getFirst() == action) Protocol.invokeLater(action);
+ }
+
+ public void removeContextAction(TCFAction action, String context_id) {
+ assert Protocol.isDispatchThread();
+ LinkedList<Runnable> list = context_action_queue.get(context_id);
+ if (list == null) return;
+ assert list.getFirst() == action;
+ list.removeFirst();
+ context_action_cnt--;
+ if (!list.isEmpty()) {
+ assert context_action_cnt > 0;
+ Protocol.invokeLater(list.getFirst());
+ }
+ else if (context_action_cnt == 0) {
+ for (Listener l : listeners) l.onContextActionsDone(this);
+ }
+ }
+
+ public void removeContextActions(String context_id) {
+ assert Protocol.isDispatchThread();
+ LinkedList<Runnable> list = context_action_queue.remove(context_id);
+ if (list == null) return;
+ context_action_cnt -= list.size();
+ if (context_action_cnt == 0) {
+ for (Listener l : listeners) l.onContextActionsDone(this);
+ }
+ }
+
+ public boolean hasPendingContextActions() {
+ return context_action_cnt > 0;
+ }
}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java
new file mode 100644
index 000000000..00405ed49
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 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.model;
+
+import java.math.BigInteger;
+
+import org.eclipse.tm.tcf.services.ILineNumbers;
+
+/**
+ * Objects of this class represent a mapping between an address and source code area.
+ */
+public class TCFSourceRef {
+ public BigInteger address;
+ public ILineNumbers.CodeArea area;
+ public Throwable error;
+}

Back to the top