/******************************************************************************* * Copyright (c) 2009 IBM Corporation 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: * IBM Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.debug.core.zend.model; import java.io.File; import java.util.*; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.debug.core.*; import org.eclipse.debug.core.model.*; import org.eclipse.debug.ui.AbstractDebugView; import org.eclipse.debug.ui.IDebugUIConstants; import org.eclipse.dltk.core.environment.EnvironmentPathUtils; import org.eclipse.php.debug.core.debugger.IDebugHandler; import org.eclipse.php.debug.core.debugger.parameters.IDebugParametersInitializer; import org.eclipse.php.internal.debug.core.IPHPConsoleEventListener; import org.eclipse.php.internal.debug.core.IPHPDebugConstants; import org.eclipse.php.internal.debug.core.Logger; import org.eclipse.php.internal.debug.core.PHPDebugPlugin; import org.eclipse.php.internal.debug.core.launching.PHPProcess; import org.eclipse.php.internal.debug.core.model.*; import org.eclipse.php.internal.debug.core.pathmapper.DebugSearchEngine; import org.eclipse.php.internal.debug.core.pathmapper.PathEntry; import org.eclipse.php.internal.debug.core.pathmapper.PathEntry.Type; import org.eclipse.php.internal.debug.core.pathmapper.PathMapper; import org.eclipse.php.internal.debug.core.pathmapper.PathMapper.Mapping.MappingSource; import org.eclipse.php.internal.debug.core.pathmapper.PathMapperRegistry; import org.eclipse.php.internal.debug.core.zend.communication.DebugConnection; import org.eclipse.php.internal.debug.core.zend.debugger.*; import org.eclipse.php.internal.debug.core.zend.debugger.Breakpoint; import org.eclipse.php.internal.server.core.Server; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.wst.sse.ui.internal.StructuredResourceMarkerAnnotationModel; /** * PHP Debug Target */ @SuppressWarnings("restriction") public class PHPDebugTarget extends PHPDebugElement implements IPHPDebugTarget, IBreakpointManagerListener, IStepFilters { protected ContextManager fContextManager; // use step filter or not protected boolean isStepFiltersEnabled; // containing launch object protected ILaunch fLaunch; protected IProcess fProcess; // program name protected String fName; protected String fURL; protected int fRequestPort; protected DebugOutput fDebugOutput = new DebugOutput(); // suspend state protected boolean fSuspended = false; // terminated state protected boolean fTerminated = false; protected boolean fTermainateCalled = false; // threads protected PHPThread fThread; protected IThread[] fThreads; protected IRemoteDebugger debugger; protected String fLastcmd; protected boolean fStatus; protected int fLastStop; protected String fLastFileName; protected boolean fIsPHPCGI; protected boolean fIsRunAsDebug; protected PHPResponseHandler fPHPResponseHandler; protected org.eclipse.php.internal.debug.core.zend.debugger.Debugger.StartResponseHandler fStartResponseHandler; protected org.eclipse.php.internal.debug.core.zend.debugger.Debugger.BreakpointAddedResponseHandler fBreakpointAddedResponseHandler; protected org.eclipse.php.internal.debug.core.zend.debugger.Debugger.BreakpointRemovedResponseHandler fBreakpointRemovedResponseHandler; protected org.eclipse.php.internal.debug.core.zend.debugger.Debugger.StepIntoResponseHandler fStepIntoResponseHandler; protected org.eclipse.php.internal.debug.core.zend.debugger.Debugger.StepOverResponseHandler fStepOverResponseHandler; protected org.eclipse.php.internal.debug.core.zend.debugger.Debugger.StepOutResponseHandler fStepOutResponseHandler; protected org.eclipse.php.internal.debug.core.zend.debugger.Debugger.GoResponseHandler fGoResponseHandler; protected org.eclipse.php.internal.debug.core.zend.debugger.Debugger.PauseResponseHandler fPauseResponseHandler; protected org.eclipse.php.internal.debug.core.zend.debugger.Debugger.AddFilesResponseHandler fAddFilesResponseHandler; protected DefaultExpressionsManager expressionsManager; // private IVariable[] fVariables; protected IProject fProject; protected int fSuspendCount; protected Vector<IPHPConsoleEventListener> fConsoleEventListeners = new Vector<IPHPConsoleEventListener>(); protected Set<DebugError> fDebugErrors = new HashSet<DebugError>(); protected StartLock fStartLock = new StartLock(); protected BreakpointSet fBreakpointSet; protected IBreakpointManager fBreakpointManager; protected boolean fIsServerWindows = false; protected DebugConnection fDebugConnection; protected Set<String> fAddFilesPaths; /** * Constructs a new debug target in the given launch for the associated PHP * Debugger on a Apache Server. * * @param connection * The debug connection for the communication read and write * processes. * @param launch * containing launch * @param URL * URL of the debugger * @param requestPort * port to send requests to the bebugger * * @exception CoreException * if unable to connect to host */ public PHPDebugTarget(DebugConnection connection, ILaunch launch, String URL, int requestPort, IProcess process, boolean runAsDebug, boolean stopAtFirstLine, IProject project) throws CoreException { super(null); fDebugConnection = connection; fURL = URL; fIsPHPCGI = false; initDebugTarget(launch, requestPort, process, runAsDebug, stopAtFirstLine, project); } /** * Constructs a new debug target in the given launch for the associated PHP * Debugger using PHP exe. * * @param connectionThread * The debug connection for the communication read and write * processes. * @param launch * containing launch * @param String * full path to the PHP executable * @param requestPort * port to send requests to the bebugger * * @exception CoreException * if unable to connect to host */ public PHPDebugTarget(DebugConnection connectionThread, ILaunch launch, String phpExe, IFile fileToDebug, int requestPort, IProcess process, boolean runAsDebug, boolean stopAtFirstLine, IProject project) throws CoreException { this(connectionThread, launch, phpExe, fileToDebug.getName(), requestPort, process, runAsDebug, stopAtFirstLine, project); } public PHPDebugTarget(DebugConnection connectionThread, ILaunch launch, String phpExe, String fileToDebug, int requestPort, IProcess process, boolean runAsDebug, boolean stopAtFirstLine, IProject project) throws CoreException { super(null); fDebugConnection = connectionThread; fName = fileToDebug; fIsPHPCGI = true; initDebugTarget(launch, requestPort, process, runAsDebug, stopAtFirstLine, project); } /** * Returns the DebugConnectionThread for this PHPDebugTarget. * * @return The DebugConnectionThread. */ public DebugConnection getDebugConnection() { return fDebugConnection; } /* * Initialize the debug target. * * @param launch * * @param requestPort * * @param process * * @param runAsDebug * * @param stopAtFirstLine * * @param project * * @throws CoreException */ private void initDebugTarget(ILaunch launch, int requestPort, IProcess process, boolean runAsDebug, boolean stopAtFirstLine, IProject project) throws CoreException { fLaunch = launch; fProcess = process; fIsRunAsDebug = runAsDebug; fProject = project; fProcess.setAttribute(IProcess.ATTR_PROCESS_TYPE, IPHPDebugConstants.PHPProcessType); if (fProcess instanceof PHPProcess) { ((PHPProcess) fProcess).setDebugTarget(this); } fRequestPort = requestPort; // synchronized (fUsedPorts) { // if (fUsedPorts.containsKey(String.valueOf(requestPort))) { // Logger.debugMSG("PHPDebugTarget: Debug Port already in use"); // String errorMessage = PHPDebugCoreMessages.DebuggerDebugPortInUse_1; // completeTerminated(); // throw new DebugException(new Status(IStatus.ERROR, // PHPDebugPlugin.getID(), IPHPConstants.INTERNAL_ERROR, errorMessage, // null)); // } else { // fUsedPorts.put(String.valueOf(requestPort), new // Integer(requestPort)); // fRequestPort = requestPort; // } // } fBreakpointSet = new BreakpointSet(project, fIsPHPCGI); IDebugHandler debugHandler = null; IDebugParametersInitializer parametersInitializer = DebugParametersInitializersRegistry .getBestMatchDebugParametersInitializer(launch); if (parametersInitializer != null) { String debugHandlerID = parametersInitializer.getDebugHandler(); if (debugHandlerID != null) { try { debugHandler = DebugHandlersRegistry.getHandler(debugHandlerID); } catch (Exception e) { PHPDebugPlugin.log(e); } } } // If couldn't find contributed IDebugHandler - use default if (debugHandler == null) { debugHandler = new ServerDebugHandler(); } debugHandler.setDebugTarget(this); debugger = debugHandler.getRemoteDebugger(); fThread = new PHPThread(this); fThreads = new IThread[] { fThread }; fTerminated = false; // create response handlers fPHPResponseHandler = new PHPResponseHandler(this); fStartResponseHandler = fPHPResponseHandler.new StartResponseHandler(); fBreakpointAddedResponseHandler = fPHPResponseHandler.new BreakpointAddedResponseHandler(); fBreakpointRemovedResponseHandler = fPHPResponseHandler.new BreakpointRemovedResponseHandler(); fStepIntoResponseHandler = fPHPResponseHandler.new StepIntoResponseHandler(); fStepOverResponseHandler = fPHPResponseHandler.new StepOverResponseHandler(); fStepOutResponseHandler = fPHPResponseHandler.new StepOutResponseHandler(); fGoResponseHandler = fPHPResponseHandler.new GoResponseHandler(); fPauseResponseHandler = fPHPResponseHandler.new PauseResponseHandler(); fAddFilesResponseHandler = fPHPResponseHandler.new AddFilesResponseHandler(); fSuspendCount = 0; fContextManager = new ContextManager(this, debugger); fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager(); fBreakpointManager.addBreakpointListener(this); fBreakpointManager.addBreakpointManagerListener(this); fAddFilesPaths = new HashSet<String>(); } public IProcess getProcess() { return fProcess; } public IRemoteDebugger getRemoteDebugger() { return debugger; } /* * (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 !fTerminated && fThreads.length > 0; } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IDebugTarget#getName() */ public String getName() throws DebugException { if (fName == null) { fName = fURL; } return fName; } public String getURL() { return fURL; } int getLastStop() { return fLastStop; } public String getLastFileName() { return fLastFileName; } public int getSuspendCount() { return fSuspendCount; } /* * (non-Javadoc) * * @see * org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse * .debug.core.model.IBreakpoint) */ public boolean supportsBreakpoint(IBreakpoint breakpoint) { if (breakpoint.getModelIdentifier().equals(IPHPDebugConstants.ID_PHP_DEBUG_CORE)) { if (breakpoint instanceof IPHPExceptionBreakpoint) // Not supported return false; boolean support = fBreakpointSet.supportsBreakpoint(breakpoint); return support; } return false; } /* * (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 !fTerminated; } /* * (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 { StartLock startLock = getStartLock(); // Don't synchronize on lock, debugger may be hung. Just terminate. if (!startLock.isStarted()) { terminated(); fTermainateCalled = true; return; } IThread[] threads = getThreads(); if (threads != null && threads.length > 0) { ((PHPThread) threads[0]).setStepping(false); } fTerminated = true; fSuspended = false; fLastcmd = "terminate"; //$NON-NLS-1$ Logger.debugMSG("PHPDebugTarget: Calling closeDebugSession()"); //$NON-NLS-1$ debugger.closeDebugSession(); terminated(); fTermainateCalled = true; } /** * Called when this debug target terminates. */ public void terminated() { fTerminated = true; fSuspended = false; Logger.debugMSG("PHPDebugTarget: Calling debugger.closeConnection()"); //$NON-NLS-1$ if (!fTermainateCalled) { debugger.closeConnection(); } completeTerminated(); PHPSessionLaunchMapper.updateSystemProperty(DebugPlugin.getDefault().getLaunchManager().getLaunches()); } private void completeTerminated() { fTerminated = true; fSuspended = false; fThreads = new IThread[0]; Logger.debugMSG("PHPDebugTarget: Calling removeBreakpointListener(this);"); //$NON-NLS-1$ DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(this); DebugPlugin.getDefault().getBreakpointManager().removeBreakpointManagerListener(this); Logger.debugMSG("PHPDebugTarget: Firing terminate"); //$NON-NLS-1$ fireTerminateEvent(); // Refresh the launch-viewer to display the debug elements in their real // terminated state. // This is needed since the migration to 3.3 (Europa) Display.getDefault().asyncExec(new Runnable() { public void run() { IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (activeWorkbenchWindow == null) { return; } IWorkbenchPage page = activeWorkbenchWindow.getActivePage(); if (page == null) return; AbstractDebugView view = (AbstractDebugView) page.findView(IDebugUIConstants.ID_DEBUG_VIEW); if (view == null) return; view.getViewer().refresh(); } }); } /* * (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 fSuspended; } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.ISuspendResume#resume() */ public void resume() throws DebugException { fLastcmd = "resume"; //$NON-NLS-1$ // Fix for bug #163780 - Debugger irregular state control // Call for the resumed before the debugger.stepOut int detail = DebugEvent.CLIENT_REQUEST; resumed(detail); ((PHPThread) getThreads()[0]).setStepping(false); fStatus = debugger.go(fGoResponseHandler); if (!fStatus) { Logger.log(Logger.ERROR, "PHPDebugTarget: debugger.go return false"); //$NON-NLS-1$ } } /** * Notification the target has resumed for the given reason * * @param detail * reason for the resume */ private void resumed(int detail) { fSuspended = false; fThread.fireResumeEvent(detail); } /** * Notification the target has suspended for the given reason * * @param detail * reason for the suspend */ public void suspended(int detail) { fSuspended = true; fSuspendCount++; System.setProperty("org.eclipse.debugger.variables", "true"); //$NON-NLS-1$ //$NON-NLS-2$ try { ((PHPThread) getThreads()[0]).setStepping(false); } catch (DebugException e) { // PHPThread doesn't throw exception } fThread.fireSuspendEvent(detail); } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.ISuspendResume#suspend() */ public void suspend() throws DebugException { fLastcmd = "suspend"; //$NON-NLS-1$ ((PHPThread) getThreads()[0]).setStepping(false); fStatus = debugger.pause(fPauseResponseHandler); if (!fStatus) { Logger.log(Logger.ERROR, "PHPDebugTarget: debugger.pause return false"); //$NON-NLS-1$ } int detail = DebugEvent.CLIENT_REQUEST; suspended(detail); } /* * (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()) { fLastcmd = "breakpointAdded"; //$NON-NLS-1$ PHPLineBreakpoint bp = (PHPLineBreakpoint) breakpoint; IMarker marker = bp.getMarker(); Breakpoint runtimeBreakpoint = bp.getRuntimeBreakpoint(); int lineNumber = runtimeBreakpoint.getLineNumber(); String fileName = null; if (breakpoint instanceof PHPRunToLineBreakpoint) { PHPRunToLineBreakpoint rtl = (PHPRunToLineBreakpoint) breakpoint; IResource resource = rtl.getSourceFile(); fileName = resource.getFullPath().toString(); } else { lineNumber = marker.getAttribute(IMarker.LINE_NUMBER, 0); runtimeBreakpoint.setLineNumber(lineNumber); } if (fileName == null) { fileName = (String) marker.getAttribute( StructuredResourceMarkerAnnotationModel.SECONDARY_ID_KEY, (String) marker.getAttribute(IMarker.LOCATION)); IPath localPath = EnvironmentPathUtils.getLocalPath(Path.fromPortableString(fileName)); fileName = localPath.toString(); } fileName = RemoteDebugger.convertToRemoteFilename(fileName, this); runtimeBreakpoint.setFileName(fileName); Logger.debugMSG("PHPDebugTarget: Setting Breakpoint - File " //$NON-NLS-1$ + fileName + " Line Number " + lineNumber); //$NON-NLS-1$ debugger.addBreakpoint(bp.getRuntimeBreakpoint(), fBreakpointAddedResponseHandler); } } catch (CoreException e1) { Logger.logException("PHPDebugTarget: Exception Adding Breakpoint", e1); //$NON-NLS-1$ } } } /* * (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)) { if (breakpoint instanceof PHPRunToLineBreakpoint) return; fLastcmd = "breakpointRemoved"; //$NON-NLS-1$ PHPLineBreakpoint bp = (PHPLineBreakpoint) breakpoint; Breakpoint runtimeBreakpoint = bp.getRuntimeBreakpoint(); Logger.debugMSG("PHPDebugTarget: Removing Breakpoint - File " //$NON-NLS-1$ + runtimeBreakpoint.getFileName() + " Line Number " //$NON-NLS-1$ + runtimeBreakpoint.getLineNumber()); fStatus = debugger.removeBreakpoint(runtimeBreakpoint, fBreakpointRemovedResponseHandler); if (!fStatus && debugger.isActive()) { Logger.log(Logger.ERROR, "PHPDebugTarget: debugger.removeBreakpoint return false"); //$NON-NLS-1$ } } } /* * (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 (!fBreakpointManager.isEnabled()) return; int deltaLNumber = delta.getAttribute(IMarker.LINE_NUMBER, 0); IMarker marker = breakpoint.getMarker(); int lineNumber = marker.getAttribute(IMarker.LINE_NUMBER, 0); if (supportsBreakpoint(breakpoint)) { try { if (((PHPLineBreakpoint) breakpoint).isConditionChanged()) { ((PHPLineBreakpoint) breakpoint).setConditionChanged(false); if (breakpoint.isEnabled()) { breakpointRemoved(breakpoint, null); } else { return; } } if (lineNumber != deltaLNumber) { if (breakpoint.isEnabled()) { breakpointRemoved(breakpoint, null); } else { return; } } if (breakpoint.isEnabled()) { breakpointAdded(breakpoint); } else { breakpointRemoved(breakpoint, null); } } catch (CoreException e) { Logger.logException("PHPDebugTarget: Exception Changing Breakpoint", e); //$NON-NLS-1$ } } } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect() */ public boolean canDisconnect() { return false; } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IDisconnect#disconnect() */ public void disconnect() throws DebugException { } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected() */ public boolean isDisconnected() { return false; } /* * (non-Javadoc) * * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval# * supportsStorageRetrieval () */ public boolean supportsStorageRetrieval() { return false; } /* * (non-Javadoc) * * @see * org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, * long) */ public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { return null; } /** * Notification we have connected to the debugger and it has started. . */ public void started() { fSuspended = false; fireCreationEvent(); } /** * Install breakpoints that are already registered with the breakpoint * manager. In case {@link #isRunWithDebug()} returns true, nothing will * happen. */ public void installDeferredBreakpoints() throws CoreException { /* * if (fIsRunAsDebug) { return; } if (!fBreakpointManager.isEnabled()) * return; IBreakpoint[] breakpoints = * fBreakpointManager.getBreakpoints( * IPHPDebugConstants.ID_PHP_DEBUG_CORE); for (IBreakpoint element : * breakpoints) { ((PHPLineBreakpoint) * element).setConditionChanged(false); if (element.isEnabled()){ * breakpointAdded(element); } } */ } /** * Returns the current stack frames in the target. * * @return the current stack frames in the target * @throws DebugException * if unable to perform the request */ protected IStackFrame[] getStackFrames() throws DebugException { return fContextManager.getStackFrames(); } /** * Returns the Expression Manager for the Debug Target. * * @return the current Expression Manager target */ public DefaultExpressionsManager getExpressionManager() { return expressionsManager; } public void setExpressionManager(DefaultExpressionsManager expressionManager) { this.expressionsManager = expressionManager; } /** * Step Return the debugger. * * @throws DebugException * if the request fails */ protected void stepReturn() throws DebugException { fLastcmd = "stepReturn"; //$NON-NLS-1$ Logger.debugMSG("PHPDebugTarget: stepReturn "); //$NON-NLS-1$ // Fix for bug #163780 - Debugger irregular state control // Call for the resumed before the debugger.stepOut int detail = DebugEvent.STEP_RETURN; resumed(detail); fStatus = debugger.stepOut(fStepOutResponseHandler); if (!fStatus) { Logger.log(Logger.ERROR_DEBUG, "PHPDebugTarget: debugger.stepOut return false"); //$NON-NLS-1$ } } /** * Step Over the debugger. * * @throws DebugException * if the request fails */ protected void stepOver() throws DebugException { fLastcmd = "stepOver"; //$NON-NLS-1$ Logger.debugMSG("PHPDebugTarget: stepOver"); //$NON-NLS-1$ // Fix for bug #163780 - Debugger irregular state control // Call for the resumed before the debugger.stepOver int detail = DebugEvent.STEP_OVER; resumed(detail); fStatus = debugger.stepOver(fStepOverResponseHandler); if (!fStatus) { Logger.log(Logger.ERROR_DEBUG, "PHPDebugTarget: debugger.stepOver return false"); //$NON-NLS-1$ } } /** * Step Into the debugger. * * @throws DebugException * if the request fails */ protected void stepInto() throws DebugException { Logger.debugMSG("PHPDebugTarget: stepInto "); //$NON-NLS-1$ fLastcmd = "stepInto"; //$NON-NLS-1$ // Fix for bug #163780 - Debugger irregular state control // Call for the resumed before the debugger.stepInto int detail = DebugEvent.STEP_INTO; resumed(detail); fStatus = debugger.stepInto(fStepIntoResponseHandler); if (!fStatus) { Logger.log(Logger.ERROR_DEBUG, "PHPDebugTarget: debugger.stepInto return false"); //$NON-NLS-1$ } } /** * Returns the Local Variabales for the Debug Target. * * @return the Local Variabales for the target */ public IVariable[] getVariables(PHPStackFrame stackFrame) { return fContextManager.getVariables(stackFrame); } /** * Notification a breakpoint was encountered. Determine which breakpoint was * hit and fire a suspend event. * * @param event * debug event */ public void breakpointHit(String fileName, int lineNumber) { // determine which breakpoint was hit, and set the thread's breakpoint IBreakpoint breakpoint = findBreakpoint(fileName, lineNumber); if (breakpoint != null) { fThread.setBreakpoints(new IBreakpoint[] { breakpoint }); } else { fThread.setBreakpoints(new IBreakpoint[] {}); } suspended(DebugEvent.BREAKPOINT); } /** * Finds the breakpoint hit * * @param fileName * Filename containing the breakpoint * @param lineNumber * Linenumber of breakpoint * @return the Local Variabales for the target * */ protected IBreakpoint findBreakpoint(String fileName, int lineNumber) { // determine which breakpoint was hit, and set the thread's breakpoint IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager() .getBreakpoints(IPHPDebugConstants.ID_PHP_DEBUG_CORE); for (IBreakpoint breakpoint : breakpoints) { if (supportsBreakpoint(breakpoint)) { if (breakpoint instanceof PHPLineBreakpoint) { PHPLineBreakpoint lineBreakpoint = (PHPLineBreakpoint) breakpoint; Breakpoint zBP = lineBreakpoint.getRuntimeBreakpoint(); String bFileName = zBP.getFileName(); int bLineNumber = zBP.getLineNumber(); if (bLineNumber == lineNumber && bFileName.equals(fileName)) { return breakpoint; } } } } return null; } /** * Finds the breakpoint hit * * @param enabled * Enabled or Disable breakpoints. * */ public void breakpointManagerEnablementChanged(boolean enabled) { IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager() .getBreakpoints(getModelIdentifier()); for (IBreakpoint element : breakpoints) { if (supportsBreakpoint(element)) { if (enabled) { ((PHPLineBreakpoint) element).setConditionChanged(false); breakpointAdded(element); } else { breakpointRemoved(element, null); } } } } /** * Registers the given event listener. The listener will be notified of * events in the program being interpretted. Has no effect if the listener * is already registered. * * @param listener * event listener */ public void addConsoleEventListener(IPHPConsoleEventListener listener) { if (!fConsoleEventListeners.contains(listener)) { fConsoleEventListeners.add(listener); } for (DebugError debugError : fDebugErrors) { listener.handleEvent(debugError); } } /** * Deregisters the given event listener. Has no effect if the listener is * not currently registered. * * @param listener * event listener */ public void removeConsoleEventListener(IPHPConsoleEventListener listener) { fConsoleEventListeners.remove(listener); } public List<IPHPConsoleEventListener> getConsoleEventListeners() { return fConsoleEventListeners; } /** * Returns the Output buffer for the Debug Target. * * @return the Output buffer for the target */ public DebugOutput getOutputBuffer() { return fDebugOutput; } /** * Returns whether running with debug info. * * @return boolean - whether running with debug info */ public boolean isRunWithDebug() { return fIsRunAsDebug; } /** * Throws a IStatus in a Debug Event * */ public void fireError(String errorMessage, Exception e1) { Status status = new Status(IStatus.ERROR, PHPDebugPlugin.getID(), IPHPDebugConstants.INTERNAL_ERROR, errorMessage, e1); DebugEvent event = new DebugEvent(this, DebugEvent.MODEL_SPECIFIC); event.setData(status); fireEvent(event); } /** * Throws a IStatus in a Debug Event * */ public void fireError(IStatus status) { DebugEvent event = new DebugEvent(this, DebugEvent.MODEL_SPECIFIC); event.setData(status); fireEvent(event); } public void setLastStop(int lineNumber) { fLastStop = lineNumber; } public void setLastFileName(String string) { fLastFileName = string; } public void setBreakpoints(IBreakpoint[] breakpoints) { fThread.setBreakpoints(new IBreakpoint[] {}); } public boolean isPHPCGI() { return fIsPHPCGI; } public StartLock getStartLock() { return fStartLock; } public void setLastCommand(String command) { fLastcmd = command; } public String getLastCommand() { return fLastcmd; } public int getRequestPort() { return fRequestPort; } public IProject getProject() { return fProject; } public void setProject(IProject project) { fProject = project; } public Collection<DebugError> getDebugErrors() { return fDebugErrors; } public boolean isServerWindows() { return fIsServerWindows; } public void setServerWindows(boolean isServerWindows) { fIsServerWindows = isServerWindows; } public org.eclipse.php.internal.debug.core.zend.debugger.Debugger.StartResponseHandler getStartResponseHandler() { return fStartResponseHandler; } public org.eclipse.php.internal.debug.core.zend.debugger.Debugger.AddFilesResponseHandler getAddFilesResponseHandler() { return fAddFilesResponseHandler; } public ContextManager getContextManager() { return fContextManager; } public IBreakpointManager getBreakpointManager() { return fBreakpointManager; } /** * Maps first debug file in the path mapper * * @param remoteFile * Server file path * @return mapped path entry or <code>null</code> in case of error */ public PathEntry mapFirstDebugFile(String remoteFile) { if (getContextManager().isResolveBlacklisted(remoteFile)) { return null; } try { ILaunchConfiguration launchConfiguration = getLaunch().getLaunchConfiguration(); PathMapper pathMapper = PathMapperRegistry.getByLaunchConfiguration(launchConfiguration); if (pathMapper != null) { PathEntry pathEntry = pathMapper.getLocalFile(remoteFile); // If such file doesn't exist in path mapper yet, add it: if (pathEntry == null) { // Try to find a map point: String debugFileName = launchConfiguration.getAttribute(Server.FILE_NAME, (String) null); if (debugFileName == null) { debugFileName = launchConfiguration.getAttribute(IPHPDebugConstants.ATTR_FILE, (String) null); } if (debugFileName != null) { IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(debugFileName); if (resource instanceof IFile) { pathEntry = new PathEntry(debugFileName, Type.WORKSPACE, resource.getParent()); } else if (new File(debugFileName).exists()) { pathEntry = new PathEntry(debugFileName, Type.EXTERNAL, new File(debugFileName).getParentFile()); } } if (pathEntry != null) { // Map remote file to the map point: pathMapper.addEntry(remoteFile, pathEntry, MappingSource.ENVIRONMENT); PathMapperRegistry.storeToPreferences(); } else { // Find the local file, and map it: pathEntry = DebugSearchEngine.find(remoteFile, this); } } // Assign this project to Debug Target: if (getProject() == null && pathEntry != null && pathEntry.getType() == Type.WORKSPACE) { IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(pathEntry.getPath()); IProject project = resource.getProject(); setProject(project); try { ILaunchConfigurationWorkingCopy wc = launchConfiguration.getWorkingCopy(); wc.getAttribute(IPHPDebugConstants.PHP_Project, project.getName()); wc.doSave(); } catch (CoreException e) { PHPDebugPlugin.log(e); } } return pathEntry; } } catch (Exception e) { PHPDebugPlugin.log(e); } return null; } public boolean isStepFiltersEnabled() { return isStepFiltersEnabled; } public void setStepFiltersEnabled(boolean enabled) { isStepFiltersEnabled = enabled; } public boolean supportsStepFilters() { return isStepFiltersEnabled; } /** * always return false, this concept is xdebug specific. */ public boolean isWaiting() { return false; } public boolean isFirstBreakpointAdded(IBreakpoint breakpoint) { return fAddFilesPaths.size() == 0; } public void addBreakpointFiles(IProject... projects) { if (debugger.getCurrentProtocolID() >= RemoteDebugger.PROTOCOL_ID_2012121702) { List<String> paths = new ArrayList<String>(); try { if (fBreakpointManager.isEnabled()) { List<IBreakpoint> breakpoints = new ArrayList<IBreakpoint>( Arrays.asList(fBreakpointManager.getBreakpoints(IPHPDebugConstants.ID_PHP_DEBUG_CORE))); if (breakpoints != null && breakpoints.size() > 0) { for (IProject project : projects) { getBreakpointFiles(project, paths, breakpoints); getBreakpointsIncludePath(project, paths, breakpoints); } int oldSize = fAddFilesPaths.size(); fAddFilesPaths.addAll(paths); if (oldSize < fAddFilesPaths.size()) { debugger.addFiles(fAddFilesPaths.toArray(new String[fAddFilesPaths.size()])); } } else if (fLastFileName != null) { debugger.addFiles(new String[] { fLastFileName }); } } } catch (CoreException e) { PHPDebugPlugin.log(e); } } } private void getBreakpointsIncludePath(IProject container, List<String> paths, List<IBreakpoint> breakpoints) throws CoreException { if (container == null) { String localFile = ((RemoteDebugger) debugger).convertToLocalFilename(fLastFileName); if (localFile != null) { IPath localPath = new Path(localFile); String projectName = localPath.segment(0); container = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); if (container == null || !container.exists()) { return; } } } List<IPath> includePaths = ((RemoteDebugger) debugger).getIncludePaths(fProject); for (IBreakpoint bp : breakpoints) { String secondaryId = (String) bp.getMarker() .getAttribute(StructuredResourceMarkerAnnotationModel.SECONDARY_ID_KEY); if (secondaryId != null) { IPath path = Path.fromPortableString(secondaryId); if ((path.getDevice() == null) && (path.toString().startsWith("org.eclipse.dltk"))) { //$NON-NLS-1$ String fullPathString = path.toString(); String absolutePath = fullPathString.substring(fullPathString.indexOf(':') + 1); path = Path.fromPortableString(absolutePath); } else { path = EnvironmentPathUtils.getLocalPath(path); } if (path != null) { for (IPath includePath : includePaths) { int size = includePath.segmentCount(); if (path.matchingFirstSegments(includePath) == size) { String remotePath = RemoteDebugger.convertToRemoteFilename(path.toString(), this); if (remotePath != null && remotePath.length() > 0) { paths.add(remotePath); } } } } } } } private void getBreakpointFiles(IContainer container, List<String> paths, List<IBreakpoint> breakpoints) throws CoreException { if (container == null) { String localFile = ((RemoteDebugger) debugger).convertToLocalFilename(fLastFileName); if (localFile != null) { IPath localPath = new Path(localFile); String projectName = localPath.segment(0); container = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); if (container == null || !container.exists()) { return; } } } IResource[] members = container.members(); for (IResource res : members) { if (res instanceof IContainer) { getBreakpointFiles((IContainer) res, paths, breakpoints); } else { List<IBreakpoint> toRemove = new ArrayList<IBreakpoint>(); for (IBreakpoint bp : breakpoints) { if (bp.getMarker().getResource().equals(res)) { String remotePath = RemoteDebugger.convertToRemoteFilename(res.getFullPath().toString(), this); if (remotePath != null && remotePath.length() > 0) { paths.add(remotePath); toRemove.add(bp); } break; } } breakpoints.removeAll(toRemove); } } } }