/* * #%~ * org.overture.ide.debug * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.ide.debug.core.model.internal; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.URI; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.WeakHashMap; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; 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.IStepFilters; import org.eclipse.debug.core.model.ITerminate; import org.eclipse.debug.core.model.IThread; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.overture.ide.core.resources.IVdmProject; import org.overture.ide.core.resources.IVdmSourceUnit; import org.overture.ide.debug.core.ExtendedDebugEventDetails; import org.overture.ide.debug.core.IDbgpService; import org.overture.ide.debug.core.IDebugConstants; import org.overture.ide.debug.core.IDebugOptions; import org.overture.ide.debug.core.VdmDebugPlugin; import org.overture.ide.debug.core.dbgp.IDbgpSession; import org.overture.ide.debug.core.dbgp.IDbgpStreamFilter; import org.overture.ide.debug.core.dbgp.IDbgpThreadAcceptor; import org.overture.ide.debug.core.model.DebugEventHelper; import org.overture.ide.debug.core.model.DefaultDebugOptions; import org.overture.ide.debug.core.model.IDebugLaunchConstants; import org.overture.ide.debug.core.model.IVdmBreakpointPathMapper; import org.overture.ide.debug.core.model.IVdmDebugTarget; import org.overture.ide.debug.core.model.IVdmDebugTargetListener; import org.overture.ide.debug.core.model.IVdmDebugThreadConfigurator; import org.overture.ide.debug.core.model.IVdmThread; import org.overture.ide.debug.core.model.IVdmVariable; import org.overture.ide.debug.logging.LogItem; import org.overture.ide.debug.logging.LogView; import org.overture.ide.debug.utils.CharOperation; public class VdmDebugTarget extends VdmDebugElement implements IVdmDebugTarget, IVdmThreadManagerListener, IStepFilters { // /** // * @deprecated // * @see #getVdmProject() // */ // private static final String LAUNCH_CONFIGURATION_ATTR_PROJECT = "project"; //$NON-NLS-1$ private static final int THREAD_TERMINATION_TIMEOUT = 5000; // 5 seconds private final ListenerList listeners; private IVdmStreamProxy streamProxy; private VdmConsoleInputListener consoleInputListener; private IProcess process; private final ILaunch launch; // private String name; private boolean disconnected; private final IVdmThreadManager threadManager; final VdmBreakpointManager breakpointManager; private final IDbgpService dbgpService; private final String sessionId; private final String modelId; private static final WeakHashMap<VdmDebugTarget, String> targets = new WeakHashMap<VdmDebugTarget, String>(); private String[] stepFilters; private boolean useStepFilters; private final Object processLock = new Object(); private boolean initialized = false; private boolean retrieveGlobalVariables; private boolean retrieveClassVariables; private boolean retrieveLocalVariables; private final IDebugOptions options; private boolean logging = false; static private LogView logView; private IVdmProject vdmProject = null; public static List<VdmDebugTarget> getAllTargets() { synchronized (targets) { return new ArrayList<VdmDebugTarget>(targets.keySet()); } } public static LogView getLogView() { return logView; } public VdmDebugTarget(String modelId, IDbgpService dbgpService, String sessionId, ILaunch launch, IProcess process) { this(modelId, dbgpService, sessionId, launch, process, DefaultDebugOptions.getDefaultInstance()); } public VdmDebugTarget(String modelId, IDbgpService dbgpService, String sessionId, ILaunch launch, IProcess process, IDebugOptions options) { Assert.isNotNull(options); try { setLogging(launch); } catch (CoreException e) { // OK } this.modelId = modelId; this.listeners = new ListenerList(); this.process = process; this.launch = launch; this.options = options; this.threadManager = new /* New */VdmThreadManager(this); this.threadManager.addListener(this); this.sessionId = sessionId; this.dbgpService = dbgpService; this.disconnected = false; // this.streamProxy = new VdmStreamProxy(getIOConsole()); this.breakpointManager = new VdmBreakpointManager(this, createPathMapper()); DebugEventHelper.fireCreateEvent(this); synchronized (targets) { targets.put(this, ""); //$NON-NLS-1$ } } // private IOConsole getIOConsole() // { // try // { // IOConsole console = new // IOConsole(VdmLaunchConfigurationDelegate.getVdmProject(this.launch.getLaunchConfiguration()).toString(), null); // console.activate(); // ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[] { console }); // return console; // } catch (CoreException e) // { // // TODO Auto-generated catch block // e.printStackTrace(); // } // return null; // } public void shutdown() { try { terminate(true); } catch (DebugException e) { VdmDebugPlugin.log(e); } } public String getSessionId() { return sessionId; } public IDebugTarget getDebugTarget() { return this; } public String getModelIdentifier() { return modelId; } public ILaunch getLaunch() { return launch; } // IDebugTarget public IProcess getProcess() { synchronized (processLock) { return process; } } public void setProcess(IProcess process) { synchronized (processLock) { this.process = process; } } public boolean hasThreads() { return threadManager.hasThreads(); } public IThread[] getThreads() { return threadManager.getThreads(); } public String getName() { return "VDM Application"; } // ITerminate public boolean canTerminate() { // return true; synchronized (processLock) { return threadManager.canTerminate() || process != null && process.canTerminate(); } } public boolean isTerminated() { // return true; synchronized (processLock) { boolean res = threadManager.isTerminated() && (process == null || process.isTerminated() || isRemote()); try { // Handle the case where the debug process died because of an internal error etc. res = res || process != null && process.isTerminated() && process.getExitValue() > 0; } catch (DebugException e) { } return res; } } protected static boolean waitTerminated(ITerminate terminate, int chunk, long timeout) { final long start = System.currentTimeMillis(); while (!terminate.isTerminated()) { if (System.currentTimeMillis() - start > timeout) { return false; } try { Thread.sleep(chunk); } catch (InterruptedException e) { // interrupted } } return true; } public void terminate() throws DebugException { terminate(true); } protected void terminate(boolean waitTermination) throws DebugException { fireTargetTerminating(); threadManager.sendTerminationRequest(); if (waitTermination) { final IProcess p = getProcess(); final int CHUNK = 500; if (!(waitTerminated(threadManager, CHUNK, THREAD_TERMINATION_TIMEOUT) && (p == null || waitTerminated(p, CHUNK, THREAD_TERMINATION_TIMEOUT)))) { // Debugging process is not answering, so terminating it if (p != null && p.canTerminate()) { p.terminate(); } } } threadManager.removeListener(this); breakpointManager.threadTerminated(); DebugEventHelper.fireTerminateEvent(this); } // ISuspendResume public boolean canSuspend() { return threadManager.canSuspend(); } public boolean isSuspended() { return threadManager.isSuspended(); } public void suspend() throws DebugException { threadManager.suspend(); } public boolean canResume() { return threadManager.canResume(); } public void resume() throws DebugException { threadManager.resume(); } // IDisconnect public boolean canDisconnect() { // Detach feature support!!! return false; } public void disconnect() { disconnected = true; } public boolean isDisconnected() { return disconnected; } // IMemoryBlockRetrieval public boolean supportsStorageRetrieval() { return false; } public IMemoryBlock getMemoryBlock(long startAddress, long length) { return null; } public IVdmVariable findVariable(String variableName) { // TODO Auto-generated method stub return null; } // Request timeout public int getRequestTimeout() { // TODO Auto-generated method stub return 0; } public void setRequestTimeout(int timeout) { // TODO Auto-generated method stub } // IBreakpointListener public void breakpointAdded(IBreakpoint breakpoint) { breakpointManager.breakpointAdded(breakpoint); } public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { breakpointManager.breakpointChanged(breakpoint, delta); } public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { breakpointManager.breakpointRemoved(breakpoint, delta); } // Streams public IVdmStreamProxy getStreamProxy() { return streamProxy; } public void setStreamProxy(IVdmStreamProxy proxy) { this.streamProxy = proxy; if (proxy != null) { proxy.setEncoding(getConsoleEncoding()); if (consoleInputListener != null) { consoleInputListener.stop(); } consoleInputListener = new VdmConsoleInputListener(this, proxy); consoleInputListener.start(); try { if (getLaunch().getLaunchConfiguration().getAttribute(IDebugConstants.VDM_LAUNCH_CONFIG_CONSOLE_ENTRY, false)) { this.streamProxy.getStdout().write(IDebugConstants.CONSOLE_INTERACTIVE_WELCOME_MESSAGE.getBytes()); } else { this.streamProxy.getStdout().write(IDebugConstants.CONSOLE_MESSAGE.getBytes()); } } catch (IOException e) { VdmDebugPlugin.logError("Fails to set welcome message in proxy console.", e); } catch (CoreException e) { VdmDebugPlugin.logError("Fails to get value from launch config about console mode, for the set welcome message in proxy console.", e); } } } // IDbgpThreadManagerListener public void threadAccepted(IVdmThread thread, boolean first) { if (first) { DebugEventHelper.fireExtendedEvent(this, ExtendedDebugEventDetails.BEFORE_CODE_LOADED); initialized = true; fireTargetInitialized(); } } protected IVdmBreakpointPathMapper createPathMapper() { return new NopVdmbreakpointPathMapper(); } public void allThreadsTerminated() { try { if (consoleInputListener != null) { consoleInputListener.stop(); } if (streamProxy != null) { streamProxy.close(); } terminate(false); } catch (DebugException e) { VdmDebugPlugin.log(e); } } public String toString() { return "Debugging engine (id = " + this.sessionId + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } // IVdmDebugTarget public void runToLine(URI uri, int lineNumber) throws DebugException { breakpointManager.setBreakpointUntilFirstSuspend(uri, lineNumber); resume(); } public boolean isInitialized() { return initialized; } protected void fireTargetInitialized() { Object[] list = listeners.getListeners(); for (int i = 0; i < list.length; ++i) { ((IVdmDebugTargetListener) list[i]).targetInitialized(); } } protected void fireTargetTerminating() { Object[] list = listeners.getListeners(); for (int i = 0; i < list.length; ++i) { ((IVdmDebugTargetListener) list[i]).targetTerminating(); } } public void addListener(IVdmDebugTargetListener listener) { listeners.add(listener); } public void removeListener(IVdmDebugTargetListener listener) { listeners.remove(listener); } public boolean supportsBreakpoint(IBreakpoint breakpoint) { return breakpointManager.supportsBreakpoint(breakpoint); } public void setFilters(String[] activeFilters) { this.stepFilters = activeFilters; } public String[] getFilters() { if (this.stepFilters != null) { return this.stepFilters; } return CharOperation.NO_STRINGS; } public boolean isUseStepFilters() { return useStepFilters; } public void setUseStepFilters(boolean useStepFilters) { this.useStepFilters = useStepFilters; } // /** // * @deprecated project should not be used to detect nature, since the // nature // * is already known before launch. Also, at some point we will // * have multiple natures in the same project, so it will not // * work correctly either. // */ // protected IVdmProject getVdmProject() { // final ILaunchConfiguration configuration = launch // .getLaunchConfiguration(); // if (configuration != null) { // try { // String projectName = configuration.getAttribute( // LAUNCH_CONFIGURATION_ATTR_PROJECT, (String) null); // if (projectName != null) { // projectName = projectName.trim(); // if (projectName.length() > 0) { // IProject project = ResourcesPlugin.getWorkspace() // .getRoot().getProject(projectName); // return DLTKCore.create(project); // } // } // } catch (CoreException e) { // if (DLTKCore.DEBUG) { // e.printStackTrace(); // } // } // } // return null; // } public boolean breakOnFirstLineEnabled() { return IDebugLaunchConstants.isBreakOnFirstLine(launch); // return true; } public void toggleGlobalVariables(boolean enabled) { retrieveGlobalVariables = enabled; threadManager.refreshThreads(); } public void toggleClassVariables(boolean enabled) { retrieveClassVariables = enabled; threadManager.refreshThreads(); } public void toggleLocalVariables(boolean enabled) { retrieveLocalVariables = enabled; threadManager.refreshThreads(); } public boolean retrieveClassVariables() { return retrieveClassVariables; } public boolean retrieveGlobalVariables() { return retrieveGlobalVariables; } public boolean retrieveLocalVariables() { return retrieveLocalVariables; } public String getConsoleEncoding() { String encoding = "UTF-8"; //$NON-NLS-1$ try { encoding = getLaunch().getLaunchConfiguration().getAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING, encoding); } catch (CoreException e) { e.printStackTrace(); } return encoding; } public void setVdmDebugThreadConfigurator( IVdmDebugThreadConfigurator configurator) { this.threadManager.setVdmThreadConfigurator(configurator); } public IDebugOptions getOptions() { return options; } public boolean isStepFiltersEnabled() { return isUseStepFilters(); } public void setStepFiltersEnabled(boolean enabled) { setUseStepFilters(enabled); } public boolean supportsStepFilters() { return true; } /* * @see org.eclipse.dltk.debug.core.model.IVdmDebugTarget#getSessions() */ public IDbgpSession[] getSessions() { return breakpointManager.getSessions(); } public IVdmBreakpointPathMapper getPathMapper() { return breakpointManager.bpPathMapper; } /** * @param streamFilters */ public void setStreamFilters(IDbgpStreamFilter[] streamFilters) { ((VdmThreadManager) threadManager).setStreamFilters(streamFilters); } public IDbgpService getDbgpService() { return dbgpService; } public IDbgpThreadAcceptor getDbgpThreadAcceptor() { return threadManager; } /** * @since 2.0 */ public boolean isRemote() { try { return launch.getLaunchConfiguration().getAttribute(IDebugConstants.VDM_LAUNCH_CONFIG_REMOTE_DEBUG, false); } catch (CoreException e) { return false; } } public void setVdmProject(IVdmProject project) { this.vdmProject = project; } public IVdmProject getVdmProject() { return vdmProject; } private void setLogging(ILaunch launch) throws CoreException { if (launch.getLaunchConfiguration().getAttribute(IDebugConstants.VDM_LAUNCH_CONFIG_ENABLE_LOGGING, false)) { logging = true; final IWorkbench wb = PlatformUI.getWorkbench(); if (wb.getWorkbenchWindowCount() > 0) { wb.getDisplay().syncExec(new Runnable() { public void run() { IWorkbenchPage page = wb.getWorkbenchWindows()[0].getActivePage(); IViewPart v; try { v = page.showView(IDebugConstants.LogViewId); if (v instanceof LogView) { logView = (LogView) v; } } catch (PartInitException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } if (logView != null) { logView.clear(); } } } // / Extract private boolean isCoverageEnabled() throws CoreException { return getLaunch().getLaunchConfiguration().getAttribute(IDebugConstants.VDM_LAUNCH_CONFIG_CREATE_COVERAGE, false); } public static void writeFile(File outputFolder, String fileName, String content) throws IOException { FileWriter outputFileReader = new FileWriter(new File(outputFolder, fileName)); BufferedWriter outputStream = new BufferedWriter(outputFileReader); outputStream.write(content); outputStream.close(); } protected File getOutputFolder(IVdmProject vdmProject) { IProject project = (IProject) vdmProject.getAdapter(IProject.class); Assert.isNotNull(project, "Project could not be adapted"); File outputDir = vdmProject.getModelBuildPath().getOutput().getLocation().toFile();// new // File(project.getLocation().toFile(), // "generated"); outputDir.mkdirs(); return outputDir; } // / End Extract public void printLog(LogItem item) { if (logging) { logView.log(item); logView.setFocus(); } } public void handleCustomTerminationCommands(IDbgpSession dbgpSession) { try { if (isCoverageEnabled()) { DateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); File coverageDir = new File(new File(getOutputFolder(vdmProject), "coverage"), dateFormat.format(new Date())); coverageDir.mkdirs(); dbgpSession.getOvertureCommands().writeCompleteCoverage(coverageDir); for (IVdmSourceUnit source : this.vdmProject.getSpecFiles()) { String name = source.getSystemFile().getName() + "cov"; IProject p = (IProject) vdmProject.getAdapter(IProject.class); p.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); String outputFolderSegement = coverageDir.toURI().toASCIIString().substring(p.getLocationURI().toASCIIString().length() + 1); IResource folder = p.findMember(new Path(outputFolderSegement)); source.getFile().copy(new Path(folder.getFullPath() + "/" + name), true, new NullProgressMonitor()); } } IProject project = (IProject) vdmProject.getAdapter(IProject.class); if (project != null) { project.refreshLocal(IResource.DEPTH_INFINITE, null); } } catch (Exception e) { if (VdmDebugPlugin.DEBUG) { e.printStackTrace(); } } } }