/*********************************************************************************************************************************** * Copyright (c) 2000, 2002 IBM Corp. and others. All rights reserved. This program and the accompanying materials are made * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: IBM Corporation - Initial implementation Vicente Fernando - www.alfersoft.com.ar Christian Perkonig - remote debug **********************************************************************************************************************************/ package net.sourceforge.phpdt.internal.debug.core; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.util.Map; import net.sourceforge.phpdt.internal.debug.core.breakpoints.PHPLineBreakpoint; import net.sourceforge.phpdt.internal.debug.core.model.PHPDebugTarget; import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame; import net.sourceforge.phpdt.internal.debug.core.model.PHPThread; import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable; import net.sourceforge.phpeclipse.PHPeclipsePlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.model.IBreakpoint; public class PHPDBGProxy { private ServerSocket server = null; private Socket socket; private BufferedReader reader = null; private PHPDBGInterface DBGInt = null; private PHPDebugTarget debugTarget = null; private PHPLoop phpLoop; private PHPThread PHPMainThread; private PHPDBGProxy thisProxy = null; private int port; private boolean remote; private boolean pathtranslation; private Map pathmap; private IPath remoteSourcePath; public PHPDBGProxy() { thisProxy = this; } public PHPDBGProxy(boolean remote, String remoteSourcePath,boolean pathTranslate,Map paths) { thisProxy = this; this.remote = remote; this.remoteSourcePath = new Path(remoteSourcePath); this.pathmap=paths; this.pathtranslation=pathTranslate; } public void start() { createServerSocket(); this.startPHPLoop(); } public void stop() { phpLoop.setShouldStop(); if (DBGInt != null) DBGInt.setShouldStop(); if (!remote) { try { getDebugTarget().getProcess().terminate(); } catch (DebugException e) { e.printStackTrace(); } } phpLoop.notifyWait(); } protected ServerSocket getServerSocket() throws IOException { if (server == null) { createServerSocket(); } return server; } protected void createServerSocket() { port = SocketUtil.findUnusedLocalPort("localhost", 10001, 10101); // port = 10001; if (port == -1) { PHPDebugCorePlugin.log(5, "Cannot find free port!!!!"); return; } try { if (server == null) { server = new ServerSocket(port); //System.out.println("ServerSocket on port: " + port); } } catch (IOException e) { // IO Error PHPDebugCorePlugin.log(e); stop(); } } public Socket getSocket() throws IOException { return socket; } protected void setDBGInterface(PHPDBGInterface DBGInt) { this.DBGInt = DBGInt; } public BufferedReader getReader() throws IOException { if (reader == null) { reader = new BufferedReader(new InputStreamReader(this.getSocket().getInputStream(), "ISO8859_1")); } return reader; } public BufferedReader getReader(Socket socket) throws IOException { if (socket != null) return new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO8859_1")); else return null; } public OutputStream getOutputStream() throws IOException { return this.getSocket().getOutputStream(); } protected void setBreakPoints() throws IOException, CoreException { IBreakpoint[] breakpoints = DebugPlugin.getDefault() .getBreakpointManager().getBreakpoints(); for (int i = 0; i < breakpoints.length; i++) { if (breakpoints[i].isEnabled()) { addBreakpoint(breakpoints[i]); } } } private String MapPath(PHPLineBreakpoint phpLBP) { IPath filename; if (remote) { filename = phpLBP.getMarker().getResource() .getProjectRelativePath(); filename = remoteSourcePath.append(filename); } else filename = phpLBP.getMarker().getResource().getLocation(); String path = filename.toOSString(); if (pathmap != null && remote) { java.util.Iterator i = pathmap.keySet().iterator(); while (i.hasNext()) { String k = (String) i.next(); if (path.startsWith(k)) { path = pathmap.get(k) + path.substring(k.length()); break; } } } if (pathtranslation && remote) { if (remoteSourcePath.toString().substring(0, 1).equals("/")) path = path.replace('\\', '/'); else path = path.replace('/', '\\'); } return path; } public void addBreakpoint(IBreakpoint breakpoint) { if (DBGInt == null) return; int bpNo = 0; try { PHPLineBreakpoint phpLBP; if (breakpoint.getModelIdentifier() == PHPDebugCorePlugin.getUniqueIdentifier()) { phpLBP = (PHPLineBreakpoint) breakpoint; // bpNo= DBGInt.addBreakpoint(phpLBP.getMarker().getResource().getLocation().toOSString(), phpLBP.getLineNumber()); bpNo = DBGInt.addBreakpoint(MapPath(phpLBP), phpLBP.getLineNumber()); phpLBP.setDBGBpNo(bpNo); } } catch (IOException e) { PHPDebugCorePlugin.log(e); stop(); } catch (CoreException e) { PHPDebugCorePlugin.log(e); stop(); } } public void removeBreakpoint(IBreakpoint breakpoint) { if (DBGInt == null) return; try { PHPLineBreakpoint phpLBP; if (breakpoint.getModelIdentifier() == PHPDebugCorePlugin.getUniqueIdentifier()) { phpLBP = (PHPLineBreakpoint) breakpoint; // bpNo= DBGInt.addBreakpoint(filename.toOSString(), phpLBP.getLineNumber()); DBGInt.removeBreakpoint(MapPath(phpLBP), phpLBP.getLineNumber(), phpLBP.getDBGBpNo()); } } catch (IOException e) { PHPDebugCorePlugin.log(e); stop(); } catch (CoreException e) { PHPDebugCorePlugin.log(e); stop(); } } public void phpLoopNotify() { phpLoop.notifyWait(); } public void startPHPLoop() { phpLoop = new PHPLoop(); phpLoop.start(); } public void resume() { try { DBGInt.continueExecution(); phpLoop.notifyWait(); } catch (IOException e) { PHPeclipsePlugin.log("Debugging session ended.", e); stop(); } } public void pause() { try { if (null != DBGInt) DBGInt.pauseExecution(); else { // TODO Make sure the Suspend action is grayed out // when DBGInt is null } } catch (IOException e) { PHPDebugCorePlugin.log(e); stop(); } } protected PHPDebugTarget getDebugTarget() { return debugTarget; } public void setDebugTarget(PHPDebugTarget debugTarget) { this.debugTarget = debugTarget; debugTarget.setPHPDBGProxy(this); } public PHPVariable[] readVariables(PHPStackFrame frame) { try { return DBGInt.getVariables(frame); } catch (IOException ioex) { ioex.printStackTrace(); throw new RuntimeException(ioex.getMessage()); } catch (DebugException ex) { ex.printStackTrace(); throw new RuntimeException(ex.getMessage()); } } public PHPVariable[] eval(PHPStackFrame frame, String evalString) { try { return DBGInt.evalBlock(frame, evalString); // return DBGInt.getVariables(frame); } catch (IOException ioex) { ioex.printStackTrace(); throw new RuntimeException(ioex.getMessage()); } catch (DebugException ex) { ex.printStackTrace(); throw new RuntimeException(ex.getMessage()); } } public void readStepOverEnd(PHPStackFrame stackFrame) { try { DBGInt.stepOver(); phpLoop.notifyWait(); } catch (Exception e) { PHPDebugCorePlugin.log(e); } } public void readStepReturnEnd(PHPStackFrame stackFrame) { try { DBGInt.stepOut(); phpLoop.notifyWait(); } catch (Exception e) { PHPDebugCorePlugin.log(e); } } public void readStepIntoEnd(PHPStackFrame stackFrame) { try { DBGInt.stepInto(); phpLoop.notifyWait(); } catch (Exception e) { PHPDebugCorePlugin.log(e); } } /* * public PHPStackFrame[] readFrames(PHPThread thread) { //try { //this.println("th " + thread.getId() + " ; f "); //return new * FramesReader(getMultiReaderStrategy()).readFrames(thread); return null; //} catch (IOException e) { // * PHPDebugCorePlugin.log(e); // return null; //} * } */ public void closeSocket() throws IOException { if (socket != null) { socket.close(); } } public void closeServerSocket() throws IOException { if (server != null) { server.close(); } } public int getPort() { return port; } class PHPLoop extends Thread { private boolean shouldStop; public PHPLoop() { shouldStop = false; this.setName("PHPDebuggerLoop"); } public synchronized void setShouldStop() { shouldStop = true; try { // If the loop thread is blocked on the server socket, // forcibly unblock it to avoid leaking the thread, // the socket and the port closeServerSocket(); } catch (IOException x) { // Log this as a warning? PHPDebugCorePlugin.log(x); } } public synchronized void notifyWait() { notify(); } public void run() { try { char[] buf = new char[16]; int i, pos, timeout; long interval = 200; // 200ms String line; PHPStackFrame[] StackList; boolean endFile = false; boolean newconnect = false; Socket newSocket = null; PHPDBGInterface newDBGInt; int sid = -1; // synchronized (this) { // wait(); // } PHPMainThread = new PHPThread(getDebugTarget(), getPort()); PHPMainThread.setName("Thread [main]"); timeout = 0; // while ((getDebugTarget() == null) && (timeout < 100)) { // sleep(100); // timeout++; // } // Be sure debug target is set // PHPMainThread.setDebugTarget(getDebugTarget()); getDebugTarget().addThread(PHPMainThread); //System.out.println("Waiting for breakpoints."); while (!shouldStop) { newconnect = true; try { newSocket = server.accept(); //System.out.println("Accepted! : " + socket.toString()); } catch (SocketTimeoutException e) { // no one wants to connect newconnect = false; } catch (IOException e) { PHPDebugCorePlugin.log(e); return; } if (newconnect) { if (DBGInt == null) server.setSoTimeout(1); newDBGInt = new PHPDBGInterface(getReader(newSocket), newSocket.getOutputStream(), thisProxy); newDBGInt.waitResponse(1000); newDBGInt.flushAllPackets(); // Check version and session ID if ((DBGInt == null) || (DBGInt.getSID() == newDBGInt.getSID())) { DBGInt = newDBGInt; try { closeSocket(); } catch (IOException e) { PHPDebugCorePlugin.log(e); shouldStop = true; } socket = newSocket; setBreakPoints(); DBGInt.continueExecution(); } else { newDBGInt.continueExecution(); newSocket.close(); } } if (DBGInt.waitResponse(interval)) { DBGInt.flushAllPackets(); if (DBGInt.BPUnderHit != 0) { StackList = DBGInt.getStackList(); if (StackList.length > 0) { for (i = 0; i < StackList.length; i++) { StackList[i].setThread(PHPMainThread); if (DBGInt.getModByNo(StackList[i].getModNo()).equals("")) { DBGInt.getSourceTree(); } StackList[i].setFile(DBGInt.getModByNo(StackList[i].getModNo())); } PHPMainThread.setStackFrames(StackList); } // Fire debug event PHPMainThread.suspend(); synchronized (this) { wait(); } } } if (remote) { if (PHPMainThread.isTerminated()) { shouldStop = true; break; } } else { if (PHPMainThread.isTerminated() || getDebugTarget().getProcess().isTerminated()) { shouldStop = true; break; } } } } catch (Exception ex) { PHPDebugCorePlugin.log(ex); System.out.println(ex); } finally { try { getDebugTarget().terminate(); closeSocket(); closeServerSocket(); } catch (IOException e) { PHPDebugCorePlugin.log(e); return; } //System.out.println("Socket loop finished."); } } } }