/******************************************************************************* * Copyright (c) 2009-2012 CWI * 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: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI * * Emilie Balland - (CWI) * * Arnold Lankamp - Arnold.Lankamp@cwi.nl * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package org.rascalmpl.eclipse.debug.core.model; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.IBreakpointManager; import org.eclipse.debug.core.IBreakpointManagerListener; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IThread; import org.rascalmpl.debug.IDebugMessage; import org.rascalmpl.debug.IDebugSupport; import org.rascalmpl.debug.IRascalEventListener; import org.rascalmpl.debug.IRascalEventTrigger; import org.rascalmpl.debug.IRascalRuntimeInspection; import org.rascalmpl.debug.RascalEvent; import org.rascalmpl.eclipse.debug.core.breakpoints.RascalSourceLocationBreakpoint; /** * Rascal Debug Target */ public class RascalDebugTarget extends RascalDebugElement implements IDebugTarget, IBreakpointManagerListener, IRascalEventListener { // containing launch object private final ILaunch fLaunch; // associated interpreter event trigger to receive // notifications from the runtime private IRascalEventTrigger fInterpreterEventTrigger; // associated debug support interface private final IDebugSupport fDebugSupport; // terminated state private boolean fTerminated = false; // threads private IThread[] fThreads; private RascalThread fThread; private final IRascalRuntimeInspection fEvaluator; /** * Constructs a new debug target in the given launch for the * associated Rascal console. * * @param console Rascal console * @exception CoreException if unable to connect to host */ public RascalDebugTarget(IRascalRuntimeInspection eval, ILaunch launch, IRascalEventTrigger eventTrigger, IDebugSupport debugSupport) throws CoreException { super(null); fEvaluator = eval; fInterpreterEventTrigger = eventTrigger; fDebugSupport = debugSupport; addEventListener(this); fLaunch = launch; fThread = new RascalThread(this); fThreads = new IThread[]{fThread}; IBreakpointManager breakpointManager = getBreakpointManager(); breakpointManager.addBreakpointListener(this); breakpointManager.addBreakpointManagerListener(this); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#getProcess() */ public IProcess getProcess() { return null; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#getThreads() */ public IThread[] getThreads() throws DebugException { return fThreads; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads() */ public boolean hasThreads() throws DebugException { return true; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#getName() */ public String getName() throws DebugException { return "Rascal"; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint) */ public boolean supportsBreakpoint(IBreakpoint breakpoint) { return breakpoint instanceof RascalSourceLocationBreakpoint; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() */ public IDebugTarget getDebugTarget() { return this; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() */ public ILaunch getLaunch() { return fLaunch; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ITerminate#canTerminate() */ public boolean canTerminate() { return !isTerminated(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ITerminate#isTerminated() */ public boolean isTerminated() { return fTerminated; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ITerminate#terminate() */ public void terminate() throws DebugException { getThread().terminate(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#canResume() */ public boolean canResume() { return !isTerminated() && isSuspended(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() */ public boolean canSuspend() { return !isTerminated() && !isSuspended(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() */ public boolean isSuspended() { return !isTerminated() && getThread().isSuspended(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#resume() */ public void resume() throws DebugException { getThread().resume(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#suspend() */ public void suspend() throws DebugException { getThread().suspend(); } /** * When the breakpoint manager disables, remove all registered breakpoints * requests from the VM. When it enables, reinstall them. */ public void breakpointManagerEnablementChanged(boolean enabled) { IBreakpoint[] breakpoints = getBreakpointManager().getBreakpoints(getModelIdentifier()); for(IBreakpoint breakpoint : breakpoints) { if (enabled) { breakpointAdded(breakpoint); } else { breakpointRemoved(breakpoint, null); } } } /* (non-Javadoc) * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint) */ public void breakpointAdded(IBreakpoint breakpoint) { if (supportsBreakpoint(breakpoint)) { try { if ((breakpoint.isEnabled() && getBreakpointManager().isEnabled()) || !breakpoint.isRegistered()) { RascalSourceLocationBreakpoint rascalBreakpoint = (RascalSourceLocationBreakpoint)breakpoint; rascalBreakpoint.install(this); } } catch (CoreException e) { } } } /* (non-Javadoc) * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) */ public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { if (supportsBreakpoint(breakpoint)) { try { RascalSourceLocationBreakpoint rascalBreakpoint = (RascalSourceLocationBreakpoint)breakpoint; rascalBreakpoint.remove(this); } catch (CoreException e) { } } } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect() * * Feature <em>disconnect</em> is not supported currently. */ public boolean canDisconnect() { return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDisconnect#disconnect() * * Feature <em>disconnect</em> is not supported currently. */ public void disconnect() throws DebugException { } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected() * * Feature <em>disconnect</em> is not supported currently. */ public boolean isDisconnected() { return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval() * * Feature <em>memory block retrieval</em> is not supported currently. */ public boolean supportsStorageRetrieval() { return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long) * * Feature <em>memory block retrieval</em> is not supported currently. */ public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { return null; } /** * Returns this debug target's single thread, or <code>null</code> * if terminated. * * @return this debug target's single thread, or <code>null</code> * if terminated */ public synchronized RascalThread getThread() { return fThread; } /* (non-Javadoc) * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) */ public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { if (supportsBreakpoint(breakpoint)) { try { if (breakpoint.isEnabled() && getBreakpointManager().isEnabled()) { breakpointAdded(breakpoint); } else { breakpointRemoved(breakpoint, null); } } catch (CoreException e) { } } } /* (non-Javadoc) * @see org.rascalmpl.eclipse.debug.core.model.RascalDebugElement#sendRequest(org.rascalmpl.interpreter.debug.IDebugMessage) */ public void sendRequest(IDebugMessage message) { fDebugSupport.processMessage(message); } /** * Registers the given event listener. The listener will be notified of * events in the program being interpreted. Has no effect if the listener * is already registered. * * @param listener event listener */ public void addEventListener(IRascalEventListener listener) { fInterpreterEventTrigger.addRascalEventListener(listener); } /** * Deregisters the given event listener. Has no effect if the listener is * not currently registered. * * @param listener event listener */ public void removeEventListener(IRascalEventListener listener) { fInterpreterEventTrigger.removeRascalEventListener(listener); } /** * Notification we have connected to the VM and it has started. * Resume the VM. */ private void started() { fireCreationEvent(); installDeferredBreakpoints(); try { resume(); } catch (DebugException e) { } } /** * Install breakpoints that are already registered with the breakpoint * manager. */ private void installDeferredBreakpoints() { IBreakpoint[] breakpoints = getBreakpointManager().getBreakpoints(getModelIdentifier()); for (IBreakpoint bp : breakpoints) { breakpointAdded(bp); } } /** * Called when this debug target terminates. */ private synchronized void terminated() { fTerminated = true; fThread = null; fThreads = new IThread[0]; IBreakpointManager breakpointManager = getBreakpointManager(); breakpointManager.removeBreakpointListener(this); breakpointManager.removeBreakpointManagerListener(this); fireTerminateEvent(); removeEventListener(this); } @Override public void handleRascalEvent(RascalEvent event) { switch (event.getKind()) { case CREATE: started(); break; case TERMINATE: terminated(); break; default: break; } } public IRascalRuntimeInspection getEvaluator() { return fEvaluator; } }