1) Open port 7869 for dbg communication if we run a non remote debug session, as...
[phpeclipse.git] / net.sourceforge.phpeclipse.debug.core / src / net / sourceforge / phpdt / internal / debug / core / PHPDBGInterface.java
index 957c86e..89ef3a2 100644 (file)
@@ -15,6 +15,7 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Vector;
+import java.util.Collections;
 
 import net.sourceforge.phpdt.internal.debug.core.model.PHPDBGEvalString;
 import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame;
@@ -25,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;
@@ -71,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);
        }
 
        /**
@@ -177,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
 
@@ -200,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)
@@ -217,6 +211,30 @@ 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?
@@ -393,96 +411,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:
-        * <ul>
-        * <li> It looks for new variables within the DBG variables list and
-        *      adds them to the 'static' list.
-        * <li> It looks for changed variables copies the current value to the variable within
-        *              the 'static list' and mark these variables as 'hasChanged' (which uses the UI
-        *              for showing the variable with a different color).
-        * <li> It looks for variables within the 'static' list, and removes them
-        *              from the 'static' list in case the do not appear within the DBG list.
-        * </ul>
-        *
-        * @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
@@ -491,7 +419,7 @@ public class PHPDBGInterface {
         * @param stack The stackframe for which we want the variables.
         * @return      The array of variables
         */
-       public PHPVariable[] getVariables (PHPStackFrame stack) throws IOException, DebugException  {
+       public Vector getVariables (PHPStackFrame stack) throws IOException, DebugException  {
                PHPDBGPacket            DBGPacket;
                PHPDBGFrame             DBGFrame1;
                PHPDBGEvalString        evalStr;
@@ -514,9 +442,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 (PHPVariable[]) DBGVarList.toArray (new PHPVariable[DBGVarList.size ()]);        // Convert the list to an array and return the array
+               return DBGVarList;                                                                                      // Return the variables as list
        }
 
        /**
@@ -546,7 +491,10 @@ 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);
@@ -572,7 +520,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);
@@ -662,6 +612,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;
@@ -677,10 +631,23 @@ public class PHPDBGInterface {
         *
         * The stackList contains the currently read stackframes which were sent
         * from DBG. The DBG interface holds a list of the active stack frames.
-        * This method looks whether the sent stackframes are already in the list.
+        * This method replicates the 'static' stackframe list with the DBG stackframe list
+        * Replication is done in the following way:
+        * <ul>
+        * <li> It looks for new stackframes within the DBG stackframe list and
+        *      adds them to the 'static' list.
+        * <li> 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.
+        * <li> It looks for stackframes which are already existent and replicates the
+        *              line number and the index number.
+        * <li> At the end the 'static' stackfram list has to be sorted by the stackframes
+        *              index numbers.
+        * </ul>
+        *
         * Removes the unused stackframes from the list, or adds stackframes which
         * are not yet in the list.
         *
+        *
         * @param stackList
         */
        private void updateStackFrameList (Vector stackList) {
@@ -694,10 +661,12 @@ public class PHPDBGInterface {
                        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 (stackFrameNew.getModNo () == stackFrameOld.getModNo ()) {   // Did we find the sent stackframe within the list of old stackframes?
-                                       stackFrameOld.setLineNumber (stackFrameNew.getLineNumber());
+                               if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) &&
+                                       stackFrameNew.getLineNumber() == stackFrameOld.getLineNumber()) {// Did we find the sent stackframe within the list of old stackframes?
+                                       stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ());
+                                       stackFrameOld.setIndex (stackFrameNew.getIndex ());
 
                                        break;                                                                  //  Yes, then break;
                                }
@@ -711,12 +680,13 @@ 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);                           // ---
+                       stackFrameOld = (PHPStackFrame) stackListOld.get (n);                           //
 
                        for (i = 0; i < stackList.size (); i++) {                                                       // For all stackList entries
                                stackFrameNew = (PHPStackFrame) stackList.get (i);
 
-                               if (stackFrameNew.getModNo () == stackFrameOld.getModNo ()) {   // Did we find the sent stackframe within the list of old stackframes?
+                               if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) &&
+                                       stackFrameNew.getLineNumber() == stackFrameOld.getLineNumber()) {// Did we find the sent stackframe within the list of old stackframes?
                                        break;                                                                  //  Yes, then break;
                                }
                        }
@@ -727,6 +697,8 @@ public class PHPDBGInterface {
                        }
                }
 
+               Collections.sort (stackListOld);                                                                                // Sort the 'static' stackframe list by the stackframe index numbers.
+                                                                                                                                                               //
                newStackList = new PHPStackFrame[stackListOld.size ()];
                newStackList = (PHPStackFrame[]) stackListOld.toArray (newStackList);
                DBGStackList = newStackList;
@@ -782,7 +754,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
@@ -834,10 +806,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;
 
@@ -875,11 +843,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,
@@ -964,10 +927,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;
 
@@ -1017,6 +976,7 @@ public class PHPDBGInterface {
 
                                case PHPDBGBase.DBGC_END:
                                        sessionEnded = true;
+                                       this.proxy.setTerminated();
                                        break;
 
                                case PHPDBGBase.DBGC_BREAKPOINT: