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.model.PHPDBGEvalString;
21 import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame;
22 import net.sourceforge.phpdt.internal.debug.core.model.PHPValue;
23 import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable;
25 import org.eclipse.core.runtime.IStatus;
26 import org.eclipse.core.runtime.Status;
27 import org.eclipse.debug.core.DebugException;
30 * The interface object are created by the proxy
33 public class PHPDBGInterface {
34 public boolean sessionEnded = false;
35 public int sessType = -1;
36 public int BPUnderHit = 0;
37 public String sessID = new String();
39 private int[] LastBPRead = new int[10];
40 private Vector DBGBPList = new Vector();
41 private Vector DBGVarList = new Vector();
42 private PHPStackFrame[] DBGStackList = new PHPStackFrame[0];
43 private Vector DBGMods = new Vector(); // The module names and their numbers
44 private Vector stackListOld = new Vector();
45 private BufferedReader in;
46 private OutputStream os; // The stream which goes to DBG
47 private boolean shouldStop = false;
48 private String evalRet = new String("");
49 private int rawCounter = 1000; // An rawData frame ID counter
50 private PHPDBGProxy proxy = null;
51 private int lastCmd = -1;
53 private boolean stopOnError = false;
54 private char[] lastCommand = new char[4];
56 private static final String GlobalVariablesTitle = PHPDebugCorePlugin
57 .getResourceString("VariablesView.GlobalVariables.title");
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.
64 public PHPDBGInterface (BufferedReader in, OutputStream os, PHPDBGProxy proxy) {
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 * @param hitCount The number of hit counts before suspend.
77 * @param condition The break condition
78 * @return Breakpoint ID ???.
80 public int addBreakpoint (String mod_name, int line, int hitCount, String condition) throws IOException {
81 return setBreakpoint (mod_name, condition, line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, hitCount, 0, 0, 0);
86 * @param mod_name The module (source file) to which we add the breakpoint.
87 * @param line The line where the breakpoint is set.
88 * @param bpNo The breakpoint ID ???.
90 public void removeBreakpoint (String mod_name, int line, int bpNo) throws IOException {
91 setBreakpoint (mod_name, "", line, PHPDBGBase.BPS_DISABLED, 0, 0, 0, bpNo, 0);
95 * Is this method used anywhere?
98 public void requestDBGVersion () throws IOException {
99 PHPDBGPacket DBGPacket; // A DBG message packet
100 PHPDBGFrame DBGFrame; // A frame within a DBG packet
102 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
103 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_VER); // We want the version of DBG
105 DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet
107 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
111 DBGPacket.sendPacket (os); // Send the request to DBG
115 * Called by the proxy
118 public void getSourceTree () throws IOException {
119 PHPDBGPacket DBGPacket; // A DBG message packet
120 PHPDBGFrame DBGFrame; // A frame within a DBG packet
122 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
123 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_SRC_TREE); // We want a source tree from DBG
125 DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet
127 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
131 DBGPacket.sendPacket (os); // Send the request to DBG
133 waitResponse (1000); // Wait for the DBG response (1 second)
134 flushAllPackets (); // Read and process the response from DBG
138 * Is this method called from anywhere?
140 * @param modName The modul (filename).
142 public void addDBGModName (String modName) throws IOException {
143 PHPDBGPacket DBGPacket; // A DBG message packet
144 PHPDBGFrame DBGFrame; // A frame within a DBG packet
146 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
147 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA); // We want Module name from DBG
149 rawCounter++; // Increment the rawData ID counter
150 DBGFrame.addInt (rawCounter); // FRAME_RAWDATA ID
151 DBGFrame.addInt (modName.length () + 1); // The length of rawdata string (incl. null char termination)
152 DBGFrame.addString (modName); // The file name (module name)
153 DBGFrame.addChar ('\0'); // Add the C-String null termination
155 DBGPacket.addFrame (DBGFrame);
157 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
161 DBGPacket.sendPacket (os);
165 * This method is called for adding or removing breakpoints.
167 * @param mod_name The module name (file name).
168 * @param condition Info about the condition when to break (not used at the moment).
169 * @param line The breakpoints line.
170 * @param state Info whether this breakpoint has to be dis- or enabled.
171 * @param istep Always 0.
172 * @param hitcount Always 0.
173 * @param skiphits Always 0.
174 * @param bpno The breakpoint ID.
175 * @param isunderhit ???
178 private int setBreakpoint (String mod_name, String condition, int line, int state, int istemp, int hitcount, int skiphits, int bpno, int isunderhit) throws IOException {
179 PHPDBGPacket DBGPacket;
180 PHPDBGFrame DBGFrame1;
181 PHPDBGFrame DBGFrame2;
182 PHPDBGFrame DBGFrame3;
185 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);
186 DBGFrame1 = new PHPDBGFrame (PHPDBGBase.FRAME_BPS);
187 DBGFrame2 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
188 DBGFrame3 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
190 modNo = getModByName (mod_name); // Get the module ID by name
192 if (modNo >= 0) { // Did we find a module ID for the module name?
193 DBGFrame1.addInt (modNo); // Add the module ID to frame 1
195 DBGFrame1.addInt (0); // mod number (0 use file name)
198 DBGFrame1.addInt (line); // line number
200 if (modNo >= 0) { // Did we find a module ID for the module name?
201 DBGFrame1.addInt (0); // use mod number
204 DBGFrame1.addInt (rawCounter); // ID of FRAME_RAWDATA to send file name
207 if (modNo < 0) { // Did we find a module ID for the module name?
208 DBGFrame2.addInt (rawCounter); // FRAME_RAWDATA ID
209 DBGFrame2.addInt (mod_name.length() + 1); // length of rawdata (+ null char)
210 DBGFrame2.addString (mod_name); // file name
211 DBGFrame2.addChar ('\0'); // null char
213 DBGPacket.addFrame (DBGFrame2); // First add file name data
216 DBGFrame1.addInt (state); // state BPS_*
217 DBGFrame1.addInt (istemp); // istemp
218 DBGFrame1.addInt (0); // hit count; this is not supported as one might think
219 DBGFrame1.addInt (hitcount); // skip hits is what we think is hit count.
221 if (!condition.equals ("")) { // Do we have a condition for breakpoint
222 rawCounter++; // Set to new ID
223 DBGFrame1.addInt (rawCounter); // ID of condition
225 DBGFrame3.addInt (rawCounter); // FRAME_RAWDATA ID
226 DBGFrame3.addInt (condition.length() + 1); // length of rawdata (+ null char)
227 DBGFrame3.addString (condition); // The break condition
228 DBGFrame3.addChar ('\0'); // null char
230 DBGPacket.addFrame (DBGFrame3); // First add break condition
233 DBGFrame1.addInt (0); // ID of condition is 0, because there is no condition
236 DBGFrame1.addInt (bpno); // breakpoint number
237 DBGFrame1.addInt (isunderhit); // is under hit
239 DBGPacket.addFrame (DBGFrame1); // Second add command data
241 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
245 DBGPacket.sendPacket (os); // Send the request to DBG
249 waitResponse (1000); // Wait for the DBG response (1 second)
250 flushAllPackets (); // Read and process the response from DBG
252 return LastBPRead[8]; // Return what ???
258 private void clearLastBP () {
261 for (i = 0; i < LastBPRead.length; i++) {
269 private void copyToLastBP (int[] BPBody) {
272 for (i = 0; i < LastBPRead.length; i++) {
273 LastBPRead[i] = BPBody[i];
280 public void continueExecution () throws IOException {
281 PHPDBGPacket DBGPacket;
284 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_CONTINUE);
286 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 Vector globalList = getVariables(DBGStackList[DBGStackList.length - 1], PHPDBGBase.GLOBAL_SCOPE_ID);
431 if (!globalList.isEmpty()) {
432 // remove unresolved '$this=?' variable
433 removeUnresolvedThisVar(globalList);
435 PHPVariable var = (PHPVariable) globalList.get(0);
436 var.setName(GlobalVariablesTitle);
437 var.setModifiable(false);
440 int scopeID = stack.getScopeID();
441 if (!globalList.isEmpty()
442 && ((DBGStackList.length == 1)
443 || (scopeID == PHPDBGBase.CURLOC_SCOPE_ID + 1))) {
444 // 'main()' stackframe
445 PHPVariable var = (PHPVariable) globalList.get(0);
446 PHPValue val = (PHPValue) var.getValue();
447 DBGVarList = val.getChildVariables();
450 } else if (scopeID == PHPDBGBase.CURLOC_SCOPE_ID) {
451 // current stackframe
452 DBGVarList = getVariables(stack, PHPDBGBase.CURLOC_SCOPE_ID);
455 // back-trace stackframe
456 //DBGVarList = getVariables(stack, scopeID);
457 //removeUnresolvedThisVar(DBGVarList);
458 // DBG 2.15.5 causes Application Error (on win32) in *some* cases.
462 if (DBGVarList.size() > 0) { // Did we get back variables?
463 PHPVariable var = (PHPVariable) DBGVarList.get(0); // Yes, then get the first PHPVariable
464 PHPValue val = (PHPValue) var.getValue(); // Get the value
466 if (var.getName().equals("")) { // Is the root node an empty node (usually it is)
467 DBGVarList = val.getChildVariables(); // Then remove the empty node.
468 // With removing the empty root node, it wouldn't be necessary to
469 // set the name to an empty string. So the code below is just for
470 // info or in case the users want to have the empty root node.
472 // The eclipse variable view cannot handle Variables which have an empty name
473 // when it comes to variable tree restore operation. Without a name, no restore!
474 //var.setName (" "); // Give a name to the variable root node. Even if it is only a space :-)
475 } // TO DO the best would be to remove the empty root node, but this would
476 // require a understanding and reworking of the PHPDBGEvalstring class.
479 if (!globalList.isEmpty()) {
480 DBGVarList.add(globalList.get(0));
483 return DBGVarList; // Return the variables as list
489 private Vector getVariables(PHPStackFrame stack, int scope_id) throws IOException {
490 PHPDBGPacket DBGPacket = new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
491 PHPDBGFrame DBGFrame1 = new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
494 DBGFrame1.addInt(scope_id);
496 DBGPacket.addFrame(DBGFrame1);
499 if (proxy.getSocket().isClosed()) {
502 DBGPacket.sendPacket(os);
507 PHPDBGEvalString evalStr = new PHPDBGEvalString(stack, evalRet);
508 return evalStr.getVariables();
512 * Remove unresolved $this variable
514 * DBG returns $this=? in function's or intermediate stackframes.
515 * (In current method's stackframe, DBG returns $this=classname)
519 private void removeUnresolvedThisVar(Vector varList) {
520 if (varList.size() > 0) {
521 PHPVariable var = (PHPVariable) varList.get(0);
522 PHPValue val = (PHPValue) var.getValue();
523 Vector workList = val.getChildVariables();
524 for (int i = 0; i < workList.size(); i++) {
525 PHPVariable workvar = (PHPVariable) workList.get(i);
526 if (workvar.getName().equals("$this")) {
527 String workval = ((PHPValue) workvar.getValue()).getValueString();
528 if (workval.equals("?") || workval.equals("NULL")) {
541 public void log(String logString) throws IOException, DebugException {
542 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
543 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_LOG);
544 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
547 DBGFrame1.addInt(rawCounter); // ilog
548 DBGFrame1.addInt(1); // type
549 DBGFrame1.addInt(0); // mod_no
550 DBGFrame1.addInt(0); // line_no
551 DBGFrame1.addInt(0); // imod_name
552 DBGFrame1.addInt(0); // ext_info
554 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
555 DBGFrame2.addInt(logString.length() + 1); // length of rawdata (+ null char)
556 DBGFrame2.addString(logString); // log string
557 DBGFrame2.addChar('\0'); // null char
559 // Add raw data first
560 DBGPacket.addFrame(DBGFrame2);
562 DBGPacket.addFrame(DBGFrame1);
564 if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication?
565 return; // No, then leave here
568 DBGPacket.sendPacket(os);
574 public synchronized PHPVariable[] evalBlock(PHPStackFrame stack, String evalString) throws IOException, DebugException {
575 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
576 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
577 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
580 DBGFrame1.addInt(rawCounter); // istr = raw data ID
581 //DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth
582 int scope_id = stack.getScopeID();
583 /* test code : unnecessary
584 if (DBGStackList.length == 1 || scope_id == (PHPDBGBase.CURLOC_SCOPE_ID + 1)) {
585 scope_id = PHPDBGBase.GLOBAL_SCOPE_ID;
588 DBGFrame1.addInt(scope_id);
590 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
591 DBGFrame2.addInt(evalString.length() + 1); // length of rawdata (+ null char)
592 DBGFrame2.addString(evalString); // eval block
593 DBGFrame2.addChar('\0'); // null char
595 // Add raw data first
596 DBGPacket.addFrame(DBGFrame2);
598 DBGPacket.addFrame(DBGFrame1);
600 if (proxy.getSocket().isClosed()) { // Do we have a socket for DBG communication?
601 return null; // No, then leave here
603 DBGPacket.sendPacket(os);
608 PHPDBGEvalString evalStr=new PHPDBGEvalString(stack, evalRet);
610 return evalStr.getVars();
614 * Read and process everthing we got from DBG
616 public void flushAllPackets () throws IOException {
617 while (readResponse() != 0);
621 * Get the modules name by its number
623 * @param modNo The number (id) of the module
624 * @return The name of the module
626 public String getModByNo (int modNo) {
630 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
631 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
633 if (dbg_mod.getNo () == modNo) { // Is the module from the array the module we want?
634 return dbg_mod.getName (); // Yes, return the name of the module
638 return ""; // If nothing was found return emtpy string
643 * @param modName The name of the module for which we want the ID
645 * - The ID of the module
646 * - -1 if nothing was found
648 private int getModByName (String modName) {
652 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
653 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
655 if (dbg_mod.getName ().equalsIgnoreCase (modName)) { // Is the module from the array the module we want?
656 return dbg_mod.getNo (); // Yes, return the name of the module
660 return -1; // If nothing was found return -1
664 * Return the string for the given frame number
666 * @param framesInfo The buffer which is to read
667 * @param frameNo The frame number
670 private String getRawFrameData (char[] framesInfo, int frameNo) {
671 int nextFrame = 0; // The current read position within the buffer
672 int[] dbg_frame = new int[2]; // The two frame header numbers
674 while (nextFrame < framesInfo.length) { // As long we have something within the buffer
675 dbg_frame[0] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame); // The frame type
676 dbg_frame[1] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The frame size
678 nextFrame += 8; // The current read position
680 if (dbg_frame[1] == 0) { // If frame size is 0
681 return ""; // return an emtpy string
684 switch (dbg_frame[0]) { // Switch for the frame type
685 case PHPDBGBase.FRAME_RAWDATA: // The only frame type we are interrested in
686 if (frameNo == PHPDBGBase.Char4ToInt (framesInfo, nextFrame)) { // Is it correct number of the frame
689 toRead = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The size of the string
691 if ((int) framesInfo[nextFrame + 8 + toRead - 1] == 0) { // Is there a string termination at the end?
692 return String.copyValueOf (framesInfo, nextFrame + 8, toRead - 1); // Then copy frame content to String without the \0 and return
695 return String.copyValueOf (framesInfo, nextFrame + 8, toRead); // Copy frame content to String and return
700 nextFrame += dbg_frame[1]; // Go for the next frame (add the length of the current one)
703 return ""; // We did not found any FRAM_RAWDATA, so return an emtpy strin
707 * Reset the availability flag for all stackframes in the list.
709 * @param list The list of old stackframes
711 private void resetAvailability (Vector list) {
714 for (i = 0; i < list.size (); i++) {
715 ((PHPStackFrame) list.get(i)).setAvailable (false); //
720 * Check whether the new stackframe is in the list of old stackframes.
721 * Test for identical stackframe (identical means same description and same line number).
723 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
724 * @param list The list of old stackframes
726 * - true if we have found the identical stackframe within the list
727 * - false if we did not find the identical stackframe within the list
729 private boolean isStackFrameInList (PHPStackFrame stackFrameNew, Vector list) {
731 PHPStackFrame stackFrameOld;
733 for (i = 0; i < list.size (); i++) {
734 stackFrameOld = (PHPStackFrame) list.get (i); //
736 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) &&
737 stackFrameNew.getLineNumber () == stackFrameOld.getLineNumber ()) { // Did we find the sent stackframe within the list of old stackframes?
738 stackFrameOld.setAvailable (true); // We found the new stackframe in the list of old stack frames
739 stackFrameOld.setIndex (stackFrameNew.getIndex ());
740 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
741 return true; // The stackframe was found in the list
749 * Check whether the new stackframe is in the list of old stackframes.
750 * Test for exact stackframe (exact means same description and same line number).
752 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
753 * @param list The list of old stackframes
755 * - true if we have exactly this stackframe within the list
756 * - false if we did not find the exact stackframe within the list
758 private void markIdenticalStackFrames (Vector oldList, Vector newList) {
760 PHPStackFrame stackFrameNew;
762 resetAvailability (oldList); // Reset the availability flag of the old stack frames
763 resetAvailability (newList); // Reset the availability flag of the old stack frames
765 for (i = 0; i < newList.size (); i++) { // For all stackList entries
766 stackFrameNew = (PHPStackFrame) newList.get (i);
768 if (isStackFrameInList (stackFrameNew, oldList)) { // Is this stackframe in the list
769 stackFrameNew.setAvailable (true); //
778 * The stackList contains the currently read stackframes which were sent
779 * from DBG. The DBG interface holds a list of the active stack frames.
780 * This method replicates the 'static' stackframe list with the DBG stackframe list
781 * Replication is done in the following way:
783 * <li> It looks for new stackframes within the DBG stackframe list and
784 * adds them to the 'static' list.
785 * <li> It looks for stackframes within the 'static' list, and removes them
786 * from the 'static' list in case they do not appear within the DBG list.
787 * <li> It looks for stackframes which are already existent and replicates the
788 * line number and the index number.
789 * <li> At the end, the 'static' stackframe list has to be sorted by the stackframes
793 * Removes the unused stackframes from the list, or adds stackframes which
794 * are not yet in the list.
799 private void updateStackFrameList (Vector stackList) {
802 PHPStackFrame stackFrameNew;
803 PHPStackFrame stackFrameOld;
804 PHPStackFrame[] newStackList;
806 markIdenticalStackFrames (stackListOld, stackList); // Check whether the newly send stack frames can be found in the list
807 // of old stack frames
809 for (i = 0; i < stackList.size (); i++) { // For all stackList entries
810 stackFrameNew = (PHPStackFrame) stackList.get(i);
812 for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list
813 stackFrameOld = (PHPStackFrame) stackListOld.get (n); //
815 if (stackFrameOld.isAvailable ()) { // If this stack frame was already found in the new list skip it
819 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) {// Did we find the sent stackframe within the list of old stackframes?
820 stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ());
821 stackFrameOld.setIndex (stackFrameNew.getIndex ());
822 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
824 stackFrameOld.setAvailable (true); // And mark this stack frame as available
825 stackFrameNew.setAvailable (true); // And mark this stack frame as available
827 break; // Yes, then break;
831 if (!stackFrameNew.isAvailable ()) { // Did not find the new stackframe within the list?
832 stackFrameNew.setAvailable (true); // Mark the stack frame as available and
833 stackListOld.add (stackFrameNew); // then add the new stackframe
837 // And now for removing unused stackframes from list
839 for (n = 0; n < stackListOld.size(); n++) {
840 stackFrameOld = (PHPStackFrame) stackListOld.get(n);
842 if (!stackFrameOld.isAvailable()) {
843 stackListOld.remove(n--);
847 Collections.sort (stackListOld); // Sort the 'static' stackframe list by the stackframe index numbers.
849 newStackList = new PHPStackFrame[stackListOld.size ()];
850 newStackList = (PHPStackFrame[]) stackListOld.toArray (newStackList);
851 DBGStackList = newStackList;
855 * Read the response from DBG and process the frame
858 * - The received command
859 * - or 0 if something was wrong
861 public int readResponse () throws IOException {
862 int bytesToRead = 0; // The number of byte to read for the current DBG block
863 int nextFrame = 0; // The current read position within entirePack
867 boolean errorStack = false;
868 char[] dbg_header_struct_read = new char[16]; // The buffer for the first 16 bytes of a block
869 int[] dbg_header_struct = new int[4]; // The first four numbers (long) of a block
870 int[] dbg_bpl_tmp = new int[10];
871 int[] dbg_frame = new int[2];
872 int[] dbg_eval_tmp = new int[3];
873 int[] dbg_src_tree_tmp = new int[4]; //
874 int[] dbg_error_tmp = new int[2];
875 Vector rawList = new Vector();
876 Vector stackList = new Vector(); // Intermediate stacklist which is build up in FRAME_STACK frame
882 while (readInput (dbg_header_struct_read, 16) != 0) { // Read 16 byte from input stream
883 dbg_header_struct[0] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 0); // Debug sync header
884 dbg_header_struct[1] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 4); // Command
885 dbg_header_struct[2] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 8); //
886 dbg_header_struct[3] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 12); // Bytes within this block
888 if (dbg_header_struct[0] != 0x5953) { // Check DBG sync bytes
889 return 0; // Wrong header
892 cmdReceived = dbg_header_struct[1]; // Get the command
893 setLastCmd (cmdReceived); // Store the info about the current command
894 bytesToRead = dbg_header_struct[3]; // Get the number of bytes to read for this block
896 //System.out.println("Response Received: " + cmdReceived);
897 char[] entirePack = new char[bytesToRead]; // Store the block data into buffer 'entirePack'
899 if (bytesToRead > 0) { // If there is something within the frame
900 if (readInput (entirePack, bytesToRead) < bytesToRead) { // Read the frame into the buffer
901 return 0; // We did not read enough bytes, error
905 nextFrame = 0; // Start with the first frame
907 while (nextFrame < bytesToRead) { // As long as we have something within this block
908 dbg_frame[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame); // The name of the frame
909 dbg_frame[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The size of the frame
910 nextFrame += 8; // The next read position
912 if (dbg_frame[1] == 0) { // Something within the frame?
913 return 0; // Nothing to read, error
916 switch (dbg_frame[0]) {
917 case PHPDBGBase.FRAME_STACK:
918 int[] dbg_stack_new = new int[4]; //
920 dbg_stack_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Source line number
921 dbg_stack_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Module number
922 dbg_stack_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // Scope id
923 dbg_stack_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // ID of description string
925 if ((dbg_stack_new[1] != 0) && !errorStack) {
926 PHPStackFrame newStack;
929 newStack = new PHPStackFrame (null, // The thread
930 getModByNo (dbg_stack_new[1]), // The name of the module (file)
931 dbg_stack_new[0], // The source line number
933 getRawFrameData (entirePack, // Get the string from this packet
934 dbg_stack_new[3]), // The frame ID for which we want the string
935 dbg_stack_new[1], // The module number
937 stackList.add (newStack);
943 case PHPDBGBase.FRAME_SOURCE: // Nothing to be done here
944 break; // TODO: what's with that frame? Something interesting
946 case PHPDBGBase.FRAME_SRC_TREE: //
947 dbg_src_tree_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // The parent module number
948 dbg_src_tree_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The parent line number (not used)
949 dbg_src_tree_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // The module number
950 dbg_src_tree_tmp[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // The filename number
952 if (getModByNo (dbg_src_tree_tmp[2]).equals ("")) {
955 fileName = new String (getRawFrameData (entirePack, dbg_src_tree_tmp[3])); // Get the filename
957 if (dbg_src_tree_tmp[2] != 0) { // If there is a module number
960 modNew = new PHPDBGMod (dbg_src_tree_tmp[2], fileName); // Create a module object
962 DBGMods.add (modNew); // And store it to array
967 case PHPDBGBase.FRAME_RAWDATA: // Nothing to be done here
968 break; // FRAME_RAWDATA are processed within getRawFrameData
970 case PHPDBGBase.FRAME_ERROR: // An error frame
971 errorStack = true; // Yes, we have an error stack
972 dbg_error_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Error type
973 dbg_error_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Error message ID
975 String error = "\n"; //
977 switch (dbg_error_tmp[0]) { // Switch on error type
978 case PHPDBGBase.E_ERROR: error += "[Error]"; break;
979 case PHPDBGBase.E_WARNING: error += "[Warning]"; break;
980 case PHPDBGBase.E_PARSE: error += "[Parse Error]"; break;
981 case PHPDBGBase.E_NOTICE: error += "[Notice]"; break;
982 case PHPDBGBase.E_CORE_ERROR: error += "[Core Error]"; break;
983 case PHPDBGBase.E_CORE_WARNING: error += "[Core Warning]"; break;
984 case PHPDBGBase.E_COMPILE_ERROR: error += "[Compile Error]"; break;
985 case PHPDBGBase.E_COMPILE_WARNING: error += "[Compile Warning]"; break;
986 case PHPDBGBase.E_USER_ERROR: error += "[User Error]"; break;
987 case PHPDBGBase.E_USER_WARNING: error += "[User Warning]"; break;
988 case PHPDBGBase.E_USER_NOTICE: error += "[User Notice]"; break;
989 default: error += "[Unexpected Error]"; break;
993 error += new String (getRawFrameData (entirePack, dbg_error_tmp[1])); // Add the error string for this error message ID
994 error += "\n"; // Append a CR
996 PHPDebugCorePlugin.log (new DebugException (new Status (IStatus.WARNING,
997 PHPDebugCorePlugin.PLUGIN_ID,
1001 // To print errors on the console, I must execute a code in the
1002 // php context, that write the stderr... I didn't found a better way
1003 // TODO: Find a better way????
1005 // String codeExec= "";
1006 // codeExec= "fwrite(fopen('php://stderr', 'w'),\\\"" + error + "\\\");";
1008 // evalBlock("eval(\"" + codeExec + "\");");
1009 // } catch (DebugException e) {
1010 // PHPDebugCorePlugin.log(e);
1013 if (!stopOnError) { // Is always false (Did not see where this is set to true!?)
1014 if (lastCommand.equals (PHPDBGBase.DBGA_CONTINUE)) { // If last command for PHP was a 'continue',
1015 continueExecution (); // send continue again
1016 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPINTO)) { // If last command for PHP was a 'step into',
1017 stepInto (); // send 'step into' again
1018 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOUT)) { // If last command for PHP was a 'step out',
1019 stepOut (); // send 'step out' again
1020 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOVER)) { // If last command for PHP was a 'step over',
1021 stepOver (); // send 'step over' again
1026 case PHPDBGBase.FRAME_EVAL:
1027 //String evalString;
1029 //evalString = new String ("");
1030 dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // istr
1031 dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // iresult
1032 dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // ierror
1034 evalRet = getRawFrameData (entirePack, dbg_eval_tmp[1]); //
1035 //evalString = getRawFrameData (entirePack, dbg_eval_tmp[0]); //
1038 case PHPDBGBase.FRAME_BPS: //
1041 case PHPDBGBase.FRAME_BPL:
1044 dbg_bpl_new = new int[10];
1045 dbg_bpl_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);
1046 dbg_bpl_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);
1047 dbg_bpl_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);
1048 dbg_bpl_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);
1049 dbg_bpl_new[4] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 16);
1050 dbg_bpl_new[5] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 20);
1051 dbg_bpl_new[6] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 24);
1052 dbg_bpl_new[7] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 28);
1053 dbg_bpl_new[8] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 32);
1054 dbg_bpl_new[9] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 36);
1056 // look if breakpoint already exists in vector
1057 for (i = 0; i < DBGBPList.size (); i++) {
1058 dbg_bpl_tmp = (int[]) DBGBPList.get (i);
1060 if (dbg_bpl_tmp[8] == dbg_bpl_new[8]) {
1061 DBGBPList.remove (i);
1067 // add breakpoint to vector
1068 DBGBPList.add (dbg_bpl_new);
1069 copyToLastBP (dbg_bpl_new);
1072 if (getModByNo (dbg_bpl_new[0]).equals ("")) {
1075 fileName = new String (getRawFrameData (entirePack, dbg_bpl_new[2]));
1077 if (dbg_bpl_new[0] != 0) {
1080 modNew = new PHPDBGMod (dbg_bpl_new[0], fileName);
1082 DBGMods.add (modNew);
1087 case PHPDBGBase.FRAME_VER:
1090 case PHPDBGBase.FRAME_SID:
1091 sid = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0);
1094 case PHPDBGBase.FRAME_SRCLINESINFO:
1097 case PHPDBGBase.FRAME_SRCCTXINFO:
1100 case PHPDBGBase.FRAME_LOG:
1103 case PHPDBGBase.FRAME_PROF:
1106 case PHPDBGBase.FRAME_PROF_C:
1109 case PHPDBGBase.FRAME_SET_OPT:
1113 nextFrame += dbg_frame[1]; // go to next frame
1116 // Now process command
1117 switch(cmdReceived) {
1118 case PHPDBGBase.DBGC_REPLY:
1121 case PHPDBGBase.DBGC_STARTUP:
1124 case PHPDBGBase.DBGC_END:
1125 sessionEnded = true;
1126 this.proxy.setTerminated();
1129 case PHPDBGBase.DBGC_BREAKPOINT:
1130 BPUnderHit = getBPUnderHit ();
1131 updateStackFrameList (stackList);
1134 case PHPDBGBase.DBGC_STEPINTO_DONE:
1135 case PHPDBGBase.DBGC_STEPOVER_DONE:
1136 case PHPDBGBase.DBGC_STEPOUT_DONE:
1137 case PHPDBGBase.DBGC_EMBEDDED_BREAK:
1138 case PHPDBGBase.DBGC_PAUSE:
1140 updateStackFrameList (stackList);
1143 case PHPDBGBase.DBGC_ERROR:
1145 updateStackFrameList (stackList);
1148 case PHPDBGBase.DBGC_LOG:
1151 case PHPDBGBase.DBGC_SID:
1156 return cmdReceived; // Return the command we received with this block
1163 public PHPStackFrame[] getStackList() {
1164 return DBGStackList;
1168 * Reads from input buffer (response sent from DBG) the given number of chars
1169 * into frame buffer.
1171 * @param buffer The frame buffer where to store the read data from DBG.
1172 * @param bytes The number of bytes (chars) which are to read from input stream.
1173 * @return The number of bytes actually read.
1175 private int readInput (char[] buffer, int bytes) throws IOException {
1176 int bytesRead = 0; // Reset the bytes read counter
1178 for (int i = 0; i < bytes; i++) { // For the number of bytes we should read
1179 if (in.ready ()) { // If input stream is ready for reading
1180 buffer[i] = (char) (in.read () & 0x00FF); // Read a char and store only the least significant 8-bits
1181 bytesRead++; // Increment the bytes read counter
1183 else { // Input stream is not ready
1184 break; // Break the loop
1188 return bytesRead; // Return the number of bytes actually read
1192 * PHPProxy could stop the waiting for a response with this method.
1195 public void setShouldStop () {
1196 this.shouldStop = true;
1200 * @param milliseconds The maximum time in milliseconds we wait for something
1201 * to be send from DBG.
1202 * @return - true if something was received from DBG
1203 * - false if nothing was send from DBG within the given time
1206 public boolean waitResponse (long milliseconds) throws IOException {
1209 timeout = System.currentTimeMillis () + milliseconds; // Calculate the system time till we wait.
1211 while (System.currentTimeMillis () < timeout) { // Is waiting time running out?
1212 if (in.ready () || shouldStop) { // No, so did we get something or should we stop now
1213 break; // Yes, break the waiting
1217 return in.ready (); // true if we got something from DBG