X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse.debug.core/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGInterface.java b/net.sourceforge.phpeclipse.debug.core/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGInterface.java index 9d40c3f..d2262ae 100644 --- a/net.sourceforge.phpeclipse.debug.core/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGInterface.java +++ b/net.sourceforge.phpeclipse.debug.core/src/net/sourceforge/phpdt/internal/debug/core/PHPDBGInterface.java @@ -14,70 +14,77 @@ package net.sourceforge.phpdt.internal.debug.core; import java.io.BufferedReader; import java.io.IOException; import java.io.OutputStream; -import java.util.Vector; import java.util.Collections; +import java.util.Vector; +//import net.sourceforge.phpdt.internal.debug.core.PHPDBGProxy.PHPLoop; import net.sourceforge.phpdt.internal.debug.core.model.PHPDBGEvalString; import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame; -import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable; import net.sourceforge.phpdt.internal.debug.core.model.PHPValue; +import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugException; -import java.io.RandomAccessFile; - /** * The interface object are created by the proxy * */ public class PHPDBGInterface { - - public boolean sessionEnded = false; - public int sessType = -1; - public int BPUnderHit = 0; - public String sessID = new String (); - - private int[] LastBPRead = new int[10]; - private Vector DBGBPList = new Vector (); - private Vector DBGVarList = new Vector (); - private PHPStackFrame[] DBGStackList; - private Vector DBGMods = new Vector (); // The module names and their numbers - private Vector stackListOld = new Vector (); - private BufferedReader in; - private OutputStream os; // The stream which goes to DBG - private boolean shouldStop = false; - private String evalRet = new String (""); - private String serGlobals = new String (""); - private int rawCounter = 1000; // An rawData frame ID counter - private PHPDBGProxy proxy = null; - private int lastCmd = -1; - private int sid = 0; - private boolean stopOnError = false; - private char[] lastCommand = new char[4]; + public boolean sessionEnded = false; + public int sessType = -1; + public int BPUnderHit = 0; + public String sessID = new String(); + + private int[] LastBPRead = new int[10]; + private Vector DBGBPList = new Vector(); + private Vector DBGVarList = new Vector(); + private PHPStackFrame[] DBGStackList = new PHPStackFrame[0]; + private Vector DBGMods = new Vector(); // The module names and their numbers + private Vector stackListOld = new Vector(); + private BufferedReader dbgInput; + private OutputStream dbgOutput; // The stream which goes to DBG + private boolean shouldStop = false; + private String evalRet = new String(""); + private int rawCounter = 1000; // An rawData frame ID counter + private PHPDBGProxy proxy = null; +// private int lastCmd = -1; + private int sid = 0; + private boolean stopOnError = false; // If we the debugger should be relaunched after script termination + private boolean bRelaunch = true; + private char[] lastCommand = new char[4]; + private boolean bBusy = false; + private boolean bDebug = true; // Prints text to console for debugging purposes + + private static final String GlobalVariablesTitle = PHPDebugCorePlugin + .getResourceString("VariablesView.GlobalVariables.title"); /** - * @param in The input stream (communication from DBG). - * @param os The output stream (communication to DBG). - * @param proxy The proxy to which this interface belongs. + * @param in The input stream (communication from DBG). + * @param os The output stream (communication to DBG). + * @param proxy The proxy to which this interface belongs. + * @param bRelaunch The debugger should be relaunched after PHP script termination */ - public PHPDBGInterface (BufferedReader in, OutputStream os, PHPDBGProxy proxy) { + public PHPDBGInterface (BufferedReader in, OutputStream os, PHPDBGProxy proxy, boolean bRelaunch) { DBGBPList.clear (); - this.in = in; - this.os = os; - this.proxy = proxy; + this.dbgInput = in; + this.dbgOutput = os; + this.proxy = proxy; + this.bRelaunch = bRelaunch; } /** * - * @param mod_name The module (source file) to which we add the breakpoint. - * @param line The line where the breakpoint is set. - * @return Breakpoint ID ???. + * @param mod_name The module (source file) to which we add the breakpoint. + * @param line The line where the breakpoint is set. + * @param hitCount The number of hit counts before suspend. + * @param condition The break condition + * @return Breakpoint ID ???. */ - public int addBreakpoint (String mod_name, int line) throws IOException { - return setBreakpoint (mod_name, "", line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, 0, 0, 0, 0); + public int addBreakpoint (String mod_name, int line, int hitCount, String condition) throws IOException { + return setBreakpoint (mod_name, condition, line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, hitCount, 0, 0, 0); } /** @@ -94,21 +101,21 @@ public class PHPDBGInterface { * Is this method used anywhere? * */ - public void requestDBGVersion () throws IOException { - PHPDBGPacket DBGPacket; // A DBG message packet - PHPDBGFrame DBGFrame; // A frame within a DBG packet - - DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG - DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_VER); // We want the version of DBG - - DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet - - if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? - return; // No - } - - DBGPacket.sendPacket (os); // Send the request to DBG - } +// public void requestDBGVersion () throws IOException { +// PHPDBGPacket DBGPacket; // A DBG message packet +// PHPDBGFrame DBGFrame; // A frame within a DBG packet +// +// DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG +// DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_VER); // We want the version of DBG +// +// DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet +// +// if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? +// return; // No +// } +// +// DBGPacket.sendPacket (os); // Send the request to DBG +// } /** * Called by the proxy @@ -118,16 +125,26 @@ public class PHPDBGInterface { PHPDBGPacket DBGPacket; // A DBG message packet PHPDBGFrame DBGFrame; // A frame within a DBG packet + while (bBusy) { + } + + bBusy = true; + + if (bDebug) { + System.out.println ("PHPDBGInterface: getSourceTree"); + } + DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_SRC_TREE); // We want a source tree from DBG DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? + bBusy = false; return; // No } - DBGPacket.sendPacket (os); // Send the request to DBG + DBGPacket.sendPacket (dbgOutput); // Send the request to DBG waitResponse (1000); // Wait for the DBG response (1 second) flushAllPackets (); // Read and process the response from DBG @@ -138,27 +155,27 @@ public class PHPDBGInterface { * * @param modName The modul (filename). */ - public void addDBGModName (String modName) throws IOException { - PHPDBGPacket DBGPacket; // A DBG message packet - PHPDBGFrame DBGFrame; // A frame within a DBG packet - - DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG - DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA); // We want Module name from DBG - - rawCounter++; // Increment the rawData ID counter - DBGFrame.addInt (rawCounter); // FRAME_RAWDATA ID - DBGFrame.addInt (modName.length () + 1); // The length of rawdata string (incl. null char termination) - DBGFrame.addString (modName); // The file name (module name) - DBGFrame.addChar ('\0'); // Add the C-String null termination - - DBGPacket.addFrame (DBGFrame); - - if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? - return; // No - } - - DBGPacket.sendPacket (os); - } +// public void addDBGModName (String modName) throws IOException { +// PHPDBGPacket DBGPacket; // A DBG message packet +// PHPDBGFrame DBGFrame; // A frame within a DBG packet +// +// DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG +// DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA); // We want Module name from DBG +// +// rawCounter++; // Increment the rawData ID counter +// DBGFrame.addInt (rawCounter); // FRAME_RAWDATA ID +// DBGFrame.addInt (modName.length () + 1); // The length of rawdata string (incl. null char termination) +// DBGFrame.addString (modName); // The file name (module name) +// DBGFrame.addChar ('\0'); // Add the C-String null termination +// +// DBGPacket.addFrame (DBGFrame); +// +// if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? +// return; // No +// } +// +// DBGPacket.sendPacket (os); +// } /** * This method is called for adding or removing breakpoints. @@ -178,11 +195,22 @@ public class PHPDBGInterface { PHPDBGPacket DBGPacket; PHPDBGFrame DBGFrame1; PHPDBGFrame DBGFrame2; + PHPDBGFrame DBGFrame3; int modNo; + while (bBusy) { + } + + bBusy = true; + + if (bDebug) { + System.out.println ("PHPDBGInterface: setBreakpoint"); + } + DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); DBGFrame1 = new PHPDBGFrame (PHPDBGBase.FRAME_BPS); DBGFrame2 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA); + DBGFrame3 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA); modNo = getModByName (mod_name); // Get the module ID by name @@ -201,14 +229,6 @@ public class PHPDBGInterface { DBGFrame1.addInt (rawCounter); // ID of FRAME_RAWDATA to send file name } - DBGFrame1.addInt (state); // state BPS_* - DBGFrame1.addInt (istemp); // istep - DBGFrame1.addInt (hitcount); // hit count - DBGFrame1.addInt (skiphits); // skip hits - DBGFrame1.addInt (0); // ID of condition - DBGFrame1.addInt (bpno); // breakpoint number - DBGFrame1.addInt (isunderhit); // is under hit - if (modNo < 0) { // Did we find a module ID for the module name? DBGFrame2.addInt (rawCounter); // FRAME_RAWDATA ID DBGFrame2.addInt (mod_name.length() + 1); // length of rawdata (+ null char) @@ -218,13 +238,37 @@ public class PHPDBGInterface { DBGPacket.addFrame (DBGFrame2); // First add file name data } + DBGFrame1.addInt (state); // state BPS_* + DBGFrame1.addInt (istemp); // istemp + DBGFrame1.addInt (0); // hit count; this is not supported as one might think + DBGFrame1.addInt (hitcount); // skip hits is what we think is hit count. + + if (!condition.equals ("")) { // Do we have a condition for breakpoint + rawCounter++; // Set to new ID + DBGFrame1.addInt (rawCounter); // ID of condition + + DBGFrame3.addInt (rawCounter); // FRAME_RAWDATA ID + DBGFrame3.addInt (condition.length() + 1); // length of rawdata (+ null char) + DBGFrame3.addString (condition); // The break condition + DBGFrame3.addChar ('\0'); // null char + + DBGPacket.addFrame (DBGFrame3); // First add break condition + } + else { + DBGFrame1.addInt (0); // ID of condition is 0, because there is no condition + } + + DBGFrame1.addInt (bpno); // breakpoint number + DBGFrame1.addInt (isunderhit); // is under hit + DBGPacket.addFrame (DBGFrame1); // Second add command data if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? + bBusy = false; return 0; // No } - DBGPacket.sendPacket (os); // Send the request to DBG + DBGPacket.sendPacket (dbgOutput); // Send the request to DBG clearLastBP (); @@ -262,14 +306,17 @@ public class PHPDBGInterface { public void continueExecution () throws IOException { PHPDBGPacket DBGPacket; + if (bDebug) { + System.out.println ("PHPDBGInterface: continueExecution"); + } + BPUnderHit = 0; DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_CONTINUE); if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? return; // No } - - DBGPacket.sendPacket (os); // Send the request to DBG + DBGPacket.sendPacket (dbgOutput); // Send the request to DBG lastCommand = PHPDBGBase.DBGA_CONTINUE; // Store the info about the command we sent } @@ -280,13 +327,17 @@ public class PHPDBGInterface { public void pauseExecution () throws IOException { PHPDBGPacket DBGPacket; + if (bDebug) { + System.out.println ("PHPDBGInterface: pauseExecution"); + } + DBGPacket = new PHPDBGPacket (PHPDBGBase.IntToChar4 (PHPDBGBase.DBGC_PAUSE)); if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? return; // No } - DBGPacket.sendPacket (os); // Send the request to DBG + DBGPacket.sendPacket (dbgOutput); // Send the request to DBG } /** @@ -308,10 +359,10 @@ public class PHPDBGInterface { return BPUnder; } - public int getLastCmd() - { - return lastCmd; - } +// public int getLastCmd() +// { +// return lastCmd; +// } public int getSID() { @@ -320,78 +371,129 @@ public class PHPDBGInterface { public void setLastCmd (int cmd) { - lastCmd = cmd; + //lastCmd = cmd; } /** * */ - public void stepInto () throws IOException { + public boolean stepInto () throws IOException { PHPDBGPacket DBGPacket; + if (bBusy) { + if (bDebug) { + System.out.println ("PHPDBGInterface: stepOver vetoed"); + } + } + + while (bBusy) { + } + + bBusy = true; + + if (bDebug) { + System.out.println ("PHPDBGInterface: stepInto"); + } + BPUnderHit = 0; DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPINTO); if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? - return; // No + return false; // No } - DBGPacket.sendPacket (os); // Send the request to DBG + DBGPacket.sendPacket (dbgOutput); // Send the request to DBG lastCommand = PHPDBGBase.DBGA_STEPINTO; // Store the info about the command we sent + + return true; } /** * */ - public void stepOver () throws IOException { + public boolean stepOver () throws IOException { PHPDBGPacket DBGPacket; + if (bBusy) { + if (bDebug) { + System.out.println ("PHPDBGInterface: stepOver vetoed"); + } + } + + while (bBusy) { + } + + bBusy = true; + + if (bDebug) { + System.out.println ("PHPDBGInterface: stepOver"); + } + BPUnderHit = 0; DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOVER); if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? - return; // No + return false; // No } - DBGPacket.sendPacket (os); // Send the request to DBG + DBGPacket.sendPacket (dbgOutput); // Send the request to DBG lastCommand = PHPDBGBase.DBGA_STEPOVER; // Store the info about the command we sent + + return true; } /** * */ - public void stepOut () throws IOException { + public boolean stepOut () throws IOException { PHPDBGPacket DBGPacket; + if (bBusy) { + if (bDebug) { + System.out.println ("PHPDBGInterface: stepOver vetoed"); + } + } + + while (bBusy) { + } + + bBusy = true; + + if (bDebug) { + System.out.println ("PHPDBGInterface: stepOut"); + } + BPUnderHit = 0; DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOUT); if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? - return; // No + return false; // No } - DBGPacket.sendPacket (os); // Send the request to DBG + DBGPacket.sendPacket (dbgOutput); // Send the request to DBG lastCommand = PHPDBGBase.DBGA_STEPOUT; // Store the info about the command we sent + + return true; } /** * */ - public void stopExecution () throws IOException { - PHPDBGPacket DBGPacket; - - BPUnderHit = 0; - DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STOP); - - if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? - return; // No - } - - DBGPacket.sendPacket (os); // Send the request to DBG - } +// public void stopExecution () throws IOException { +// PHPDBGPacket DBGPacket; +// +// BPUnderHit = 0; +// DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STOP); +// +// if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG? +// return; // No +// } +// +// DBGPacket.sendPacket (os); // Send the request to DBG +// } /** * This method is called by the proxy. @@ -402,45 +504,154 @@ public class PHPDBGInterface { * @param stack The stackframe for which we want the variables. * @return The array of variables */ - public Vector getVariables (PHPStackFrame stack) throws IOException, DebugException { - PHPDBGPacket DBGPacket; - PHPDBGFrame DBGFrame1; - PHPDBGEvalString evalStr; + public synchronized Vector getVariables(PHPStackFrame stack) throws IOException, DebugException { + if (DBGStackList.length == 0) { + DBGVarList.clear(); - DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // - DBGFrame1 = new PHPDBGFrame (PHPDBGBase.FRAME_EVAL); // + return DBGVarList; + } - DBGFrame1.addInt (0); // istr = raw data ID - DBGFrame1.addInt (1); // scope_id = -1 means current location, 0 never used, +1 first depth + // get global variables (and assign them to 'main()' stackframe) + int global_scope_id = (DBGStackList.length > 1) ? 2 : PHPDBGBase.GLOBAL_SCOPE_ID; + // DBG 2.13.1 doesn't return Super Globals with GLOBAL_SCOPE_ID in nested stackframes, + // so using 2(most out-standing stack context) instead of GLOBAL_SCOPE_ID. + // Also note that 2.13.1 doesn't return $this in class context. + // (You can inspect $this in Expressions View. And once it is shown, 2.13.1 comes to return $this.) + Vector globalList = getVariables(DBGStackList[DBGStackList.length - 1], global_scope_id); + + if (!globalList.isEmpty()) { + // remove unresolved '$this=?' variable + removeUnresolvedThisVar(globalList); + + PHPVariable var = (PHPVariable) globalList.get(0); + var.setName(GlobalVariablesTitle); + var.setModifiable(false); + } - DBGPacket.addFrame (DBGFrame1); // Add command data + int scopeID = stack.getScopeID(); - if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication? - return null; // No, then leave here - } + if (!globalList.isEmpty () && + ((DBGStackList.length == 1) || (scopeID == PHPDBGBase.CURLOC_SCOPE_ID + 1))) { + // 'main()' stackframe + PHPVariable var = (PHPVariable) globalList.get(0); + PHPValue val = (PHPValue) var.getValue(); - DBGPacket.sendPacket (os); // Send the request to DBG + DBGVarList = val.getChildVariables(); - waitResponse (1000); // Wait for the DBG response (1 second) - flushAllPackets (); // Read and process the response from DBG + return DBGVarList; + } + else if (scopeID == PHPDBGBase.CURLOC_SCOPE_ID) { + // current stackframe + DBGVarList = getVariables(stack, PHPDBGBase.CURLOC_SCOPE_ID); + } + else { + // back-trace stackframe + //DBGVarList = getVariables(stack, scopeID); + //removeUnresolvedThisVar(DBGVarList); + // DBG 2.15.5 causes Application Error (on win32) in *some* cases. + DBGVarList.clear(); + } - evalStr = new PHPDBGEvalString (stack, serGlobals); // Process serialized variables - DBGVarList = evalStr.getVariables (); + if (DBGVarList.size() > 0) { // Did we get back variables? + PHPVariable var = (PHPVariable) DBGVarList.get(0); // Yes, then get the first PHPVariable + PHPValue val = (PHPValue) var.getValue(); // Get the value - PHPVariable var = (PHPVariable) DBGVarList.get (0); + if (var.getName().equals("")) { // Is the root node an empty node (usually it is) + DBGVarList = val.getChildVariables(); // Then remove the empty node. + // With removing the empty root node, it wouldn't be necessary to + // set the name to an empty string. So the code below is just for + // info or in case the users want to have the empty root node. - if (var.getName ().equals ("")) { // The eclipse variable view cannot handle Variables which have an empty name + // The eclipse variable view cannot handle Variables which have an empty name // when it comes to variable tree restore operation. Without a name, no restore! - var.setName (" "); // Give a name to the variable root node. Even if it is only a space :.) - } // TODO the best would be to remove the empty root node, but this would + //var.setName (" "); // Give a name to the variable root node. Even if it is only a space :-) + } // TO DO the best would be to remove the empty root node, but this would // require a understanding and reworking of the PHPDBGEvalstring class. + } + if (!globalList.isEmpty()) { + DBGVarList.add(globalList.get(0)); + } return DBGVarList; // Return the variables as list } /** * + */ + private Vector getVariables(PHPStackFrame stack, int scope_id) throws IOException { + PHPDBGPacket DBGPacket = new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST); + PHPDBGFrame DBGFrame1 = new PHPDBGFrame(PHPDBGBase.FRAME_EVAL); + + if (bBusy) { + if (bDebug) { + System.out.println ("PHPDBGInterface: getVariables vetoed"); + } + } + + while (bBusy) { + } + + bBusy = true; + + if (bDebug) { + System.out.println ("PHPDBGInterface: getVariables"); + } + + DBGFrame1.addInt(0); + DBGFrame1.addInt(scope_id); + + DBGPacket.addFrame(DBGFrame1); + evalRet = ""; + + if (proxy.getSocket().isClosed()) { + bBusy = false; + return new Vector(); + } + + DBGPacket.sendPacket(dbgOutput); + + waitResponse(1000); + flushAllPackets(); + + bBusy = false; // Already done in flushAllPackets () + + PHPDBGEvalString evalStr = new PHPDBGEvalString(stack, evalRet); + return evalStr.getVariables(); + } + + /** + * Remove unresolved $this variable + * + * DBG returns $this=? in function's or intermediate stackframes. + * (In current method's stackframe, DBG returns $this=classname) + * + * @param varList + */ + private void removeUnresolvedThisVar(Vector varList) { + if (varList.size() > 0) { + PHPVariable var = (PHPVariable) varList.get(0); + PHPValue val = (PHPValue) var.getValue(); + Vector workList = val.getChildVariables (); + + for (int i = 0; i < workList.size(); i++) { + PHPVariable workvar = (PHPVariable) workList.get(i); + + if (workvar.getName().equals ("$this")) { + String workval = ((PHPValue) workvar.getValue ()).getValueString (); + + if (workval.equals ("?") || + workval.equals ("NULL")) { + workList.remove (i); + } + break; + } + } + } + } + + /** + * * @param logString */ public void log(String logString) throws IOException, DebugException { @@ -448,6 +659,15 @@ public class PHPDBGInterface { PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_LOG); PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA); + while (bBusy) { + } + + bBusy = true; + + if (bDebug) { + System.out.println ("PHPDBGInterface: log"); + } + rawCounter++; DBGFrame1.addInt(rawCounter); // ilog DBGFrame1.addInt(1); // type @@ -466,21 +686,41 @@ public class PHPDBGInterface { // Add command data DBGPacket.addFrame(DBGFrame1); - if(proxy.getSocket().isClosed()) return; - DBGPacket.sendPacket(os); + if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication? + bBusy = false; + return; // No, then leave here + } + + DBGPacket.sendPacket(dbgOutput); waitResponse(1000); flushAllPackets(); } - public PHPVariable[] evalBlock(PHPStackFrame stack, String evalString) throws IOException, DebugException { + public synchronized PHPVariable[] evalBlock(PHPStackFrame stack, String evalString) throws IOException, DebugException { PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST); PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL); PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA); + while (bBusy) { + } + + bBusy = true; + + if (bDebug) { + System.out.println ("PHPDBGInterface: evalBlock"); + } + rawCounter++; DBGFrame1.addInt(rawCounter); // istr = raw data ID - DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth + //DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth + int scope_id = stack.getScopeID(); + /* test code : unnecessary + if (DBGStackList.length == 1 || scope_id == (PHPDBGBase.CURLOC_SCOPE_ID + 1)) { + scope_id = PHPDBGBase.GLOBAL_SCOPE_ID; + } + */ + DBGFrame1.addInt(scope_id); DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID DBGFrame2.addInt(evalString.length() + 1); // length of rawdata (+ null char) @@ -492,16 +732,19 @@ public class PHPDBGInterface { // Add command data DBGPacket.addFrame(DBGFrame1); - if(proxy.getSocket().isClosed()) return null; - DBGPacket.sendPacket(os); + if (proxy.getSocket().isClosed()) { // Do we have a socket for DBG communication? + bBusy = false; + return null; // No, then leave here + } + + DBGPacket.sendPacket(dbgOutput); waitResponse(1000); flushAllPackets(); - PHPDBGEvalString evalStr=new PHPDBGEvalString(stack,evalRet); + PHPDBGEvalString evalStr=new PHPDBGEvalString(stack, evalRet); return evalStr.getVars(); - } /** @@ -582,6 +825,10 @@ public class PHPDBGInterface { toRead = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The size of the string + if ((int) framesInfo[nextFrame + 8 + toRead - 1] == 0) { // Is there a string termination at the end? + return String.copyValueOf (framesInfo, nextFrame + 8, toRead - 1); // Then copy frame content to String without the \0 and return + } + return String.copyValueOf (framesInfo, nextFrame + 8, toRead); // Copy frame content to String and return } break; @@ -594,6 +841,77 @@ public class PHPDBGInterface { } /** + * Reset the availability flag for all stackframes in the list. + * + * @param list The list of old stackframes + */ + private void resetAvailability (Vector list) { + int i; + + for (i = 0; i < list.size (); i++) { + ((PHPStackFrame) list.get(i)).setAvailable (false); // + } + } + + /** + * Check whether the new stackframe is in the list of old stackframes. + * Test for identical stackframe (identical means same description and same line number). + * + * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list + * @param list The list of old stackframes + * @return + * - true if we have found the identical stackframe within the list + * - false if we did not find the identical stackframe within the list + */ + private boolean isStackFrameInList (PHPStackFrame stackFrameNew, Vector list) { + int i; + PHPStackFrame stackFrameOld; + + for (i = 0; i < list.size (); i++) { + stackFrameOld = (PHPStackFrame) list.get (i); // + + if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) && + stackFrameNew.getLineNumber () == stackFrameOld.getLineNumber ()) { // Did we find the sent stackframe within the list of old stackframes? + stackFrameOld.setAvailable (true); // We found the new stackframe in the list of old stack frames + stackFrameOld.setIndex (stackFrameNew.getIndex ()); + stackFrameOld.setScopeID(stackFrameNew.getScopeID()); + + return true; // The stackframe was found in the list + } + } + + return false; + } + + /** + * Check whether the new stackframe is in the list of old stackframes. + * Test for exact stackframe (exact means same description and same line number). + * + * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list + * @param list The list of old stackframes + * @return + * - true if we have exactly this stackframe within the list + * - false if we did not find the exact stackframe within the list + */ + private void markIdenticalStackFrames (Vector oldList, Vector newList) { + int i; + PHPStackFrame stackFrameNew; + + resetAvailability (oldList); // Reset the availability flag of the old stack frames + resetAvailability (newList); // Reset the availability flag of the old stack frames + + for (i = 0; i < newList.size (); i++) { // For all stackList entries + stackFrameNew = (PHPStackFrame) newList.get (i); + + if (isStackFrameInList (stackFrameNew, oldList)) { // Is this stackframe in the list + stackFrameNew.setAvailable (true); // + // +// break; + } + } + } + + /** * * The stackList contains the currently read stackframes which were sent * from DBG. The DBG interface holds a list of the active stack frames. @@ -603,10 +921,10 @@ public class PHPDBGInterface { *
  • It looks for new stackframes within the DBG stackframe list and * adds them to the 'static' list. *
  • It looks for stackframes within the 'static' list, and removes them - * from the 'static' list in case the do not appear within the DBG list. + * from the 'static' list in case they do not appear within the DBG list. *
  • It looks for stackframes which are already existent and replicates the * line number and the index number. - *
  • At the end the 'static' stackfram list has to be sorted by the stackframes + *
  • At the end, the 'static' stackframe list has to be sorted by the stackframes * index numbers. * * @@ -623,41 +941,48 @@ public class PHPDBGInterface { PHPStackFrame stackFrameOld; PHPStackFrame[] newStackList; + if (bDebug) { + System.out.println ("PHPDBGInterface: updateStackFrameList Start"); + } + + markIdenticalStackFrames (stackListOld, stackList); // Check whether the newly send stack frames can be found in the list + // of old stack frames + for (i = 0; i < stackList.size (); i++) { // For all stackList entries stackFrameNew = (PHPStackFrame) stackList.get(i); for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list stackFrameOld = (PHPStackFrame) stackListOld.get (n); // - if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) { // Did we find the sent stackframe within the list of old stackframes? + if (stackFrameOld.isAvailable ()) { // If this stack frame was already found in the new list skip it + continue; + } + + if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) {// Did we find the sent stackframe within the list of old stackframes? stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ()); stackFrameOld.setIndex (stackFrameNew.getIndex ()); + stackFrameOld.setScopeID(stackFrameNew.getScopeID()); + + stackFrameOld.setAvailable (true); // And mark this stack frame as available + stackFrameNew.setAvailable (true); // And mark this stack frame as available break; // Yes, then break; } } - if (n == stackListOld.size ()) { // Did not find the new stackframe within the list + if (!stackFrameNew.isAvailable ()) { // Did not find the new stackframe within the list? + stackFrameNew.setAvailable (true); // Mark the stack frame as available and stackListOld.add (stackFrameNew); // then add the new stackframe } } // And now for removing unused stackframes from list - for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list - stackFrameOld = (PHPStackFrame) stackListOld.get (n); // - - for (i = 0; i < stackList.size (); i++) { // For all stackList entries - stackFrameNew = (PHPStackFrame) stackList.get (i); - - if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) { // Did we find the sent stackframe within the list of old stackframes? - break; // Yes, then break; - } - } + for (n = 0; n < stackListOld.size(); n++) { + stackFrameOld = (PHPStackFrame) stackListOld.get(n); - if (i == stackList.size ()) { // Did not find the old stackframe within the list of new ones - stackListOld.remove (n); // then remove the old stackframe from list - n -= 1; // Adjust the stack list index + if (!stackFrameOld.isAvailable()) { + stackListOld.remove(n--); } } @@ -666,6 +991,10 @@ public class PHPDBGInterface { newStackList = new PHPStackFrame[stackListOld.size ()]; newStackList = (PHPStackFrame[]) stackListOld.toArray (newStackList); DBGStackList = newStackList; + + if (bDebug) { + System.out.println ("PHPDBGInterface: updateStackFrameList End"); + } } /** @@ -692,6 +1021,10 @@ public class PHPDBGInterface { Vector rawList = new Vector(); Vector stackList = new Vector(); // Intermediate stacklist which is build up in FRAME_STACK frame + if (bDebug) { + System.out.println ("PHPDBGInterface: readResponse start"); + } + rawList.clear (); stackList.clear (); @@ -703,6 +1036,11 @@ public class PHPDBGInterface { dbg_header_struct[3] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 12); // Bytes within this block if (dbg_header_struct[0] != 0x5953) { // Check DBG sync bytes + if (bDebug) { + System.out.println ("PHPDBGInterface: readResponse. Wrong sync"); + } + + bBusy = false; return 0; // Wrong header } @@ -715,6 +1053,11 @@ public class PHPDBGInterface { if (bytesToRead > 0) { // If there is something within the frame if (readInput (entirePack, bytesToRead) < bytesToRead) { // Read the frame into the buffer + if (bDebug) { + System.out.println ("PHPDBGInterface: readResponse. Did not read enough"); + } + + bBusy = false; return 0; // We did not read enough bytes, error } } @@ -727,6 +1070,11 @@ public class PHPDBGInterface { nextFrame += 8; // The next read position if (dbg_frame[1] == 0) { // Something within the frame? + if (bDebug) { + System.out.println ("PHPDBGInterface: readResponse. Nothing within the frame"); + } + + bBusy = false; return 0; // Nothing to read, error } @@ -749,7 +1097,8 @@ public class PHPDBGInterface { stackIndex, getRawFrameData (entirePack, // Get the string from this packet dbg_stack_new[3]), // The frame ID for which we want the string - dbg_stack_new[1]); // The module number + dbg_stack_new[1], // The module number + dbg_stack_new[2]); stackList.add (newStack); } @@ -770,10 +1119,6 @@ public class PHPDBGInterface { fileName = new String (getRawFrameData (entirePack, dbg_src_tree_tmp[3])); // Get the filename - if (fileName.length () > 0) { // If we have a filename - fileName = fileName.substring (0, fileName.length () - 1); // Remove '\0' char - } - if (dbg_src_tree_tmp[2] != 0) { // If there is a module number PHPDBGMod modNew; @@ -811,11 +1156,6 @@ public class PHPDBGInterface { error += ": "; error += new String (getRawFrameData (entirePack, dbg_error_tmp[1])); // Add the error string for this error message ID - - if (error.length () > 0) { // If we have a error message - error = error.substring (0, error.length () - 1); // Remove '\0' char - } - error += "\n"; // Append a CR PHPDebugCorePlugin.log (new DebugException (new Status (IStatus.WARNING, @@ -849,16 +1189,15 @@ public class PHPDBGInterface { break; case PHPDBGBase.FRAME_EVAL: - String evalString; + //String evalString; - evalString = new String (""); + //evalString = new String (""); dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // istr dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // iresult dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // ierror evalRet = getRawFrameData (entirePack, dbg_eval_tmp[1]); // - evalString = getRawFrameData (entirePack, dbg_eval_tmp[0]); // - serGlobals = evalRet; // + //evalString = getRawFrameData (entirePack, dbg_eval_tmp[0]); // break; case PHPDBGBase.FRAME_BPS: // @@ -900,10 +1239,6 @@ public class PHPDBGInterface { fileName = new String (getRawFrameData (entirePack, dbg_bpl_new[2])); - if (fileName.length () > 0) { // If we have filename - fileName = fileName.substring (0, fileName.length () - 1); // Remove '\0' char - } - if (dbg_bpl_new[0] != 0) { PHPDBGMod modNew; @@ -952,7 +1287,15 @@ public class PHPDBGInterface { break; case PHPDBGBase.DBGC_END: - sessionEnded = true; + if (bRelaunch) { + continueExecution (); // Inform dbg that we want to continue execution + proxy.updateView (); // Sent a change event and create thread event to eclipse core + updateStackFrameList (stackList); // ??? Just a try + } + else { + sessionEnded = true; + proxy.setTerminated (); + } break; case PHPDBGBase.DBGC_BREAKPOINT: @@ -982,6 +1325,12 @@ public class PHPDBGInterface { } } + if (bDebug) { + System.out.println ("PHPDBGInterface: readResponse finish, received: " + cmdReceived); + } + + bBusy = false; + return cmdReceived; // Return the command we received with this block } @@ -1003,14 +1352,51 @@ public class PHPDBGInterface { */ private int readInput (char[] buffer, int bytes) throws IOException { int bytesRead = 0; // Reset the bytes read counter + int nRetry = 0; // Retry counter - for (int i = 0; i < bytes; i++) { // For the number of bytes we should read - if (in.ready ()) { // If input stream is ready for reading - buffer[i] = (char) (in.read () & 0x00FF); // Read a char and store only the least significant 8-bits + if (bDebug) { + System.out.println ("PHPDBGInterface: readInput " + bytes); + } + + for (int i = 0; i < bytes;) { // For the number of bytes we should read + if (dbgInput.ready ()) { // If input stream is ready for reading + nRetry = 0; // Reset the retry counter + buffer[i] = (char) (dbgInput.read () & 0x00FF); // Read a char and store only the least significant 8-bits bytesRead++; // Increment the bytes read counter + i++; } else { // Input stream is not ready - break; // Break the loop + nRetry++; // Increment the retry counter + + if (nRetry > 10) { // If nothing received within 100 retries + if (i > 0) { + if (bDebug) { + System.out.println ("PHPDBGInterface: Too many retries without receiving something"); + } + } + break; // we break the loop + } + + synchronized (dbgInput) { + if (i > 0) { + if (bDebug) { + System.out.println ("PHPDBGInterface: retry: " + nRetry + " Wait for something to receive, received: " + i + " need " + bytes); + } + } + try { + dbgInput.wait (10); // wait 5 ms maximum for something to receive + } catch (InterruptedException e) { + } + } + } + } + + if (bytesRead > 0) { + if (bytes != bytesRead) { + if (bDebug) { + System.out.println ("PHPDBGInterface: readInput: Possible error: not enough bytes in buffer should read: " + bytes + + " actually read: " + bytesRead); + } } } @@ -1031,18 +1417,33 @@ public class PHPDBGInterface { * @return - true if something was received from DBG * - false if nothing was send from DBG within the given time * + * This method has been a busy wait loop. It was changed to use + * a non busy wait to avoid a heavy load after automatic relaunch + * after script termination + * */ public boolean waitResponse (long milliseconds) throws IOException { long timeout; + if (bDebug) { + System.out.println ("PHPDBGInterface: waitResponse " + milliseconds); + } + timeout = System.currentTimeMillis () + milliseconds; // Calculate the system time till we wait. while (System.currentTimeMillis () < timeout) { // Is waiting time running out? - if (in.ready () || shouldStop) { // No, so did we get something or should we stop now - break; // Yes, break the waiting + synchronized (dbgInput) { + try { + dbgInput.wait (5); // wait 5 ms maximum for something to receive + } catch (InterruptedException e) { + } + } + + if (dbgInput.ready () || shouldStop) { // If something is received of if we should stop now + break; // break the waiting loop } } - return in.ready (); // true if we got something from DBG + return dbgInput.ready (); // true if we got something from DBG } }