4 package net.sourceforge.phpeclipse.xdebug.php.model;
6 //import java.io.ByteArrayInputStream;
7 //import java.io.IOException;
10 import javax.xml.parsers.DocumentBuilder;
11 import javax.xml.parsers.DocumentBuilderFactory;
12 import javax.xml.parsers.ParserConfigurationException;
14 import net.sourceforge.phpeclipse.xdebug.core.IPHPDebugEvent;
15 import net.sourceforge.phpeclipse.xdebug.core.IProxyEventListener;
16 import net.sourceforge.phpeclipse.xdebug.core.IXDebugPreferenceConstants;
17 import net.sourceforge.phpeclipse.xdebug.core.PHPDebugUtils;
18 import net.sourceforge.phpeclipse.xdebug.core.PathMapItem;
19 import net.sourceforge.phpeclipse.xdebug.core.XDebugCorePlugin;
20 import net.sourceforge.phpeclipse.xdebug.core.XDebugProxy;
21 import net.sourceforge.phpeclipse.xdebug.php.launching.IXDebugConstants;
23 import org.eclipse.core.resources.IMarker;
24 import org.eclipse.core.resources.IMarkerDelta;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IPath;
27 import org.eclipse.debug.core.DebugEvent;
28 import org.eclipse.debug.core.DebugException;
29 import org.eclipse.debug.core.DebugPlugin;
30 import org.eclipse.debug.core.IDebugEventSetListener;
31 import org.eclipse.debug.core.ILaunch;
33 import org.eclipse.debug.core.model.IBreakpoint;
34 import org.eclipse.debug.core.model.IDebugTarget;
35 import org.eclipse.debug.core.model.ILineBreakpoint;
36 import org.eclipse.debug.core.model.IMemoryBlock;
37 import org.eclipse.debug.core.model.IProcess;
38 import org.eclipse.debug.core.model.IThread;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.NamedNodeMap;
41 import org.w3c.dom.Node;
42 //import org.xml.sax.SAXException;
44 import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener;
45 import net.sourceforge.phpeclipse.xdebug.core.xdebug.XDebugConnection;
46 import net.sourceforge.phpeclipse.xdebug.core.xdebug.XDebugResponse;
52 public class XDebugTarget extends XDebugElement implements IDebugTarget, IDebugEventSetListener, IProxyEventListener {
53 private IProcess fProcess;
55 private ILaunch fLaunch;
57 private int fDebugPort;
59 private boolean fSuspended = false;
61 private boolean fTerminated = false;
63 private XDebugThread fThread;
64 private IThread[] fThreads;
66 private XDebugConnection fDebugConnection;
68 private ResponseListener fResponseListener;
70 private String fIdeKey;
74 * Constructs a new debug target in the given launch and waits until
75 * someone with the ideKey connects to the Debugproxy
78 * @param launch containing launch
79 * @param process process of the interpreter
81 * @exception CoreException if unable to connect to host
83 public XDebugTarget(ILaunch launch, IProcess process, String ideKey) throws CoreException {
86 fDebugConnection = null;
88 fThreads = new IThread[0];
91 fDebugPort = XDebugCorePlugin.getDefault().getPreferenceStore().getInt(IXDebugPreferenceConstants.DEBUGPORT_PREFERENCE);
92 if (fDebugPort == 0) {
93 fDebugPort = IXDebugPreferenceConstants.DEFAULT_DEBUGPORT;
96 DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this);
97 DebugPlugin.getDefault().addDebugEventListener(this);
101 * @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
103 public IProcess getProcess() {
108 * @see org.eclipse.debug.core.model.IDebugTarget#getThreads()
110 public IThread[] getThreads() throws DebugException {
115 * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads()
117 public boolean hasThreads() throws DebugException {
118 return (fThreads.length > 0);
122 * @see org.eclipse.debug.core.model.IDebugTarget#getName()
124 public String getName() throws DebugException {
125 return "PHP XDebug Client at localhost:" + fDebugPort;
129 * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint)
131 public boolean supportsBreakpoint(IBreakpoint breakpoint) {
132 if (breakpoint.getModelIdentifier().equals(IXDebugConstants.ID_PHP_DEBUG_MODEL)) {
139 * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
141 public IDebugTarget getDebugTarget() {
146 * @see org.eclipse.debug.core.model.IDebugElement#getLaunch()
148 public ILaunch getLaunch() {
153 * @see org.eclipse.debug.core.model.ITerminate#canTerminate()
155 public boolean canTerminate() {
156 if (getProcess()!=null) // ther is no running Process in remote debugging
157 return getProcess().canTerminate();
162 * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
164 public boolean isTerminated() {
165 // return getProcess().isTerminated();
170 * @see org.eclipse.debug.core.model.ITerminate#terminate()
172 public void terminate() throws DebugException {
177 if (XDebugCorePlugin.getDefault() != null) {
178 XDebugProxy proxy = XDebugCorePlugin.getDefault().getXDebugProxy();
179 proxy.removeProxyEventListener(this, fIdeKey);
181 System.out.println("XDebug.Target: ProxyEventlistener removed");
186 XDebugCorePlugin.getBreakpointManager().removeBreakpointListener(this);
187 fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
188 DebugPlugin.getDefault().removeDebugEventListener(this);
193 * @see org.eclipse.debug.core.model.ISuspendResume#canResume()
195 public boolean canResume() {
200 * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
202 public boolean canSuspend() {
207 * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
209 public boolean isSuspended() {
214 * @see org.eclipse.debug.core.model.ISuspendResume#resume()
216 public void resume() throws DebugException {
217 if (fDebugConnection != null) {
218 fThread.setBreakpoints(null);
219 resumed(DebugEvent.RESUME);
220 fDebugConnection.run();
225 * Notification the target has resumed for the given reason
227 * @param detail reason for the resume
229 private void resumed(int detail) {
231 fThread.fireResumeEvent(detail);
235 * Notification the target has suspended for the given reason
237 * @param detail reason for the suspend
239 public void suspended(int detail) {
241 fThread.fireSuspendEvent(detail);
245 * @see org.eclipse.debug.core.model.ISuspendResume#suspend()
247 public void suspend() throws DebugException {
251 * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
253 public void breakpointAdded(IBreakpoint breakpoint) {
254 IMarker marker = breakpoint.getMarker();
255 IPath path = marker.getResource().getLocation();
256 IPath cp = path.removeLastSegments(1);
259 pathMap = fLaunch.getLaunchConfiguration().getAttribute(IXDebugConstants.ATTR_PHP_PATHMAP,(List)null);
260 } catch (CoreException e2) {
261 // TODO Auto-generated catch block
262 e2.printStackTrace();
265 if (fDebugConnection != null)
266 if (!fDebugConnection.isClosed()) {
267 if (fProcess == null) {
268 PathMapItem pmi = null;
269 for (int i = 0; i < pathMap.size(); i++) {
270 pmi = new PathMapItem((String) pathMap.get(i));
271 IPath local = (IPath)pmi.getLocalPath().clone();
272 local = local.makeAbsolute();
273 int matchedSegments = local.segmentCount();
274 if (local.matchingFirstSegments(cp) == matchedSegments) {
275 IPath newPath = pmi.getRemotePath();
276 newPath = newPath.append(path.removeFirstSegments(matchedSegments));
277 newPath = newPath.makeAbsolute();
278 if (supportsBreakpoint(breakpoint)) {
280 if (breakpoint.isEnabled()) {
281 if (marker != null) {
282 int id = fDebugConnection.breakpointSet(newPath.toString(), ((ILineBreakpoint)breakpoint).getLineNumber(), marker.getAttribute(XDebugBreakpoint.HIT_COUNT,-1));
283 XDebugResponse dr = getResponse(id);
285 String bpid = dr.getAttributeValue("id");
287 if (!"".equals(bpid))
288 marker.setAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,Integer.parseInt(bpid));
291 } catch (DebugException e) {
293 } catch (CoreException e) {
300 if (supportsBreakpoint(breakpoint)) {
302 if (breakpoint.isEnabled()) {
303 if (marker != null) {
304 int id = fDebugConnection.breakpointSet(path.toString(), ((ILineBreakpoint)breakpoint).getLineNumber(), marker.getAttribute(XDebugBreakpoint.HIT_COUNT,-1));
305 XDebugResponse dr = getResponse(id);
306 String bpid = dr.getAttributeValue("id");
308 if (!"".equals(bpid))
309 marker.setAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,Integer.parseInt(bpid));
312 } catch (DebugException e) {
314 } catch (CoreException e) {
323 * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
325 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
326 if (supportsBreakpoint(breakpoint)) {
328 int id =((XDebugLineBreakpoint)breakpoint).getID();
330 fDebugConnection.breakpointRemove(id);
331 } catch (CoreException e) {
337 * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
339 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
340 // if (supportsBreakpoint(breakpoint)) {
342 // if (breakpoint.isEnabled()) {
343 // breakpointAdded(breakpoint);
345 // breakpointRemoved(breakpoint, null);
347 // } catch (CoreException e) {
353 * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
355 public boolean canDisconnect() {
360 * @see org.eclipse.debug.core.model.IDisconnect#disconnect()
362 public void disconnect() throws DebugException {
366 * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
368 public boolean isDisconnected() {
373 * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
375 public boolean supportsStorageRetrieval() {
380 * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long)
382 public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
387 * Notification we have connected to the PHP debugger and it has been started.
388 * Resume the the debugger.
390 public void started() throws DebugException {
391 fThread.setBreakpoints(null);
392 fThread.setStepping(false);
394 int id = fDebugConnection.featureGet("detach");
396 XDebugResponse response = getResponse(id);
398 Integer.parseInt(response.getValue());
399 System.out.println("in Target.started()");
402 // Need to refactory plugin to get variables in lazy mode.
403 int id1 = fDebugConnection.featureSet("max_depth", "1024" );
404 XDebugResponse response1 = getResponse(id1);
405 if (response1.getAttributeValue("success").equals("1") ) {
406 System.out.println("Set depth to 1024 (hack)");
408 int id2 = fDebugConnection.featureSet("max_children", "1024" );
409 XDebugResponse response2 = getResponse(id2);
410 if (response2.getAttributeValue("success").equals("1") ) {
411 System.out.println("Set children to 1024 (hack)");
414 installDeferredBreakpoints();
417 } catch (DebugException e) {
423 * Install breakpoints that are already registered with the breakpoint
426 private void installDeferredBreakpoints() {
427 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
428 for (int i = 0; i < breakpoints.length; i++) {
429 breakpointAdded(breakpoints[i]);
434 * Returns the current stack frames in the target.
436 * @return the current stack frames in the target
437 * @throws DebugException if unable to perform the request
439 public XDebugResponse getStackFrames() throws DebugException {
440 int id = fDebugConnection.stackGet();
441 XDebugResponse lastResponse = getResponse(id);
446 * Single step the interpreter.
448 * @throws DebugException if the request fails
450 protected void step_over() throws DebugException {
451 fThread.setStepping(true);
452 resumed(DebugEvent.STEP_OVER);
453 fDebugConnection.stepOver();
457 * Single step the interpreter.
459 * @throws DebugException if the request fails
461 protected void step_into() throws DebugException {
462 fThread.setStepping(true);
463 resumed(DebugEvent.STEP_INTO);
464 fDebugConnection.stepInto();
468 * Single step the interpreter.
470 * @throws DebugException if the request fails
472 protected void step_out() throws DebugException {
473 fThread.setStepping(true);
474 resumed(DebugEvent.STEP_RETURN);
475 fDebugConnection.stepOut();
478 public boolean setVarValue(String name, String value) {
479 int id = fDebugConnection.setVarValue(name,value);
480 XDebugResponse response = getResponse(id);
482 if ((response.getAttributeValue("success")).equals("1")) {
489 public Node eval(String expression) throws DebugException {
490 Node evalProperty = null;
491 if (fDebugConnection != null) {
492 int id = fDebugConnection.eval(expression);
493 //Node evalProperty = new Node("");
495 XDebugResponse response = getResponse(id);
497 Node evalResponse = response.getParentNode();
498 /*Node*/ evalProperty = evalResponse.getFirstChild();
503 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
504 DocumentBuilder builder = null;
508 builder = factory.newDocumentBuilder();
509 } catch (ParserConfigurationException e) {
513 doc = builder.newDocument(); // .parse("");
514 evalProperty = doc.createElement("value");
515 /*} catch (SAXException e) {
517 } catch (IOException e) {
525 public void handleDebugEvents(DebugEvent[] events) {
526 for (int i = 0; i < events.length; i++) {
527 DebugEvent event = events[i];
529 if (fResponseListener != null) {
531 s = event.getSource();
532 if (s instanceof ResponseListener) {
533 if (!fResponseListener.equals((ResponseListener) s)) {
541 if (event.getKind() == DebugEvent.MODEL_SPECIFIC) {
542 switch (event.getDetail()) {
543 case IPHPDebugEvent.BREAKPOINT_HIT:
544 int id = fDebugConnection.stackGet();
545 XDebugResponse lastResponse = getResponse(id);
547 IBreakpoint breakpoint = breakpointHit(lastResponse.getParentNode());
549 if (breakpoint != null) {
550 fThread.setBreakpoints(new IBreakpoint[]{breakpoint});
551 fThread.incrementStepCounter();
552 suspended(DebugEvent.BREAKPOINT);
556 } catch (DebugException e ) {
561 case IPHPDebugEvent.STEP_END:
562 fThread.incrementStepCounter();
563 suspended(DebugEvent.STEP_END);
565 case IPHPDebugEvent.STOPPED:
573 public void stopped() {
574 if(fDebugConnection == null) {
578 resumed(DebugEvent.TERMINATE);
581 fDebugConnection.close();
585 // Dirty hack to check debugging mode (remote or local)
586 if (fProcess != null) {
589 } catch (DebugException e) {
593 fDebugConnection = null;
594 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
597 fThread.removeEventListeners();
599 fThreads = new IThread[0];
602 public void handleProxyEvent(XDebugConnection connection) {
603 setDebugConnection(connection);
604 //System.out.println("* New Connection - XDebug.Target: " + fDebugConnection.getSessionID());
606 fThread = new XDebugThread(this);
607 fThreads = new IThread[] {fThread};
608 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
611 } catch( DebugException e ){
616 private void setDebugConnection(XDebugConnection connection) {
617 if (connection != null) {
618 fDebugConnection = connection;
619 fResponseListener = new ResponseListener(connection);
625 * @return Returns the fDebugConnection.
627 public XDebugConnection getDebugConnection() {
628 return fDebugConnection;
631 public void addProcess(IProcess p) {
635 public Node getLocalVariables(int level) throws DebugException {
636 int id = fDebugConnection.contextGet(level, 0);
637 XDebugResponse response = getResponse(id);
639 return response.getParentNode();
642 public Node getGlobalVariables(int level) throws DebugException {
643 int id = fDebugConnection.contextGet(level, 1);
644 XDebugResponse response = getResponse(id);
646 return response.getParentNode();
650 fDebugConnection.stop();
653 protected IBreakpoint breakpointHit(Node node) {
654 Node child = node.getFirstChild();
655 if (child.getNodeName().equals("stack")) {
656 int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "lineno"));
657 String filename = PHPDebugUtils.getAttributeValue(child, "filename");
658 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
659 for (int i = 0; i < breakpoints.length; i++) {
660 IBreakpoint breakpoint = breakpoints[i];
661 if (supportsBreakpoint(breakpoint)) {
662 if (breakpoint instanceof ILineBreakpoint) {
663 ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoint;
665 if (breakpoint.isEnabled()) {
666 IMarker marker = breakpoint.getMarker();
667 if (marker != null) {
670 if (getProcess() == null) {
671 endfilename = marker.getResource().getLocation().lastSegment();
673 endfilename = marker.getResource().getLocation().toOSString();
676 int id = fDebugConnection.breakpointGet(marker.getAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,-1));
677 XDebugResponse dr = getResponse(id);
679 Node hitCo = dr.getParentNode().getFirstChild();
681 if (hitCo.hasAttributes()) {
682 NamedNodeMap listAttribute = hitCo.getAttributes();
683 Node attribute = listAttribute.getNamedItem("hit_count");
684 if (attribute !=null) {
685 hitCount = Integer.parseInt(attribute.getNodeValue());
689 if(PHPDebugUtils.unescapeString(filename).endsWith(endfilename)
690 && (lineBreakpoint.getLineNumber() == lineNumber) ) {
691 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) > 0) {
692 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) == hitCount) {
701 } catch (CoreException e) {
711 public void startListener() {
712 fResponseListener.schedule();
715 public void stopListener() {
716 fResponseListener.cancel();
718 public XDebugResponse getResponse(int id) {
719 XDebugResponse response = fResponseListener.getResponse(id);