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
9 Vicente Fernando - www.alfersoft.com.ar - Initial implementation
10 Christian Perkonig - remote debug
11 **********************************************************************/
12 package net.sourceforge.phpdt.internal.debug.core;
14 import java.io.BufferedReader;
15 import java.io.IOException;
16 import java.io.OutputStream;
17 import java.util.Collections;
18 import java.util.Vector;
20 //import net.sourceforge.phpdt.internal.debug.core.PHPDBGProxy.PHPLoop;
21 import net.sourceforge.phpdt.internal.debug.core.model.PHPDBGEvalString;
22 import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame;
23 import net.sourceforge.phpdt.internal.debug.core.model.PHPValue;
24 import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.Status;
28 import org.eclipse.debug.core.DebugException;
31 * The interface object are created by the proxy
34 public class PHPDBGInterface {
35 public boolean sessionEnded = false;
36 public int sessType = -1;
37 public int BPUnderHit = 0;
38 public String sessID = new String();
40 private int[] LastBPRead = new int[10];
41 private Vector DBGBPList = new Vector();
42 private Vector DBGVarList = new Vector();
43 private PHPStackFrame[] DBGStackList = new PHPStackFrame[0];
44 private Vector DBGMods = new Vector(); // The module names and their numbers
45 private Vector stackListOld = new Vector();
46 private BufferedReader dbgInput;
47 private OutputStream dbgOutput; // The stream which goes to DBG
48 private boolean shouldStop = false;
49 private String evalRet = new String("");
50 private int rawCounter = 1000; // An rawData frame ID counter
51 private PHPDBGProxy proxy = null;
52 // private int lastCmd = -1;
54 private boolean stopOnError = false; // If we the debugger should be relaunched after script termination
55 private boolean bRelaunch = true;
56 private char[] lastCommand = new char[4];
57 private boolean bBusy = false;
58 private boolean bDebug = true; // Prints text to console for debugging purposes
60 private static final String GlobalVariablesTitle = PHPDebugCorePlugin
61 .getResourceString("VariablesView.GlobalVariables.title");
64 * @param in The input stream (communication from DBG).
65 * @param os The output stream (communication to DBG).
66 * @param proxy The proxy to which this interface belongs.
67 * @param bRelaunch The debugger should be relaunched after PHP script termination
69 public PHPDBGInterface (BufferedReader in, OutputStream os, PHPDBGProxy proxy, boolean bRelaunch) {
75 this.bRelaunch = bRelaunch;
80 * @param mod_name The module (source file) to which we add the breakpoint.
81 * @param line The line where the breakpoint is set.
82 * @param hitCount The number of hit counts before suspend.
83 * @param condition The break condition
84 * @return Breakpoint ID ???.
86 public int addBreakpoint (String mod_name, int line, int hitCount, String condition) throws IOException {
87 return setBreakpoint (mod_name, condition, line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, hitCount, 0, 0, 0);
92 * @param mod_name The module (source file) to which we add the breakpoint.
93 * @param line The line where the breakpoint is set.
94 * @param bpNo The breakpoint ID ???.
96 public void removeBreakpoint (String mod_name, int line, int bpNo) throws IOException {
97 setBreakpoint (mod_name, "", line, PHPDBGBase.BPS_DISABLED, 0, 0, 0, bpNo, 0);
101 * Is this method used anywhere?
104 // public void requestDBGVersion () throws IOException {
105 // PHPDBGPacket DBGPacket; // A DBG message packet
106 // PHPDBGFrame DBGFrame; // A frame within a DBG packet
108 // DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
109 // DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_VER); // We want the version of DBG
111 // DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet
113 // if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
117 // DBGPacket.sendPacket (os); // Send the request to DBG
121 * Called by the proxy
124 public void getSourceTree () throws IOException {
125 PHPDBGPacket DBGPacket; // A DBG message packet
126 PHPDBGFrame DBGFrame; // A frame within a DBG packet
134 System.out.println ("PHPDBGInterface: getSourceTree");
137 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
138 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_SRC_TREE); // We want a source tree from DBG
140 DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet
142 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
147 DBGPacket.sendPacket (dbgOutput); // Send the request to DBG
149 waitResponse (1000); // Wait for the DBG response (1 second)
150 flushAllPackets (); // Read and process the response from DBG
154 * Is this method called from anywhere?
156 * @param modName The modul (filename).
158 // public void addDBGModName (String modName) throws IOException {
159 // PHPDBGPacket DBGPacket; // A DBG message packet
160 // PHPDBGFrame DBGFrame; // A frame within a DBG packet
162 // DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
163 // DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA); // We want Module name from DBG
165 // rawCounter++; // Increment the rawData ID counter
166 // DBGFrame.addInt (rawCounter); // FRAME_RAWDATA ID
167 // DBGFrame.addInt (modName.length () + 1); // The length of rawdata string (incl. null char termination)
168 // DBGFrame.addString (modName); // The file name (module name)
169 // DBGFrame.addChar ('\0'); // Add the C-String null termination
171 // DBGPacket.addFrame (DBGFrame);
173 // if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
177 // DBGPacket.sendPacket (os);
181 * This method is called for adding or removing breakpoints.
183 * @param mod_name The module name (file name).
184 * @param condition Info about the condition when to break (not used at the moment).
185 * @param line The breakpoints line.
186 * @param state Info whether this breakpoint has to be dis- or enabled.
187 * @param istep Always 0.
188 * @param hitcount Always 0.
189 * @param skiphits Always 0.
190 * @param bpno The breakpoint ID.
191 * @param isunderhit ???
194 private int setBreakpoint (String mod_name, String condition, int line, int state, int istemp, int hitcount, int skiphits, int bpno, int isunderhit) throws IOException {
195 PHPDBGPacket DBGPacket;
196 PHPDBGFrame DBGFrame1;
197 PHPDBGFrame DBGFrame2;
198 PHPDBGFrame DBGFrame3;
207 System.out.println ("PHPDBGInterface: setBreakpoint");
210 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);
211 DBGFrame1 = new PHPDBGFrame (PHPDBGBase.FRAME_BPS);
212 DBGFrame2 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
213 DBGFrame3 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
215 modNo = getModByName (mod_name); // Get the module ID by name
217 if (modNo >= 0) { // Did we find a module ID for the module name?
218 DBGFrame1.addInt (modNo); // Add the module ID to frame 1
220 DBGFrame1.addInt (0); // mod number (0 use file name)
223 DBGFrame1.addInt (line); // line number
225 if (modNo >= 0) { // Did we find a module ID for the module name?
226 DBGFrame1.addInt (0); // use mod number
229 DBGFrame1.addInt (rawCounter); // ID of FRAME_RAWDATA to send file name
232 if (modNo < 0) { // Did we find a module ID for the module name?
233 DBGFrame2.addInt (rawCounter); // FRAME_RAWDATA ID
234 DBGFrame2.addInt (mod_name.length() + 1); // length of rawdata (+ null char)
235 DBGFrame2.addString (mod_name); // file name
236 DBGFrame2.addChar ('\0'); // null char
238 DBGPacket.addFrame (DBGFrame2); // First add file name data
241 DBGFrame1.addInt (state); // state BPS_*
242 DBGFrame1.addInt (istemp); // istemp
243 DBGFrame1.addInt (0); // hit count; this is not supported as one might think
244 DBGFrame1.addInt (hitcount); // skip hits is what we think is hit count.
246 if (!condition.equals ("")) { // Do we have a condition for breakpoint
247 rawCounter++; // Set to new ID
248 DBGFrame1.addInt (rawCounter); // ID of condition
250 DBGFrame3.addInt (rawCounter); // FRAME_RAWDATA ID
251 DBGFrame3.addInt (condition.length() + 1); // length of rawdata (+ null char)
252 DBGFrame3.addString (condition); // The break condition
253 DBGFrame3.addChar ('\0'); // null char
255 DBGPacket.addFrame (DBGFrame3); // First add break condition
258 DBGFrame1.addInt (0); // ID of condition is 0, because there is no condition
261 DBGFrame1.addInt (bpno); // breakpoint number
262 DBGFrame1.addInt (isunderhit); // is under hit
264 DBGPacket.addFrame (DBGFrame1); // Second add command data
266 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
271 DBGPacket.sendPacket (dbgOutput); // Send the request to DBG
275 waitResponse (1000); // Wait for the DBG response (1 second)
276 flushAllPackets (); // Read and process the response from DBG
278 return LastBPRead[8]; // Return what ???
284 private void clearLastBP () {
287 for (i = 0; i < LastBPRead.length; i++) {
295 private void copyToLastBP (int[] BPBody) {
298 for (i = 0; i < LastBPRead.length; i++) {
299 LastBPRead[i] = BPBody[i];
306 public void continueExecution () throws IOException {
307 PHPDBGPacket DBGPacket;
310 System.out.println ("PHPDBGInterface: continueExecution");
314 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_CONTINUE);
316 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
319 DBGPacket.sendPacket (dbgOutput); // Send the request to DBG
321 lastCommand = PHPDBGBase.DBGA_CONTINUE; // Store the info about the command we sent
327 public void pauseExecution () throws IOException {
328 PHPDBGPacket DBGPacket;
331 System.out.println ("PHPDBGInterface: pauseExecution");
334 DBGPacket = new PHPDBGPacket (PHPDBGBase.IntToChar4 (PHPDBGBase.DBGC_PAUSE));
336 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
340 DBGPacket.sendPacket (dbgOutput); // Send the request to DBG
346 private int getBPUnderHit () {
349 int[] dbg_bpl_body = new int[10];
351 for (i = 0; i < DBGBPList.size (); i++) { // look for bp under hit
352 dbg_bpl_body = (int[]) DBGBPList.get (i);
354 if (dbg_bpl_body[9] == 1) {
355 BPUnder = dbg_bpl_body[8];
362 // public int getLastCmd()
372 public void setLastCmd (int cmd)
380 public boolean stepInto () throws IOException {
381 PHPDBGPacket DBGPacket;
385 System.out.println ("PHPDBGInterface: stepOver vetoed");
395 System.out.println ("PHPDBGInterface: stepInto");
399 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPINTO);
401 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
405 DBGPacket.sendPacket (dbgOutput); // Send the request to DBG
407 lastCommand = PHPDBGBase.DBGA_STEPINTO; // Store the info about the command we sent
415 public boolean stepOver () throws IOException {
416 PHPDBGPacket DBGPacket;
420 System.out.println ("PHPDBGInterface: stepOver vetoed");
430 System.out.println ("PHPDBGInterface: stepOver");
434 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOVER);
436 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
440 DBGPacket.sendPacket (dbgOutput); // Send the request to DBG
442 lastCommand = PHPDBGBase.DBGA_STEPOVER; // Store the info about the command we sent
450 public boolean stepOut () throws IOException {
451 PHPDBGPacket DBGPacket;
455 System.out.println ("PHPDBGInterface: stepOver vetoed");
465 System.out.println ("PHPDBGInterface: stepOut");
469 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOUT);
471 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
475 DBGPacket.sendPacket (dbgOutput); // Send the request to DBG
477 lastCommand = PHPDBGBase.DBGA_STEPOUT; // Store the info about the command we sent
485 // public void stopExecution () throws IOException {
486 // PHPDBGPacket DBGPacket;
489 // DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STOP);
491 // if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
495 // DBGPacket.sendPacket (os); // Send the request to DBG
499 * This method is called by the proxy.
500 * It sends a request to DBG to get the current variables
501 * with their values. It waits for the response and processes
502 * the input from DBG.
504 * @param stack The stackframe for which we want the variables.
505 * @return The array of variables
507 public synchronized Vector getVariables(PHPStackFrame stack) throws IOException, DebugException {
508 if (DBGStackList.length == 0) {
514 // get global variables (and assign them to 'main()' stackframe)
515 int global_scope_id = (DBGStackList.length > 1) ? 2 : PHPDBGBase.GLOBAL_SCOPE_ID;
516 // DBG 2.13.1 doesn't return Super Globals with GLOBAL_SCOPE_ID in nested stackframes,
517 // so using 2(most out-standing stack context) instead of GLOBAL_SCOPE_ID.
518 // Also note that 2.13.1 doesn't return $this in class context.
519 // (You can inspect $this in Expressions View. And once it is shown, 2.13.1 comes to return $this.)
520 Vector globalList = getVariables(DBGStackList[DBGStackList.length - 1], global_scope_id);
522 if (!globalList.isEmpty()) {
523 // remove unresolved '$this=?' variable
524 removeUnresolvedThisVar(globalList);
526 PHPVariable var = (PHPVariable) globalList.get(0);
527 var.setName(GlobalVariablesTitle);
528 var.setModifiable(false);
531 int scopeID = stack.getScopeID();
533 if (!globalList.isEmpty () &&
534 ((DBGStackList.length == 1) || (scopeID == PHPDBGBase.CURLOC_SCOPE_ID + 1))) {
535 // 'main()' stackframe
536 PHPVariable var = (PHPVariable) globalList.get(0);
537 PHPValue val = (PHPValue) var.getValue();
539 DBGVarList = val.getChildVariables();
543 else if (scopeID == PHPDBGBase.CURLOC_SCOPE_ID) {
544 // current stackframe
545 DBGVarList = getVariables(stack, PHPDBGBase.CURLOC_SCOPE_ID);
548 // back-trace stackframe
549 //DBGVarList = getVariables(stack, scopeID);
550 //removeUnresolvedThisVar(DBGVarList);
551 // DBG 2.15.5 causes Application Error (on win32) in *some* cases.
555 if (DBGVarList.size() > 0) { // Did we get back variables?
556 PHPVariable var = (PHPVariable) DBGVarList.get(0); // Yes, then get the first PHPVariable
557 PHPValue val = (PHPValue) var.getValue(); // Get the value
559 if (var.getName().equals("")) { // Is the root node an empty node (usually it is)
560 DBGVarList = val.getChildVariables(); // Then remove the empty node.
561 // With removing the empty root node, it wouldn't be necessary to
562 // set the name to an empty string. So the code below is just for
563 // info or in case the users want to have the empty root node.
565 // The eclipse variable view cannot handle Variables which have an empty name
566 // when it comes to variable tree restore operation. Without a name, no restore!
567 //var.setName (" "); // Give a name to the variable root node. Even if it is only a space :-)
568 } // TO DO the best would be to remove the empty root node, but this would
569 // require a understanding and reworking of the PHPDBGEvalstring class.
572 if (!globalList.isEmpty()) {
573 DBGVarList.add(globalList.get(0));
576 return DBGVarList; // Return the variables as list
582 private Vector getVariables(PHPStackFrame stack, int scope_id) throws IOException {
583 PHPDBGPacket DBGPacket = new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
584 PHPDBGFrame DBGFrame1 = new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
588 System.out.println ("PHPDBGInterface: getVariables vetoed");
598 System.out.println ("PHPDBGInterface: getVariables");
602 DBGFrame1.addInt(scope_id);
604 DBGPacket.addFrame(DBGFrame1);
607 if (proxy.getSocket().isClosed()) {
612 DBGPacket.sendPacket(dbgOutput);
617 bBusy = false; // Already done in flushAllPackets ()
619 PHPDBGEvalString evalStr = new PHPDBGEvalString(stack, evalRet);
620 return evalStr.getVariables();
624 * Remove unresolved $this variable
626 * DBG returns $this=? in function's or intermediate stackframes.
627 * (In current method's stackframe, DBG returns $this=classname)
631 private void removeUnresolvedThisVar(Vector varList) {
632 if (varList.size() > 0) {
633 PHPVariable var = (PHPVariable) varList.get(0);
634 PHPValue val = (PHPValue) var.getValue();
635 Vector workList = val.getChildVariables ();
637 for (int i = 0; i < workList.size(); i++) {
638 PHPVariable workvar = (PHPVariable) workList.get(i);
640 if (workvar.getName().equals ("$this")) {
641 String workval = ((PHPValue) workvar.getValue ()).getValueString ();
643 if (workval.equals ("?") ||
644 workval.equals ("NULL")) {
657 public void log(String logString) throws IOException, DebugException {
658 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
659 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_LOG);
660 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
668 System.out.println ("PHPDBGInterface: log");
672 DBGFrame1.addInt(rawCounter); // ilog
673 DBGFrame1.addInt(1); // type
674 DBGFrame1.addInt(0); // mod_no
675 DBGFrame1.addInt(0); // line_no
676 DBGFrame1.addInt(0); // imod_name
677 DBGFrame1.addInt(0); // ext_info
679 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
680 DBGFrame2.addInt(logString.length() + 1); // length of rawdata (+ null char)
681 DBGFrame2.addString(logString); // log string
682 DBGFrame2.addChar('\0'); // null char
684 // Add raw data first
685 DBGPacket.addFrame(DBGFrame2);
687 DBGPacket.addFrame(DBGFrame1);
689 if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication?
691 return; // No, then leave here
694 DBGPacket.sendPacket(dbgOutput);
700 public synchronized PHPVariable[] evalBlock(PHPStackFrame stack, String evalString) throws IOException, DebugException {
701 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
702 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
703 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
711 System.out.println ("PHPDBGInterface: evalBlock");
715 DBGFrame1.addInt(rawCounter); // istr = raw data ID
716 //DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth
717 int scope_id = stack.getScopeID();
718 /* test code : unnecessary
719 if (DBGStackList.length == 1 || scope_id == (PHPDBGBase.CURLOC_SCOPE_ID + 1)) {
720 scope_id = PHPDBGBase.GLOBAL_SCOPE_ID;
723 DBGFrame1.addInt(scope_id);
725 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
726 DBGFrame2.addInt(evalString.length() + 1); // length of rawdata (+ null char)
727 DBGFrame2.addString(evalString); // eval block
728 DBGFrame2.addChar('\0'); // null char
730 // Add raw data first
731 DBGPacket.addFrame(DBGFrame2);
733 DBGPacket.addFrame(DBGFrame1);
735 if (proxy.getSocket().isClosed()) { // Do we have a socket for DBG communication?
737 return null; // No, then leave here
740 DBGPacket.sendPacket(dbgOutput);
745 PHPDBGEvalString evalStr=new PHPDBGEvalString(stack, evalRet);
747 return evalStr.getVars();
751 * Read and process everthing we got from DBG
753 public void flushAllPackets () throws IOException {
754 while (readResponse() != 0);
758 * Get the modules name by its number
760 * @param modNo The number (id) of the module
761 * @return The name of the module
763 public String getModByNo (int modNo) {
767 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
768 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
770 if (dbg_mod.getNo () == modNo) { // Is the module from the array the module we want?
771 return dbg_mod.getName (); // Yes, return the name of the module
775 return ""; // If nothing was found return emtpy string
780 * @param modName The name of the module for which we want the ID
782 * - The ID of the module
783 * - -1 if nothing was found
785 private int getModByName (String modName) {
789 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
790 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
792 if (dbg_mod.getName ().equalsIgnoreCase (modName)) { // Is the module from the array the module we want?
793 return dbg_mod.getNo (); // Yes, return the name of the module
797 return -1; // If nothing was found return -1
801 * Return the string for the given frame number
803 * @param framesInfo The buffer which is to read
804 * @param frameNo The frame number
807 private String getRawFrameData (char[] framesInfo, int frameNo) {
808 int nextFrame = 0; // The current read position within the buffer
809 int[] dbg_frame = new int[2]; // The two frame header numbers
811 while (nextFrame < framesInfo.length) { // As long we have something within the buffer
812 dbg_frame[0] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame); // The frame type
813 dbg_frame[1] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The frame size
815 nextFrame += 8; // The current read position
817 if (dbg_frame[1] == 0) { // If frame size is 0
818 return ""; // return an emtpy string
821 switch (dbg_frame[0]) { // Switch for the frame type
822 case PHPDBGBase.FRAME_RAWDATA: // The only frame type we are interrested in
823 if (frameNo == PHPDBGBase.Char4ToInt (framesInfo, nextFrame)) { // Is it correct number of the frame
826 toRead = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The size of the string
828 if ((int) framesInfo[nextFrame + 8 + toRead - 1] == 0) { // Is there a string termination at the end?
829 return String.copyValueOf (framesInfo, nextFrame + 8, toRead - 1); // Then copy frame content to String without the \0 and return
832 return String.copyValueOf (framesInfo, nextFrame + 8, toRead); // Copy frame content to String and return
837 nextFrame += dbg_frame[1]; // Go for the next frame (add the length of the current one)
840 return ""; // We did not found any FRAM_RAWDATA, so return an emtpy strin
844 * Reset the availability flag for all stackframes in the list.
846 * @param list The list of old stackframes
848 private void resetAvailability (Vector list) {
851 for (i = 0; i < list.size (); i++) {
852 ((PHPStackFrame) list.get(i)).setAvailable (false); //
857 * Check whether the new stackframe is in the list of old stackframes.
858 * Test for identical stackframe (identical means same description and same line number).
860 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
861 * @param list The list of old stackframes
863 * - true if we have found the identical stackframe within the list
864 * - false if we did not find the identical stackframe within the list
866 private boolean isStackFrameInList (PHPStackFrame stackFrameNew, Vector list) {
868 PHPStackFrame stackFrameOld;
870 for (i = 0; i < list.size (); i++) {
871 stackFrameOld = (PHPStackFrame) list.get (i); //
873 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) &&
874 stackFrameNew.getLineNumber () == stackFrameOld.getLineNumber ()) { // Did we find the sent stackframe within the list of old stackframes?
875 stackFrameOld.setAvailable (true); // We found the new stackframe in the list of old stack frames
876 stackFrameOld.setIndex (stackFrameNew.getIndex ());
877 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
879 return true; // The stackframe was found in the list
887 * Check whether the new stackframe is in the list of old stackframes.
888 * Test for exact stackframe (exact means same description and same line number).
890 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
891 * @param list The list of old stackframes
893 * - true if we have exactly this stackframe within the list
894 * - false if we did not find the exact stackframe within the list
896 private void markIdenticalStackFrames (Vector oldList, Vector newList) {
898 PHPStackFrame stackFrameNew;
900 resetAvailability (oldList); // Reset the availability flag of the old stack frames
901 resetAvailability (newList); // Reset the availability flag of the old stack frames
903 for (i = 0; i < newList.size (); i++) { // For all stackList entries
904 stackFrameNew = (PHPStackFrame) newList.get (i);
906 if (isStackFrameInList (stackFrameNew, oldList)) { // Is this stackframe in the list
907 stackFrameNew.setAvailable (true); //
916 * The stackList contains the currently read stackframes which were sent
917 * from DBG. The DBG interface holds a list of the active stack frames.
918 * This method replicates the 'static' stackframe list with the DBG stackframe list
919 * Replication is done in the following way:
921 * <li> It looks for new stackframes within the DBG stackframe list and
922 * adds them to the 'static' list.
923 * <li> It looks for stackframes within the 'static' list, and removes them
924 * from the 'static' list in case they do not appear within the DBG list.
925 * <li> It looks for stackframes which are already existent and replicates the
926 * line number and the index number.
927 * <li> At the end, the 'static' stackframe list has to be sorted by the stackframes
931 * Removes the unused stackframes from the list, or adds stackframes which
932 * are not yet in the list.
937 private void updateStackFrameList (Vector stackList) {
940 PHPStackFrame stackFrameNew;
941 PHPStackFrame stackFrameOld;
942 PHPStackFrame[] newStackList;
945 System.out.println ("PHPDBGInterface: updateStackFrameList Start");
948 markIdenticalStackFrames (stackListOld, stackList); // Check whether the newly send stack frames can be found in the list
949 // of old stack frames
951 for (i = 0; i < stackList.size (); i++) { // For all stackList entries
952 stackFrameNew = (PHPStackFrame) stackList.get(i);
954 for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list
955 stackFrameOld = (PHPStackFrame) stackListOld.get (n); //
957 if (stackFrameOld.isAvailable ()) { // If this stack frame was already found in the new list skip it
961 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) {// Did we find the sent stackframe within the list of old stackframes?
962 stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ());
963 stackFrameOld.setIndex (stackFrameNew.getIndex ());
964 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
966 stackFrameOld.setAvailable (true); // And mark this stack frame as available
967 stackFrameNew.setAvailable (true); // And mark this stack frame as available
969 break; // Yes, then break;
973 if (!stackFrameNew.isAvailable ()) { // Did not find the new stackframe within the list?
974 stackFrameNew.setAvailable (true); // Mark the stack frame as available and
975 stackListOld.add (stackFrameNew); // then add the new stackframe
979 // And now for removing unused stackframes from list
981 for (n = 0; n < stackListOld.size(); n++) {
982 stackFrameOld = (PHPStackFrame) stackListOld.get(n);
984 if (!stackFrameOld.isAvailable()) {
985 stackListOld.remove(n--);
989 Collections.sort (stackListOld); // Sort the 'static' stackframe list by the stackframe index numbers.
991 newStackList = new PHPStackFrame[stackListOld.size ()];
992 newStackList = (PHPStackFrame[]) stackListOld.toArray (newStackList);
993 DBGStackList = newStackList;
996 System.out.println ("PHPDBGInterface: updateStackFrameList End");
1001 * Read the response from DBG and process the frame
1004 * - The received command
1005 * - or 0 if something was wrong
1007 public int readResponse () throws IOException {
1008 int bytesToRead = 0; // The number of byte to read for the current DBG block
1009 int nextFrame = 0; // The current read position within entirePack
1011 int cmdReceived = 0;
1013 boolean errorStack = false;
1014 char[] dbg_header_struct_read = new char[16]; // The buffer for the first 16 bytes of a block
1015 int[] dbg_header_struct = new int[4]; // The first four numbers (long) of a block
1016 int[] dbg_bpl_tmp = new int[10];
1017 int[] dbg_frame = new int[2];
1018 int[] dbg_eval_tmp = new int[3];
1019 int[] dbg_src_tree_tmp = new int[4]; //
1020 int[] dbg_error_tmp = new int[2];
1021 Vector rawList = new Vector();
1022 Vector stackList = new Vector(); // Intermediate stacklist which is build up in FRAME_STACK frame
1025 System.out.println ("PHPDBGInterface: readResponse start");
1032 while (readInput (dbg_header_struct_read, 16) != 0) { // Read 16 byte from input stream
1033 dbg_header_struct[0] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 0); // Debug sync header
1034 dbg_header_struct[1] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 4); // Command
1035 dbg_header_struct[2] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 8); //
1036 dbg_header_struct[3] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 12); // Bytes within this block
1038 if (dbg_header_struct[0] != 0x5953) { // Check DBG sync bytes
1040 System.out.println ("PHPDBGInterface: readResponse. Wrong sync");
1044 return 0; // Wrong header
1047 cmdReceived = dbg_header_struct[1]; // Get the command
1048 setLastCmd (cmdReceived); // Store the info about the current command
1049 bytesToRead = dbg_header_struct[3]; // Get the number of bytes to read for this block
1051 //System.out.println("Response Received: " + cmdReceived);
1052 char[] entirePack = new char[bytesToRead]; // Store the block data into buffer 'entirePack'
1054 if (bytesToRead > 0) { // If there is something within the frame
1055 if (readInput (entirePack, bytesToRead) < bytesToRead) { // Read the frame into the buffer
1057 System.out.println ("PHPDBGInterface: readResponse. Did not read enough");
1061 return 0; // We did not read enough bytes, error
1065 nextFrame = 0; // Start with the first frame
1067 while (nextFrame < bytesToRead) { // As long as we have something within this block
1068 dbg_frame[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame); // The name of the frame
1069 dbg_frame[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The size of the frame
1070 nextFrame += 8; // The next read position
1072 if (dbg_frame[1] == 0) { // Something within the frame?
1074 System.out.println ("PHPDBGInterface: readResponse. Nothing within the frame");
1078 return 0; // Nothing to read, error
1081 switch (dbg_frame[0]) {
1082 case PHPDBGBase.FRAME_STACK:
1083 int[] dbg_stack_new = new int[4]; //
1085 dbg_stack_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Source line number
1086 dbg_stack_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Module number
1087 dbg_stack_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // Scope id
1088 dbg_stack_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // ID of description string
1090 if ((dbg_stack_new[1] != 0) && !errorStack) {
1091 PHPStackFrame newStack;
1094 newStack = new PHPStackFrame (null, // The thread
1095 getModByNo (dbg_stack_new[1]), // The name of the module (file)
1096 dbg_stack_new[0], // The source line number
1098 getRawFrameData (entirePack, // Get the string from this packet
1099 dbg_stack_new[3]), // The frame ID for which we want the string
1100 dbg_stack_new[1], // The module number
1102 stackList.add (newStack);
1108 case PHPDBGBase.FRAME_SOURCE: // Nothing to be done here
1109 break; // TODO: what's with that frame? Something interesting
1111 case PHPDBGBase.FRAME_SRC_TREE: //
1112 dbg_src_tree_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // The parent module number
1113 dbg_src_tree_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The parent line number (not used)
1114 dbg_src_tree_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // The module number
1115 dbg_src_tree_tmp[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // The filename number
1117 if (getModByNo (dbg_src_tree_tmp[2]).equals ("")) {
1120 fileName = new String (getRawFrameData (entirePack, dbg_src_tree_tmp[3])); // Get the filename
1122 if (dbg_src_tree_tmp[2] != 0) { // If there is a module number
1125 modNew = new PHPDBGMod (dbg_src_tree_tmp[2], fileName); // Create a module object
1127 DBGMods.add (modNew); // And store it to array
1132 case PHPDBGBase.FRAME_RAWDATA: // Nothing to be done here
1133 break; // FRAME_RAWDATA are processed within getRawFrameData
1135 case PHPDBGBase.FRAME_ERROR: // An error frame
1136 errorStack = true; // Yes, we have an error stack
1137 dbg_error_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Error type
1138 dbg_error_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Error message ID
1140 String error = "\n"; //
1142 switch (dbg_error_tmp[0]) { // Switch on error type
1143 case PHPDBGBase.E_ERROR: error += "[Error]"; break;
1144 case PHPDBGBase.E_WARNING: error += "[Warning]"; break;
1145 case PHPDBGBase.E_PARSE: error += "[Parse Error]"; break;
1146 case PHPDBGBase.E_NOTICE: error += "[Notice]"; break;
1147 case PHPDBGBase.E_CORE_ERROR: error += "[Core Error]"; break;
1148 case PHPDBGBase.E_CORE_WARNING: error += "[Core Warning]"; break;
1149 case PHPDBGBase.E_COMPILE_ERROR: error += "[Compile Error]"; break;
1150 case PHPDBGBase.E_COMPILE_WARNING: error += "[Compile Warning]"; break;
1151 case PHPDBGBase.E_USER_ERROR: error += "[User Error]"; break;
1152 case PHPDBGBase.E_USER_WARNING: error += "[User Warning]"; break;
1153 case PHPDBGBase.E_USER_NOTICE: error += "[User Notice]"; break;
1154 default: error += "[Unexpected Error]"; break;
1158 error += new String (getRawFrameData (entirePack, dbg_error_tmp[1])); // Add the error string for this error message ID
1159 error += "\n"; // Append a CR
1161 PHPDebugCorePlugin.log (new DebugException (new Status (IStatus.WARNING,
1162 PHPDebugCorePlugin.PLUGIN_ID,
1166 // To print errors on the console, I must execute a code in the
1167 // php context, that write the stderr... I didn't found a better way
1168 // TODO: Find a better way????
1170 // String codeExec= "";
1171 // codeExec= "fwrite(fopen('php://stderr', 'w'),\\\"" + error + "\\\");";
1173 // evalBlock("eval(\"" + codeExec + "\");");
1174 // } catch (DebugException e) {
1175 // PHPDebugCorePlugin.log(e);
1178 if (!stopOnError) { // Is always false (Did not see where this is set to true!?)
1179 if (lastCommand.equals (PHPDBGBase.DBGA_CONTINUE)) { // If last command for PHP was a 'continue',
1180 continueExecution (); // send continue again
1181 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPINTO)) { // If last command for PHP was a 'step into',
1182 stepInto (); // send 'step into' again
1183 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOUT)) { // If last command for PHP was a 'step out',
1184 stepOut (); // send 'step out' again
1185 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOVER)) { // If last command for PHP was a 'step over',
1186 stepOver (); // send 'step over' again
1191 case PHPDBGBase.FRAME_EVAL:
1192 //String evalString;
1194 //evalString = new String ("");
1195 dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // istr
1196 dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // iresult
1197 dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // ierror
1199 evalRet = getRawFrameData (entirePack, dbg_eval_tmp[1]); //
1200 //evalString = getRawFrameData (entirePack, dbg_eval_tmp[0]); //
1203 case PHPDBGBase.FRAME_BPS: //
1206 case PHPDBGBase.FRAME_BPL:
1209 dbg_bpl_new = new int[10];
1210 dbg_bpl_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);
1211 dbg_bpl_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);
1212 dbg_bpl_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);
1213 dbg_bpl_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);
1214 dbg_bpl_new[4] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 16);
1215 dbg_bpl_new[5] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 20);
1216 dbg_bpl_new[6] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 24);
1217 dbg_bpl_new[7] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 28);
1218 dbg_bpl_new[8] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 32);
1219 dbg_bpl_new[9] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 36);
1221 // look if breakpoint already exists in vector
1222 for (i = 0; i < DBGBPList.size (); i++) {
1223 dbg_bpl_tmp = (int[]) DBGBPList.get (i);
1225 if (dbg_bpl_tmp[8] == dbg_bpl_new[8]) {
1226 DBGBPList.remove (i);
1232 // add breakpoint to vector
1233 DBGBPList.add (dbg_bpl_new);
1234 copyToLastBP (dbg_bpl_new);
1237 if (getModByNo (dbg_bpl_new[0]).equals ("")) {
1240 fileName = new String (getRawFrameData (entirePack, dbg_bpl_new[2]));
1242 if (dbg_bpl_new[0] != 0) {
1245 modNew = new PHPDBGMod (dbg_bpl_new[0], fileName);
1247 DBGMods.add (modNew);
1252 case PHPDBGBase.FRAME_VER:
1255 case PHPDBGBase.FRAME_SID:
1256 sid = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0);
1259 case PHPDBGBase.FRAME_SRCLINESINFO:
1262 case PHPDBGBase.FRAME_SRCCTXINFO:
1265 case PHPDBGBase.FRAME_LOG:
1268 case PHPDBGBase.FRAME_PROF:
1271 case PHPDBGBase.FRAME_PROF_C:
1274 case PHPDBGBase.FRAME_SET_OPT:
1278 nextFrame += dbg_frame[1]; // go to next frame
1281 // Now process command
1282 switch(cmdReceived) {
1283 case PHPDBGBase.DBGC_REPLY:
1286 case PHPDBGBase.DBGC_STARTUP:
1289 case PHPDBGBase.DBGC_END:
1291 continueExecution (); // Inform dbg that we want to continue execution
1292 proxy.updateView (); // Sent a change event and create thread event to eclipse core
1293 updateStackFrameList (stackList); // ??? Just a try
1296 sessionEnded = true;
1297 proxy.setTerminated ();
1301 case PHPDBGBase.DBGC_BREAKPOINT:
1302 BPUnderHit = getBPUnderHit ();
1303 updateStackFrameList (stackList);
1306 case PHPDBGBase.DBGC_STEPINTO_DONE:
1307 case PHPDBGBase.DBGC_STEPOVER_DONE:
1308 case PHPDBGBase.DBGC_STEPOUT_DONE:
1309 case PHPDBGBase.DBGC_EMBEDDED_BREAK:
1310 case PHPDBGBase.DBGC_PAUSE:
1312 updateStackFrameList (stackList);
1315 case PHPDBGBase.DBGC_ERROR:
1317 updateStackFrameList (stackList);
1320 case PHPDBGBase.DBGC_LOG:
1323 case PHPDBGBase.DBGC_SID:
1329 System.out.println ("PHPDBGInterface: readResponse finish, received: " + cmdReceived);
1334 return cmdReceived; // Return the command we received with this block
1341 public PHPStackFrame[] getStackList() {
1342 return DBGStackList;
1346 * Reads from input buffer (response sent from DBG) the given number of chars
1347 * into frame buffer.
1349 * @param buffer The frame buffer where to store the read data from DBG.
1350 * @param bytes The number of bytes (chars) which are to read from input stream.
1351 * @return The number of bytes actually read.
1353 private int readInput (char[] buffer, int bytes) throws IOException {
1354 int bytesRead = 0; // Reset the bytes read counter
1355 int nRetry = 0; // Retry counter
1358 System.out.println ("PHPDBGInterface: readInput " + bytes);
1361 for (int i = 0; i < bytes;) { // For the number of bytes we should read
1362 if (dbgInput.ready ()) { // If input stream is ready for reading
1363 nRetry = 0; // Reset the retry counter
1364 buffer[i] = (char) (dbgInput.read () & 0x00FF); // Read a char and store only the least significant 8-bits
1365 bytesRead++; // Increment the bytes read counter
1368 else { // Input stream is not ready
1369 nRetry++; // Increment the retry counter
1371 if (nRetry > 10) { // If nothing received within 100 retries
1374 System.out.println ("PHPDBGInterface: Too many retries without receiving something");
1377 break; // we break the loop
1380 synchronized (dbgInput) {
1383 System.out.println ("PHPDBGInterface: retry: " + nRetry + " Wait for something to receive, received: " + i + " need " + bytes);
1387 dbgInput.wait (10); // wait 5 ms maximum for something to receive
1388 } catch (InterruptedException e) {
1394 if (bytesRead > 0) {
1395 if (bytes != bytesRead) {
1397 System.out.println ("PHPDBGInterface: readInput: Possible error: not enough bytes in buffer should read: " + bytes +
1398 " actually read: " + bytesRead);
1403 return bytesRead; // Return the number of bytes actually read
1407 * PHPProxy could stop the waiting for a response with this method.
1410 public void setShouldStop () {
1411 this.shouldStop = true;
1415 * @param milliseconds The maximum time in milliseconds we wait for something
1416 * to be send from DBG.
1417 * @return - true if something was received from DBG
1418 * - false if nothing was send from DBG within the given time
1420 * This method has been a busy wait loop. It was changed to use
1421 * a non busy wait to avoid a heavy load after automatic relaunch
1422 * after script termination
1425 public boolean waitResponse (long milliseconds) throws IOException {
1429 System.out.println ("PHPDBGInterface: waitResponse " + milliseconds);
1432 timeout = System.currentTimeMillis () + milliseconds; // Calculate the system time till we wait.
1434 while (System.currentTimeMillis () < timeout) { // Is waiting time running out?
1435 synchronized (dbgInput) {
1437 dbgInput.wait (5); // wait 5 ms maximum for something to receive
1438 } catch (InterruptedException e) {
1442 if (dbgInput.ready () || shouldStop) { // If something is received of if we should stop now
1443 break; // break the waiting loop
1447 return dbgInput.ready (); // true if we got something from DBG