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 d0576f9..0ae3bc0 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 @@ -26,14 +26,11 @@ 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; @@ -72,12 +69,14 @@ public class PHPDBGInterface { /** * - * @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); } /** @@ -178,11 +177,13 @@ public class PHPDBGInterface { PHPDBGPacket DBGPacket; PHPDBGFrame DBGFrame1; PHPDBGFrame DBGFrame2; + PHPDBGFrame DBGFrame3; int modNo; 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 +202,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,6 +211,29 @@ 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? @@ -394,96 +410,6 @@ public class PHPDBGInterface { } /** - * This method updates the 'static' variables list. - * It does a replication between the 'static' list (the variable list which - * is a member of this DBG interface object) and the DBG variable list - * (the list of variables which is received from PHP via DBG with the current suspend) - * Replication is done in the following way: - * - * - * @param varListOld The 'static' list of variables which are to be updated. - * @param varListNew The new list of (current) variables from DBG. - */ - private void updateVariableList (Vector varListOld, Vector varListNew) - { - PHPVariable varOld; // The variable from the 'static' list - PHPVariable varNew; // The variable from the DBG list - PHPValue valOld; // The value of the current variable from 'static' list - PHPValue valNew; // The value of the current variable from DBG list - int n; // Index for the DBG list - int o; // Index for the static list - - // Add the variables (and childs) to the static list if they are new - // and update the values of variables which are already existend within - // the 'static' list. - - for (n = 0; n < varListNew.size (); n++) { // For every variable in 'DBG list' - varNew = (PHPVariable) varListNew.get (n); // Get the DBG variable - - for (o = 0; o < varListOld.size (); o++) { // For every variable in static list - varOld = (PHPVariable) varListOld.get (o); // Get the static variable - - if (varNew.getName ().equals (varOld.getName ())) { // Did we found the variable within the 'static' list? - valOld = (PHPValue) varOld.getValue (); // Get the value from 'static' - valNew = (PHPValue) varNew.getValue (); // Get the value from DBG - - try { - if (valOld.hasVariables () || // If the 'static' value has child variables - valNew.hasVariables ()) { // or if the DBG value has child variables - updateVariableList (valOld.getChildVariables (), // Update the variable list for the child variables - valNew.getChildVariables ()); - } - else if (!valOld.getValueString ().equals (valNew.getValueString ())) { // Has the value changed? - valOld.setValueString (valNew.getValueString ()); // Yes, set the 'static' value (variable) to the new value - varOld.setValueChanged (true); // and set the 'has changed' flag, so that the variable view - // could show the user the changed status with a different - // color - } - else { - varOld.setValueChanged (false); // Reset the 'has changed' flag - } - } - catch (DebugException e) { // That's, because of the hasVariables method - } - - break; // Found the variable, - } - } - - if (o == varListOld.size ()) { // Did we found the variable within the static list? - varListOld.add (varNew); // No, then add the DBG variable to the static list - } - } - - // Look for the variables we can remove from the 'static' list - - for (o = 0; o < varListOld.size (); o++) { // For every variable in 'static' list - varOld = (PHPVariable) varListOld.get (o); // Get the static variable - - for (n = 0; n < varListNew.size (); n++) { // For all variables in 'DBG' list - varNew = (PHPVariable) varListNew.get (n); // Get the variable from the 'DBG' list - - if (varNew.getName ().equals (varOld.getName ())) { // Did we found the 'static' list variable within the 'DBG' list? - break; // Yes we found the variable, then leave the loop - } - } - - if (n == varListNew.size ()) { // Did not find the 'static' list variable within the 'DBG' list? - varListOld.remove (o); // then remove the 'static' list variable from list - o -= 1; // Adjust the 'static' list index - } - } - } - - /** * This method is called by the proxy. * It sends a request to DBG to get the current variables * with their values. It waits for the response and processes @@ -492,7 +418,7 @@ 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 { + public synchronized Vector getVariables (PHPStackFrame stack) throws IOException, DebugException { PHPDBGPacket DBGPacket; PHPDBGFrame DBGFrame1; PHPDBGEvalString evalStr; @@ -506,7 +432,7 @@ public class PHPDBGInterface { DBGPacket.addFrame (DBGFrame1); // Add command data if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication? - return null; // No, then leave here + return new Vector (); // No, then leave here with an empty vector } DBGPacket.sendPacket (os); // Send the request to DBG @@ -515,9 +441,26 @@ public class PHPDBGInterface { flushAllPackets (); // Read and process the response from DBG evalStr = new PHPDBGEvalString (stack, serGlobals); // Process serialized variables - updateVariableList (DBGVarList, evalStr.getVariables ()); // Replicate the 'static' variable list and the via DBG received variable list + 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 + + 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. + + // 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 + // require a understanding and reworking of the PHPDBGEvalstring class. + } - return DBGVarList; // Convert the list to an array and return the array + return DBGVarList; // Return the variables as list } /** @@ -547,14 +490,17 @@ public class PHPDBGInterface { // Add command data DBGPacket.addFrame(DBGFrame1); - if(proxy.getSocket().isClosed()) return; + if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication? + return; // No, then leave here + } + DBGPacket.sendPacket(os); 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); @@ -573,7 +519,9 @@ public class PHPDBGInterface { // Add command data DBGPacket.addFrame(DBGFrame1); - if(proxy.getSocket().isClosed()) return null; + if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication? + return null; // No, then leave here + } DBGPacket.sendPacket(os); waitResponse(1000); @@ -663,6 +611,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; @@ -675,6 +627,75 @@ 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 ()); + 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. @@ -684,10 +705,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. * * @@ -704,21 +725,32 @@ public class PHPDBGInterface { PHPStackFrame stackFrameOld; PHPStackFrame[] newStackList; + 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); // --- + stackFrameOld = (PHPStackFrame) stackListOld.get (n); // + + if (stackFrameOld.isAvailable ()) { // If this stack frame was already found in the new list skip it + continue; + } - if (stackFrameNew.getModNo () == stackFrameOld.getModNo ()) { // Did we find the sent stackframe within the list of old stackframes? + 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.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 } } @@ -726,14 +758,11 @@ public class PHPDBGInterface { // 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); + stackFrameOld = (PHPStackFrame) stackListOld.get (n); // - if (stackFrameNew.getModNo () == stackFrameOld.getModNo ()) { // Did we find the sent stackframe within the list of old stackframes? - break; // Yes, then break; - } + i = 0; + if (!stackFrameOld.isAvailable ()) { + i = stackList.size (); } if (i == stackList.size ()) { // Did not find the old stackframe within the list of new ones @@ -799,7 +828,7 @@ public class PHPDBGInterface { return 0; // We did not read enough bytes, error } } - + nextFrame = 0; // Start with the first frame while (nextFrame < bytesToRead) { // As long as we have something within this block @@ -851,10 +880,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; @@ -892,11 +917,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, @@ -981,10 +1001,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; @@ -1034,6 +1050,7 @@ public class PHPDBGInterface { case PHPDBGBase.DBGC_END: sessionEnded = true; + this.proxy.setTerminated(); break; case PHPDBGBase.DBGC_BREAKPOINT: