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 in;
47 private OutputStream os; // 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;
55 private char[] lastCommand = new char[4];
57 private static final String GlobalVariablesTitle = PHPDebugCorePlugin
58 .getResourceString("VariablesView.GlobalVariables.title");
61 * @param in The input stream (communication from DBG).
62 * @param os The output stream (communication to DBG).
63 * @param proxy The proxy to which this interface belongs.
65 public PHPDBGInterface (BufferedReader in, OutputStream os, PHPDBGProxy proxy) {
75 * @param mod_name The module (source file) to which we add the breakpoint.
76 * @param line The line where the breakpoint is set.
77 * @param hitCount The number of hit counts before suspend.
78 * @param condition The break condition
79 * @return Breakpoint ID ???.
81 public int addBreakpoint (String mod_name, int line, int hitCount, String condition) throws IOException {
82 return setBreakpoint (mod_name, condition, line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, hitCount, 0, 0, 0);
87 * @param mod_name The module (source file) to which we add the breakpoint.
88 * @param line The line where the breakpoint is set.
89 * @param bpNo The breakpoint ID ???.
91 public void removeBreakpoint (String mod_name, int line, int bpNo) throws IOException {
92 setBreakpoint (mod_name, "", line, PHPDBGBase.BPS_DISABLED, 0, 0, 0, bpNo, 0);
96 * Is this method used anywhere?
99 public void requestDBGVersion () throws IOException {
100 PHPDBGPacket DBGPacket; // A DBG message packet
101 PHPDBGFrame DBGFrame; // A frame within a DBG packet
103 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
104 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_VER); // We want the version of DBG
106 DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet
108 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
112 DBGPacket.sendPacket (os); // Send the request to DBG
116 * Called by the proxy
119 public void getSourceTree () throws IOException {
120 PHPDBGPacket DBGPacket; // A DBG message packet
121 PHPDBGFrame DBGFrame; // A frame within a DBG packet
123 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
124 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_SRC_TREE); // We want a source tree from DBG
126 DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet
128 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
132 DBGPacket.sendPacket (os); // Send the request to DBG
134 waitResponse (1000); // Wait for the DBG response (1 second)
135 flushAllPackets (); // Read and process the response from DBG
139 * Is this method called from anywhere?
141 * @param modName The modul (filename).
143 public void addDBGModName (String modName) throws IOException {
144 PHPDBGPacket DBGPacket; // A DBG message packet
145 PHPDBGFrame DBGFrame; // A frame within a DBG packet
147 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
148 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA); // We want Module name from DBG
150 rawCounter++; // Increment the rawData ID counter
151 DBGFrame.addInt (rawCounter); // FRAME_RAWDATA ID
152 DBGFrame.addInt (modName.length () + 1); // The length of rawdata string (incl. null char termination)
153 DBGFrame.addString (modName); // The file name (module name)
154 DBGFrame.addChar ('\0'); // Add the C-String null termination
156 DBGPacket.addFrame (DBGFrame);
158 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
162 DBGPacket.sendPacket (os);
166 * This method is called for adding or removing breakpoints.
168 * @param mod_name The module name (file name).
169 * @param condition Info about the condition when to break (not used at the moment).
170 * @param line The breakpoints line.
171 * @param state Info whether this breakpoint has to be dis- or enabled.
172 * @param istep Always 0.
173 * @param hitcount Always 0.
174 * @param skiphits Always 0.
175 * @param bpno The breakpoint ID.
176 * @param isunderhit ???
179 private int setBreakpoint (String mod_name, String condition, int line, int state, int istemp, int hitcount, int skiphits, int bpno, int isunderhit) throws IOException {
180 PHPDBGPacket DBGPacket;
181 PHPDBGFrame DBGFrame1;
182 PHPDBGFrame DBGFrame2;
183 PHPDBGFrame DBGFrame3;
186 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);
187 DBGFrame1 = new PHPDBGFrame (PHPDBGBase.FRAME_BPS);
188 DBGFrame2 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
189 DBGFrame3 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
191 modNo = getModByName (mod_name); // Get the module ID by name
193 if (modNo >= 0) { // Did we find a module ID for the module name?
194 DBGFrame1.addInt (modNo); // Add the module ID to frame 1
196 DBGFrame1.addInt (0); // mod number (0 use file name)
199 DBGFrame1.addInt (line); // line number
201 if (modNo >= 0) { // Did we find a module ID for the module name?
202 DBGFrame1.addInt (0); // use mod number
205 DBGFrame1.addInt (rawCounter); // ID of FRAME_RAWDATA to send file name
208 if (modNo < 0) { // Did we find a module ID for the module name?
209 DBGFrame2.addInt (rawCounter); // FRAME_RAWDATA ID
210 DBGFrame2.addInt (mod_name.length() + 1); // length of rawdata (+ null char)
211 DBGFrame2.addString (mod_name); // file name
212 DBGFrame2.addChar ('\0'); // null char
214 DBGPacket.addFrame (DBGFrame2); // First add file name data
217 DBGFrame1.addInt (state); // state BPS_*
218 DBGFrame1.addInt (istemp); // istemp
219 DBGFrame1.addInt (0); // hit count; this is not supported as one might think
220 DBGFrame1.addInt (hitcount); // skip hits is what we think is hit count.
222 if (!condition.equals ("")) { // Do we have a condition for breakpoint
223 rawCounter++; // Set to new ID
224 DBGFrame1.addInt (rawCounter); // ID of condition
226 DBGFrame3.addInt (rawCounter); // FRAME_RAWDATA ID
227 DBGFrame3.addInt (condition.length() + 1); // length of rawdata (+ null char)
228 DBGFrame3.addString (condition); // The break condition
229 DBGFrame3.addChar ('\0'); // null char
231 DBGPacket.addFrame (DBGFrame3); // First add break condition
234 DBGFrame1.addInt (0); // ID of condition is 0, because there is no condition
237 DBGFrame1.addInt (bpno); // breakpoint number
238 DBGFrame1.addInt (isunderhit); // is under hit
240 DBGPacket.addFrame (DBGFrame1); // Second add command data
242 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
246 DBGPacket.sendPacket (os); // Send the request to DBG
250 waitResponse (1000); // Wait for the DBG response (1 second)
251 flushAllPackets (); // Read and process the response from DBG
253 return LastBPRead[8]; // Return what ???
259 private void clearLastBP () {
262 for (i = 0; i < LastBPRead.length; i++) {
270 private void copyToLastBP (int[] BPBody) {
273 for (i = 0; i < LastBPRead.length; i++) {
274 LastBPRead[i] = BPBody[i];
281 public void continueExecution () throws IOException {
282 PHPDBGPacket DBGPacket;
285 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_CONTINUE);
287 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
290 DBGPacket.sendPacket (os); // Send the request to DBG
292 lastCommand = PHPDBGBase.DBGA_CONTINUE; // Store the info about the command we sent
298 public void pauseExecution () throws IOException {
299 PHPDBGPacket DBGPacket;
301 DBGPacket = new PHPDBGPacket (PHPDBGBase.IntToChar4 (PHPDBGBase.DBGC_PAUSE));
303 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
307 DBGPacket.sendPacket (os); // Send the request to DBG
313 private int getBPUnderHit () {
316 int[] dbg_bpl_body = new int[10];
318 for (i = 0; i < DBGBPList.size (); i++) { // look for bp under hit
319 dbg_bpl_body = (int[]) DBGBPList.get (i);
321 if (dbg_bpl_body[9] == 1) {
322 BPUnder = dbg_bpl_body[8];
329 public int getLastCmd()
339 public void setLastCmd (int cmd)
347 public void stepInto () throws IOException {
348 PHPDBGPacket DBGPacket;
351 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPINTO);
353 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
357 DBGPacket.sendPacket (os); // Send the request to DBG
359 lastCommand = PHPDBGBase.DBGA_STEPINTO; // Store the info about the command we sent
365 public void stepOver () throws IOException {
366 PHPDBGPacket DBGPacket;
369 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOVER);
371 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
375 DBGPacket.sendPacket (os); // Send the request to DBG
377 lastCommand = PHPDBGBase.DBGA_STEPOVER; // Store the info about the command we sent
383 public void stepOut () throws IOException {
384 PHPDBGPacket DBGPacket;
387 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOUT);
389 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
393 DBGPacket.sendPacket (os); // Send the request to DBG
395 lastCommand = PHPDBGBase.DBGA_STEPOUT; // Store the info about the command we sent
401 public void stopExecution () throws IOException {
402 PHPDBGPacket DBGPacket;
405 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STOP);
407 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
411 DBGPacket.sendPacket (os); // Send the request to DBG
415 * This method is called by the proxy.
416 * It sends a request to DBG to get the current variables
417 * with their values. It waits for the response and processes
418 * the input from DBG.
420 * @param stack The stackframe for which we want the variables.
421 * @return The array of variables
423 public synchronized Vector getVariables(PHPStackFrame stack) throws IOException, DebugException {
424 if (DBGStackList.length == 0) {
429 // get global variables (and assign them to 'main()' stackframe)
430 int global_scope_id = (DBGStackList.length > 1) ? 2 : PHPDBGBase.GLOBAL_SCOPE_ID;
431 // DBG 2.13.1 doesn't return Super Globals with GLOBAL_SCOPE_ID in nested stackframes,
432 // so using 2(most out-standing stack context) instead of GLOBAL_SCOPE_ID.
433 // Also note that 2.13.1 doesn't return $this in class context.
434 // (You can inspect $this in Expressions View. And once it is shown, 2.13.1 comes to return $this.)
435 Vector globalList = getVariables(DBGStackList[DBGStackList.length - 1], global_scope_id);
436 if (!globalList.isEmpty()) {
437 // remove unresolved '$this=?' variable
438 removeUnresolvedThisVar(globalList);
440 PHPVariable var = (PHPVariable) globalList.get(0);
441 var.setName(GlobalVariablesTitle);
442 var.setModifiable(false);
445 int scopeID = stack.getScopeID();
446 if (!globalList.isEmpty()
447 && ((DBGStackList.length == 1)
448 || (scopeID == PHPDBGBase.CURLOC_SCOPE_ID + 1))) {
449 // 'main()' stackframe
450 PHPVariable var = (PHPVariable) globalList.get(0);
451 PHPValue val = (PHPValue) var.getValue();
452 DBGVarList = val.getChildVariables();
455 } else if (scopeID == PHPDBGBase.CURLOC_SCOPE_ID) {
456 // current stackframe
457 DBGVarList = getVariables(stack, PHPDBGBase.CURLOC_SCOPE_ID);
460 // back-trace stackframe
461 //DBGVarList = getVariables(stack, scopeID);
462 //removeUnresolvedThisVar(DBGVarList);
463 // DBG 2.15.5 causes Application Error (on win32) in *some* cases.
467 if (DBGVarList.size() > 0) { // Did we get back variables?
468 PHPVariable var = (PHPVariable) DBGVarList.get(0); // Yes, then get the first PHPVariable
469 PHPValue val = (PHPValue) var.getValue(); // Get the value
471 if (var.getName().equals("")) { // Is the root node an empty node (usually it is)
472 DBGVarList = val.getChildVariables(); // Then remove the empty node.
473 // With removing the empty root node, it wouldn't be necessary to
474 // set the name to an empty string. So the code below is just for
475 // info or in case the users want to have the empty root node.
477 // The eclipse variable view cannot handle Variables which have an empty name
478 // when it comes to variable tree restore operation. Without a name, no restore!
479 //var.setName (" "); // Give a name to the variable root node. Even if it is only a space :-)
480 } // TO DO the best would be to remove the empty root node, but this would
481 // require a understanding and reworking of the PHPDBGEvalstring class.
484 if (!globalList.isEmpty()) {
485 DBGVarList.add(globalList.get(0));
488 return DBGVarList; // Return the variables as list
494 private Vector getVariables(PHPStackFrame stack, int scope_id) throws IOException {
495 PHPDBGPacket DBGPacket = new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
496 PHPDBGFrame DBGFrame1 = new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
499 DBGFrame1.addInt(scope_id);
501 DBGPacket.addFrame(DBGFrame1);
504 if (proxy.getSocket().isClosed()) {
507 DBGPacket.sendPacket(os);
512 PHPDBGEvalString evalStr = new PHPDBGEvalString(stack, evalRet);
513 return evalStr.getVariables();
517 * Remove unresolved $this variable
519 * DBG returns $this=? in function's or intermediate stackframes.
520 * (In current method's stackframe, DBG returns $this=classname)
524 private void removeUnresolvedThisVar(Vector varList) {
525 if (varList.size() > 0) {
526 PHPVariable var = (PHPVariable) varList.get(0);
527 PHPValue val = (PHPValue) var.getValue();
528 Vector workList = val.getChildVariables();
529 for (int i = 0; i < workList.size(); i++) {
530 PHPVariable workvar = (PHPVariable) workList.get(i);
531 if (workvar.getName().equals("$this")) {
532 String workval = ((PHPValue) workvar.getValue()).getValueString();
533 if (workval.equals("?") || workval.equals("NULL")) {
546 public void log(String logString) throws IOException, DebugException {
547 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
548 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_LOG);
549 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
552 DBGFrame1.addInt(rawCounter); // ilog
553 DBGFrame1.addInt(1); // type
554 DBGFrame1.addInt(0); // mod_no
555 DBGFrame1.addInt(0); // line_no
556 DBGFrame1.addInt(0); // imod_name
557 DBGFrame1.addInt(0); // ext_info
559 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
560 DBGFrame2.addInt(logString.length() + 1); // length of rawdata (+ null char)
561 DBGFrame2.addString(logString); // log string
562 DBGFrame2.addChar('\0'); // null char
564 // Add raw data first
565 DBGPacket.addFrame(DBGFrame2);
567 DBGPacket.addFrame(DBGFrame1);
569 if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication?
570 return; // No, then leave here
573 DBGPacket.sendPacket(os);
579 public synchronized PHPVariable[] evalBlock(PHPStackFrame stack, String evalString) throws IOException, DebugException {
580 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
581 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
582 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
585 DBGFrame1.addInt(rawCounter); // istr = raw data ID
586 //DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth
587 int scope_id = stack.getScopeID();
588 /* test code : unnecessary
589 if (DBGStackList.length == 1 || scope_id == (PHPDBGBase.CURLOC_SCOPE_ID + 1)) {
590 scope_id = PHPDBGBase.GLOBAL_SCOPE_ID;
593 DBGFrame1.addInt(scope_id);
595 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
596 DBGFrame2.addInt(evalString.length() + 1); // length of rawdata (+ null char)
597 DBGFrame2.addString(evalString); // eval block
598 DBGFrame2.addChar('\0'); // null char
600 // Add raw data first
601 DBGPacket.addFrame(DBGFrame2);
603 DBGPacket.addFrame(DBGFrame1);
605 if (proxy.getSocket().isClosed()) { // Do we have a socket for DBG communication?
606 return null; // No, then leave here
608 DBGPacket.sendPacket(os);
613 PHPDBGEvalString evalStr=new PHPDBGEvalString(stack, evalRet);
615 return evalStr.getVars();
619 * Read and process everthing we got from DBG
621 public void flushAllPackets () throws IOException {
622 while (readResponse() != 0);
626 * Get the modules name by its number
628 * @param modNo The number (id) of the module
629 * @return The name of the module
631 public String getModByNo (int modNo) {
635 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
636 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
638 if (dbg_mod.getNo () == modNo) { // Is the module from the array the module we want?
639 return dbg_mod.getName (); // Yes, return the name of the module
643 return ""; // If nothing was found return emtpy string
648 * @param modName The name of the module for which we want the ID
650 * - The ID of the module
651 * - -1 if nothing was found
653 private int getModByName (String modName) {
657 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
658 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
660 if (dbg_mod.getName ().equalsIgnoreCase (modName)) { // Is the module from the array the module we want?
661 return dbg_mod.getNo (); // Yes, return the name of the module
665 return -1; // If nothing was found return -1
669 * Return the string for the given frame number
671 * @param framesInfo The buffer which is to read
672 * @param frameNo The frame number
675 private String getRawFrameData (char[] framesInfo, int frameNo) {
676 int nextFrame = 0; // The current read position within the buffer
677 int[] dbg_frame = new int[2]; // The two frame header numbers
679 while (nextFrame < framesInfo.length) { // As long we have something within the buffer
680 dbg_frame[0] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame); // The frame type
681 dbg_frame[1] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The frame size
683 nextFrame += 8; // The current read position
685 if (dbg_frame[1] == 0) { // If frame size is 0
686 return ""; // return an emtpy string
689 switch (dbg_frame[0]) { // Switch for the frame type
690 case PHPDBGBase.FRAME_RAWDATA: // The only frame type we are interrested in
691 if (frameNo == PHPDBGBase.Char4ToInt (framesInfo, nextFrame)) { // Is it correct number of the frame
694 toRead = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The size of the string
696 if ((int) framesInfo[nextFrame + 8 + toRead - 1] == 0) { // Is there a string termination at the end?
697 return String.copyValueOf (framesInfo, nextFrame + 8, toRead - 1); // Then copy frame content to String without the \0 and return
700 return String.copyValueOf (framesInfo, nextFrame + 8, toRead); // Copy frame content to String and return
705 nextFrame += dbg_frame[1]; // Go for the next frame (add the length of the current one)
708 return ""; // We did not found any FRAM_RAWDATA, so return an emtpy strin
712 * Reset the availability flag for all stackframes in the list.
714 * @param list The list of old stackframes
716 private void resetAvailability (Vector list) {
719 for (i = 0; i < list.size (); i++) {
720 ((PHPStackFrame) list.get(i)).setAvailable (false); //
725 * Check whether the new stackframe is in the list of old stackframes.
726 * Test for identical stackframe (identical means same description and same line number).
728 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
729 * @param list The list of old stackframes
731 * - true if we have found the identical stackframe within the list
732 * - false if we did not find the identical stackframe within the list
734 private boolean isStackFrameInList (PHPStackFrame stackFrameNew, Vector list) {
736 PHPStackFrame stackFrameOld;
738 for (i = 0; i < list.size (); i++) {
739 stackFrameOld = (PHPStackFrame) list.get (i); //
741 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) &&
742 stackFrameNew.getLineNumber () == stackFrameOld.getLineNumber ()) { // Did we find the sent stackframe within the list of old stackframes?
743 stackFrameOld.setAvailable (true); // We found the new stackframe in the list of old stack frames
744 stackFrameOld.setIndex (stackFrameNew.getIndex ());
745 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
746 return true; // The stackframe was found in the list
754 * Check whether the new stackframe is in the list of old stackframes.
755 * Test for exact stackframe (exact means same description and same line number).
757 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
758 * @param list The list of old stackframes
760 * - true if we have exactly this stackframe within the list
761 * - false if we did not find the exact stackframe within the list
763 private void markIdenticalStackFrames (Vector oldList, Vector newList) {
765 PHPStackFrame stackFrameNew;
767 resetAvailability (oldList); // Reset the availability flag of the old stack frames
768 resetAvailability (newList); // Reset the availability flag of the old stack frames
770 for (i = 0; i < newList.size (); i++) { // For all stackList entries
771 stackFrameNew = (PHPStackFrame) newList.get (i);
773 if (isStackFrameInList (stackFrameNew, oldList)) { // Is this stackframe in the list
774 stackFrameNew.setAvailable (true); //
783 * The stackList contains the currently read stackframes which were sent
784 * from DBG. The DBG interface holds a list of the active stack frames.
785 * This method replicates the 'static' stackframe list with the DBG stackframe list
786 * Replication is done in the following way:
788 * <li> It looks for new stackframes within the DBG stackframe list and
789 * adds them to the 'static' list.
790 * <li> It looks for stackframes within the 'static' list, and removes them
791 * from the 'static' list in case they do not appear within the DBG list.
792 * <li> It looks for stackframes which are already existent and replicates the
793 * line number and the index number.
794 * <li> At the end, the 'static' stackframe list has to be sorted by the stackframes
798 * Removes the unused stackframes from the list, or adds stackframes which
799 * are not yet in the list.
804 private void updateStackFrameList (Vector stackList) {
807 PHPStackFrame stackFrameNew;
808 PHPStackFrame stackFrameOld;
809 PHPStackFrame[] newStackList;
811 markIdenticalStackFrames (stackListOld, stackList); // Check whether the newly send stack frames can be found in the list
812 // of old stack frames
814 for (i = 0; i < stackList.size (); i++) { // For all stackList entries
815 stackFrameNew = (PHPStackFrame) stackList.get(i);
817 for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list
818 stackFrameOld = (PHPStackFrame) stackListOld.get (n); //
820 if (stackFrameOld.isAvailable ()) { // If this stack frame was already found in the new list skip it
824 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) {// Did we find the sent stackframe within the list of old stackframes?
825 stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ());
826 stackFrameOld.setIndex (stackFrameNew.getIndex ());
827 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
829 stackFrameOld.setAvailable (true); // And mark this stack frame as available
830 stackFrameNew.setAvailable (true); // And mark this stack frame as available
832 break; // Yes, then break;
836 if (!stackFrameNew.isAvailable ()) { // Did not find the new stackframe within the list?
837 stackFrameNew.setAvailable (true); // Mark the stack frame as available and
838 stackListOld.add (stackFrameNew); // then add the new stackframe
842 // And now for removing unused stackframes from list
844 for (n = 0; n < stackListOld.size(); n++) {
845 stackFrameOld = (PHPStackFrame) stackListOld.get(n);
847 if (!stackFrameOld.isAvailable()) {
848 stackListOld.remove(n--);
852 Collections.sort (stackListOld); // Sort the 'static' stackframe list by the stackframe index numbers.
854 newStackList = new PHPStackFrame[stackListOld.size ()];
855 newStackList = (PHPStackFrame[]) stackListOld.toArray (newStackList);
856 DBGStackList = newStackList;
860 * Read the response from DBG and process the frame
863 * - The received command
864 * - or 0 if something was wrong
866 public int readResponse () throws IOException {
867 int bytesToRead = 0; // The number of byte to read for the current DBG block
868 int nextFrame = 0; // The current read position within entirePack
872 boolean errorStack = false;
873 char[] dbg_header_struct_read = new char[16]; // The buffer for the first 16 bytes of a block
874 int[] dbg_header_struct = new int[4]; // The first four numbers (long) of a block
875 int[] dbg_bpl_tmp = new int[10];
876 int[] dbg_frame = new int[2];
877 int[] dbg_eval_tmp = new int[3];
878 int[] dbg_src_tree_tmp = new int[4]; //
879 int[] dbg_error_tmp = new int[2];
880 Vector rawList = new Vector();
881 Vector stackList = new Vector(); // Intermediate stacklist which is build up in FRAME_STACK frame
887 while (readInput (dbg_header_struct_read, 16) != 0) { // Read 16 byte from input stream
888 dbg_header_struct[0] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 0); // Debug sync header
889 dbg_header_struct[1] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 4); // Command
890 dbg_header_struct[2] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 8); //
891 dbg_header_struct[3] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 12); // Bytes within this block
893 if (dbg_header_struct[0] != 0x5953) { // Check DBG sync bytes
894 return 0; // Wrong header
897 cmdReceived = dbg_header_struct[1]; // Get the command
898 setLastCmd (cmdReceived); // Store the info about the current command
899 bytesToRead = dbg_header_struct[3]; // Get the number of bytes to read for this block
901 //System.out.println("Response Received: " + cmdReceived);
902 char[] entirePack = new char[bytesToRead]; // Store the block data into buffer 'entirePack'
904 if (bytesToRead > 0) { // If there is something within the frame
905 if (readInput (entirePack, bytesToRead) < bytesToRead) { // Read the frame into the buffer
906 return 0; // We did not read enough bytes, error
910 nextFrame = 0; // Start with the first frame
912 while (nextFrame < bytesToRead) { // As long as we have something within this block
913 dbg_frame[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame); // The name of the frame
914 dbg_frame[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The size of the frame
915 nextFrame += 8; // The next read position
917 if (dbg_frame[1] == 0) { // Something within the frame?
918 return 0; // Nothing to read, error
921 switch (dbg_frame[0]) {
922 case PHPDBGBase.FRAME_STACK:
923 int[] dbg_stack_new = new int[4]; //
925 dbg_stack_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Source line number
926 dbg_stack_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Module number
927 dbg_stack_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // Scope id
928 dbg_stack_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // ID of description string
930 if ((dbg_stack_new[1] != 0) && !errorStack) {
931 PHPStackFrame newStack;
934 newStack = new PHPStackFrame (null, // The thread
935 getModByNo (dbg_stack_new[1]), // The name of the module (file)
936 dbg_stack_new[0], // The source line number
938 getRawFrameData (entirePack, // Get the string from this packet
939 dbg_stack_new[3]), // The frame ID for which we want the string
940 dbg_stack_new[1], // The module number
942 stackList.add (newStack);
948 case PHPDBGBase.FRAME_SOURCE: // Nothing to be done here
949 break; // TODO: what's with that frame? Something interesting
951 case PHPDBGBase.FRAME_SRC_TREE: //
952 dbg_src_tree_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // The parent module number
953 dbg_src_tree_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The parent line number (not used)
954 dbg_src_tree_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // The module number
955 dbg_src_tree_tmp[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // The filename number
957 if (getModByNo (dbg_src_tree_tmp[2]).equals ("")) {
960 fileName = new String (getRawFrameData (entirePack, dbg_src_tree_tmp[3])); // Get the filename
962 if (dbg_src_tree_tmp[2] != 0) { // If there is a module number
965 modNew = new PHPDBGMod (dbg_src_tree_tmp[2], fileName); // Create a module object
967 DBGMods.add (modNew); // And store it to array
972 case PHPDBGBase.FRAME_RAWDATA: // Nothing to be done here
973 break; // FRAME_RAWDATA are processed within getRawFrameData
975 case PHPDBGBase.FRAME_ERROR: // An error frame
976 errorStack = true; // Yes, we have an error stack
977 dbg_error_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Error type
978 dbg_error_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Error message ID
980 String error = "\n"; //
982 switch (dbg_error_tmp[0]) { // Switch on error type
983 case PHPDBGBase.E_ERROR: error += "[Error]"; break;
984 case PHPDBGBase.E_WARNING: error += "[Warning]"; break;
985 case PHPDBGBase.E_PARSE: error += "[Parse Error]"; break;
986 case PHPDBGBase.E_NOTICE: error += "[Notice]"; break;
987 case PHPDBGBase.E_CORE_ERROR: error += "[Core Error]"; break;
988 case PHPDBGBase.E_CORE_WARNING: error += "[Core Warning]"; break;
989 case PHPDBGBase.E_COMPILE_ERROR: error += "[Compile Error]"; break;
990 case PHPDBGBase.E_COMPILE_WARNING: error += "[Compile Warning]"; break;
991 case PHPDBGBase.E_USER_ERROR: error += "[User Error]"; break;
992 case PHPDBGBase.E_USER_WARNING: error += "[User Warning]"; break;
993 case PHPDBGBase.E_USER_NOTICE: error += "[User Notice]"; break;
994 default: error += "[Unexpected Error]"; break;
998 error += new String (getRawFrameData (entirePack, dbg_error_tmp[1])); // Add the error string for this error message ID
999 error += "\n"; // Append a CR
1001 PHPDebugCorePlugin.log (new DebugException (new Status (IStatus.WARNING,
1002 PHPDebugCorePlugin.PLUGIN_ID,
1006 // To print errors on the console, I must execute a code in the
1007 // php context, that write the stderr... I didn't found a better way
1008 // TODO: Find a better way????
1010 // String codeExec= "";
1011 // codeExec= "fwrite(fopen('php://stderr', 'w'),\\\"" + error + "\\\");";
1013 // evalBlock("eval(\"" + codeExec + "\");");
1014 // } catch (DebugException e) {
1015 // PHPDebugCorePlugin.log(e);
1018 if (!stopOnError) { // Is always false (Did not see where this is set to true!?)
1019 if (lastCommand.equals (PHPDBGBase.DBGA_CONTINUE)) { // If last command for PHP was a 'continue',
1020 continueExecution (); // send continue again
1021 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPINTO)) { // If last command for PHP was a 'step into',
1022 stepInto (); // send 'step into' again
1023 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOUT)) { // If last command for PHP was a 'step out',
1024 stepOut (); // send 'step out' again
1025 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOVER)) { // If last command for PHP was a 'step over',
1026 stepOver (); // send 'step over' again
1031 case PHPDBGBase.FRAME_EVAL:
1032 //String evalString;
1034 //evalString = new String ("");
1035 dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // istr
1036 dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // iresult
1037 dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // ierror
1039 evalRet = getRawFrameData (entirePack, dbg_eval_tmp[1]); //
1040 //evalString = getRawFrameData (entirePack, dbg_eval_tmp[0]); //
1043 case PHPDBGBase.FRAME_BPS: //
1046 case PHPDBGBase.FRAME_BPL:
1049 dbg_bpl_new = new int[10];
1050 dbg_bpl_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);
1051 dbg_bpl_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);
1052 dbg_bpl_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);
1053 dbg_bpl_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);
1054 dbg_bpl_new[4] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 16);
1055 dbg_bpl_new[5] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 20);
1056 dbg_bpl_new[6] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 24);
1057 dbg_bpl_new[7] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 28);
1058 dbg_bpl_new[8] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 32);
1059 dbg_bpl_new[9] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 36);
1061 // look if breakpoint already exists in vector
1062 for (i = 0; i < DBGBPList.size (); i++) {
1063 dbg_bpl_tmp = (int[]) DBGBPList.get (i);
1065 if (dbg_bpl_tmp[8] == dbg_bpl_new[8]) {
1066 DBGBPList.remove (i);
1072 // add breakpoint to vector
1073 DBGBPList.add (dbg_bpl_new);
1074 copyToLastBP (dbg_bpl_new);
1077 if (getModByNo (dbg_bpl_new[0]).equals ("")) {
1080 fileName = new String (getRawFrameData (entirePack, dbg_bpl_new[2]));
1082 if (dbg_bpl_new[0] != 0) {
1085 modNew = new PHPDBGMod (dbg_bpl_new[0], fileName);
1087 DBGMods.add (modNew);
1092 case PHPDBGBase.FRAME_VER:
1095 case PHPDBGBase.FRAME_SID:
1096 sid = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0);
1099 case PHPDBGBase.FRAME_SRCLINESINFO:
1102 case PHPDBGBase.FRAME_SRCCTXINFO:
1105 case PHPDBGBase.FRAME_LOG:
1108 case PHPDBGBase.FRAME_PROF:
1111 case PHPDBGBase.FRAME_PROF_C:
1114 case PHPDBGBase.FRAME_SET_OPT:
1118 nextFrame += dbg_frame[1]; // go to next frame
1121 // Now process command
1122 switch(cmdReceived) {
1123 case PHPDBGBase.DBGC_REPLY:
1126 case PHPDBGBase.DBGC_STARTUP:
1129 case PHPDBGBase.DBGC_END:
1130 sessionEnded = true;
1131 this.proxy.setTerminated();
1134 case PHPDBGBase.DBGC_BREAKPOINT:
1135 BPUnderHit = getBPUnderHit ();
1136 updateStackFrameList (stackList);
1139 case PHPDBGBase.DBGC_STEPINTO_DONE:
1140 case PHPDBGBase.DBGC_STEPOVER_DONE:
1141 case PHPDBGBase.DBGC_STEPOUT_DONE:
1142 case PHPDBGBase.DBGC_EMBEDDED_BREAK:
1143 case PHPDBGBase.DBGC_PAUSE:
1145 updateStackFrameList (stackList);
1148 case PHPDBGBase.DBGC_ERROR:
1150 updateStackFrameList (stackList);
1153 case PHPDBGBase.DBGC_LOG:
1156 case PHPDBGBase.DBGC_SID:
1161 return cmdReceived; // Return the command we received with this block
1168 public PHPStackFrame[] getStackList() {
1169 return DBGStackList;
1173 * Reads from input buffer (response sent from DBG) the given number of chars
1174 * into frame buffer.
1176 * @param buffer The frame buffer where to store the read data from DBG.
1177 * @param bytes The number of bytes (chars) which are to read from input stream.
1178 * @return The number of bytes actually read.
1180 private int readInput (char[] buffer, int bytes) throws IOException {
1181 int bytesRead = 0; // Reset the bytes read counter
1183 for (int i = 0; i < bytes; i++) { // For the number of bytes we should read
1184 if (in.ready ()) { // If input stream is ready for reading
1185 buffer[i] = (char) (in.read () & 0x00FF); // Read a char and store only the least significant 8-bits
1186 bytesRead++; // Increment the bytes read counter
1188 else { // Input stream is not ready
1189 break; // Break the loop
1193 return bytesRead; // Return the number of bytes actually read
1197 * PHPProxy could stop the waiting for a response with this method.
1200 public void setShouldStop () {
1201 this.shouldStop = true;
1205 * @param milliseconds The maximum time in milliseconds we wait for something
1206 * to be send from DBG.
1207 * @return - true if something was received from DBG
1208 * - false if nothing was send from DBG within the given time
1211 public boolean waitResponse (long milliseconds) throws IOException {
1214 timeout = System.currentTimeMillis () + milliseconds; // Calculate the system time till we wait.
1216 while (System.currentTimeMillis () < timeout) { // Is waiting time running out?
1217 if (in.ready () || shouldStop) { // No, so did we get something or should we stop now
1218 break; // Yes, break the waiting
1222 return in.ready (); // true if we got something from DBG