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", "1024" );
406 XDebugResponse response1 = getResponse(id1);
407 if (response1.getAttributeValue("success").equals("1") ) {
408 System.out.println("Set depth to 1024 (hack)");
410 int id2 = fDebugConnection.featureSet("max_children", "1024" );
411 XDebugResponse response2 = getResponse(id2);
412 if (response2.getAttributeValue("success").equals("1") ) {
413 System.out.println("Set children to 1024 (hack)");
416 installDeferredBreakpoints();
419 } catch (DebugException e) {
425 * Install breakpoints that are already registered with the breakpoint
428 private void installDeferredBreakpoints() {
429 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
430 for (int i = 0; i < breakpoints.length; i++) {
431 breakpointAdded(breakpoints[i]);
436 * Returns the current stack frames in the target.
438 * @return the current stack frames in the target
439 * @throws DebugException if unable to perform the request
441 public XDebugResponse getStackFrames() throws DebugException {
442 int id = fDebugConnection.stackGet();
443 XDebugResponse lastResponse = getResponse(id);
448 * Single step the interpreter.
450 * @throws DebugException if the request fails
452 protected void step_over() throws DebugException {
453 fThread.setStepping(true);
454 resumed(DebugEvent.STEP_OVER);
455 fDebugConnection.stepOver();
459 * Single step the interpreter.
461 * @throws DebugException if the request fails
463 protected void step_into() throws DebugException {
464 fThread.setStepping(true);
465 resumed(DebugEvent.STEP_INTO);
466 fDebugConnection.stepInto();
470 * Single step the interpreter.
472 * @throws DebugException if the request fails
474 protected void step_out() throws DebugException {
475 fThread.setStepping(true);
476 resumed(DebugEvent.STEP_RETURN);
477 fDebugConnection.stepOut();
480 public boolean setVarValue(String name, String value) {
481 int id = fDebugConnection.setVarValue(name,value);
482 XDebugResponse response = getResponse(id);
484 if ((response.getAttributeValue("success")).equals("1")) {
491 public void handleDebugEvents(DebugEvent[] events) {
492 for (int i = 0; i < events.length; i++) {
493 DebugEvent event = events[i];
495 if (fResponseListener != null) {
497 s = event.getSource();
498 if (s instanceof ResponseListener) {
499 if (!fResponseListener.equals((ResponseListener) s)) {
507 if (event.getKind() == DebugEvent.MODEL_SPECIFIC) {
508 switch (event.getDetail()) {
509 case IPHPDebugEvent.BREAKPOINT_HIT:
510 int id = fDebugConnection.stackGet();
511 XDebugResponse lastResponse = getResponse(id);
513 IBreakpoint breakpoint = breakpointHit(lastResponse.getParentNode());
515 if (breakpoint != null) {
516 fThread.setBreakpoints(new IBreakpoint[]{breakpoint});
517 fThread.incrementStepCounter();
518 suspended(DebugEvent.BREAKPOINT);
522 } catch (DebugException e ) {
527 case IPHPDebugEvent.STEP_END:
528 fThread.incrementStepCounter();
529 suspended(DebugEvent.STEP_END);
531 case IPHPDebugEvent.STOPPED:
539 public void stopped() {
540 if(fDebugConnection == null) {
545 fDebugConnection.close();
547 fThread.removeEventListeners();
549 fThreads = new IThread[0];
552 fDebugConnection.close();*/
556 // Dirty hack to check debugging mode (remote or local)
557 if (fProcess!=null) {
560 } catch (DebugException e) {
564 fDebugConnection = null;
565 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
569 public void handleProxyEvent(/*String ideKey,*/ XDebugConnection connection) {
570 setDebugConnection(connection);
571 System.out.println("* New Connection - XDebug.Target: " + fDebugConnection.getSessionID());
573 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
575 fThread = new XDebugThread(this);
576 fThreads = new IThread[] {fThread};
579 } catch( DebugException e ){
584 private void setDebugConnection(XDebugConnection connection) {
585 if (connection != null) {
586 fDebugConnection = connection;
587 fResponseListener = new ResponseListener(connection);
593 * @return Returns the fDebugConnection.
595 public XDebugConnection getDebugConnection() {
596 return fDebugConnection;
599 public void addProcess(IProcess p) {
603 public Node getLocalVariables(int level) throws DebugException {
604 // XDebugResponse response = fDebugConnection.contextGet(level, 0);
605 int id = fDebugConnection.contextGet(level, 0);
606 XDebugResponse response = getResponse(id);
608 return response.getParentNode();
611 public Node getGlobalVariables(int level) throws DebugException {
612 //XDebugResponse response = fDebugConnection.contextGet(level, 1);
614 int id = fDebugConnection.contextGet(level, 1);
615 XDebugResponse response = getResponse(id);
617 return response.getParentNode();
620 protected IBreakpoint breakpointHit(Node node) {
621 Node child = node.getFirstChild();
622 if (child.getNodeName().equals("stack")) {
623 int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "lineno"));
624 String filename=PHPDebugUtils.getAttributeValue(child, "filename");
625 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
626 for (int i = 0; i < breakpoints.length; i++) {
627 IBreakpoint breakpoint = breakpoints[i];
628 if (supportsBreakpoint(breakpoint)) {
629 if (breakpoint instanceof ILineBreakpoint) {
630 ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoint;
632 if (breakpoint.isEnabled()) {
633 IMarker marker = breakpoint.getMarker();
634 if (marker != null) {
637 if (getProcess() == null) {
638 endfilename = marker.getResource().getLocation().lastSegment();
640 endfilename = marker.getResource().getLocation().toOSString();
643 int id = fDebugConnection.breakpointGet(marker.getAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,-1));
644 XDebugResponse dr = getResponse(id);
646 //String bpid = dr.getAttributeValue("command");
647 Node hitCo = dr.getParentNode().getFirstChild();
649 if (hitCo.hasAttributes()) {
650 NamedNodeMap listAttribute = hitCo.getAttributes();
651 Node attribute = listAttribute.getNamedItem("hit_count");
652 if (attribute !=null) {
653 hitCount = Integer.parseInt(attribute.getNodeValue());
657 //String hitCount = hitCo.getAttributeValue("hit_count");
658 if(PHPDebugUtils.unescapeString(filename).endsWith(endfilename)
659 && (lineBreakpoint.getLineNumber() == lineNumber) ) {
660 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) > 0) {
661 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) == hitCount) {
670 } catch (CoreException e) {
680 public void startListener() {
681 fResponseListener.schedule();
684 public /*boolean*/ void stopListener() {
685 /*return*/ fResponseListener.cancel(); //done(null); //.cancel();
687 public XDebugResponse getResponse(int id) {
688 XDebugResponse response = fResponseListener.getResponse(id);