Patches from Robert Kraske (robekras):
[phpeclipse.git] / net.sourceforge.phpeclipse.debug.core / src / net / sourceforge / phpdt / internal / debug / core / PHPDBGInterface.java
1 /**********************************************************************
2 Copyright (c) 2000, 2002 IBM Corp. and others.
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
7
8 Contributors:
9         Vicente Fernando - www.alfersoft.com.ar - Initial implementation
10         Christian Perkonig - remote debug
11 **********************************************************************/
12 package net.sourceforge.phpdt.internal.debug.core;
13
14 import java.io.BufferedReader;
15 import java.io.IOException;
16 import java.io.OutputStream;
17 import java.util.Vector;
18
19 import net.sourceforge.phpdt.internal.debug.core.model.PHPDBGEvalString;
20 import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame;
21 import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable;
22 import net.sourceforge.phpdt.internal.debug.core.model.PHPValue;
23
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.core.runtime.Status;
26 import org.eclipse.debug.core.DebugException;
27
28 import java.io.RandomAccessFile;
29
30 /**
31  * The interface object are created by the proxy
32  *
33  */
34 public class PHPDBGInterface {
35
36         public boolean                  sessionEnded = false;
37         public int                              sessType         = -1;
38         public int                              BPUnderHit       = 0;
39         public String                   sessID           = new String ();
40
41         private int[]                   LastBPRead   = new int[10];
42         private Vector                  DBGBPList    = new Vector ();
43         private Vector          DBGVarList   = new Vector ();
44         private PHPStackFrame[] DBGStackList;
45         private Vector                  DBGMods          = new Vector ();                       // The module names and their numbers
46         private Vector          stackListOld = new Vector ();
47         private BufferedReader  in;
48         private OutputStream    os;                                                                             // The stream which goes to DBG
49         private boolean                 shouldStop       = false;
50         private String                  evalRet          = new String ("");
51         private String                  serGlobals       = new String ("");
52         private int                     rawCounter       = 1000;                                        // An rawData frame ID counter
53         private PHPDBGProxy     proxy            = null;
54         private int                     lastCmd          = -1;
55         private int                     sid                      = 0;
56         private boolean                 stopOnError      = false;
57         private char[]                  lastCommand      = new char[4];
58
59         /**
60          * @param in    The input stream (communication from DBG).
61          * @param os    The output stream (communication to DBG).
62          * @param proxy The proxy to which this interface belongs.
63          */
64         public PHPDBGInterface (BufferedReader in, OutputStream os, PHPDBGProxy proxy) {
65                 DBGBPList.clear ();
66
67                 this.in         = in;
68                 this.os         = os;
69                 this.proxy      = proxy;
70         }
71
72         /**
73          *
74          * @param mod_name The module (source file) to which we add the breakpoint.
75          * @param line     The line where the breakpoint is set.
76          * @return         Breakpoint ID ???.
77          */
78         public int addBreakpoint (String mod_name, int line) throws IOException {
79                 return setBreakpoint (mod_name, "", line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, 0, 0, 0, 0);
80         }
81
82         /**
83          *
84          * @param mod_name The module (source file) to which we add the breakpoint.
85          * @param line     The line where the breakpoint is set.
86          * @param bpNo     The breakpoint ID ???.
87          */
88         public void removeBreakpoint (String mod_name, int line, int bpNo) throws IOException {
89                 setBreakpoint (mod_name, "", line, PHPDBGBase.BPS_DISABLED, 0, 0, 0, bpNo, 0);
90         }
91
92         /**
93          * Is this method used anywhere?
94          *
95          */
96         public void requestDBGVersion () throws IOException {
97                 PHPDBGPacket DBGPacket;                                     // A DBG message packet
98                 PHPDBGFrame  DBGFrame;                                      // A frame within a DBG packet
99
100                 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);     // A request for DBG
101                 DBGFrame  = new PHPDBGFrame (PHPDBGBase.FRAME_VER);         // We want the version of DBG
102
103                 DBGPacket.addFrame (DBGFrame);                              // Add the 'what we want' to the DBG packet
104
105                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
106                         return;                                                 //  No
107                 }
108
109                 DBGPacket.sendPacket (os);                                                                      // Send the request to DBG
110         }
111
112         /**
113          * Called by the proxy
114          *
115          */
116         public void getSourceTree () throws IOException {
117                 PHPDBGPacket DBGPacket;                                     // A DBG message packet
118                 PHPDBGFrame  DBGFrame;                                      // A frame within a DBG packet
119
120                 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);     // A request for DBG
121                 DBGFrame  = new PHPDBGFrame (PHPDBGBase.FRAME_SRC_TREE);        // We want a source tree from DBG
122
123                 DBGPacket.addFrame (DBGFrame);                              // Add the 'what we want' to the DBG packet
124
125                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
126                         return;                                                                                                 //  No
127                 }
128
129                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
130
131                 waitResponse (1000);                                        // Wait for the DBG response (1 second)
132                 flushAllPackets ();                                                                             // Read and process the response from DBG
133         }
134
135         /**
136          * Is this method called from anywhere?
137          *
138          * @param modName The modul (filename).
139          */
140         public void addDBGModName (String modName) throws IOException {
141                 PHPDBGPacket DBGPacket;                                     // A DBG message packet
142                 PHPDBGFrame  DBGFrame;                                      // A frame within a DBG packet
143
144                 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);     // A request for DBG
145                 DBGFrame  = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);     // We want Module name from DBG
146
147                 rawCounter++;                                               // Increment the rawData ID counter
148                 DBGFrame.addInt (rawCounter);                                                           // FRAME_RAWDATA ID
149                 DBGFrame.addInt (modName.length () + 1);                                        // The length of rawdata string (incl. null char termination)
150                 DBGFrame.addString (modName);                                                           // The file name (module name)
151                 DBGFrame.addChar ('\0');                                                                        // Add the C-String null termination
152
153                 DBGPacket.addFrame (DBGFrame);
154
155                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
156                         return;                                                                                                 //  No
157                 }
158
159                 DBGPacket.sendPacket (os);
160         }
161
162         /**
163          * This method is called for adding or removing breakpoints.
164          *
165          * @param mod_name      The module name (file name).
166          * @param condition     Info about the condition when to break (not used at the moment).
167          * @param line          The breakpoints line.
168          * @param state         Info whether this breakpoint has to be dis- or enabled.
169          * @param istep         Always 0.
170          * @param hitcount      Always 0.
171          * @param skiphits      Always 0.
172          * @param bpno          The breakpoint ID.
173          * @param isunderhit    ???
174          * @return
175          */
176         private int setBreakpoint (String mod_name, String condition, int line, int state, int istemp, int hitcount, int skiphits, int bpno, int isunderhit) throws IOException {
177                 PHPDBGPacket    DBGPacket;
178                 PHPDBGFrame     DBGFrame1;
179                 PHPDBGFrame     DBGFrame2;
180                 int                     modNo;
181
182                 DBGPacket       = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);
183                 DBGFrame1       = new PHPDBGFrame (PHPDBGBase.FRAME_BPS);
184                 DBGFrame2       = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
185
186                 modNo           = getModByName (mod_name);                                              // Get the module ID by name
187
188                 if (modNo >= 0) {                                           // Did we find a module ID for the module name?
189                         DBGFrame1.addInt (modNo);                                                               // Add the module ID to frame 1
190                 } else {
191                         DBGFrame1.addInt (0);                                                                   // mod number (0 use file name)
192                 }
193
194                 DBGFrame1.addInt (line);                                                                        // line number
195
196                 if (modNo >= 0) {                                           // Did we find a module ID for the module name?
197                         DBGFrame1.addInt (0);                                                                   // use mod number
198                 } else {
199                         rawCounter++;
200                         DBGFrame1.addInt (rawCounter);                                                  // ID of FRAME_RAWDATA to send file name
201                 }
202
203                 DBGFrame1.addInt (state);                                       // state BPS_*
204                 DBGFrame1.addInt (istemp);                                      // istep
205                 DBGFrame1.addInt (hitcount);                                // hit count
206                 DBGFrame1.addInt (skiphits);                                // skip hits
207                 DBGFrame1.addInt (0);                                           // ID of condition
208                 DBGFrame1.addInt (bpno);                                            // breakpoint number
209                 DBGFrame1.addInt (isunderhit);                                  // is under hit
210
211                 if (modNo < 0) {                                            // Did we find a module ID for the module name?
212                         DBGFrame2.addInt (rawCounter);                                      // FRAME_RAWDATA ID
213                         DBGFrame2.addInt (mod_name.length() + 1);                   // length of rawdata (+ null char)
214                         DBGFrame2.addString (mod_name);                                     // file name
215                         DBGFrame2.addChar ('\0');                                                   // null char
216
217                         DBGPacket.addFrame (DBGFrame2);                         // First add file name data
218                 }
219
220                 DBGPacket.addFrame (DBGFrame1);                                                         // Second add command data
221
222                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
223                         return 0;                                               //  No
224                 }
225
226                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
227
228                 clearLastBP ();
229
230                 waitResponse (1000);                                        // Wait for the DBG response (1 second)
231                 flushAllPackets ();                                         // Read and process the response from DBG
232
233                 return LastBPRead[8];                                                                           // Return what ???
234         }
235
236         /**
237          *
238          */
239         private void clearLastBP () {
240                 int i;
241
242                 for (i = 0; i < LastBPRead.length; i++) {
243                         LastBPRead[i] = 0;
244                 }
245         }
246
247         /**
248          *
249          */
250         private void copyToLastBP (int[] BPBody) {
251                 int i;
252
253                 for (i = 0; i < LastBPRead.length; i++) {
254                         LastBPRead[i] = BPBody[i];
255                 }
256         }
257
258         /**
259          *
260          */
261         public void continueExecution () throws IOException {
262                 PHPDBGPacket DBGPacket;
263
264                 BPUnderHit = 0;
265                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_CONTINUE);
266
267                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
268                         return;                                                 //  No
269                 }
270
271                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
272
273                 lastCommand = PHPDBGBase.DBGA_CONTINUE;                     // Store the info about the command we sent
274         }
275
276         /**
277          *
278          */
279         public void pauseExecution () throws IOException {
280                 PHPDBGPacket DBGPacket;
281
282                 DBGPacket = new PHPDBGPacket (PHPDBGBase.IntToChar4 (PHPDBGBase.DBGC_PAUSE));
283
284                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
285                          return;                                                //  No
286                 }
287
288                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
289         }
290
291         /**
292          *
293          */
294         private int getBPUnderHit () {
295                 int i;
296                 int BPUnder             = 0;
297                 int[] dbg_bpl_body      = new int[10];
298
299                 for (i = 0; i < DBGBPList.size (); i++) {                               // look for bp under hit
300                         dbg_bpl_body = (int[]) DBGBPList.get (i);
301
302                         if (dbg_bpl_body[9] == 1) {
303                                 BPUnder = dbg_bpl_body[8];
304                         }
305                 }
306
307                 return BPUnder;
308         }
309
310         public int getLastCmd()
311         {
312                 return lastCmd;
313         }
314
315         public int getSID()
316         {
317           return sid;
318         }
319
320         public void setLastCmd (int cmd)
321         {
322                 lastCmd = cmd;
323         }
324
325         /**
326          *
327          */
328         public void stepInto () throws IOException {
329                 PHPDBGPacket DBGPacket;
330
331                 BPUnderHit = 0;
332                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_STEPINTO);
333
334                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
335                         return;                                                 //  No
336                 }
337
338                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
339
340                 lastCommand = PHPDBGBase.DBGA_STEPINTO;                                         // Store the info about the command we sent
341         }
342
343         /**
344          *
345          */
346         public void stepOver () throws IOException {
347                 PHPDBGPacket DBGPacket;
348
349                 BPUnderHit = 0;
350                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOVER);
351
352                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
353                         return;                                                 //  No
354                 }
355
356                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
357
358                 lastCommand = PHPDBGBase.DBGA_STEPOVER;                     // Store the info about the command we sent
359         }
360
361         /**
362          *
363          */
364         public void stepOut () throws IOException {
365                 PHPDBGPacket DBGPacket;
366
367                 BPUnderHit = 0;
368                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOUT);
369
370                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
371                         return;                                                 //  No
372                 }
373
374                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
375
376                 lastCommand = PHPDBGBase.DBGA_STEPOUT;                      // Store the info about the command we sent
377         }
378
379         /**
380          *
381          */
382         public void stopExecution () throws IOException {
383                 PHPDBGPacket DBGPacket;
384
385                 BPUnderHit = 0;
386                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_STOP);
387
388                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
389                         return;                                                 //  No
390                 }
391
392                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
393         }
394
395         /**
396          * This method updates the 'static' variables list.
397          * It does a replication between the 'static' list (the variable list which
398          * is a member of this DBG interface object) and the DBG variable list
399          * (the list of variables which is received from PHP via DBG with the current suspend)
400          * Replication is done in the following way:
401          * <ul>
402          * <li> It looks for new variables within the DBG variables list and
403          *      adds them to the 'static' list.
404          * <li> It looks for changed variables copies the current value to the variable within
405          *              the 'static list' and mark these variables as 'hasChanged' (which uses the UI
406          *              for showing the variable with a different color).
407          * <li> It looks for variables within the 'static' list, and removes them
408          *              from the 'static' list in case the do not appear within the DBG list.
409          * </ul>
410          *
411          * @param varListOld The 'static' list of variables which are to be updated.
412          * @param varListNew The new list of (current) variables from DBG.
413          */
414         private void updateVariableList (Vector varListOld, Vector varListNew)
415         {
416                 PHPVariable     varOld;                                                                                 // The variable from the 'static' list
417                 PHPVariable varNew;                                                                                     // The variable from the DBG list
418                 PHPValue    valOld;                                                                                     // The value of the current variable from 'static' list
419                 PHPValue    valNew;                                                                                     // The value of the current variable from DBG list
420                 int         n;                                                                                          // Index for the DBG list
421                 int         o;                                                                                          // Index for the static list
422
423                 // Add the variables (and childs) to the static list if they are new
424                 //  and update the values of variables which are already existend within
425                 //  the 'static' list.
426
427                 for (n = 0; n < varListNew.size (); n++) {                  // For every variable in 'DBG list'
428                         varNew = (PHPVariable) varListNew.get (n);                              // Get the DBG variable
429
430                         for (o = 0; o < varListOld.size (); o++) {                              // For every variable in static list
431                                 varOld = (PHPVariable) varListOld.get (o);                      // Get the static variable
432
433                                 if (varNew.getName ().equals (varOld.getName ())) { // Did we found the variable within the 'static' list?
434                                         valOld = (PHPValue) varOld.getValue ();         // Get the value from 'static'
435                                         valNew = (PHPValue) varNew.getValue ();         // Get the value from DBG
436
437                                         try {
438                                                 if (valOld.hasVariables () ||                                   // If the 'static' value has child variables
439                                                     valNew.hasVariables ()) {                                                   //  or if the DBG value has child variables
440                                                         updateVariableList (valOld.getChildVariables (),        // Update the variable list for the child variables
441                                                                                                 valNew.getChildVariables ());
442                                                 }
443                                                 else if (!valOld.getValueString ().equals (valNew.getValueString ())) { // Has the value changed?
444                                                         valOld.setValueString (valNew.getValueString ());                   // Yes, set the 'static' value (variable) to the new value
445                                                         varOld.setValueChanged (true);                                                                          // and set the 'has changed' flag, so that the variable view
446                                                                                                                                                                                                 // could show the user the changed status with a different
447                                                                                                                                                                                                 // color
448                                                 }
449                                                 else {
450                                                         varOld.setValueChanged (false);                                     // Reset the 'has changed' flag
451                                                 }
452                                         }
453                                         catch (DebugException e) {                                                  // That's, because of the hasVariables method
454                                         }
455
456                                         break;                                          // Found the variable,
457                                 }
458                         }
459
460                         if (o == varListOld.size ()) {                          // Did we found the variable within the static list?
461                                 varListOld.add (varNew);                                                        //  No, then add the DBG variable to the static list
462                         }
463                 }
464
465                 // Look for the variables we can remove from the 'static' list
466
467                 for (o = 0; o < varListOld.size (); o++) {                                              // For every variable in 'static' list
468                         varOld = (PHPVariable) varListOld.get (o);                                                      // Get the static variable
469
470                         for (n = 0; n < varListNew.size (); n++) {                                                      // For all variables in 'DBG' list
471                                 varNew = (PHPVariable) varListNew.get (n);                                              // Get the variable from the 'DBG' list
472
473                                 if (varNew.getName ().equals (varOld.getName ())) {                     // Did we found the 'static' list variable within the 'DBG' list?
474                                         break;                                                                                                          // Yes we found the variable, then leave the loop
475                                 }
476                         }
477
478                         if (n == varListNew.size ()) {                                          // Did not find the 'static' list variable within the 'DBG' list?
479                                  varListOld.remove (o);                                         // then remove the 'static' list variable from list
480                                  o -= 1;                                                        // Adjust the 'static' list index
481                         }
482                 }
483         }
484
485         /**
486          * This method is called by the proxy.
487          * It sends a request to DBG to get the current variables
488          * with their values. It waits for the response and processes
489          * the input from DBG.
490          *
491          * @param stack The stackframe for which we want the variables.
492          * @return      The array of variables
493          */
494         public PHPVariable[] getVariables (PHPStackFrame stack) throws IOException, DebugException  {
495                 PHPDBGPacket            DBGPacket;
496                 PHPDBGFrame             DBGFrame1;
497                 PHPDBGEvalString        evalStr;
498
499                 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);     //
500             DBGFrame1 = new PHPDBGFrame (PHPDBGBase.FRAME_EVAL);        //
501
502                 DBGFrame1.addInt (0);                                                                           // istr = raw data ID
503                 DBGFrame1.addInt (1);                                                                           // scope_id = -1 means current location, 0 never used, +1 first depth
504
505                 DBGPacket.addFrame (DBGFrame1);                             // Add command data
506
507                 if (proxy.getSocket ().isClosed ()) {                       // Do we have a socket for DBG communication?
508                         return null;                                                                                    //  No, then leave here
509                 }
510
511                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
512
513                 waitResponse (1000);                                        // Wait for the DBG response (1 second)
514                 flushAllPackets ();                                         // Read and process the response from DBG
515
516                 evalStr         = new PHPDBGEvalString (stack, serGlobals); // Process serialized variables
517                 updateVariableList (DBGVarList, evalStr.getVariables ());       // Replicate the 'static' variable list and the via DBG received variable list
518
519                 return (PHPVariable[]) DBGVarList.toArray (new PHPVariable[DBGVarList.size ()]);        // Convert the list to an array and return the array
520         }
521
522         /**
523          *
524          * @param logString
525          */
526         public void log(String logString) throws IOException, DebugException  {
527                 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
528                 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_LOG);
529                 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
530
531                 rawCounter++;
532                 DBGFrame1.addInt(rawCounter);                           // ilog
533                 DBGFrame1.addInt(1);                                            // type
534                 DBGFrame1.addInt(0);                                            // mod_no
535                 DBGFrame1.addInt(0);                                            // line_no
536                 DBGFrame1.addInt(0);                                            // imod_name
537                 DBGFrame1.addInt(0);                                            // ext_info
538
539                 DBGFrame2.addInt(rawCounter);                           // FRAME_RAWDATA ID
540                 DBGFrame2.addInt(logString.length() + 1);       // length of rawdata (+ null char)
541                 DBGFrame2.addString(logString);                         // log string
542                 DBGFrame2.addChar('\0');                                        // null char
543
544                 // Add raw data first
545                 DBGPacket.addFrame(DBGFrame2);
546                 // Add command data
547                 DBGPacket.addFrame(DBGFrame1);
548
549                 if(proxy.getSocket().isClosed()) return;
550                 DBGPacket.sendPacket(os);
551
552                 waitResponse(1000);
553                 flushAllPackets();
554         }
555
556         public PHPVariable[] evalBlock(PHPStackFrame stack, String evalString) throws IOException, DebugException  {
557                 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
558                 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
559                 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
560
561                 rawCounter++;
562                 DBGFrame1.addInt(rawCounter);                           // istr = raw data ID
563                 DBGFrame1.addInt(1);                                            // scope_id = -1 means current location, 0 never used, +1 first depth
564
565                 DBGFrame2.addInt(rawCounter);                           // FRAME_RAWDATA ID
566                 DBGFrame2.addInt(evalString.length() + 1);      // length of rawdata (+ null char)
567                 DBGFrame2.addString(evalString);                        // eval block
568                 DBGFrame2.addChar('\0');                                        // null char
569
570                 // Add raw data first
571                 DBGPacket.addFrame(DBGFrame2);
572                 // Add command data
573                 DBGPacket.addFrame(DBGFrame1);
574
575                 if(proxy.getSocket().isClosed()) return null;
576                 DBGPacket.sendPacket(os);
577
578                 waitResponse(1000);
579                 flushAllPackets();
580
581                 PHPDBGEvalString evalStr=new PHPDBGEvalString(stack,evalRet);
582
583                 return evalStr.getVars();
584
585         }
586
587         /**
588          * Read and process everthing we got from DBG
589          */
590         public void flushAllPackets () throws IOException {
591                 while (readResponse() != 0);
592         }
593
594         /**
595          * Get the modules name by its number
596          *
597          * @param modNo The number (id) of the module
598          * @return      The name of the module
599          */
600         public String getModByNo (int modNo) {
601                 int             i;
602                 PHPDBGMod       dbg_mod;
603
604                 for (i = 0; i < DBGMods.size (); i++) {                         // For all the modules we have within the array
605                         dbg_mod = (PHPDBGMod) DBGMods.get (i);                      // Get the module
606
607                         if (dbg_mod.getNo () == modNo) {                            // Is the module from the array the module we want?
608                                 return dbg_mod.getName ();                              //  Yes, return the name of the module
609                         }
610                 }
611
612                 return "";                                                      // If nothing was found return emtpy string
613         }
614
615         /**
616          *
617          * @param  modName The name of the module for which we want the ID
618          * @return
619          * - The ID of the module
620          * - -1 if nothing was found
621          */
622         private int getModByName (String modName) {
623                 int             i;
624                 PHPDBGMod       dbg_mod;
625
626                 for (i = 0; i < DBGMods.size (); i++) {                         // For all the modules we have within the array
627                         dbg_mod = (PHPDBGMod) DBGMods.get (i);                      // Get the module
628
629                         if (dbg_mod.getName ().equalsIgnoreCase (modName)) {            // Is the module from the array the module we want?
630                                 return dbg_mod.getNo ();                                //  Yes, return the name of the module
631                         }
632                 }
633
634                 return -1;                                                      // If nothing was found return -1
635         }
636
637         /**
638          * Return the string for the given frame number
639          *
640          * @param framesInfo The buffer which is to read
641          * @param frameNo    The frame number
642          * @return
643          */
644         private String getRawFrameData (char[] framesInfo, int frameNo) {
645                 int   nextFrame = 0;                                                    // The current read position within the buffer
646                 int[] dbg_frame = new int[2];                                           // The two frame header numbers
647
648                 while (nextFrame < framesInfo.length) {                                 // As long we have something within the buffer
649                         dbg_frame[0] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame);           // The frame type
650                         dbg_frame[1] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4);       // The frame size
651
652                         nextFrame   += 8;                                                   // The current read position
653
654                         if (dbg_frame[1] == 0) {                                            // If frame size is 0
655                                 return "";                                                      //  return an emtpy string
656                         }
657
658                         switch (dbg_frame[0]) {                                                     // Switch for the frame type
659                                 case PHPDBGBase.FRAME_RAWDATA:                                                  // The only frame type we are interrested in
660                                         if (frameNo == PHPDBGBase.Char4ToInt (framesInfo, nextFrame)) {         // Is it correct  number of the frame
661                                                 int toRead;                                                     //
662
663                                                 toRead = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4);     // The size of the string
664
665                                                 return String.copyValueOf (framesInfo, nextFrame + 8, toRead);  // Copy frame content to String and return
666                                         }
667                                         break;
668                         }
669
670                         nextFrame += dbg_frame[1];                                                                      // Go for the next frame (add the length of the current one)
671                 }
672
673                 return "";                                                                                                                                              // We did not found any FRAM_RAWDATA, so return an emtpy strin
674         }
675
676         /**
677          *
678          * The stackList contains the currently read stackframes which were sent
679          * from DBG. The DBG interface holds a list of the active stack frames.
680          * This method looks whether the sent stackframes are already in the list.
681          * Removes the unused stackframes from the list, or adds stackframes which
682          * are not yet in the list.
683          *
684          * @param stackList
685          */
686         private void updateStackFrameList (Vector stackList) {
687                 int                     i;
688                 int             n;
689                 PHPStackFrame   stackFrameNew;
690                 PHPStackFrame   stackFrameOld;
691                 PHPStackFrame[] newStackList;
692
693                 for (i = 0; i < stackList.size (); i++) {                                                               // For all stackList entries
694                         stackFrameNew = (PHPStackFrame) stackList.get(i);
695
696                         for (n = 0; n < stackListOld.size (); n++) {                                    // For all StackFrames in the StackFrame list
697                                 stackFrameOld = (PHPStackFrame) stackListOld.get (n);                   // ---
698
699                                 if (stackFrameNew.getModNo () == stackFrameOld.getModNo ()) {   // Did we find the sent stackframe within the list of old stackframes?
700                                         stackFrameOld.setLineNumber (stackFrameNew.getLineNumber());
701
702                                         break;                                                                  //  Yes, then break;
703                                 }
704                         }
705
706                         if (n == stackListOld.size ()) {                                    // Did not find the new stackframe within the list
707                                  stackListOld.add (stackFrameNew);                              //  then add the new stackframe
708                         }
709                 }
710
711                 // And now for removing unused stackframes from list
712
713                 for (n = 0; n < stackListOld.size (); n++) {                                            // For all StackFrames in the StackFrame list
714                         stackFrameOld = (PHPStackFrame) stackListOld.get (n);                           // ---
715
716                         for (i = 0; i < stackList.size (); i++) {                                                       // For all stackList entries
717                                 stackFrameNew = (PHPStackFrame) stackList.get (i);
718
719                                 if (stackFrameNew.getModNo () == stackFrameOld.getModNo ()) {   // Did we find the sent stackframe within the list of old stackframes?
720                                         break;                                                                  //  Yes, then break;
721                                 }
722                         }
723
724                         if (i == stackList.size ()) {                                           // Did not find the old stackframe within the list of new ones
725                                  stackListOld.remove (n);                                       //  then remove the old stackframe from list
726                                  n -= 1;                                                        // Adjust the stack list index
727                         }
728                 }
729
730                 newStackList = new PHPStackFrame[stackListOld.size ()];
731                 newStackList = (PHPStackFrame[]) stackListOld.toArray (newStackList);
732                 DBGStackList = newStackList;
733         }
734
735     /**
736      * Read the response from DBG and process the frame
737      *
738          * @return
739          * - The received command
740          * - or 0 if something was wrong
741      */
742         public int readResponse () throws IOException {
743         int     bytesToRead            = 0;                         // The number of byte to read for the current DBG block
744         int     nextFrame              = 0;                         // The current read position within entirePack
745         int     i                      = 0;
746         int     cmdReceived            = 0;
747         int     stackIndex             = 0;
748         boolean errorStack             = false;
749         char[]  dbg_header_struct_read = new char[16];              // The buffer for the first 16 bytes of a block
750         int[]   dbg_header_struct      = new int[4];                // The first four numbers (long) of a block
751         int[]   dbg_bpl_tmp            = new int[10];
752         int[]   dbg_frame              = new int[2];
753         int[]   dbg_eval_tmp           = new int[3];
754         int[]   dbg_src_tree_tmp       = new int[4];                //
755         int[]   dbg_error_tmp          = new int[2];
756         Vector  rawList                = new Vector();
757         Vector  stackList              = new Vector();              // Intermediate stacklist which is build up in FRAME_STACK frame
758
759         rawList.clear ();
760         stackList.clear ();
761
762                 // Read from input
763         while (readInput (dbg_header_struct_read, 16) != 0) {                               // Read 16 byte from input stream
764                         dbg_header_struct[0] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 0);               // Debug sync header
765             dbg_header_struct[1] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 4);           // Command
766             dbg_header_struct[2] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 8);       //
767             dbg_header_struct[3] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 12);      // Bytes within this block
768
769             if (dbg_header_struct[0] != 0x5953) {                                           // Check DBG sync bytes
770                 return 0;                                                                   // Wrong header
771             }
772
773             cmdReceived = dbg_header_struct[1];                                             // Get the command
774             setLastCmd (cmdReceived);                                                                                                           // Store the info about the current command
775             bytesToRead = dbg_header_struct[3];                                                                                         // Get the number of bytes to read for this block
776
777                         //System.out.println("Response Received: " + cmdReceived);
778                         char[] entirePack = new char[bytesToRead];                                      // Store the block data into buffer 'entirePack'
779
780             if (bytesToRead > 0) {                                                          // If there is something within the frame
781                 if (readInput (entirePack, bytesToRead) < bytesToRead) {                    // Read the frame into the buffer
782                     return 0;                                                               // We did not read enough bytes, error
783                 }
784                         }
785
786                         nextFrame = 0;                                                                  // Start with the first frame
787
788                         while (nextFrame < bytesToRead) {                                               // As long as we have something within this block
789                                 dbg_frame[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame);                           // The name of the frame
790                                 dbg_frame[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);               // The size of the frame
791                                 nextFrame   += 8;                                                           // The next read position
792
793                                 if (dbg_frame[1] == 0) {                                                    // Something within the frame?
794                                         return 0;                                                               //  Nothing to read, error
795                                 }
796
797                                 switch (dbg_frame[0]) {
798                                         case PHPDBGBase.FRAME_STACK:
799                                                 int[] dbg_stack_new = new int[4];                                       //
800
801                                                 dbg_stack_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);   // Source line number
802                                                 dbg_stack_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);   // Module number
803                                                 dbg_stack_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);   // Scope id
804                                                 dbg_stack_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);  // ID of description string
805
806                                                 if ((dbg_stack_new[1] != 0) && !errorStack) {
807                                                         PHPStackFrame newStack;
808
809                                                         stackIndex++;
810                                                         newStack = new PHPStackFrame (null,                                 // The thread
811                                                                                       getModByNo (dbg_stack_new[1]),        // The name of the module (file)
812                                                                                       dbg_stack_new[0],                     // The source line number
813                                                                                                                   stackIndex,
814                                                                                                                   getRawFrameData (entirePack,          // Get the string from this packet
815                                                                                                                                    dbg_stack_new[3]),   // The frame ID for which we want the string
816                                                                                                                   dbg_stack_new[1]);                                    // The module number
817                                                         stackList.add (newStack);
818                                                 }
819
820                                                 errorStack = false;
821                                                 break;
822
823                                         case PHPDBGBase.FRAME_SOURCE:                                                   // Nothing to be done here
824                                                 break;                                                                      // TODO: what's with that frame? Something interesting
825
826                                         case PHPDBGBase.FRAME_SRC_TREE:                                                 //
827                                                 dbg_src_tree_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);        // The parent module number
828                                                 dbg_src_tree_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);        // The parent line number (not used)
829                                                 dbg_src_tree_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);        // The module number
830                                                 dbg_src_tree_tmp[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);       // The filename number
831
832                                                 if (getModByNo (dbg_src_tree_tmp[2]).equals ("")) {
833                                                         String fileName;
834
835                                                         fileName = new String (getRawFrameData (entirePack, dbg_src_tree_tmp[3]));      // Get the filename
836
837                                                         if (fileName.length () > 0) {                                               // If we have a filename
838                                                                 fileName = fileName.substring (0, fileName.length () - 1);              // Remove '\0' char
839                                                         }
840
841                                                         if (dbg_src_tree_tmp[2] != 0) {                                             // If there is a module number
842                                                                 PHPDBGMod modNew;
843
844                                                                 modNew = new PHPDBGMod (dbg_src_tree_tmp[2], fileName);                 // Create a module object
845
846                                                                 DBGMods.add (modNew);                                                   // And store it to array
847                                                         }
848                                                 }
849                                                 break;
850
851                                         case PHPDBGBase.FRAME_RAWDATA:                                                      // Nothing to be done here
852                                                 break;                                                                          //  FRAME_RAWDATA are processed within getRawFrameData
853
854                                         case PHPDBGBase.FRAME_ERROR:                                                                                                            // An error frame
855                                                 errorStack       = true;                                                                                                                // Yes, we have an error stack
856                                                 dbg_error_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);                   // Error type
857                                                 dbg_error_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);                   // Error message ID
858
859                                                 String error = "\n";                                                            //
860
861                                                 switch (dbg_error_tmp[0]) {                                                                                                             // Switch on error type
862                                                         case PHPDBGBase.E_ERROR:                        error += "[Error]";                     break;
863                                                         case PHPDBGBase.E_WARNING:                      error += "[Warning]";                   break;
864                                                         case PHPDBGBase.E_PARSE:                        error += "[Parse Error]";               break;
865                                                         case PHPDBGBase.E_NOTICE:                       error += "[Notice]";                    break;
866                                                         case PHPDBGBase.E_CORE_ERROR:           error += "[Core Error]";                break;
867                                                         case PHPDBGBase.E_CORE_WARNING:         error += "[Core Warning]";              break;
868                                                         case PHPDBGBase.E_COMPILE_ERROR:        error += "[Compile Error]";             break;
869                                                         case PHPDBGBase.E_COMPILE_WARNING:      error += "[Compile Warning]";   break;
870                                                         case PHPDBGBase.E_USER_ERROR:           error += "[User Error]";                break;
871                                                         case PHPDBGBase.E_USER_WARNING:         error += "[User Warning]";              break;
872                                                         case PHPDBGBase.E_USER_NOTICE:          error += "[User Notice]";               break;
873                                                         default:                                                        error += "[Unexpected Error]";  break;
874                                                 }
875
876                                                 error += ": ";
877                                                 error += new String (getRawFrameData (entirePack, dbg_error_tmp[1]));                   // Add the error string for this error message ID
878
879                                                 if (error.length () > 0) {                                                                                                              // If we have a error message
880                                                          error = error.substring (0, error.length () - 1);                                                      //  Remove '\0' char
881                                                 }
882
883                                                 error += "\n";                                                                  // Append a CR
884
885                                                 PHPDebugCorePlugin.log (new DebugException (new Status (IStatus.WARNING,
886                                                                                                         PHPDebugCorePlugin.PLUGIN_ID,
887                                                                                                                                                                 IStatus.OK,
888                                                                                                                                                                 error, null)));
889
890                                                 // To print errors on the console, I must execute a code in the
891                                                 // php context, that write the stderr... I didn't found a better way
892                                                 // TODO: Find a better way????
893
894 //                                              String codeExec= "";
895 //                                              codeExec= "fwrite(fopen('php://stderr', 'w'),\\\"" + error + "\\\");";
896 //                                              try {
897 //                                                      evalBlock("eval(\"" + codeExec + "\");");
898 //                                              } catch (DebugException e) {
899 //                                                      PHPDebugCorePlugin.log(e);
900 //                                              }
901 //
902                                                 if (!stopOnError) {                                                             // Is always false (Did not see where this is set to true!?)
903                                                         if (lastCommand.equals (PHPDBGBase.DBGA_CONTINUE)) {                        // If last command for PHP was a 'continue',
904                                                                 continueExecution ();                                                   //  send continue again
905                                                         } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPINTO)) {                 // If last command for PHP was a 'step into',
906                                                                 stepInto ();                                                            //  send 'step into' again
907                                                         } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOUT)) {                  // If last command for PHP was a 'step out',
908                                                                 stepOut ();                                                             //  send 'step out' again
909                                                         } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOVER)) {                 // If last command for PHP was a 'step over',
910                                                                 stepOver ();                                                            //  send 'step over' again
911                                                         }
912                                                 }
913                                                 break;
914
915                                         case PHPDBGBase.FRAME_EVAL:
916                                                 String evalString;
917
918                                                 evalString      = new String ("");
919                                                 dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);                    // istr
920                                                 dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);                    // iresult
921                                                 dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);                    // ierror
922
923                                                 evalRet                 = getRawFrameData (entirePack, dbg_eval_tmp[1]);                //
924                                                 evalString              = getRawFrameData (entirePack, dbg_eval_tmp[0]);                //
925                                                 serGlobals              = evalRet;                                                      //
926                                                 break;
927
928                                         case PHPDBGBase.FRAME_BPS:                                                          //
929                                                 break;                                                                          //
930
931                                         case PHPDBGBase.FRAME_BPL:
932                                                 int[] dbg_bpl_new;
933
934                                                 dbg_bpl_new        = new int[10];
935                                                 dbg_bpl_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);
936                                                 dbg_bpl_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);
937                                                 dbg_bpl_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);
938                                                 dbg_bpl_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);
939                                                 dbg_bpl_new[4] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 16);
940                                                 dbg_bpl_new[5] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 20);
941                                                 dbg_bpl_new[6] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 24);
942                                                 dbg_bpl_new[7] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 28);
943                                                 dbg_bpl_new[8] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 32);
944                                                 dbg_bpl_new[9] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 36);
945
946                                                 // look if breakpoint already exists in vector
947                                                 for (i = 0; i < DBGBPList.size (); i++) {
948                                                         dbg_bpl_tmp = (int[]) DBGBPList.get (i);
949
950                                                         if (dbg_bpl_tmp[8] == dbg_bpl_new[8]) {
951                                                                 DBGBPList.remove (i);
952
953                                                                 break;
954                                                         }
955                                                 }
956
957                                                 // add breakpoint to vector
958                                                 DBGBPList.add (dbg_bpl_new);
959                                                 copyToLastBP (dbg_bpl_new);
960
961                                                 // mod no returned?
962                                                 if (getModByNo (dbg_bpl_new[0]).equals ("")) {
963                                                         String fileName;
964
965                                                         fileName = new String (getRawFrameData (entirePack, dbg_bpl_new[2]));
966
967                                                         if (fileName.length () > 0) {                                               // If we have filename
968                                                                 fileName = fileName.substring (0, fileName.length () - 1);                              //  Remove '\0' char
969                                                         }
970
971                                                         if (dbg_bpl_new[0] != 0) {
972                                                                 PHPDBGMod modNew;
973
974                                                                 modNew = new PHPDBGMod (dbg_bpl_new[0], fileName);
975
976                                                                 DBGMods.add (modNew);
977                                                         }
978                                                 }
979                                                 break;
980
981                                         case PHPDBGBase.FRAME_VER:
982                                                 break;
983
984                                         case PHPDBGBase.FRAME_SID:
985                                                 sid = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0);
986                                                 break;
987
988                                         case PHPDBGBase.FRAME_SRCLINESINFO:
989                                                 break;
990
991                                         case PHPDBGBase.FRAME_SRCCTXINFO:
992                                                 break;
993
994                                         case PHPDBGBase.FRAME_LOG:
995                                                 break;
996
997                                         case PHPDBGBase.FRAME_PROF:
998                                                 break;
999
1000                                         case PHPDBGBase.FRAME_PROF_C:
1001                                                 break;
1002
1003                                         case PHPDBGBase.FRAME_SET_OPT:
1004                                                 break;
1005                                 }
1006
1007                                 nextFrame += dbg_frame[1];                                                      // go to next frame
1008                         }
1009
1010                         // Now process command
1011                         switch(cmdReceived) {
1012                                 case PHPDBGBase.DBGC_REPLY:
1013                                         break;
1014
1015                                 case PHPDBGBase.DBGC_STARTUP:
1016                                         break;
1017
1018                                 case PHPDBGBase.DBGC_END:
1019                                         sessionEnded = true;
1020                                         break;
1021
1022                                 case PHPDBGBase.DBGC_BREAKPOINT:
1023                                         BPUnderHit   = getBPUnderHit ();
1024                                         updateStackFrameList (stackList);
1025                                         break;
1026
1027                                 case PHPDBGBase.DBGC_STEPINTO_DONE:
1028                                 case PHPDBGBase.DBGC_STEPOVER_DONE:
1029                                 case PHPDBGBase.DBGC_STEPOUT_DONE:
1030                                 case PHPDBGBase.DBGC_EMBEDDED_BREAK:
1031                                 case PHPDBGBase.DBGC_PAUSE:
1032                                         BPUnderHit   = 1;
1033                                         updateStackFrameList (stackList);
1034                                         break;
1035
1036                                 case PHPDBGBase.DBGC_ERROR:
1037                                         stackList.clear ();
1038                                         updateStackFrameList (stackList);
1039                                         break;
1040
1041                                 case PHPDBGBase.DBGC_LOG:
1042                                         break;
1043
1044                                 case PHPDBGBase.DBGC_SID:
1045                                         break;
1046                         }
1047                 }
1048
1049                 return cmdReceived;                                         // Return the command we received with this block
1050         }
1051
1052     /**
1053      *
1054      */
1055
1056         public PHPStackFrame[] getStackList() {
1057                 return DBGStackList;
1058         }
1059
1060         /**
1061          * Reads from input buffer (response sent from DBG) the given number of chars
1062          * into frame buffer.
1063          *
1064          * @param buffer  The frame buffer where to store the read data from DBG.
1065          * @param bytes   The number of bytes (chars) which are to read from input stream.
1066          * @return        The number of bytes actually read.
1067          */
1068         private int readInput (char[] buffer, int bytes) throws IOException {
1069                 int bytesRead = 0;                                                                                      // Reset the bytes read counter
1070
1071                 for (int i = 0; i < bytes; i++) {                           // For the number of bytes we should read
1072                         if (in.ready ()) {                                                                              // If input stream is ready for reading
1073                                 buffer[i] = (char) (in.read () & 0x00FF);           // Read a char and store only the least significant 8-bits
1074                                 bytesRead++;                                        // Increment the bytes read counter
1075                         }
1076                         else {                                                  // Input stream is not ready
1077                                 break;                                              // Break the loop
1078                         }
1079                 }
1080
1081                 return bytesRead;                                                                                       // Return the number of bytes actually read
1082         }
1083
1084         /**
1085          * PHPProxy could stop the waiting for a response with this method.
1086          *
1087          */
1088         public void setShouldStop () {
1089                 this.shouldStop = true;
1090         }
1091
1092         /**
1093          * @param milliseconds The maximum time in milliseconds we wait for something
1094          *                     to be send from DBG.
1095          * @return             - true if something was received from DBG
1096          *                                         - false if nothing was send from DBG within the given time
1097          *
1098          */
1099         public boolean waitResponse (long milliseconds) throws IOException {
1100                 long timeout;
1101
1102                 timeout = System.currentTimeMillis () + milliseconds;           // Calculate the system time till we wait.
1103
1104                 while (System.currentTimeMillis () < timeout) {             // Is waiting time running out?
1105                         if (in.ready () || shouldStop) {                        //  No, so did we get something or should we stop now
1106                                 break;                                              //   Yes, break the waiting
1107                         }
1108                 }
1109
1110                 return in.ready ();                                         // true if we got something from DBG
1111         }
1112 }