/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.debug.core.server; import com.google.dart.tools.debug.core.DartDebugCorePlugin; import com.google.dart.tools.debug.core.server.VmListener.PausedReason; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import java.io.IOException; import java.util.List; /** * The IDebugTarget implementation for the VM debug elements. */ public class ServerDebugThread extends ServerDebugElement implements IThread { private static final IBreakpoint[] EMPTY_BREAKPOINTS = new IBreakpoint[0]; private static final ServerDebugStackFrame[] EMPTY_FRAMES = new ServerDebugStackFrame[0]; private ServerDebugStackFrame[] suspendedFrames = EMPTY_FRAMES; private IBreakpoint[] suspendedBreakpoints = EMPTY_BREAKPOINTS; private boolean suspended; private int expectedSuspendReason = DebugEvent.UNSPECIFIED; private int expectedResumeReason = DebugEvent.UNSPECIFIED; private VmIsolate vmIsolate; /** * @param target */ public ServerDebugThread(IDebugTarget target, VmIsolate vmIsolate) { super(target); this.vmIsolate = vmIsolate; } @Override public boolean canResume() { return !isDisconnected() && isSuspended(); } @Override public boolean canStepInto() { return isSuspended(); } @Override public boolean canStepOver() { return isSuspended(); } @Override public boolean canStepReturn() { return isSuspended(); } @Override public boolean canSuspend() { return !isTerminated() && !isSuspended(); } @Override public boolean canTerminate() { return true; } @Override public IBreakpoint[] getBreakpoints() { return suspendedBreakpoints; } /** * Return a pseudo stack frame for the current isolate. This frame will be able to enumerate all * the libraries in the current isolate, and each library's top-level variables. * * @return a stack frame representing the libraries and top-level variables for the isolate */ public IStackFrame getIsolateVarsPseudoFrame() { return new ServerDebugIsolateFrame(this); } @Override public String getName() throws DebugException { String name = vmIsolate == null ? "isolate-0" : vmIsolate.getName(); return name + (isSuspended() ? " [suspended]" : ""); } @Override public int getPriority() throws DebugException { return 0; } @Override public IStackFrame[] getStackFrames() throws DebugException { return suspendedFrames; } @Override public IStackFrame getTopStackFrame() throws DebugException { IStackFrame[] frames = getStackFrames(); return frames.length > 0 ? frames[0] : null; } @Override public boolean hasStackFrames() throws DebugException { return isSuspended(); } @Override public boolean isStepping() { return expectedResumeReason == DebugEvent.STEP_INTO || expectedResumeReason == DebugEvent.STEP_OVER || expectedResumeReason == DebugEvent.STEP_RETURN || expectedSuspendReason == DebugEvent.STEP_END; } @Override public boolean isSuspended() { return suspended; } @Override public boolean isTerminated() { return getTarget().isTerminated(); } @Override public void resume() throws DebugException { try { expectedResumeReason = DebugEvent.UNSPECIFIED; getConnection().resume(vmIsolate); } catch (IOException exception) { throw createDebugException(exception); } } @Override public void stepInto() throws DebugException { expectedResumeReason = DebugEvent.STEP_INTO; expectedSuspendReason = DebugEvent.STEP_END; try { getConnection().stepInto(vmIsolate); } catch (IOException exception) { expectedResumeReason = DebugEvent.UNSPECIFIED; expectedSuspendReason = DebugEvent.UNSPECIFIED; throw createDebugException(exception); } } @Override public void stepOver() throws DebugException { expectedResumeReason = DebugEvent.STEP_OVER; expectedSuspendReason = DebugEvent.STEP_END; try { getConnection().stepOver(vmIsolate); } catch (IOException exception) { expectedResumeReason = DebugEvent.UNSPECIFIED; expectedSuspendReason = DebugEvent.UNSPECIFIED; throw createDebugException(exception); } } @Override public void stepReturn() throws DebugException { expectedResumeReason = DebugEvent.STEP_RETURN; expectedSuspendReason = DebugEvent.STEP_END; try { getConnection().stepOut(vmIsolate); } catch (IOException exception) { expectedResumeReason = DebugEvent.UNSPECIFIED; expectedSuspendReason = DebugEvent.UNSPECIFIED; throw createDebugException(exception); } } @Override public void suspend() throws DebugException { try { getConnection().interrupt(vmIsolate); } catch (IOException ioe) { throw createDebugException(ioe); } } @Override public void terminate() throws DebugException { getTarget().terminate(); } protected VmIsolate getIsolate() { return vmIsolate; } protected void handleDebuggerPaused(PausedReason dbgReason, List<VmCallFrame> frames, VmValue exception) { int reason = DebugEvent.BREAKPOINT; if (expectedSuspendReason != DebugEvent.UNSPECIFIED) { reason = expectedSuspendReason; expectedSuspendReason = DebugEvent.UNSPECIFIED; } suspended = true; suspendedFrames = createFrames(frames, exception); fireSuspendEvent(reason); } void handleDebuggerResumed() { // clear data suspended = false; suspendedFrames = EMPTY_FRAMES; suspendedBreakpoints = EMPTY_BREAKPOINTS; // send event int reason = expectedResumeReason; expectedResumeReason = DebugEvent.UNSPECIFIED; fireResumeEvent(reason); } private DebugException createDebugException(IOException exception) { return new DebugException(new Status( IStatus.ERROR, DartDebugCorePlugin.PLUGIN_ID, exception.getMessage(), exception)); } private ServerDebugStackFrame[] createFrames(List<VmCallFrame> frames, VmValue exception) { ServerDebugStackFrame[] result = new ServerDebugStackFrame[frames.size()]; for (int i = 0; i < result.length; i++) { result[i] = new ServerDebugStackFrame(getTarget(), this, frames.get(i)); if (i == 0 && exception != null) { result[i].addException(exception); } } return result; } private boolean isDisconnected() { return getDebugTarget().isDisconnected(); } }