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 fDebugConnection.run();
219 * Notification the target has resumed for the given reason
221 * @param detail reason for the resume
223 private void resumed(int detail) {
225 fThread.fireResumeEvent(detail);
229 * Notification the target has suspended for the given reason
231 * @param detail reason for the suspend
233 public void suspended(int detail) {
235 fThread.fireSuspendEvent(detail);
239 * @see org.eclipse.debug.core.model.ISuspendResume#suspend()
241 public void suspend() throws DebugException {
245 * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
247 public void breakpointAdded(IBreakpoint breakpoint) {
248 IMarker marker = breakpoint.getMarker();
249 IPath path = marker.getResource().getLocation();
250 IPath cp = path.removeLastSegments(1);
253 pathMap = fLaunch.getLaunchConfiguration().getAttribute(IXDebugConstants.ATTR_PHP_PATHMAP,(List)null);
254 } catch (CoreException e2) {
255 // TODO Auto-generated catch block
256 e2.printStackTrace();
259 if (fDebugConnection != null)
260 if (!fDebugConnection.isClosed()) {
261 if (fProcess == null) {
262 PathMapItem pmi = null;
263 for (int i = 0; i < pathMap.size(); i++) {
264 pmi = new PathMapItem((String) pathMap.get(i));
265 IPath local = (IPath)pmi.getLocalPath().clone();
266 local = local.makeAbsolute();
267 int matchedSegments = local.segmentCount();
268 if (local.matchingFirstSegments(cp) == matchedSegments) {
269 IPath newPath = pmi.getRemotePath();
270 newPath = newPath.append(path.removeFirstSegments(matchedSegments));
271 newPath = newPath.makeAbsolute();
272 if (supportsBreakpoint(breakpoint)) {
274 if (breakpoint.isEnabled()) {
275 if (marker != null) {
276 //XDebugResponse dr = fDebugConnection.breakpointSet(newPath.toString(), ((ILineBreakpoint)breakpoint).getLineNumber());
278 int id = fDebugConnection.breakpointSet(newPath.toString(), ((ILineBreakpoint)breakpoint).getLineNumber(), marker.getAttribute(XDebugBreakpoint.HIT_COUNT,-1));
279 XDebugResponse dr = getResponse(id);
281 String bpid = dr.getAttributeValue("id");
283 if (!"".equals(bpid))
284 marker.setAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,Integer.parseInt(bpid));
287 } catch (DebugException e) {
289 } catch (CoreException e) {
296 if (supportsBreakpoint(breakpoint)) {
298 if (breakpoint.isEnabled()) {
299 if (marker != null) {
300 int id = fDebugConnection.breakpointSet(path.toString(), ((ILineBreakpoint)breakpoint).getLineNumber(), marker.getAttribute(XDebugBreakpoint.HIT_COUNT,-1));
301 XDebugResponse dr = getResponse(id);
302 String bpid = dr.getAttributeValue("id");
304 if (!"".equals(bpid))
305 marker.setAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,Integer.parseInt(bpid));
308 } catch (DebugException e) {
310 } catch (CoreException e) {
319 * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
321 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
322 if (supportsBreakpoint(breakpoint)) {
324 int id =((XDebugLineBreakpoint)breakpoint).getID();
326 fDebugConnection.breakpointRemove(id);
327 } catch (CoreException e) {
333 * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
335 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
336 // if (supportsBreakpoint(breakpoint)) {
338 // if (breakpoint.isEnabled()) {
339 // breakpointAdded(breakpoint);
341 // breakpointRemoved(breakpoint, null);
343 // } catch (CoreException e) {
349 * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
351 public boolean canDisconnect() {
356 * @see org.eclipse.debug.core.model.IDisconnect#disconnect()
358 public void disconnect() throws DebugException {
362 * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
364 public boolean isDisconnected() {
366 // return (fDebugConnection==null);
370 * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
372 public boolean supportsStorageRetrieval() {
377 * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long)
379 public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
384 * Notification we have connected to the PHP debugger and it has been started.
385 * Resume the the debugger.
387 public void started() throws DebugException {
388 fThread.setBreakpoints(null);
389 fThread.setStepping(false);
391 int id = fDebugConnection.featureGet("detach");
393 XDebugResponse response = getResponse(id);
395 Integer.parseInt(response.getValue());
396 System.out.println("in Target.started()");
397 /*XDebugResponse response = fDebugConnection.featureGet("max_children");
398 String a1 = response.getValue();
399 System.out.println("max children:"+a1);
400 XDebugResponse response1 = fDebugConnection.featureGet("max_children");
401 String a2 = response1.getValue();
402 System.out.println("max depth:"+a2);*/
405 int id1 = fDebugConnection.featureSet("max_depth", "100" );
406 XDebugResponse response1 = getResponse(id1);
407 if (response1.getAttributeValue("success").equals("1") ) {
408 System.out.println("Set depth to 100 (hack)");
411 installDeferredBreakpoints();
414 } catch (DebugException e) {
420 * Install breakpoints that are already registered with the breakpoint
423 private void installDeferredBreakpoints() {
424 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
425 for (int i = 0; i < breakpoints.length; i++) {
426 breakpointAdded(breakpoints[i]);
431 * Returns the current stack frames in the target.
433 * @return the current stack frames in the target
434 * @throws DebugException if unable to perform the request
436 public XDebugResponse getStackFrames() throws DebugException {
437 int id = fDebugConnection.stackGet();
438 XDebugResponse lastResponse = getResponse(id);
443 * Single step the interpreter.
445 * @throws DebugException if the request fails
447 protected void step_over() throws DebugException {
448 fThread.setStepping(true);
449 resumed(DebugEvent.STEP_OVER);
450 fDebugConnection.stepOver();
454 * Single step the interpreter.
456 * @throws DebugException if the request fails
458 protected void step_into() throws DebugException {
459 fThread.setStepping(true);
460 resumed(DebugEvent.STEP_INTO);
461 fDebugConnection.stepInto();
465 * Single step the interpreter.
467 * @throws DebugException if the request fails
469 protected void step_out() throws DebugException {
470 fThread.setStepping(true);
471 resumed(DebugEvent.STEP_RETURN);
472 fDebugConnection.stepOut();
475 public boolean setVarValue(String name, String value) {
476 int id = fDebugConnection.setVarValue(name,value);
477 XDebugResponse response = getResponse(id);
479 if ((response.getAttributeValue("success")).equals("1")) {
486 public void handleDebugEvents(DebugEvent[] events) {
487 for (int i = 0; i < events.length; i++) {
488 DebugEvent event = events[i];
490 if (fResponseListener != null) {
492 s = event.getSource();
493 if (s instanceof ResponseListener) {
494 if (!fResponseListener.equals((ResponseListener) s)) {
502 if (event.getKind() == DebugEvent.MODEL_SPECIFIC) {
503 switch (event.getDetail()) {
504 case IPHPDebugEvent.BREAKPOINT_HIT:
505 int id = fDebugConnection.stackGet();
506 XDebugResponse lastResponse = getResponse(id);
508 IBreakpoint breakpoint = breakpointHit(lastResponse.getParentNode());
510 if (breakpoint != null) {
511 fThread.setBreakpoints(new IBreakpoint[]{breakpoint});
512 fThread.incrementStepCounter();
513 suspended(DebugEvent.BREAKPOINT);
517 } catch (DebugException e ) {
522 case IPHPDebugEvent.STEP_END:
523 fThread.incrementStepCounter();
524 suspended(DebugEvent.STEP_END);
526 case IPHPDebugEvent.STOPPED:
534 public void stopped() {
535 if(fDebugConnection == null) {
540 fDebugConnection.close();
542 fThread.removeEventListeners();
544 fThreads = new IThread[0];
547 fDebugConnection.close();*/
551 // Dirty hack to check debugging mode (remote or local)
552 if (fProcess!=null) {
555 } catch (DebugException e) {
559 fDebugConnection = null;
560 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
564 public void handleProxyEvent(/*String ideKey,*/ XDebugConnection connection) {
565 setDebugConnection(connection);
566 System.out.println("* New Connection - XDebug.Target: " + fDebugConnection.getSessionID());
568 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
570 fThread = new XDebugThread(this);
571 fThreads = new IThread[] {fThread};
574 } catch( DebugException e ){
579 private void setDebugConnection(XDebugConnection connection) {
580 if (connection != null) {
581 fDebugConnection = connection;
582 fResponseListener = new ResponseListener(connection);
588 * @return Returns the fDebugConnection.
590 public XDebugConnection getDebugConnection() {
591 return fDebugConnection;
594 public void addProcess(IProcess p) {
598 public Node getLocalVariables(int level) throws DebugException {
599 // XDebugResponse response = fDebugConnection.contextGet(level, 0);
600 int id = fDebugConnection.contextGet(level, 0);
601 XDebugResponse response = getResponse(id);
603 return response.getParentNode();
606 public Node getGlobalVariables(int level) throws DebugException {
607 //XDebugResponse response = fDebugConnection.contextGet(level, 1);
609 int id = fDebugConnection.contextGet(level, 1);
610 XDebugResponse response = getResponse(id);
612 return response.getParentNode();
615 protected IBreakpoint breakpointHit(Node node) {
616 Node child = node.getFirstChild();
617 if (child.getNodeName().equals("stack")) {
618 int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "lineno"));
619 String filename=PHPDebugUtils.getAttributeValue(child, "filename");
620 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
621 for (int i = 0; i < breakpoints.length; i++) {
622 IBreakpoint breakpoint = breakpoints[i];
623 if (supportsBreakpoint(breakpoint)) {
624 if (breakpoint instanceof ILineBreakpoint) {
625 ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoint;
627 if (breakpoint.isEnabled()) {
628 IMarker marker = breakpoint.getMarker();
629 if (marker != null) {
632 if (getProcess() == null) {
633 endfilename = marker.getResource().getLocation().lastSegment();
635 endfilename = marker.getResource().getLocation().toOSString();
638 int id = fDebugConnection.breakpointGet(marker.getAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,-1));
639 XDebugResponse dr = getResponse(id);
641 //String bpid = dr.getAttributeValue("command");
642 Node hitCo = dr.getParentNode().getFirstChild();
644 if (hitCo.hasAttributes()) {
645 NamedNodeMap listAttribute = hitCo.getAttributes();
646 Node attribute = listAttribute.getNamedItem("hit_count");
647 if (attribute !=null) {
648 hitCount = Integer.parseInt(attribute.getNodeValue());
652 //String hitCount = hitCo.getAttributeValue("hit_count");
653 if(PHPDebugUtils.unescapeString(filename).endsWith(endfilename)
654 && (lineBreakpoint.getLineNumber() == lineNumber) ) {
655 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) > 0) {
656 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) == hitCount) {
665 } catch (CoreException e) {
675 public void startListener() {
676 fResponseListener.schedule();
679 public /*boolean*/ void stopListener() {
680 /*return*/ fResponseListener.cancel(); //done(null); //.cancel();
682 public XDebugResponse getResponse(int id) {
683 XDebugResponse response = fResponseListener.getResponse(id);