4 package net.sourceforge.phpeclipse.xdebug.php.model;
8 import net.sourceforge.phpeclipse.xdebug.core.IPHPDebugEvent;
9 import net.sourceforge.phpeclipse.xdebug.core.IProxyEventListener;
10 import net.sourceforge.phpeclipse.xdebug.core.IXDebugPreferenceConstants;
11 import net.sourceforge.phpeclipse.xdebug.core.PHPDebugUtils;
12 import net.sourceforge.phpeclipse.xdebug.core.PathMapItem;
13 import net.sourceforge.phpeclipse.xdebug.core.XDebugCorePlugin;
14 import net.sourceforge.phpeclipse.xdebug.core.XDebugProxy;
15 import net.sourceforge.phpeclipse.xdebug.php.launching.IXDebugConstants;
17 import org.eclipse.core.resources.IMarker;
18 import org.eclipse.core.resources.IMarkerDelta;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.core.runtime.IPath;
21 import org.eclipse.debug.core.DebugEvent;
22 import org.eclipse.debug.core.DebugException;
23 import org.eclipse.debug.core.DebugPlugin;
24 import org.eclipse.debug.core.IDebugEventSetListener;
25 import org.eclipse.debug.core.ILaunch;
27 import org.eclipse.debug.core.model.IBreakpoint;
28 import org.eclipse.debug.core.model.IDebugTarget;
29 import org.eclipse.debug.core.model.ILineBreakpoint;
30 import org.eclipse.debug.core.model.IMemoryBlock;
31 import org.eclipse.debug.core.model.IProcess;
32 import org.eclipse.debug.core.model.IThread;
33 import org.w3c.dom.NamedNodeMap;
34 import org.w3c.dom.Node;
36 import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener;
37 import net.sourceforge.phpeclipse.xdebug.core.xdebug.XDebugConnection;
38 import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener.XDebugResponse;
44 public class XDebugTarget extends XDebugElement implements IDebugTarget, IDebugEventSetListener, IProxyEventListener {
45 private IProcess fProcess;
47 private ILaunch fLaunch;
49 private int fDebugPort;
51 private boolean fSuspended = false;
53 private boolean fTerminated = false;
55 private XDebugThread fThread;
56 private IThread[] fThreads;
58 private XDebugConnection fDebugConnection;
60 private ResponseListener fResponseListener;
62 private String fIdeKey;
66 * Constructs a new debug target in the given launch and waits until
67 * someone with the ideKey connects to the Debugproxy
70 * @param launch containing launch
71 * @param process process of the interpreter
73 * @param pathMap Pathmap for the debug session
74 * @exception CoreException if unable to connect to host
76 public XDebugTarget(ILaunch launch, IProcess process, String ideKey) throws CoreException {
79 fDebugConnection = null;
81 fThreads = new IThread[0];
84 fDebugPort = XDebugCorePlugin.getDefault().getPreferenceStore().getInt(IXDebugPreferenceConstants.DEBUGPORT_PREFERENCE);
85 if (fDebugPort == 0) {
86 fDebugPort = IXDebugPreferenceConstants.DEFAULT_DEBUGPORT;
89 DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this);
90 DebugPlugin.getDefault().addDebugEventListener(this);
94 * @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
96 public IProcess getProcess() {
101 * @see org.eclipse.debug.core.model.IDebugTarget#getThreads()
103 public IThread[] getThreads() throws DebugException {
108 * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads()
110 public boolean hasThreads() throws DebugException {
111 return (fThreads.length > 0);
115 * @see org.eclipse.debug.core.model.IDebugTarget#getName()
117 public String getName() throws DebugException {
118 return "PHP XDebug Client at localhost:" + fDebugPort;
122 * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint)
124 public boolean supportsBreakpoint(IBreakpoint breakpoint) {
125 if (breakpoint.getModelIdentifier().equals(IXDebugConstants.ID_PHP_DEBUG_MODEL)) {
132 * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
134 public IDebugTarget getDebugTarget() {
139 * @see org.eclipse.debug.core.model.IDebugElement#getLaunch()
141 public ILaunch getLaunch() {
146 * @see org.eclipse.debug.core.model.ITerminate#canTerminate()
148 public boolean canTerminate() {
149 if (getProcess()!=null) // ther is no running Process in remote debugging
150 return getProcess().canTerminate();
155 * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
157 public boolean isTerminated() {
158 // return getProcess().isTerminated();
163 * @see org.eclipse.debug.core.model.ITerminate#terminate()
165 public void terminate() throws DebugException {
170 if (XDebugCorePlugin.getDefault() != null) {
171 XDebugProxy proxy = XDebugCorePlugin.getDefault().getXDebugProxy();
172 proxy.removeProxyEventListener(this, fIdeKey);
174 System.out.println("XDebug.Target: ProxyEventlistener removed");
179 XDebugCorePlugin.getBreakpointManager().removeBreakpointListener(this);
180 fThread.fireTerminateEvent();
181 DebugPlugin.getDefault().removeDebugEventListener(this);
183 fThread.removeEventListeners();*/
188 * @see org.eclipse.debug.core.model.ISuspendResume#canResume()
190 public boolean canResume() {
195 * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
197 public boolean canSuspend() {
202 * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
204 public boolean isSuspended() {
209 * @see org.eclipse.debug.core.model.ISuspendResume#resume()
211 public void resume() throws DebugException {
212 if (fDebugConnection != null) {
213 fThread.setBreakpoints(null);
214 resumed(DebugEvent.RESUME);
215 fDebugConnection.run();
220 * Notification the target has resumed for the given reason
222 * @param detail reason for the resume
224 private void resumed(int detail) {
226 fThread.fireResumeEvent(detail);
230 * Notification the target has suspended for the given reason
232 * @param detail reason for the suspend
234 public void suspended(int detail) {
236 fThread.fireSuspendEvent(detail);
240 * @see org.eclipse.debug.core.model.ISuspendResume#suspend()
242 public void suspend() throws DebugException {
246 * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
248 public void breakpointAdded(IBreakpoint breakpoint) {
249 IMarker marker = breakpoint.getMarker();
250 IPath path = marker.getResource().getLocation();
251 IPath cp = path.removeLastSegments(1);
254 pathMap = fLaunch.getLaunchConfiguration().getAttribute(IXDebugConstants.ATTR_PHP_PATHMAP,(List)null);
255 } catch (CoreException e2) {
256 // TODO Auto-generated catch block
257 e2.printStackTrace();
260 if (fDebugConnection != null)
261 if (!fDebugConnection.isClosed()) {
262 if (fProcess == null) {
263 PathMapItem pmi = null;
264 for (int i = 0; i < pathMap.size(); i++) {
265 pmi = new PathMapItem((String) pathMap.get(i));
266 IPath local = (IPath)pmi.getLocalPath().clone();
267 local = local.makeAbsolute();
268 int matchedSegments = local.segmentCount();
269 if (local.matchingFirstSegments(cp) == matchedSegments) {
270 IPath newPath = pmi.getRemotePath();
271 newPath = newPath.append(path.removeFirstSegments(matchedSegments));
272 newPath = newPath.makeAbsolute();
273 if (supportsBreakpoint(breakpoint)) {
275 if (breakpoint.isEnabled()) {
276 if (marker != null) {
277 //XDebugResponse dr = fDebugConnection.breakpointSet(newPath.toString(), ((ILineBreakpoint)breakpoint).getLineNumber());
279 int id = fDebugConnection.breakpointSet(newPath.toString(), ((ILineBreakpoint)breakpoint).getLineNumber(), marker.getAttribute(XDebugBreakpoint.HIT_COUNT,-1));
280 XDebugResponse dr = getResponse(id);
282 String bpid = dr.getAttributeValue("id");
284 if (!"".equals(bpid))
285 marker.setAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,Integer.parseInt(bpid));
288 } catch (DebugException e) {
290 } catch (CoreException e) {
297 if (supportsBreakpoint(breakpoint)) {
299 if (breakpoint.isEnabled()) {
300 if (marker != null) {
301 int id = fDebugConnection.breakpointSet(path.toString(), ((ILineBreakpoint)breakpoint).getLineNumber(), marker.getAttribute(XDebugBreakpoint.HIT_COUNT,-1));
302 XDebugResponse dr = getResponse(id);
303 String bpid = dr.getAttributeValue("id");
305 if (!"".equals(bpid))
306 marker.setAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,Integer.parseInt(bpid));
309 } catch (DebugException e) {
311 } catch (CoreException e) {
320 * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
322 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
323 if (supportsBreakpoint(breakpoint)) {
325 int id =((XDebugLineBreakpoint)breakpoint).getID();
327 fDebugConnection.breakpointRemove(id);
328 } catch (CoreException e) {
334 * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
336 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
337 // if (supportsBreakpoint(breakpoint)) {
339 // if (breakpoint.isEnabled()) {
340 // breakpointAdded(breakpoint);
342 // breakpointRemoved(breakpoint, null);
344 // } catch (CoreException e) {
350 * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
352 public boolean canDisconnect() {
357 * @see org.eclipse.debug.core.model.IDisconnect#disconnect()
359 public void disconnect() throws DebugException {
363 * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
365 public boolean isDisconnected() {
367 // return (fDebugConnection==null);
371 * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
373 public boolean supportsStorageRetrieval() {
378 * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long)
380 public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
385 * Notification we have connected to the PHP debugger and it has been started.
386 * Resume the the debugger.
388 public void started() throws DebugException {
389 fThread.setBreakpoints(null);
390 fThread.setStepping(false);
392 int id = fDebugConnection.featureGet("detach");
394 XDebugResponse response = getResponse(id);
396 Integer.parseInt(response.getValue());
397 System.out.println("in Target.started()");
398 /*XDebugResponse response = fDebugConnection.featureGet("max_children");
399 String a1 = response.getValue();
400 System.out.println("max children:"+a1);
401 XDebugResponse response1 = fDebugConnection.featureGet("max_children");
402 String a2 = response1.getValue();
403 System.out.println("max depth:"+a2);*/
406 int id1 = fDebugConnection.featureSet("max_depth", "1024" );
407 XDebugResponse response1 = getResponse(id1);
408 if (response1.getAttributeValue("success").equals("1") ) {
409 System.out.println("Set depth to 1024 (hack)");
411 int id2 = fDebugConnection.featureSet("max_children", "1024" );
412 XDebugResponse response2 = getResponse(id2);
413 if (response2.getAttributeValue("success").equals("1") ) {
414 System.out.println("Set children to 1024 (hack)");
417 installDeferredBreakpoints();
420 } catch (DebugException e) {
426 * Install breakpoints that are already registered with the breakpoint
429 private void installDeferredBreakpoints() {
430 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
431 for (int i = 0; i < breakpoints.length; i++) {
432 breakpointAdded(breakpoints[i]);
437 * Returns the current stack frames in the target.
439 * @return the current stack frames in the target
440 * @throws DebugException if unable to perform the request
442 public XDebugResponse getStackFrames() throws DebugException {
443 int id = fDebugConnection.stackGet();
444 XDebugResponse lastResponse = getResponse(id);
449 * Single step the interpreter.
451 * @throws DebugException if the request fails
453 protected void step_over() throws DebugException {
454 fThread.setStepping(true);
455 resumed(DebugEvent.STEP_OVER);
456 fDebugConnection.stepOver();
460 * Single step the interpreter.
462 * @throws DebugException if the request fails
464 protected void step_into() throws DebugException {
465 fThread.setStepping(true);
466 resumed(DebugEvent.STEP_INTO);
467 fDebugConnection.stepInto();
471 * Single step the interpreter.
473 * @throws DebugException if the request fails
475 protected void step_out() throws DebugException {
476 fThread.setStepping(true);
477 resumed(DebugEvent.STEP_RETURN);
478 fDebugConnection.stepOut();
481 public boolean setVarValue(String name, String value) {
482 int id = fDebugConnection.setVarValue(name,value);
483 XDebugResponse response = getResponse(id);
485 if ((response.getAttributeValue("success")).equals("1")) {
492 public Node eval(String expression) {
493 int id = fDebugConnection.eval(expression);
494 XDebugResponse response = getResponse(id);
496 Node evalResponse = response.getParentNode();
497 Node evalProperty = evalResponse.getFirstChild();
502 public void handleDebugEvents(DebugEvent[] events) {
503 for (int i = 0; i < events.length; i++) {
504 DebugEvent event = events[i];
506 if (fResponseListener != null) {
508 s = event.getSource();
509 if (s instanceof ResponseListener) {
510 if (!fResponseListener.equals((ResponseListener) s)) {
518 if (event.getKind() == DebugEvent.MODEL_SPECIFIC) {
519 switch (event.getDetail()) {
520 case IPHPDebugEvent.BREAKPOINT_HIT:
521 int id = fDebugConnection.stackGet();
522 XDebugResponse lastResponse = getResponse(id);
524 IBreakpoint breakpoint = breakpointHit(lastResponse.getParentNode());
526 if (breakpoint != null) {
527 fThread.setBreakpoints(new IBreakpoint[]{breakpoint});
528 fThread.incrementStepCounter();
529 suspended(DebugEvent.BREAKPOINT);
533 } catch (DebugException e ) {
538 case IPHPDebugEvent.STEP_END:
539 fThread.incrementStepCounter();
540 suspended(DebugEvent.STEP_END);
542 case IPHPDebugEvent.STOPPED:
550 public void stopped() {
551 if(fDebugConnection == null) {
555 resumed(DebugEvent.TERMINATE);
558 fDebugConnection.close();
560 /* fThread.removeEventListeners();
562 fThreads = new IThread[0];*/
565 fDebugConnection.close();*/
569 // Dirty hack to check debugging mode (remote or local)
570 if (fProcess!=null) {
573 } catch (DebugException e) {
577 fDebugConnection = null;
578 fThread.fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
581 fThread.removeEventListeners();
583 fThreads = new IThread[0];
586 public void handleProxyEvent(/*String ideKey,*/ XDebugConnection connection) {
587 setDebugConnection(connection);
588 System.out.println("* New Connection - XDebug.Target: " + fDebugConnection.getSessionID());
590 // fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
592 fThread = new XDebugThread(this);
593 fThreads = new IThread[] {fThread};
594 fThread.fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
597 } catch( DebugException e ){
602 private void setDebugConnection(XDebugConnection connection) {
603 if (connection != null) {
604 fDebugConnection = connection;
605 fResponseListener = new ResponseListener(connection);
611 * @return Returns the fDebugConnection.
613 public XDebugConnection getDebugConnection() {
614 return fDebugConnection;
617 public void addProcess(IProcess p) {
621 public Node getLocalVariables(int level) throws DebugException {
622 // XDebugResponse response = fDebugConnection.contextGet(level, 0);
623 int id = fDebugConnection.contextGet(level, 0);
624 XDebugResponse response = getResponse(id);
626 return response.getParentNode();
629 public Node getGlobalVariables(int level) throws DebugException {
630 //XDebugResponse response = fDebugConnection.contextGet(level, 1);
632 int id = fDebugConnection.contextGet(level, 1);
633 XDebugResponse response = getResponse(id);
635 return response.getParentNode();
639 fDebugConnection.stop();
642 protected IBreakpoint breakpointHit(Node node) {
643 Node child = node.getFirstChild();
644 if (child.getNodeName().equals("stack")) {
645 int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "lineno"));
646 String filename = PHPDebugUtils.getAttributeValue(child, "filename");
647 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
648 for (int i = 0; i < breakpoints.length; i++) {
649 IBreakpoint breakpoint = breakpoints[i];
650 if (supportsBreakpoint(breakpoint)) {
651 if (breakpoint instanceof ILineBreakpoint) {
652 ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoint;
654 if (breakpoint.isEnabled()) {
655 IMarker marker = breakpoint.getMarker();
656 if (marker != null) {
659 if (getProcess() == null) {
660 endfilename = marker.getResource().getLocation().lastSegment();
662 endfilename = marker.getResource().getLocation().toOSString();
665 int id = fDebugConnection.breakpointGet(marker.getAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,-1));
666 XDebugResponse dr = getResponse(id);
668 //String bpid = dr.getAttributeValue("command");
669 Node hitCo = dr.getParentNode().getFirstChild();
671 if (hitCo.hasAttributes()) {
672 NamedNodeMap listAttribute = hitCo.getAttributes();
673 Node attribute = listAttribute.getNamedItem("hit_count");
674 if (attribute !=null) {
675 hitCount = Integer.parseInt(attribute.getNodeValue());
679 //String hitCount = hitCo.getAttributeValue("hit_count");
680 if(PHPDebugUtils.unescapeString(filename).endsWith(endfilename)
681 && (lineBreakpoint.getLineNumber() == lineNumber) ) {
682 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) > 0) {
683 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) == hitCount) {
692 } catch (CoreException e) {
702 public void startListener() {
703 fResponseListener.schedule();
706 public /*boolean*/ void stopListener() {
707 /*return*/ fResponseListener.cancel(); //done(null); //.cancel();
709 public XDebugResponse getResponse(int id) {
710 XDebugResponse response = fResponseListener.getResponse(id);