--- /dev/null
+/**
+ *
+ */
+package net.sourceforge.phpeclipse.xdebug.php.model;
+
+import net.sourceforge.phpeclipse.xdebug.core.Base64;
+import net.sourceforge.phpeclipse.xdebug.core.DebugConnection;
+import net.sourceforge.phpeclipse.xdebug.core.PHPDebugUtils;
+import net.sourceforge.phpeclipse.xdebug.core.XDebugCorePlugin;
+import net.sourceforge.phpeclipse.xdebug.core.DebugConnection.DebugResponse;
+import net.sourceforge.phpeclipse.xdebug.php.launching.IXDebugConstants;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IDebugEventSetListener;
+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.ILineBreakpoint;
+import org.eclipse.debug.core.model.IMemoryBlock;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.core.model.IThread;
+import org.eclipse.debug.core.model.IValue;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * @author Christian
+ *
+ */
+public class XDebugTarget extends XDebugElement implements IDebugTarget,
+ IDebugEventSetListener {
+ // associated system process (VM)
+ private IProcess fProcess;
+
+ // containing launch object
+ private ILaunch fLaunch;
+
+ // debugPort
+ private int fDebugPort;
+
+ // program name
+ // private String fName;
+
+ // suspend state
+ private boolean fSuspended = true;
+
+ // terminated state
+ private boolean fTerminated = false;
+
+ // threads
+ private XDebugThread fThread;
+
+ private IThread[] fThreads;
+
+ // event dispatch job
+ // private EventDispatchJob fEventDispatch;
+
+ private DebugConnection fDebugConnection;
+
+ // private DebugResponse lastResponse;
+
+ /**
+ * Constructs a new debug target in the given launch for the associated PDA
+ * VM process.
+ *
+ * @param launch
+ * containing launch
+ * @param debugPort
+ * port to read events from
+ * @exception CoreException
+ * if unable to connect to host
+ */
+ public XDebugTarget(ILaunch launch, IProcess process, int debugPort)
+ throws CoreException {
+ super(null);
+ fLaunch = launch;
+ fProcess = process;
+ fTarget = this;
+ fDebugConnection = new DebugConnection(this, debugPort);
+ fThread = new XDebugThread(this);
+ fThreads = new IThread[] { fThread };
+ DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(
+ this);
+ DebugPlugin.getDefault().addDebugEventListener(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
+ */
+ public IProcess getProcess() {
+ return fProcess;
+ }
+
+ /*
+ * (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 (fThreads.length > 0);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.IDebugTarget#getName()
+ */
+ public String getName() throws DebugException {
+ return "PHP XDebug Client at localhost:" + fDebugPort;
+ }
+
+ /*
+ * (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(
+ IXDebugConstants.ID_PHP_DEBUG_MODEL)) {
+ return true;
+ }
+ 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 getProcess().canTerminate();
+ // return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
+ */
+ public boolean isTerminated() {
+ // return getProcess().isTerminated();
+ return fTerminated;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.ITerminate#terminate()
+ */
+ public void terminate() throws DebugException {
+ fDebugConnection.sendRequest("stop");
+ }
+
+ /*
+ * (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 {
+ fDebugConnection.sendRequest("run");
+ }
+
+ /**
+ * 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;
+ fThread.fireSuspendEvent(detail);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.ISuspendResume#suspend()
+ */
+ public void suspend() throws DebugException {
+ }
+
+ /*
+ * (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()) {
+ IMarker marker = breakpoint.getMarker();
+ if (marker != null) {
+ try {
+ String fileName = PHPDebugUtils.escapeString(marker
+ .getResource().getLocation().toString());
+ String arg = "-t line -f file:///"
+ + fileName
+ + " -n "
+ + ((ILineBreakpoint) breakpoint)
+ .getLineNumber();
+ int id = fDebugConnection.sendRequest(
+ "breakpoint_set", arg);
+ // set the marker Attribute to make later
+ // idetification possible
+ // TODO: make sure that attribute is set before
+ // response from debugger is beeing prosessed
+ marker.setAttribute(
+ XDebugLineBreakpoint.BREAKPOINT_ID, id);
+
+ } catch (CoreException e) {
+ }
+ }
+ }
+ } 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 {
+ int id = ((XDebugLineBreakpoint) breakpoint).getID();
+ if (id > 0)
+ fDebugConnection.sendRequest("breakpoint_remove", "-d "
+ + id);
+ } catch (CoreException e) {
+ }
+ }
+ }
+
+ /*
+ * (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()) {
+ // breakpointAdded(breakpoint);
+ // } else {
+ // breakpointRemoved(breakpoint, null);
+ // }
+ // } catch (CoreException e) {
+ // }
+ // }
+ }
+
+ /*
+ * (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 PHP debugger and it has started.
+ * Resume the the debugger.
+ */
+ public void started() {
+
+ fThread.setBreakpoints(null);
+ fThread.setStepping(false);
+
+ installDeferredBreakpoints();
+ try {
+ resume();
+ // step();
+ } catch (DebugException e) {
+ }
+ }
+
+ /**
+ * Install breakpoints that are already registered with the breakpoint
+ * manager.
+ */
+ private void installDeferredBreakpoints() {
+ IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
+ for (int i = 0; i < breakpoints.length; i++) {
+ breakpointAdded(breakpoints[i]);
+ }
+ }
+
+ /**
+ * Called when this debug target terminates.
+ */
+ public void terminated() {
+ fTerminated = true;
+ fSuspended = false;
+ XDebugCorePlugin.getBreakpointManager().removeBreakpointListener(this);
+ fireTerminateEvent();
+ DebugPlugin.getDefault().removeDebugEventListener(this);
+ fThread.removeEventListeners();
+ }
+
+ /**
+ * 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 {
+ int id = fDebugConnection.sendRequest("stack_get");
+ DebugResponse lastResponse = fDebugConnection.waitforTransID(id);
+ if (lastResponse.isError())
+ return new IStackFrame[0];
+ Node response = lastResponse.getParentNode();
+ NodeList frames = response.getChildNodes();
+ IStackFrame[] theFrames = new IStackFrame[frames.getLength()];
+ for (int i = 0; i < frames.getLength(); i++) {
+ Node stackNode = frames.item(i);
+ theFrames[i] = new XDebugStackFrame(fThread, stackNode, i);
+ }
+ return theFrames;
+ }
+
+ /**
+ * Single step the interpreter.
+ *
+ * @throws DebugException
+ * if the request fails
+ */
+ protected void step_over() throws DebugException {
+ fThread.setStepping(true);
+ resumed(DebugEvent.STEP_OVER);
+ fDebugConnection.sendRequest("step_over");
+ }
+
+ /**
+ * Single step the interpreter.
+ *
+ * @throws DebugException
+ * if the request fails
+ */
+ protected void step_into() throws DebugException {
+ fThread.setStepping(true);
+ resumed(DebugEvent.STEP_INTO);
+ fDebugConnection.sendRequest("step_into");
+ }
+
+ /**
+ * Single step the interpreter.
+ *
+ * @throws DebugException
+ * if the request fails
+ */
+ protected void step_out() throws DebugException {
+ fThread.setStepping(true);
+ resumed(DebugEvent.STEP_RETURN);
+ fDebugConnection.sendRequest("step_out");
+ }
+
+ /**
+ * Returns the current value of the given variable.
+ *
+ * @param variable
+ * @return variable value
+ * @throws DebugException
+ * if the request fails
+ */
+ protected IValue getVariableValue(XDebugVariable variable)
+ throws DebugException {
+ // synchronized (fDebugSocket) {
+ // fDebugConnection.sendRequest("var","" +
+ // variable.getStackFrame().getIdentifier() + " " + variable.getName());
+ // try {
+ // String value = fDebugReader.readLine();
+ // //return new XDebugValue(this, value);
+ //
+ // } catch (IOException e) {
+ // abort(MessageFormat.format("Unable to retrieve value for variable
+ // {0}", new String[]{variable.getName()}), e);
+ // }
+ // }
+ return null;
+ }
+
+ /**
+ * Returns the values on the data stack (top down)
+ *
+ * @return the values on the data stack (top down)
+ */
+ public IValue[] getDataStack() throws DebugException {
+ // synchronized (fDebugSocket) {
+ // fDebugConnection.sendRequest ("data");
+ // try {
+ // String valueString = fDebugReader.readLine();
+ // if (valueString != null && valueString.length() > 0) {
+ // String[] values = valueString.split("\\|");
+ // IValue[] theValues = new IValue[values.length];
+ // for (int i = 0; i < values.length; i++) {
+ // String value = values[values.length - i - 1];
+ // // theValues[i] = new XDebugValue(this, value);
+ // }
+ // return theValues;
+ // }
+ // } catch (IOException e) {
+ // abort("Unable to retrieve data stack", e);
+ // }
+ // }
+ return new IValue[0];
+ }
+
+ public boolean setVarValue(String name, String value) {
+ int id = -1;
+ String str = Base64.encodeBytes(value.getBytes());
+ int len = str.length();
+
+ try {
+ id = fDebugConnection.sendRequest("property_set", "-n " + name
+ + " -l " + len + " -- " + str);
+ } catch (DebugException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ DebugResponse dr = getResponse(id);
+ if ((dr.getAttributeValue("success")).equals("1"))
+ return true;
+
+ return false;
+ }
+
+ public DebugResponse getResponse(int id) {
+ return fDebugConnection.waitforTransID(id);
+ }
+
+ /**
+ * Sends a request to the Debugengine and waits for an OK.
+ *
+ * @param command
+ * debug command
+ * @throws DebugException
+ * if the request fails
+ */
+
+ public int sendRequest(String command) throws DebugException {
+ return fDebugConnection.sendRequest(command, "");
+ }
+
+ /**
+ * Sends a request to the Debugengine and waits for an OK.
+ *
+ * @param command
+ * debug command
+ * @arguments arguments for the command
+ * @throws DebugException
+ * if the request fails
+ */
+
+ public int sendRequest(String command, String arguments)
+ throws DebugException {
+ return fDebugConnection.sendRequest(command, arguments);
+ }
+
+ /**
+ * Notification a breakpoint was encountered. Determine which breakpoint was
+ * hit and fire a suspend event.
+ *
+ * @param event
+ * debug event
+ */
+ public void breakpointHit(Node node) {
+ // determine which breakpoint was hit, and set the thread's breakpoint
+ Node child = node.getFirstChild();
+ if (child.getNodeName().equals("stack")) {
+ int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue(
+ child, "lineno"));
+ String filename = PHPDebugUtils
+ .getAttributeValue(child, "filename").substring(8); // remove
+ // file:///
+ IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
+ for (int i = 0; i < breakpoints.length; i++) {
+ IBreakpoint breakpoint = breakpoints[i];
+ if (supportsBreakpoint(breakpoint)) {
+ if (breakpoint instanceof ILineBreakpoint) {
+ ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoint;
+ try {
+ if (breakpoint.isEnabled()) {
+ IMarker marker = breakpoint.getMarker();
+ if (marker != null) {
+
+ String name = marker.getResource()
+ .getLocation().toOSString();
+ if (name.equals(PHPDebugUtils
+ .unescapeString(filename))
+ && (lineBreakpoint.getLineNumber() == lineNumber)) {
+ fThread
+ .setBreakpoints(new IBreakpoint[] { breakpoint });
+ break;
+ }
+ }
+
+ }
+ } catch (CoreException e) {
+ }
+ }
+ }
+ }
+ }
+ suspended(DebugEvent.BREAKPOINT);
+ }
+
+ public void handleDebugEvents(DebugEvent[] events) {
+ for (int i = 0; i < events.length; i++) {
+ DebugEvent event = events[i];
+ if ((event.getKind() == DebugEvent.CREATE)
+ && (event.getSource() instanceof XDebugElement)) {
+ if (((XDebugElement) event.getSource()).getModelIdentifier() == IXDebugConstants.ID_PHP_DEBUG_MODEL) {
+ if (event.getKind() == DebugEvent.CREATE)
+ started();
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file