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 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 void handleDebugEvents(DebugEvent[] events) {
493 for (int i = 0; i < events.length; i++) {
494 DebugEvent event = events[i];
496 if (fResponseListener != null) {
498 s = event.getSource();
499 if (s instanceof ResponseListener) {
500 if (!fResponseListener.equals((ResponseListener) s)) {
508 if (event.getKind() == DebugEvent.MODEL_SPECIFIC) {
509 switch (event.getDetail()) {
510 case IPHPDebugEvent.BREAKPOINT_HIT:
511 int id = fDebugConnection.stackGet();
512 XDebugResponse lastResponse = getResponse(id);
514 IBreakpoint breakpoint = breakpointHit(lastResponse.getParentNode());
516 if (breakpoint != null) {
517 fThread.setBreakpoints(new IBreakpoint[]{breakpoint});
518 fThread.incrementStepCounter();
519 suspended(DebugEvent.BREAKPOINT);
523 } catch (DebugException e ) {
528 case IPHPDebugEvent.STEP_END:
529 fThread.incrementStepCounter();
530 suspended(DebugEvent.STEP_END);
532 case IPHPDebugEvent.STOPPED:
540 public void stopped() {
541 if(fDebugConnection == null) {
545 resumed(DebugEvent.TERMINATE);
548 fDebugConnection.close();
550 fThread.removeEventListeners();
552 fThreads = new IThread[0];
555 fDebugConnection.close();*/
559 // Dirty hack to check debugging mode (remote or local)
560 if (fProcess!=null) {
563 } catch (DebugException e) {
567 fDebugConnection = null;
568 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
572 public void handleProxyEvent(/*String ideKey,*/ XDebugConnection connection) {
573 setDebugConnection(connection);
574 System.out.println("* New Connection - XDebug.Target: " + fDebugConnection.getSessionID());
576 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
578 fThread = new XDebugThread(this);
579 fThreads = new IThread[] {fThread};
582 } catch( DebugException e ){
587 private void setDebugConnection(XDebugConnection connection) {
588 if (connection != null) {
589 fDebugConnection = connection;
590 fResponseListener = new ResponseListener(connection);
596 * @return Returns the fDebugConnection.
598 public XDebugConnection getDebugConnection() {
599 return fDebugConnection;
602 public void addProcess(IProcess p) {
606 public Node getLocalVariables(int level) throws DebugException {
607 // XDebugResponse response = fDebugConnection.contextGet(level, 0);
608 int id = fDebugConnection.contextGet(level, 0);
609 XDebugResponse response = getResponse(id);
611 return response.getParentNode();
614 public Node getGlobalVariables(int level) throws DebugException {
615 //XDebugResponse response = fDebugConnection.contextGet(level, 1);
617 int id = fDebugConnection.contextGet(level, 1);
618 XDebugResponse response = getResponse(id);
620 return response.getParentNode();
623 protected IBreakpoint breakpointHit(Node node) {
624 Node child = node.getFirstChild();
625 if (child.getNodeName().equals("stack")) {
626 int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "lineno"));
627 String filename=PHPDebugUtils.getAttributeValue(child, "filename");
628 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
629 for (int i = 0; i < breakpoints.length; i++) {
630 IBreakpoint breakpoint = breakpoints[i];
631 if (supportsBreakpoint(breakpoint)) {
632 if (breakpoint instanceof ILineBreakpoint) {
633 ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoint;
635 if (breakpoint.isEnabled()) {
636 IMarker marker = breakpoint.getMarker();
637 if (marker != null) {
640 if (getProcess() == null) {
641 endfilename = marker.getResource().getLocation().lastSegment();
643 endfilename = marker.getResource().getLocation().toOSString();
646 int id = fDebugConnection.breakpointGet(marker.getAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,-1));
647 XDebugResponse dr = getResponse(id);
649 //String bpid = dr.getAttributeValue("command");
650 Node hitCo = dr.getParentNode().getFirstChild();
652 if (hitCo.hasAttributes()) {
653 NamedNodeMap listAttribute = hitCo.getAttributes();
654 Node attribute = listAttribute.getNamedItem("hit_count");
655 if (attribute !=null) {
656 hitCount = Integer.parseInt(attribute.getNodeValue());
660 //String hitCount = hitCo.getAttributeValue("hit_count");
661 if(PHPDebugUtils.unescapeString(filename).endsWith(endfilename)
662 && (lineBreakpoint.getLineNumber() == lineNumber) ) {
663 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) > 0) {
664 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) == hitCount) {
673 } catch (CoreException e) {
683 public void startListener() {
684 fResponseListener.schedule();
687 public /*boolean*/ void stopListener() {
688 /*return*/ fResponseListener.cancel(); //done(null); //.cancel();
690 public XDebugResponse getResponse(int id) {
691 XDebugResponse response = fResponseListener.getResponse(id);