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 PHPDBGPacket DBGPacket;
425 PHPDBGFrame DBGFrame1;
426 PHPDBGEvalString evalStr;
428 // get global variables (and assign them to 'main()' stackframe)
429 Vector globalList = new Vector();
430 globalList = getVariables(DBGStackList[DBGStackList.length - 1], PHPDBGBase.GLOBAL_SCOPE_ID);
431 if (!globalList.isEmpty()) {
432 // remove unexpected '$this=?' variable
433 PHPVariable var = (PHPVariable) globalList.get(0);
434 PHPValue val = (PHPValue) var.getValue();
435 Vector workList = val.getChildVariables();
436 for (int i = 0; i < workList.size(); i++) {
437 if (((PHPVariable) workList.get(i)).getName().equals("$this")) {
442 var.setName(GlobalVariablesTitle);
443 var.setModifiable(false);
446 int scopeID = stack.getScopeID();
447 if (!globalList.isEmpty()
448 && ((DBGStackList.length == 1)
449 || (scopeID == PHPDBGBase.CURLOC_SCOPE_ID + 1))) {
450 // 'main()' stackframe
451 PHPVariable var = (PHPVariable) globalList.get(0);
452 PHPValue val = (PHPValue) var.getValue();
453 DBGVarList = val.getChildVariables();
456 } else if (scopeID == PHPDBGBase.CURLOC_SCOPE_ID) {
457 // current stackframe
458 DBGVarList = getVariables(stack, PHPDBGBase.CURLOC_SCOPE_ID);
461 // back-trace stackframe
462 DBGVarList = getVariables(stack, scopeID);
463 // DBG 2.15.5 causes Application Error (on win32) in some cases
464 //DBGVarList.clear();
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 } // TODO 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
493 * @throws IOException
495 private Vector getVariables(PHPStackFrame stack, int scope_id) throws IOException {
496 PHPDBGPacket DBGPacket = new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
497 PHPDBGFrame DBGFrame1 = new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
500 DBGFrame1.addInt(scope_id);
502 DBGPacket.addFrame(DBGFrame1);
505 if (proxy.getSocket().isClosed()) {
508 DBGPacket.sendPacket(os);
512 PHPDBGEvalString evalStr = new PHPDBGEvalString(stack, evalRet);
513 return evalStr.getVariables();
520 public void log(String logString) throws IOException, DebugException {
521 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
522 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_LOG);
523 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
526 DBGFrame1.addInt(rawCounter); // ilog
527 DBGFrame1.addInt(1); // type
528 DBGFrame1.addInt(0); // mod_no
529 DBGFrame1.addInt(0); // line_no
530 DBGFrame1.addInt(0); // imod_name
531 DBGFrame1.addInt(0); // ext_info
533 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
534 DBGFrame2.addInt(logString.length() + 1); // length of rawdata (+ null char)
535 DBGFrame2.addString(logString); // log string
536 DBGFrame2.addChar('\0'); // null char
538 // Add raw data first
539 DBGPacket.addFrame(DBGFrame2);
541 DBGPacket.addFrame(DBGFrame1);
543 if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication?
544 return; // No, then leave here
547 DBGPacket.sendPacket(os);
553 public synchronized PHPVariable[] evalBlock(PHPStackFrame stack, String evalString) throws IOException, DebugException {
554 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
555 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
556 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
559 DBGFrame1.addInt(rawCounter); // istr = raw data ID
560 //DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth
561 int scope_id = stack.getScopeID();
562 if (DBGStackList.length == 1 || scope_id == PHPDBGBase.CURLOC_SCOPE_ID + 1) {
563 scope_id = PHPDBGBase.GLOBAL_SCOPE_ID;
565 DBGFrame1.addInt(scope_id);
567 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
568 DBGFrame2.addInt(evalString.length() + 1); // length of rawdata (+ null char)
569 DBGFrame2.addString(evalString); // eval block
570 DBGFrame2.addChar('\0'); // null char
572 // Add raw data first
573 DBGPacket.addFrame(DBGFrame2);
575 DBGPacket.addFrame(DBGFrame1);
577 if (proxy.getSocket().isClosed()) { // Do we have a socket for DBG communication?
578 return null; // No, then leave here
580 DBGPacket.sendPacket(os);
585 PHPDBGEvalString evalStr=new PHPDBGEvalString(stack,evalRet);
587 return evalStr.getVars();
591 * Read and process everthing we got from DBG
593 public void flushAllPackets () throws IOException {
594 while (readResponse() != 0);
598 * Get the modules name by its number
600 * @param modNo The number (id) of the module
601 * @return The name of the module
603 public String getModByNo (int modNo) {
607 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
608 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
610 if (dbg_mod.getNo () == modNo) { // Is the module from the array the module we want?
611 return dbg_mod.getName (); // Yes, return the name of the module
615 return ""; // If nothing was found return emtpy string
620 * @param modName The name of the module for which we want the ID
622 * - The ID of the module
623 * - -1 if nothing was found
625 private int getModByName (String modName) {
629 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
630 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
632 if (dbg_mod.getName ().equalsIgnoreCase (modName)) { // Is the module from the array the module we want?
633 return dbg_mod.getNo (); // Yes, return the name of the module
637 return -1; // If nothing was found return -1
641 * Return the string for the given frame number
643 * @param framesInfo The buffer which is to read
644 * @param frameNo The frame number
647 private String getRawFrameData (char[] framesInfo, int frameNo) {
648 int nextFrame = 0; // The current read position within the buffer
649 int[] dbg_frame = new int[2]; // The two frame header numbers
651 while (nextFrame < framesInfo.length) { // As long we have something within the buffer
652 dbg_frame[0] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame); // The frame type
653 dbg_frame[1] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The frame size
655 nextFrame += 8; // The current read position
657 if (dbg_frame[1] == 0) { // If frame size is 0
658 return ""; // return an emtpy string
661 switch (dbg_frame[0]) { // Switch for the frame type
662 case PHPDBGBase.FRAME_RAWDATA: // The only frame type we are interrested in
663 if (frameNo == PHPDBGBase.Char4ToInt (framesInfo, nextFrame)) { // Is it correct number of the frame
666 toRead = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The size of the string
668 if ((int) framesInfo[nextFrame + 8 + toRead - 1] == 0) { // Is there a string termination at the end?
669 return String.copyValueOf (framesInfo, nextFrame + 8, toRead - 1); // Then copy frame content to String without the \0 and return
672 return String.copyValueOf (framesInfo, nextFrame + 8, toRead); // Copy frame content to String and return
677 nextFrame += dbg_frame[1]; // Go for the next frame (add the length of the current one)
680 return ""; // We did not found any FRAM_RAWDATA, so return an emtpy strin
684 * Reset the availability flag for all stackframes in the list.
686 * @param list The list of old stackframes
688 private void resetAvailability (Vector list) {
691 for (i = 0; i < list.size (); i++) {
692 ((PHPStackFrame) list.get(i)).setAvailable (false); //
697 * Check whether the new stackframe is in the list of old stackframes.
698 * Test for identical stackframe (identical means same description and same line number).
700 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
701 * @param list The list of old stackframes
703 * - true if we have found the identical stackframe within the list
704 * - false if we did not find the identical stackframe within the list
706 private boolean isStackFrameInList (PHPStackFrame stackFrameNew, Vector list) {
708 PHPStackFrame stackFrameOld;
710 for (i = 0; i < list.size (); i++) {
711 stackFrameOld = (PHPStackFrame) list.get (i); //
713 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) &&
714 stackFrameNew.getLineNumber () == stackFrameOld.getLineNumber ()) { // Did we find the sent stackframe within the list of old stackframes?
715 stackFrameOld.setAvailable (true); // We found the new stackframe in the list of old stack frames
716 stackFrameOld.setIndex (stackFrameNew.getIndex ());
717 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
718 return true; // The stackframe was found in the list
726 * Check whether the new stackframe is in the list of old stackframes.
727 * Test for exact stackframe (exact means same description and same line number).
729 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
730 * @param list The list of old stackframes
732 * - true if we have exactly this stackframe within the list
733 * - false if we did not find the exact stackframe within the list
735 private void markIdenticalStackFrames (Vector oldList, Vector newList) {
737 PHPStackFrame stackFrameNew;
739 resetAvailability (oldList); // Reset the availability flag of the old stack frames
740 resetAvailability (newList); // Reset the availability flag of the old stack frames
742 for (i = 0; i < newList.size (); i++) { // For all stackList entries
743 stackFrameNew = (PHPStackFrame) newList.get (i);
745 if (isStackFrameInList (stackFrameNew, oldList)) { // Is this stackframe in the list
746 stackFrameNew.setAvailable (true); //
755 * The stackList contains the currently read stackframes which were sent
756 * from DBG. The DBG interface holds a list of the active stack frames.
757 * This method replicates the 'static' stackframe list with the DBG stackframe list
758 * Replication is done in the following way:
760 * <li> It looks for new stackframes within the DBG stackframe list and
761 * adds them to the 'static' list.
762 * <li> It looks for stackframes within the 'static' list, and removes them
763 * from the 'static' list in case they do not appear within the DBG list.
764 * <li> It looks for stackframes which are already existent and replicates the
765 * line number and the index number.
766 * <li> At the end, the 'static' stackframe list has to be sorted by the stackframes
770 * Removes the unused stackframes from the list, or adds stackframes which
771 * are not yet in the list.
776 private void updateStackFrameList (Vector stackList) {
779 PHPStackFrame stackFrameNew;
780 PHPStackFrame stackFrameOld;
781 PHPStackFrame[] newStackList;
783 markIdenticalStackFrames (stackListOld, stackList); // Check whether the newly send stack frames can be found in the list
784 // of old stack frames
786 for (i = 0; i < stackList.size (); i++) { // For all stackList entries
787 stackFrameNew = (PHPStackFrame) stackList.get(i);
789 for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list
790 stackFrameOld = (PHPStackFrame) stackListOld.get (n); //
792 if (stackFrameOld.isAvailable ()) { // If this stack frame was already found in the new list skip it
796 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) {// Did we find the sent stackframe within the list of old stackframes?
797 stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ());
798 stackFrameOld.setIndex (stackFrameNew.getIndex ());
799 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
801 stackFrameOld.setAvailable (true); // And mark this stack frame as available
802 stackFrameNew.setAvailable (true); // And mark this stack frame as available
804 break; // Yes, then break;
808 if (!stackFrameNew.isAvailable ()) { // Did not find the new stackframe within the list?
809 stackFrameNew.setAvailable (true); // Mark the stack frame as available and
810 stackListOld.add (stackFrameNew); // then add the new stackframe
814 // And now for removing unused stackframes from list
816 for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list
817 stackFrameOld = (PHPStackFrame) stackListOld.get (n); //
820 if (!stackFrameOld.isAvailable ()) {
821 i = stackList.size ();
824 if (i == stackList.size ()) { // Did not find the old stackframe within the list of new ones
825 stackListOld.remove (n); // then remove the old stackframe from list
826 n -= 1; // Adjust the stack list index
830 Collections.sort (stackListOld); // Sort the 'static' stackframe list by the stackframe index numbers.
832 newStackList = new PHPStackFrame[stackListOld.size ()];
833 newStackList = (PHPStackFrame[]) stackListOld.toArray (newStackList);
834 DBGStackList = newStackList;
838 * Read the response from DBG and process the frame
841 * - The received command
842 * - or 0 if something was wrong
844 public int readResponse () throws IOException {
845 int bytesToRead = 0; // The number of byte to read for the current DBG block
846 int nextFrame = 0; // The current read position within entirePack
850 boolean errorStack = false;
851 char[] dbg_header_struct_read = new char[16]; // The buffer for the first 16 bytes of a block
852 int[] dbg_header_struct = new int[4]; // The first four numbers (long) of a block
853 int[] dbg_bpl_tmp = new int[10];
854 int[] dbg_frame = new int[2];
855 int[] dbg_eval_tmp = new int[3];
856 int[] dbg_src_tree_tmp = new int[4]; //
857 int[] dbg_error_tmp = new int[2];
858 Vector rawList = new Vector();
859 Vector stackList = new Vector(); // Intermediate stacklist which is build up in FRAME_STACK frame
865 while (readInput (dbg_header_struct_read, 16) != 0) { // Read 16 byte from input stream
866 dbg_header_struct[0] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 0); // Debug sync header
867 dbg_header_struct[1] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 4); // Command
868 dbg_header_struct[2] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 8); //
869 dbg_header_struct[3] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 12); // Bytes within this block
871 if (dbg_header_struct[0] != 0x5953) { // Check DBG sync bytes
872 return 0; // Wrong header
875 cmdReceived = dbg_header_struct[1]; // Get the command
876 setLastCmd (cmdReceived); // Store the info about the current command
877 bytesToRead = dbg_header_struct[3]; // Get the number of bytes to read for this block
879 //System.out.println("Response Received: " + cmdReceived);
880 char[] entirePack = new char[bytesToRead]; // Store the block data into buffer 'entirePack'
882 if (bytesToRead > 0) { // If there is something within the frame
883 if (readInput (entirePack, bytesToRead) < bytesToRead) { // Read the frame into the buffer
884 return 0; // We did not read enough bytes, error
888 nextFrame = 0; // Start with the first frame
890 while (nextFrame < bytesToRead) { // As long as we have something within this block
891 dbg_frame[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame); // The name of the frame
892 dbg_frame[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The size of the frame
893 nextFrame += 8; // The next read position
895 if (dbg_frame[1] == 0) { // Something within the frame?
896 return 0; // Nothing to read, error
899 switch (dbg_frame[0]) {
900 case PHPDBGBase.FRAME_STACK:
901 int[] dbg_stack_new = new int[4]; //
903 dbg_stack_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Source line number
904 dbg_stack_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Module number
905 dbg_stack_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // Scope id
906 dbg_stack_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // ID of description string
908 if ((dbg_stack_new[1] != 0) && !errorStack) {
909 PHPStackFrame newStack;
912 newStack = new PHPStackFrame (null, // The thread
913 getModByNo (dbg_stack_new[1]), // The name of the module (file)
914 dbg_stack_new[0], // The source line number
916 getRawFrameData (entirePack, // Get the string from this packet
917 dbg_stack_new[3]), // The frame ID for which we want the string
918 dbg_stack_new[1], // The module number
920 stackList.add (newStack);
926 case PHPDBGBase.FRAME_SOURCE: // Nothing to be done here
927 break; // TODO: what's with that frame? Something interesting
929 case PHPDBGBase.FRAME_SRC_TREE: //
930 dbg_src_tree_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // The parent module number
931 dbg_src_tree_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The parent line number (not used)
932 dbg_src_tree_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // The module number
933 dbg_src_tree_tmp[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // The filename number
935 if (getModByNo (dbg_src_tree_tmp[2]).equals ("")) {
938 fileName = new String (getRawFrameData (entirePack, dbg_src_tree_tmp[3])); // Get the filename
940 if (dbg_src_tree_tmp[2] != 0) { // If there is a module number
943 modNew = new PHPDBGMod (dbg_src_tree_tmp[2], fileName); // Create a module object
945 DBGMods.add (modNew); // And store it to array
950 case PHPDBGBase.FRAME_RAWDATA: // Nothing to be done here
951 break; // FRAME_RAWDATA are processed within getRawFrameData
953 case PHPDBGBase.FRAME_ERROR: // An error frame
954 errorStack = true; // Yes, we have an error stack
955 dbg_error_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Error type
956 dbg_error_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Error message ID
958 String error = "\n"; //
960 switch (dbg_error_tmp[0]) { // Switch on error type
961 case PHPDBGBase.E_ERROR: error += "[Error]"; break;
962 case PHPDBGBase.E_WARNING: error += "[Warning]"; break;
963 case PHPDBGBase.E_PARSE: error += "[Parse Error]"; break;
964 case PHPDBGBase.E_NOTICE: error += "[Notice]"; break;
965 case PHPDBGBase.E_CORE_ERROR: error += "[Core Error]"; break;
966 case PHPDBGBase.E_CORE_WARNING: error += "[Core Warning]"; break;
967 case PHPDBGBase.E_COMPILE_ERROR: error += "[Compile Error]"; break;
968 case PHPDBGBase.E_COMPILE_WARNING: error += "[Compile Warning]"; break;
969 case PHPDBGBase.E_USER_ERROR: error += "[User Error]"; break;
970 case PHPDBGBase.E_USER_WARNING: error += "[User Warning]"; break;
971 case PHPDBGBase.E_USER_NOTICE: error += "[User Notice]"; break;
972 default: error += "[Unexpected Error]"; break;
976 error += new String (getRawFrameData (entirePack, dbg_error_tmp[1])); // Add the error string for this error message ID
977 error += "\n"; // Append a CR
979 PHPDebugCorePlugin.log (new DebugException (new Status (IStatus.WARNING,
980 PHPDebugCorePlugin.PLUGIN_ID,
984 // To print errors on the console, I must execute a code in the
985 // php context, that write the stderr... I didn't found a better way
986 // TODO: Find a better way????
988 // String codeExec= "";
989 // codeExec= "fwrite(fopen('php://stderr', 'w'),\\\"" + error + "\\\");";
991 // evalBlock("eval(\"" + codeExec + "\");");
992 // } catch (DebugException e) {
993 // PHPDebugCorePlugin.log(e);
996 if (!stopOnError) { // Is always false (Did not see where this is set to true!?)
997 if (lastCommand.equals (PHPDBGBase.DBGA_CONTINUE)) { // If last command for PHP was a 'continue',
998 continueExecution (); // send continue again
999 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPINTO)) { // If last command for PHP was a 'step into',
1000 stepInto (); // send 'step into' again
1001 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOUT)) { // If last command for PHP was a 'step out',
1002 stepOut (); // send 'step out' again
1003 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOVER)) { // If last command for PHP was a 'step over',
1004 stepOver (); // send 'step over' again
1009 case PHPDBGBase.FRAME_EVAL:
1012 evalString = new String ("");
1013 dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // istr
1014 dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // iresult
1015 dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // ierror
1017 evalRet = getRawFrameData (entirePack, dbg_eval_tmp[1]); //
1018 evalString = getRawFrameData (entirePack, dbg_eval_tmp[0]); //
1021 case PHPDBGBase.FRAME_BPS: //
1024 case PHPDBGBase.FRAME_BPL:
1027 dbg_bpl_new = new int[10];
1028 dbg_bpl_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);
1029 dbg_bpl_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);
1030 dbg_bpl_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);
1031 dbg_bpl_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);
1032 dbg_bpl_new[4] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 16);
1033 dbg_bpl_new[5] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 20);
1034 dbg_bpl_new[6] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 24);
1035 dbg_bpl_new[7] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 28);
1036 dbg_bpl_new[8] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 32);
1037 dbg_bpl_new[9] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 36);
1039 // look if breakpoint already exists in vector
1040 for (i = 0; i < DBGBPList.size (); i++) {
1041 dbg_bpl_tmp = (int[]) DBGBPList.get (i);
1043 if (dbg_bpl_tmp[8] == dbg_bpl_new[8]) {
1044 DBGBPList.remove (i);
1050 // add breakpoint to vector
1051 DBGBPList.add (dbg_bpl_new);
1052 copyToLastBP (dbg_bpl_new);
1055 if (getModByNo (dbg_bpl_new[0]).equals ("")) {
1058 fileName = new String (getRawFrameData (entirePack, dbg_bpl_new[2]));
1060 if (dbg_bpl_new[0] != 0) {
1063 modNew = new PHPDBGMod (dbg_bpl_new[0], fileName);
1065 DBGMods.add (modNew);
1070 case PHPDBGBase.FRAME_VER:
1073 case PHPDBGBase.FRAME_SID:
1074 sid = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0);
1077 case PHPDBGBase.FRAME_SRCLINESINFO:
1080 case PHPDBGBase.FRAME_SRCCTXINFO:
1083 case PHPDBGBase.FRAME_LOG:
1086 case PHPDBGBase.FRAME_PROF:
1089 case PHPDBGBase.FRAME_PROF_C:
1092 case PHPDBGBase.FRAME_SET_OPT:
1096 nextFrame += dbg_frame[1]; // go to next frame
1099 // Now process command
1100 switch(cmdReceived) {
1101 case PHPDBGBase.DBGC_REPLY:
1104 case PHPDBGBase.DBGC_STARTUP:
1107 case PHPDBGBase.DBGC_END:
1108 sessionEnded = true;
1109 this.proxy.setTerminated();
1112 case PHPDBGBase.DBGC_BREAKPOINT:
1113 BPUnderHit = getBPUnderHit ();
1114 updateStackFrameList (stackList);
1117 case PHPDBGBase.DBGC_STEPINTO_DONE:
1118 case PHPDBGBase.DBGC_STEPOVER_DONE:
1119 case PHPDBGBase.DBGC_STEPOUT_DONE:
1120 case PHPDBGBase.DBGC_EMBEDDED_BREAK:
1121 case PHPDBGBase.DBGC_PAUSE:
1123 updateStackFrameList (stackList);
1126 case PHPDBGBase.DBGC_ERROR:
1128 updateStackFrameList (stackList);
1131 case PHPDBGBase.DBGC_LOG:
1134 case PHPDBGBase.DBGC_SID:
1139 return cmdReceived; // Return the command we received with this block
1146 public PHPStackFrame[] getStackList() {
1147 return DBGStackList;
1151 * Reads from input buffer (response sent from DBG) the given number of chars
1152 * into frame buffer.
1154 * @param buffer The frame buffer where to store the read data from DBG.
1155 * @param bytes The number of bytes (chars) which are to read from input stream.
1156 * @return The number of bytes actually read.
1158 private int readInput (char[] buffer, int bytes) throws IOException {
1159 int bytesRead = 0; // Reset the bytes read counter
1161 for (int i = 0; i < bytes; i++) { // For the number of bytes we should read
1162 if (in.ready ()) { // If input stream is ready for reading
1163 buffer[i] = (char) (in.read () & 0x00FF); // Read a char and store only the least significant 8-bits
1164 bytesRead++; // Increment the bytes read counter
1166 else { // Input stream is not ready
1167 break; // Break the loop
1171 return bytesRead; // Return the number of bytes actually read
1175 * PHPProxy could stop the waiting for a response with this method.
1178 public void setShouldStop () {
1179 this.shouldStop = true;
1183 * @param milliseconds The maximum time in milliseconds we wait for something
1184 * to be send from DBG.
1185 * @return - true if something was received from DBG
1186 * - false if nothing was send from DBG within the given time
1189 public boolean waitResponse (long milliseconds) throws IOException {
1192 timeout = System.currentTimeMillis () + milliseconds; // Calculate the system time till we wait.
1194 while (System.currentTimeMillis () < timeout) { // Is waiting time running out?
1195 if (in.ready () || shouldStop) { // No, so did we get something or should we stop now
1196 break; // Yes, break the waiting
1200 return in.ready (); // true if we got something from DBG