4 package net.sourceforge.phpeclipse.xdebug.php.model;
8 import net.sourceforge.phpeclipse.xdebug.core.AbstractDebugConnection;
9 import net.sourceforge.phpeclipse.xdebug.core.IDebugConnection;
10 import net.sourceforge.phpeclipse.xdebug.core.IPHPDebugEvent;
11 import net.sourceforge.phpeclipse.xdebug.core.IProxyEventListener;
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.ILaunchListener;
29 import org.eclipse.debug.core.model.IBreakpoint;
30 import org.eclipse.debug.core.model.IDebugTarget;
31 import org.eclipse.debug.core.model.IMemoryBlock;
32 import org.eclipse.debug.core.model.IProcess;
33 import org.eclipse.debug.core.model.IStackFrame;
34 import org.eclipse.debug.core.model.IThread;
35 import org.eclipse.debug.core.model.IValue;
36 import org.eclipse.debug.core.model.IVariable;
38 import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener.DebugResponse;
44 public class XDebugTarget extends XDebugElement implements IDebugTarget, ILaunchListener, IDebugEventSetListener, IProxyEventListener{
45 // associated system process (VM)
46 private IProcess fProcess;
48 // containing launch object
49 private ILaunch fLaunch;
52 private int fDebugPort;
55 private boolean fSuspended = false;
58 private boolean fTerminated = false;
61 private XDebugThread fThread;
62 private IThread[] fThreads;
64 private AbstractDebugConnection fDebugConnection;
66 private String fIdeKey;
69 public XDebugTarget() {
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
84 public XDebugTarget(ILaunch launch, IProcess process, String ideKey) throws CoreException {
85 init(launch, process, ideKey);
89 * Constructs a new debug target in the given launch and waits until
90 * someone with the ideKey connects to the Debugproxy
93 * @param launch containing launch
94 * @param process process of the interpreter
96 * @param pathMap Pathmap for the debug session
97 * @exception CoreException if unable to connect to host
100 /*public XDebugTarget(ILaunch launch, IProcess process, String ideKey, List<String> pathMap) throws CoreException {
102 init(launch, process, ideKey,pathMap);
105 private void init(ILaunch launch, IProcess process, String ideKey/*,List<String> pathMap*/) {
109 fDebugConnection = null;
111 fThreads = new IThread[0];
114 XDebugProxy proxy = XDebugCorePlugin.getDefault().getXDebugProxy();
115 proxy.addProxyEventListener(this,ideKey);
116 if (!proxy.isRunning())
119 proxy.setTarget(this);
121 fDebugPort = proxy.getProxyPort();
123 DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this);
124 DebugPlugin.getDefault().addDebugEventListener(this);
128 * @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
130 public IProcess getProcess() {
135 * @see org.eclipse.debug.core.model.IDebugTarget#getThreads()
137 public IThread[] getThreads() throws DebugException {
142 * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads()
144 public boolean hasThreads() throws DebugException {
145 return (fThreads.length>0);
149 * @see org.eclipse.debug.core.model.IDebugTarget#getName()
151 public String getName() throws DebugException {
152 return "PHP XDebug Client at localhost:" + fDebugPort;
156 * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint)
158 public boolean supportsBreakpoint(IBreakpoint breakpoint) {
159 if (breakpoint.getModelIdentifier().equals(IXDebugConstants.ID_PHP_DEBUG_MODEL)) {
166 * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
168 public IDebugTarget getDebugTarget() {
173 * @see org.eclipse.debug.core.model.IDebugElement#getLaunch()
175 public ILaunch getLaunch() {
180 * @see org.eclipse.debug.core.model.ITerminate#canTerminate()
182 public boolean canTerminate() {
183 if (getProcess()!=null) // ther is no running Process in remote debugging
184 return getProcess().canTerminate();
189 * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
191 public boolean isTerminated() {
192 // return getProcess().isTerminated();
197 * @see org.eclipse.debug.core.model.ITerminate#terminate()
199 public void terminate() throws DebugException {
200 //IThread t = fThreads.length();
202 XDebugProxy proxy=XDebugCorePlugin.getDefault().getXDebugProxy();
204 proxy.removeProxyEventListener(this,fIdeKey);
205 System.out.println("XDebug.Target: ProxyEventlistener removed");
207 //fDisconnected = true;
209 XDebugCorePlugin.getBreakpointManager().removeBreakpointListener(this);
210 fireTerminateEvent();
211 DebugPlugin.getDefault().removeDebugEventListener(this);
213 fThread.removeEventListeners();
217 * @see org.eclipse.debug.core.model.ISuspendResume#canResume()
219 public boolean canResume() {
220 // return !isTerminated() && isSuspended();
225 * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
227 public boolean canSuspend() {
228 // return !isTerminated() && !isSuspended();
233 * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
235 public boolean isSuspended() {
240 * @see org.eclipse.debug.core.model.ISuspendResume#resume()
242 public void resume() throws DebugException {
243 if (fDebugConnection != null) {
244 fThread.setBreakpoints(null);
245 fDebugConnection.run();
250 * Notification the target has resumed for the given reason
252 * @param detail reason for the resume
254 private void resumed(int detail) {
256 fThread.fireResumeEvent(detail);
260 * Notification the target has suspended for the given reason
262 * @param detail reason for the suspend
264 public void suspended(int detail) {
266 fThread.fireSuspendEvent(detail);
270 * @see org.eclipse.debug.core.model.ISuspendResume#suspend()
272 public void suspend() throws DebugException {
276 * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
278 public void breakpointAdded(IBreakpoint breakpoint) {
279 IMarker marker = breakpoint.getMarker();
280 IPath path = marker.getResource().getLocation();
281 IPath cp = path.removeLastSegments(1);
284 pathMap = fLaunch.getLaunchConfiguration().getAttribute(IXDebugConstants.ATTR_PHP_PATHMAP,(List)null);
285 } catch (CoreException e2) {
286 // TODO Auto-generated catch block
287 e2.printStackTrace();
290 if (!fDebugConnection.isClosed()) {
291 if (fProcess == null) {
292 PathMapItem pmi = null;
293 for (int i = 0; i < pathMap.size(); i++) {
294 pmi = new PathMapItem((String) pathMap.get(i));
295 IPath local = (IPath)pmi.getLocalPath().clone();
296 local = local./*removeFirstSegments(1).*/makeAbsolute();
297 int matchedSegments = local.segmentCount();
298 if (local.matchingFirstSegments(cp) == matchedSegments) {
299 IPath newPath = pmi.getRemotePath();
300 //newPath = newPath.removeFirstSegments(1);
301 newPath = newPath.append(path.removeFirstSegments(matchedSegments));
302 newPath = newPath.makeAbsolute();
303 if (supportsBreakpoint(breakpoint)) {
305 fDebugConnection.addBreakpoint(breakpoint, newPath);
306 } catch (DebugException e) {
313 if (supportsBreakpoint(breakpoint)) {
315 fDebugConnection.addBreakpoint(breakpoint, path);
316 } catch (DebugException e) {
325 * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
327 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
328 if (supportsBreakpoint(breakpoint)) {
330 fDebugConnection.removeBreakpoint(breakpoint);
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() {
369 return (fDebugConnection==null);
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 /*boolean CanDisconnect =*/ Integer.parseInt(fDebugConnection.featureGet("detach").getValue()) /*!= 0*/;
396 System.out.println("in Target.started()");
397 DebugResponse response = fDebugConnection.featureGet("max_children");
398 String a1 = response.getValue();
399 System.out.println("max children:"+a1);
400 DebugResponse response1 = fDebugConnection.featureGet("max_children");
401 String a2 = response1.getValue();
402 System.out.println("max depth:"+a2);
405 boolean res = fDebugConnection.featureSet("max_depth", "100" );
407 System.out.println("Set depth to 100 (hack)");
410 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 * Called when this debug target terminates.
433 public void terminated() {
436 XDebugCorePlugin.getBreakpointManager().removeBreakpointListener(this);
437 fireTerminateEvent();
438 DebugPlugin.getDefault().removeDebugEventListener(this);
439 fThread.removeEventListeners();
443 * Returns the current stack frames in the target.
445 * @return the current stack frames in the target
446 * @throws DebugException if unable to perform the request
448 protected IStackFrame[] getStackFrames() throws DebugException {
449 return fDebugConnection.getStackFrames(fThread);
453 * Single step the interpreter.
455 * @throws DebugException if the request fails
457 protected void step_over() throws DebugException {
458 fThread.setStepping(true);
459 resumed(DebugEvent.STEP_OVER);
460 fDebugConnection.stepOver();
464 * Single step the interpreter.
466 * @throws DebugException if the request fails
468 protected void step_into() throws DebugException {
469 fThread.setStepping(true);
470 resumed(DebugEvent.STEP_INTO);
471 fDebugConnection.stepInto();
475 * Single step the interpreter.
477 * @throws DebugException if the request fails
479 protected void step_out() throws DebugException {
480 fThread.setStepping(true);
481 resumed(DebugEvent.STEP_RETURN);
482 fDebugConnection.stepOut();
486 * Returns the current value of the given variable.
489 * @return variable value
490 * @throws DebugException if the request fails
492 protected IValue getVariableValue(XDebugVariable variable) throws DebugException {
497 * Returns the values on the data stack (top down)
499 * @return the values on the data stack (top down)
501 public IValue[] getDataStack() throws DebugException {
502 return new IValue[0];
505 public boolean setVarValue(String name, String value) {
506 return fDebugConnection.setVarValue(name,value);
509 public void handleDebugEvents(DebugEvent[] events) {
510 for (int i=0;i<events.length;i++) {
511 DebugEvent event=events[i];
512 if(event.getKind()==DebugEvent.MODEL_SPECIFIC) {
513 if (event.getDetail()==IPHPDebugEvent.BREAKPOINT_HIT) {
514 IBreakpoint breakpoint = (IBreakpoint) event.getData();
515 fThread.setBreakpoints(new IBreakpoint[]{breakpoint});
516 fThread.incrementStepCounter();
517 suspended(DebugEvent.BREAKPOINT);
518 } else if (event.getDetail()==IPHPDebugEvent.STEP_END) {
519 fThread.incrementStepCounter();
520 suspended(DebugEvent.STEP_END);
521 } else if (event.getDetail()==IPHPDebugEvent.STOPPED) {
522 //fDebugConnection.removeBreakpoint(breakpoint);
523 fThread.removeEventListeners();
525 fThreads= new IThread[0];
527 // TODO Dirty hack to check debugging mode (remote or local)
528 if (fProcess!=null) {
531 } catch (DebugException e) {
535 fDebugConnection = null;
536 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
550 public void handleProxyEvent(String ideKey, String initString, AbstractDebugConnection connection) {
551 System.out.println("* New Connection - XDebug.Target: "+ideKey);
552 setDebugConnection(connection);
554 XDebugProxy proxy=XDebugCorePlugin.getDefault().getXDebugProxy();
555 fDebugPort=proxy.getProxyPort();
556 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
559 // proxy.removeProxyEventListener(this,ideKey);
560 // System.out.println("XDebug.Target: ProxyEventlistener removed");
561 fThread = new XDebugThread(this);
562 fThreads = new IThread[] {fThread};
565 } catch( DebugException e ){
570 private void setDebugConnection(AbstractDebugConnection connection) {
571 if (connection != null) {
572 fDebugConnection = connection;
573 fDebugConnection.startListener();
578 * @return Returns the fDebugConnection.
580 public IDebugConnection getDebugConnection() {
581 return fDebugConnection;
584 public void addProcess(IProcess p) {
589 public void launchRemoved(ILaunch launch) {
593 * Notifies this listener that the specified launch
596 * @param launch the newly added launch
599 public void launchAdded(ILaunch launch){
603 * Notifies this listener that the specified launch
604 * has changed. For example, a process or debug target
605 * has been added to the launch.
607 * @param launch the changed launch
610 public void launchChanged(ILaunch launch) {
613 public IVariable[] getVariables(XDebugStackFrame StackFrame, int Level) {
614 return fDebugConnection.getVariables(StackFrame, Level);