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.Arrays;
18 import java.util.Collections;
19 import java.util.Vector;
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 String serGlobals = new String("");
51 private int rawCounter = 1000; // An rawData frame ID counter
52 private PHPDBGProxy proxy = null;
53 private int lastCmd = -1;
55 private boolean stopOnError = false;
56 private char[] lastCommand = new char[4];
58 private static final String GlobalVariablesTitle = PHPDebugCorePlugin
59 .getResourceString("VariablesView.GlobalVariables.title");
62 * @param in The input stream (communication from DBG).
63 * @param os The output stream (communication to DBG).
64 * @param proxy The proxy to which this interface belongs.
66 public PHPDBGInterface (BufferedReader in, OutputStream os, PHPDBGProxy proxy) {
76 * @param mod_name The module (source file) to which we add the breakpoint.
77 * @param line The line where the breakpoint is set.
78 * @param hitCount The number of hit counts before suspend.
79 * @param condition The break condition
80 * @return Breakpoint ID ???.
82 public int addBreakpoint (String mod_name, int line, int hitCount, String condition) throws IOException {
83 return setBreakpoint (mod_name, condition, line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, hitCount, 0, 0, 0);
88 * @param mod_name The module (source file) to which we add the breakpoint.
89 * @param line The line where the breakpoint is set.
90 * @param bpNo The breakpoint ID ???.
92 public void removeBreakpoint (String mod_name, int line, int bpNo) throws IOException {
93 setBreakpoint (mod_name, "", line, PHPDBGBase.BPS_DISABLED, 0, 0, 0, bpNo, 0);
97 * Is this method used anywhere?
100 public void requestDBGVersion () throws IOException {
101 PHPDBGPacket DBGPacket; // A DBG message packet
102 PHPDBGFrame DBGFrame; // A frame within a DBG packet
104 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
105 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_VER); // We want the version of DBG
107 DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet
109 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
113 DBGPacket.sendPacket (os); // Send the request to DBG
117 * Called by the proxy
120 public void getSourceTree () throws IOException {
121 PHPDBGPacket DBGPacket; // A DBG message packet
122 PHPDBGFrame DBGFrame; // A frame within a DBG packet
124 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
125 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_SRC_TREE); // We want a source tree from DBG
127 DBGPacket.addFrame (DBGFrame); // Add the 'what we want' to the DBG packet
129 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
133 DBGPacket.sendPacket (os); // Send the request to DBG
135 waitResponse (1000); // Wait for the DBG response (1 second)
136 flushAllPackets (); // Read and process the response from DBG
140 * Is this method called from anywhere?
142 * @param modName The modul (filename).
144 public void addDBGModName (String modName) throws IOException {
145 PHPDBGPacket DBGPacket; // A DBG message packet
146 PHPDBGFrame DBGFrame; // A frame within a DBG packet
148 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); // A request for DBG
149 DBGFrame = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA); // We want Module name from DBG
151 rawCounter++; // Increment the rawData ID counter
152 DBGFrame.addInt (rawCounter); // FRAME_RAWDATA ID
153 DBGFrame.addInt (modName.length () + 1); // The length of rawdata string (incl. null char termination)
154 DBGFrame.addString (modName); // The file name (module name)
155 DBGFrame.addChar ('\0'); // Add the C-String null termination
157 DBGPacket.addFrame (DBGFrame);
159 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
163 DBGPacket.sendPacket (os);
167 * This method is called for adding or removing breakpoints.
169 * @param mod_name The module name (file name).
170 * @param condition Info about the condition when to break (not used at the moment).
171 * @param line The breakpoints line.
172 * @param state Info whether this breakpoint has to be dis- or enabled.
173 * @param istep Always 0.
174 * @param hitcount Always 0.
175 * @param skiphits Always 0.
176 * @param bpno The breakpoint ID.
177 * @param isunderhit ???
180 private int setBreakpoint (String mod_name, String condition, int line, int state, int istemp, int hitcount, int skiphits, int bpno, int isunderhit) throws IOException {
181 PHPDBGPacket DBGPacket;
182 PHPDBGFrame DBGFrame1;
183 PHPDBGFrame DBGFrame2;
184 PHPDBGFrame DBGFrame3;
187 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);
188 DBGFrame1 = new PHPDBGFrame (PHPDBGBase.FRAME_BPS);
189 DBGFrame2 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
190 DBGFrame3 = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
192 modNo = getModByName (mod_name); // Get the module ID by name
194 if (modNo >= 0) { // Did we find a module ID for the module name?
195 DBGFrame1.addInt (modNo); // Add the module ID to frame 1
197 DBGFrame1.addInt (0); // mod number (0 use file name)
200 DBGFrame1.addInt (line); // line number
202 if (modNo >= 0) { // Did we find a module ID for the module name?
203 DBGFrame1.addInt (0); // use mod number
206 DBGFrame1.addInt (rawCounter); // ID of FRAME_RAWDATA to send file name
209 if (modNo < 0) { // Did we find a module ID for the module name?
210 DBGFrame2.addInt (rawCounter); // FRAME_RAWDATA ID
211 DBGFrame2.addInt (mod_name.length() + 1); // length of rawdata (+ null char)
212 DBGFrame2.addString (mod_name); // file name
213 DBGFrame2.addChar ('\0'); // null char
215 DBGPacket.addFrame (DBGFrame2); // First add file name data
218 DBGFrame1.addInt (state); // state BPS_*
219 DBGFrame1.addInt (istemp); // istemp
220 DBGFrame1.addInt (0); // hit count; this is not supported as one might think
221 DBGFrame1.addInt (hitcount); // skip hits is what we think is hit count.
223 if (!condition.equals ("")) { // Do we have a condition for breakpoint
224 rawCounter++; // Set to new ID
225 DBGFrame1.addInt (rawCounter); // ID of condition
227 DBGFrame3.addInt (rawCounter); // FRAME_RAWDATA ID
228 DBGFrame3.addInt (condition.length() + 1); // length of rawdata (+ null char)
229 DBGFrame3.addString (condition); // The break condition
230 DBGFrame3.addChar ('\0'); // null char
232 DBGPacket.addFrame (DBGFrame3); // First add break condition
235 DBGFrame1.addInt (0); // ID of condition is 0, because there is no condition
238 DBGFrame1.addInt (bpno); // breakpoint number
239 DBGFrame1.addInt (isunderhit); // is under hit
241 DBGPacket.addFrame (DBGFrame1); // Second add command data
243 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
247 DBGPacket.sendPacket (os); // Send the request to DBG
251 waitResponse (1000); // Wait for the DBG response (1 second)
252 flushAllPackets (); // Read and process the response from DBG
254 return LastBPRead[8]; // Return what ???
260 private void clearLastBP () {
263 for (i = 0; i < LastBPRead.length; i++) {
271 private void copyToLastBP (int[] BPBody) {
274 for (i = 0; i < LastBPRead.length; i++) {
275 LastBPRead[i] = BPBody[i];
282 public void continueExecution () throws IOException {
283 PHPDBGPacket DBGPacket;
286 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_CONTINUE);
288 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
292 DBGPacket.sendPacket (os); // Send the request to DBG
294 lastCommand = PHPDBGBase.DBGA_CONTINUE; // Store the info about the command we sent
300 public void pauseExecution () throws IOException {
301 PHPDBGPacket DBGPacket;
303 DBGPacket = new PHPDBGPacket (PHPDBGBase.IntToChar4 (PHPDBGBase.DBGC_PAUSE));
305 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
309 DBGPacket.sendPacket (os); // Send the request to DBG
315 private int getBPUnderHit () {
318 int[] dbg_bpl_body = new int[10];
320 for (i = 0; i < DBGBPList.size (); i++) { // look for bp under hit
321 dbg_bpl_body = (int[]) DBGBPList.get (i);
323 if (dbg_bpl_body[9] == 1) {
324 BPUnder = dbg_bpl_body[8];
331 public int getLastCmd()
341 public void setLastCmd (int cmd)
349 public void stepInto () throws IOException {
350 PHPDBGPacket DBGPacket;
353 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPINTO);
355 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
359 DBGPacket.sendPacket (os); // Send the request to DBG
361 lastCommand = PHPDBGBase.DBGA_STEPINTO; // Store the info about the command we sent
367 public void stepOver () throws IOException {
368 PHPDBGPacket DBGPacket;
371 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOVER);
373 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
377 DBGPacket.sendPacket (os); // Send the request to DBG
379 lastCommand = PHPDBGBase.DBGA_STEPOVER; // Store the info about the command we sent
385 public void stepOut () throws IOException {
386 PHPDBGPacket DBGPacket;
389 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOUT);
391 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
395 DBGPacket.sendPacket (os); // Send the request to DBG
397 lastCommand = PHPDBGBase.DBGA_STEPOUT; // Store the info about the command we sent
403 public void stopExecution () throws IOException {
404 PHPDBGPacket DBGPacket;
407 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_STOP);
409 if (proxy.getSocket ().isClosed ()) { // Can we communiate with DBG?
413 DBGPacket.sendPacket (os); // Send the request to DBG
417 * This method is called by the proxy.
418 * It sends a request to DBG to get the current variables
419 * with their values. It waits for the response and processes
420 * the input from DBG.
422 * @param stack The stackframe for which we want the variables.
423 * @return The array of variables
425 public synchronized Vector getVariables(PHPStackFrame stack) throws IOException, DebugException {
426 PHPDBGPacket DBGPacket;
427 PHPDBGFrame DBGFrame1;
428 PHPDBGEvalString evalStr;
430 Vector globalList = new Vector();
431 // IStackFrame[] stacks = stack.getThread().getStackFrames();
432 // ( PHPStackFrame.getThread().getStackFrames() returns DBGStackList )
433 if (DBGStackList.length > 1) {
434 // get global variables (and assign them to 'main()' stackframe)
435 globalList = getVariables(DBGStackList[DBGStackList.length - 1], PHPDBGBase.GLOBAL_SCOPE_ID);
436 if (!globalList.isEmpty()) {
437 // remove unexpected '$this=?' variable
438 PHPVariable var = (PHPVariable) globalList.get(0);
439 PHPValue val = (PHPValue) var.getValue();
440 Vector workList = val.getChildVariables();
441 for (int i = 0; i < workList.size(); i++) {
442 if (((PHPVariable) workList.get(i)).getName().equals("$this")) {
447 var.setName(GlobalVariablesTitle);
448 var.setModifiable(false);
452 // DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST); //
453 // DBGFrame1 = new PHPDBGFrame (PHPDBGBase.FRAME_EVAL); //
455 // DBGFrame1.addInt (0); // istr = raw data ID
456 // DBGFrame1.addInt (1); // scope_id = -1 means current location, 0 never used, +1 first depth
458 // DBGPacket.addFrame (DBGFrame1); // Add command data
460 // if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication?
461 // return new Vector (); // No, then leave here with an empty vector
465 // DBGPacket.sendPacket (os); // Send the request to DBG
467 // waitResponse (1000); // Wait for the DBG response (1 second)
468 // flushAllPackets (); // Read and process the response from DBG
470 // evalStr = new PHPDBGEvalString (stack, serGlobals); // Process serialized variables
471 // DBGVarList = evalStr.getVariables ();
473 int scopeID = stack.getScopeID();
474 if (scopeID == PHPDBGBase.CURLOC_SCOPE_ID) {
475 // current stackframe
476 DBGVarList = getVariables(stack, PHPDBGBase.CURLOC_SCOPE_ID);
477 } else if ((scopeID == PHPDBGBase.CURLOC_SCOPE_ID + 1) && !globalList.isEmpty()) {
478 // 'main()' stackframe
479 PHPVariable var = (PHPVariable) globalList.get(0);
480 PHPValue val = (PHPValue) var.getValue();
481 DBGVarList = val.getChildVariables();
484 // back-trace stackframe
485 // Never: DBGVarList = getVariables(stack, scopeID);
486 // DBG 2.15.5 causes Application Error (on win32) in some cases
490 if (DBGVarList.size() > 0) { // Did we get back variables?
491 PHPVariable var = (PHPVariable) DBGVarList.get(0); // Yes, then get the first PHPVariable
492 PHPValue val = (PHPValue) var.getValue(); // Get the value
494 if (var.getName().equals("")) { // Is the root node an empty node (usually it is)
495 DBGVarList = val.getChildVariables(); // Then remove the empty node.
496 // With removing the empty root node, it wouldn't be necessary to
497 // set the name to an empty string. So the code below is just for
498 // info or in case the users want to have the empty root node.
500 // The eclipse variable view cannot handle Variables which have an empty name
501 // when it comes to variable tree restore operation. Without a name, no restore!
502 //var.setName (" "); // Give a name to the variable root node. Even if it is only a space :-)
503 } // TODO the best would be to remove the empty root node, but this would
504 // require a understanding and reworking of the PHPDBGEvalstring class.
507 if (!globalList.isEmpty()) {
508 DBGVarList.add(globalList.get(0));
511 return DBGVarList; // Return the variables as list
516 * @throws IOException
518 private Vector getVariables(PHPStackFrame stack, int scope_id) throws IOException {
519 PHPDBGPacket DBGPacket = new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
520 PHPDBGFrame DBGFrame1 = new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
523 DBGFrame1.addInt(scope_id);
525 DBGPacket.addFrame(DBGFrame1);
528 if (proxy.getSocket().isClosed()) {
531 DBGPacket.sendPacket(os);
535 PHPDBGEvalString evalStr = new PHPDBGEvalString(stack, evalRet);
536 return evalStr.getVariables();
543 public void log(String logString) throws IOException, DebugException {
544 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
545 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_LOG);
546 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
549 DBGFrame1.addInt(rawCounter); // ilog
550 DBGFrame1.addInt(1); // type
551 DBGFrame1.addInt(0); // mod_no
552 DBGFrame1.addInt(0); // line_no
553 DBGFrame1.addInt(0); // imod_name
554 DBGFrame1.addInt(0); // ext_info
556 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
557 DBGFrame2.addInt(logString.length() + 1); // length of rawdata (+ null char)
558 DBGFrame2.addString(logString); // log string
559 DBGFrame2.addChar('\0'); // null char
561 // Add raw data first
562 DBGPacket.addFrame(DBGFrame2);
564 DBGPacket.addFrame(DBGFrame1);
566 if (proxy.getSocket ().isClosed ()) { // Do we have a socket for DBG communication?
567 return; // No, then leave here
570 DBGPacket.sendPacket(os);
576 public synchronized PHPVariable[] evalBlock(PHPStackFrame stack, String evalString) throws IOException, DebugException {
577 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
578 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
579 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
582 DBGFrame1.addInt(rawCounter); // istr = raw data ID
583 //DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth
584 DBGFrame1.addInt(stack.getScopeID());
586 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
587 DBGFrame2.addInt(evalString.length() + 1); // length of rawdata (+ null char)
588 DBGFrame2.addString(evalString); // eval block
589 DBGFrame2.addChar('\0'); // null char
591 // Add raw data first
592 DBGPacket.addFrame(DBGFrame2);
594 DBGPacket.addFrame(DBGFrame1);
596 if (proxy.getSocket().isClosed()) { // Do we have a socket for DBG communication?
597 return null; // No, then leave here
599 DBGPacket.sendPacket(os);
604 PHPDBGEvalString evalStr=new PHPDBGEvalString(stack,evalRet);
606 return evalStr.getVars();
610 * Read and process everthing we got from DBG
612 public void flushAllPackets () throws IOException {
613 while (readResponse() != 0);
617 * Get the modules name by its number
619 * @param modNo The number (id) of the module
620 * @return The name of the module
622 public String getModByNo (int modNo) {
626 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
627 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
629 if (dbg_mod.getNo () == modNo) { // Is the module from the array the module we want?
630 return dbg_mod.getName (); // Yes, return the name of the module
634 return ""; // If nothing was found return emtpy string
639 * @param modName The name of the module for which we want the ID
641 * - The ID of the module
642 * - -1 if nothing was found
644 private int getModByName (String modName) {
648 for (i = 0; i < DBGMods.size (); i++) { // For all the modules we have within the array
649 dbg_mod = (PHPDBGMod) DBGMods.get (i); // Get the module
651 if (dbg_mod.getName ().equalsIgnoreCase (modName)) { // Is the module from the array the module we want?
652 return dbg_mod.getNo (); // Yes, return the name of the module
656 return -1; // If nothing was found return -1
660 * Return the string for the given frame number
662 * @param framesInfo The buffer which is to read
663 * @param frameNo The frame number
666 private String getRawFrameData (char[] framesInfo, int frameNo) {
667 int nextFrame = 0; // The current read position within the buffer
668 int[] dbg_frame = new int[2]; // The two frame header numbers
670 while (nextFrame < framesInfo.length) { // As long we have something within the buffer
671 dbg_frame[0] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame); // The frame type
672 dbg_frame[1] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The frame size
674 nextFrame += 8; // The current read position
676 if (dbg_frame[1] == 0) { // If frame size is 0
677 return ""; // return an emtpy string
680 switch (dbg_frame[0]) { // Switch for the frame type
681 case PHPDBGBase.FRAME_RAWDATA: // The only frame type we are interrested in
682 if (frameNo == PHPDBGBase.Char4ToInt (framesInfo, nextFrame)) { // Is it correct number of the frame
685 toRead = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4); // The size of the string
687 if ((int) framesInfo[nextFrame + 8 + toRead - 1] == 0) { // Is there a string termination at the end?
688 return String.copyValueOf (framesInfo, nextFrame + 8, toRead - 1); // Then copy frame content to String without the \0 and return
691 return String.copyValueOf (framesInfo, nextFrame + 8, toRead); // Copy frame content to String and return
696 nextFrame += dbg_frame[1]; // Go for the next frame (add the length of the current one)
699 return ""; // We did not found any FRAM_RAWDATA, so return an emtpy strin
703 * Reset the availability flag for all stackframes in the list.
705 * @param list The list of old stackframes
707 private void resetAvailability (Vector list) {
710 for (i = 0; i < list.size (); i++) {
711 ((PHPStackFrame) list.get(i)).setAvailable (false); //
716 * Check whether the new stackframe is in the list of old stackframes.
717 * Test for identical stackframe (identical means same description and same line number).
719 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
720 * @param list The list of old stackframes
722 * - true if we have found the identical stackframe within the list
723 * - false if we did not find the identical stackframe within the list
725 private boolean isStackFrameInList (PHPStackFrame stackFrameNew, Vector list) {
727 PHPStackFrame stackFrameOld;
729 for (i = 0; i < list.size (); i++) {
730 stackFrameOld = (PHPStackFrame) list.get (i); //
732 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) &&
733 stackFrameNew.getLineNumber () == stackFrameOld.getLineNumber ()) { // Did we find the sent stackframe within the list of old stackframes?
734 stackFrameOld.setAvailable (true); // We found the new stackframe in the list of old stack frames
735 stackFrameOld.setIndex (stackFrameNew.getIndex ());
736 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
737 return true; // The stackframe was found in the list
745 * Check whether the new stackframe is in the list of old stackframes.
746 * Test for exact stackframe (exact means same description and same line number).
748 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
749 * @param list The list of old stackframes
751 * - true if we have exactly this stackframe within the list
752 * - false if we did not find the exact stackframe within the list
754 private void markIdenticalStackFrames (Vector oldList, Vector newList) {
756 PHPStackFrame stackFrameNew;
758 resetAvailability (oldList); // Reset the availability flag of the old stack frames
759 resetAvailability (newList); // Reset the availability flag of the old stack frames
761 for (i = 0; i < newList.size (); i++) { // For all stackList entries
762 stackFrameNew = (PHPStackFrame) newList.get (i);
764 if (isStackFrameInList (stackFrameNew, oldList)) { // Is this stackframe in the list
765 stackFrameNew.setAvailable (true); //
774 * The stackList contains the currently read stackframes which were sent
775 * from DBG. The DBG interface holds a list of the active stack frames.
776 * This method replicates the 'static' stackframe list with the DBG stackframe list
777 * Replication is done in the following way:
779 * <li> It looks for new stackframes within the DBG stackframe list and
780 * adds them to the 'static' list.
781 * <li> It looks for stackframes within the 'static' list, and removes them
782 * from the 'static' list in case they do not appear within the DBG list.
783 * <li> It looks for stackframes which are already existent and replicates the
784 * line number and the index number.
785 * <li> At the end, the 'static' stackframe list has to be sorted by the stackframes
789 * Removes the unused stackframes from the list, or adds stackframes which
790 * are not yet in the list.
795 private void updateStackFrameList (Vector stackList) {
798 PHPStackFrame stackFrameNew;
799 PHPStackFrame stackFrameOld;
800 PHPStackFrame[] newStackList;
802 markIdenticalStackFrames (stackListOld, stackList); // Check whether the newly send stack frames can be found in the list
803 // of old stack frames
805 for (i = 0; i < stackList.size (); i++) { // For all stackList entries
806 stackFrameNew = (PHPStackFrame) stackList.get(i);
808 for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list
809 stackFrameOld = (PHPStackFrame) stackListOld.get (n); //
811 if (stackFrameOld.isAvailable ()) { // If this stack frame was already found in the new list skip it
815 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) {// Did we find the sent stackframe within the list of old stackframes?
816 stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ());
817 stackFrameOld.setIndex (stackFrameNew.getIndex ());
818 stackFrameOld.setScopeID(stackFrameNew.getScopeID());
820 stackFrameOld.setAvailable (true); // And mark this stack frame as available
821 stackFrameNew.setAvailable (true); // And mark this stack frame as available
823 break; // Yes, then break;
827 if (!stackFrameNew.isAvailable ()) { // Did not find the new stackframe within the list?
828 stackFrameNew.setAvailable (true); // Mark the stack frame as available and
829 stackListOld.add (stackFrameNew); // then add the new stackframe
833 // And now for removing unused stackframes from list
835 for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list
836 stackFrameOld = (PHPStackFrame) stackListOld.get (n); //
839 if (!stackFrameOld.isAvailable ()) {
840 i = stackList.size ();
843 if (i == stackList.size ()) { // Did not find the old stackframe within the list of new ones
844 stackListOld.remove (n); // then remove the old stackframe from list
845 n -= 1; // Adjust the stack list index
849 Collections.sort (stackListOld); // Sort the 'static' stackframe list by the stackframe index numbers.
851 newStackList = new PHPStackFrame[stackListOld.size ()];
852 newStackList = (PHPStackFrame[]) stackListOld.toArray (newStackList);
853 DBGStackList = newStackList;
857 * Read the response from DBG and process the frame
860 * - The received command
861 * - or 0 if something was wrong
863 public int readResponse () throws IOException {
864 int bytesToRead = 0; // The number of byte to read for the current DBG block
865 int nextFrame = 0; // The current read position within entirePack
869 boolean errorStack = false;
870 char[] dbg_header_struct_read = new char[16]; // The buffer for the first 16 bytes of a block
871 int[] dbg_header_struct = new int[4]; // The first four numbers (long) of a block
872 int[] dbg_bpl_tmp = new int[10];
873 int[] dbg_frame = new int[2];
874 int[] dbg_eval_tmp = new int[3];
875 int[] dbg_src_tree_tmp = new int[4]; //
876 int[] dbg_error_tmp = new int[2];
877 Vector rawList = new Vector();
878 Vector stackList = new Vector(); // Intermediate stacklist which is build up in FRAME_STACK frame
884 while (readInput (dbg_header_struct_read, 16) != 0) { // Read 16 byte from input stream
885 dbg_header_struct[0] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 0); // Debug sync header
886 dbg_header_struct[1] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 4); // Command
887 dbg_header_struct[2] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 8); //
888 dbg_header_struct[3] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 12); // Bytes within this block
890 if (dbg_header_struct[0] != 0x5953) { // Check DBG sync bytes
891 return 0; // Wrong header
894 cmdReceived = dbg_header_struct[1]; // Get the command
895 setLastCmd (cmdReceived); // Store the info about the current command
896 bytesToRead = dbg_header_struct[3]; // Get the number of bytes to read for this block
898 //System.out.println("Response Received: " + cmdReceived);
899 char[] entirePack = new char[bytesToRead]; // Store the block data into buffer 'entirePack'
901 if (bytesToRead > 0) { // If there is something within the frame
902 if (readInput (entirePack, bytesToRead) < bytesToRead) { // Read the frame into the buffer
903 return 0; // We did not read enough bytes, error
907 nextFrame = 0; // Start with the first frame
909 while (nextFrame < bytesToRead) { // As long as we have something within this block
910 dbg_frame[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame); // The name of the frame
911 dbg_frame[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The size of the frame
912 nextFrame += 8; // The next read position
914 if (dbg_frame[1] == 0) { // Something within the frame?
915 return 0; // Nothing to read, error
918 switch (dbg_frame[0]) {
919 case PHPDBGBase.FRAME_STACK:
920 int[] dbg_stack_new = new int[4]; //
922 dbg_stack_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Source line number
923 dbg_stack_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Module number
924 dbg_stack_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // Scope id
925 dbg_stack_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // ID of description string
927 if ((dbg_stack_new[1] != 0) && !errorStack) {
928 PHPStackFrame newStack;
931 newStack = new PHPStackFrame (null, // The thread
932 getModByNo (dbg_stack_new[1]), // The name of the module (file)
933 dbg_stack_new[0], // The source line number
935 getRawFrameData (entirePack, // Get the string from this packet
936 dbg_stack_new[3]), // The frame ID for which we want the string
937 dbg_stack_new[1], // The module number
939 stackList.add (newStack);
945 case PHPDBGBase.FRAME_SOURCE: // Nothing to be done here
946 break; // TODO: what's with that frame? Something interesting
948 case PHPDBGBase.FRAME_SRC_TREE: //
949 dbg_src_tree_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // The parent module number
950 dbg_src_tree_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // The parent line number (not used)
951 dbg_src_tree_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // The module number
952 dbg_src_tree_tmp[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12); // The filename number
954 if (getModByNo (dbg_src_tree_tmp[2]).equals ("")) {
957 fileName = new String (getRawFrameData (entirePack, dbg_src_tree_tmp[3])); // Get the filename
959 if (dbg_src_tree_tmp[2] != 0) { // If there is a module number
962 modNew = new PHPDBGMod (dbg_src_tree_tmp[2], fileName); // Create a module object
964 DBGMods.add (modNew); // And store it to array
969 case PHPDBGBase.FRAME_RAWDATA: // Nothing to be done here
970 break; // FRAME_RAWDATA are processed within getRawFrameData
972 case PHPDBGBase.FRAME_ERROR: // An error frame
973 errorStack = true; // Yes, we have an error stack
974 dbg_error_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // Error type
975 dbg_error_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // Error message ID
977 String error = "\n"; //
979 switch (dbg_error_tmp[0]) { // Switch on error type
980 case PHPDBGBase.E_ERROR: error += "[Error]"; break;
981 case PHPDBGBase.E_WARNING: error += "[Warning]"; break;
982 case PHPDBGBase.E_PARSE: error += "[Parse Error]"; break;
983 case PHPDBGBase.E_NOTICE: error += "[Notice]"; break;
984 case PHPDBGBase.E_CORE_ERROR: error += "[Core Error]"; break;
985 case PHPDBGBase.E_CORE_WARNING: error += "[Core Warning]"; break;
986 case PHPDBGBase.E_COMPILE_ERROR: error += "[Compile Error]"; break;
987 case PHPDBGBase.E_COMPILE_WARNING: error += "[Compile Warning]"; break;
988 case PHPDBGBase.E_USER_ERROR: error += "[User Error]"; break;
989 case PHPDBGBase.E_USER_WARNING: error += "[User Warning]"; break;
990 case PHPDBGBase.E_USER_NOTICE: error += "[User Notice]"; break;
991 default: error += "[Unexpected Error]"; break;
995 error += new String (getRawFrameData (entirePack, dbg_error_tmp[1])); // Add the error string for this error message ID
996 error += "\n"; // Append a CR
998 PHPDebugCorePlugin.log (new DebugException (new Status (IStatus.WARNING,
999 PHPDebugCorePlugin.PLUGIN_ID,
1003 // To print errors on the console, I must execute a code in the
1004 // php context, that write the stderr... I didn't found a better way
1005 // TODO: Find a better way????
1007 // String codeExec= "";
1008 // codeExec= "fwrite(fopen('php://stderr', 'w'),\\\"" + error + "\\\");";
1010 // evalBlock("eval(\"" + codeExec + "\");");
1011 // } catch (DebugException e) {
1012 // PHPDebugCorePlugin.log(e);
1015 if (!stopOnError) { // Is always false (Did not see where this is set to true!?)
1016 if (lastCommand.equals (PHPDBGBase.DBGA_CONTINUE)) { // If last command for PHP was a 'continue',
1017 continueExecution (); // send continue again
1018 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPINTO)) { // If last command for PHP was a 'step into',
1019 stepInto (); // send 'step into' again
1020 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOUT)) { // If last command for PHP was a 'step out',
1021 stepOut (); // send 'step out' again
1022 } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOVER)) { // If last command for PHP was a 'step over',
1023 stepOver (); // send 'step over' again
1028 case PHPDBGBase.FRAME_EVAL:
1031 evalString = new String ("");
1032 dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0); // istr
1033 dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4); // iresult
1034 dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8); // ierror
1036 evalRet = getRawFrameData (entirePack, dbg_eval_tmp[1]); //
1037 evalString = getRawFrameData (entirePack, dbg_eval_tmp[0]); //
1038 //serGlobals = evalRet; //
1041 case PHPDBGBase.FRAME_BPS: //
1044 case PHPDBGBase.FRAME_BPL:
1047 dbg_bpl_new = new int[10];
1048 dbg_bpl_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);
1049 dbg_bpl_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);
1050 dbg_bpl_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);
1051 dbg_bpl_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);
1052 dbg_bpl_new[4] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 16);
1053 dbg_bpl_new[5] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 20);
1054 dbg_bpl_new[6] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 24);
1055 dbg_bpl_new[7] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 28);
1056 dbg_bpl_new[8] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 32);
1057 dbg_bpl_new[9] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 36);
1059 // look if breakpoint already exists in vector
1060 for (i = 0; i < DBGBPList.size (); i++) {
1061 dbg_bpl_tmp = (int[]) DBGBPList.get (i);
1063 if (dbg_bpl_tmp[8] == dbg_bpl_new[8]) {
1064 DBGBPList.remove (i);
1070 // add breakpoint to vector
1071 DBGBPList.add (dbg_bpl_new);
1072 copyToLastBP (dbg_bpl_new);
1075 if (getModByNo (dbg_bpl_new[0]).equals ("")) {
1078 fileName = new String (getRawFrameData (entirePack, dbg_bpl_new[2]));
1080 if (dbg_bpl_new[0] != 0) {
1083 modNew = new PHPDBGMod (dbg_bpl_new[0], fileName);
1085 DBGMods.add (modNew);
1090 case PHPDBGBase.FRAME_VER:
1093 case PHPDBGBase.FRAME_SID:
1094 sid = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0);
1097 case PHPDBGBase.FRAME_SRCLINESINFO:
1100 case PHPDBGBase.FRAME_SRCCTXINFO:
1103 case PHPDBGBase.FRAME_LOG:
1106 case PHPDBGBase.FRAME_PROF:
1109 case PHPDBGBase.FRAME_PROF_C:
1112 case PHPDBGBase.FRAME_SET_OPT:
1116 nextFrame += dbg_frame[1]; // go to next frame
1119 // Now process command
1120 switch(cmdReceived) {
1121 case PHPDBGBase.DBGC_REPLY:
1124 case PHPDBGBase.DBGC_STARTUP:
1127 case PHPDBGBase.DBGC_END:
1128 sessionEnded = true;
1129 this.proxy.setTerminated();
1132 case PHPDBGBase.DBGC_BREAKPOINT:
1133 BPUnderHit = getBPUnderHit ();
1134 updateStackFrameList (stackList);
1137 case PHPDBGBase.DBGC_STEPINTO_DONE:
1138 case PHPDBGBase.DBGC_STEPOVER_DONE:
1139 case PHPDBGBase.DBGC_STEPOUT_DONE:
1140 case PHPDBGBase.DBGC_EMBEDDED_BREAK:
1141 case PHPDBGBase.DBGC_PAUSE:
1143 updateStackFrameList (stackList);
1146 case PHPDBGBase.DBGC_ERROR:
1148 updateStackFrameList (stackList);
1151 case PHPDBGBase.DBGC_LOG:
1154 case PHPDBGBase.DBGC_SID:
1159 return cmdReceived; // Return the command we received with this block
1166 public PHPStackFrame[] getStackList() {
1167 return DBGStackList;
1171 * Reads from input buffer (response sent from DBG) the given number of chars
1172 * into frame buffer.
1174 * @param buffer The frame buffer where to store the read data from DBG.
1175 * @param bytes The number of bytes (chars) which are to read from input stream.
1176 * @return The number of bytes actually read.
1178 private int readInput (char[] buffer, int bytes) throws IOException {
1179 int bytesRead = 0; // Reset the bytes read counter
1181 for (int i = 0; i < bytes; i++) { // For the number of bytes we should read
1182 if (in.ready ()) { // If input stream is ready for reading
1183 buffer[i] = (char) (in.read () & 0x00FF); // Read a char and store only the least significant 8-bits
1184 bytesRead++; // Increment the bytes read counter
1186 else { // Input stream is not ready
1187 break; // Break the loop
1191 return bytesRead; // Return the number of bytes actually read
1195 * PHPProxy could stop the waiting for a response with this method.
1198 public void setShouldStop () {
1199 this.shouldStop = true;
1203 * @param milliseconds The maximum time in milliseconds we wait for something
1204 * to be send from DBG.
1205 * @return - true if something was received from DBG
1206 * - false if nothing was send from DBG within the given time
1209 public boolean waitResponse (long milliseconds) throws IOException {
1212 timeout = System.currentTimeMillis () + milliseconds; // Calculate the system time till we wait.
1214 while (System.currentTimeMillis () < timeout) { // Is waiting time running out?
1215 if (in.ready () || shouldStop) { // No, so did we get something or should we stop now
1216 break; // Yes, break the waiting
1220 return in.ready (); // true if we got something from DBG