diff options
author | eutarass | 2008-07-09 16:45:34 +0000 |
---|---|---|
committer | eutarass | 2008-07-09 16:45:34 +0000 |
commit | 67ad4de442d3a8d76c1ecfe777122cb0457017e0 (patch) | |
tree | 87be9df227fe2273ab29351bcbb701b1a10fc97a /plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal | |
parent | 7ed998ec71c68d95c0da3e678e403f9e7cf5a298 (diff) | |
download | org.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')
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; +} |