/********************************************************************** Copyright (c) 2000, 2002 IBM Corp. and others. All rights reserved. This program and the accompanying materials are made available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/cpl-v10.html Contributors: Vicente Fernando - www.alfersoft.com.ar - Initial implementation **********************************************************************/ package net.sourceforge.phpdt.internal.debug.core; import java.io.IOException; import java.io.BufferedReader; import java.io.OutputStream; import java.util.Vector; import java.lang.System; import org.eclipse.debug.core.DebugException; import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame; import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable; import net.sourceforge.phpdt.internal.debug.core.model.PHPValue; import net.sourceforge.phpdt.internal.debug.core.PHPDBGMod; public class PHPDBGInterface { // Public public boolean sessionEnded= false; public int sessType= -1; public int BPUnderHit= 0; public String sessID= new String(); // Private private int[] LastBPRead= new int[10]; private Vector DBGBPList= new Vector(); private PHPStackFrame[] DBGStackList; private PHPVariable[] DBGVariableList; private Vector DBGMods= new Vector(); private Vector DBGVars= new Vector(); private BufferedReader in; private OutputStream os; private boolean shouldStop= false, isRef= false, hasChildren= false, isObject= false; private String evalRet= new String(""); private String serGlobals= new String(""); private String typeRead= new String(""); private String className= new String(""); private int finalPos=0, refCounter=0, rawCounter=1000; public PHPDBGInterface(BufferedReader in, OutputStream os) { DBGBPList.clear(); this.in= in; this.os= os; } public int addBreakpoint(String mod_name, int line) throws IOException { return setBreakpoint(mod_name, "", line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, 0, 0, 0, 0); } public void removeBreakpoint(String mod_name, int line, int bpNo) throws IOException { setBreakpoint(mod_name, "", line, PHPDBGBase.BPS_DISABLED, 0, 0, 0, bpNo, 0); } public void requestDBGVersion() throws IOException { PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST); PHPDBGFrame DBGFrame= new PHPDBGFrame(PHPDBGBase.FRAME_VER); DBGPacket.addFrame(DBGFrame); DBGPacket.sendPacket(os); } public void addDBGModName(String modName) throws IOException { PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST); PHPDBGFrame DBGFrame= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA); rawCounter++; DBGFrame.addInt(rawCounter); // FRAME_RAWDATA ID DBGFrame.addInt(modName.length() + 1); // length of rawdata (+ null char) DBGFrame.addString(modName); // file name DBGFrame.addChar('\0'); // null char DBGPacket.addFrame(DBGFrame); DBGPacket.sendPacket(os); } // Returns DBG Breakpoint ID private int setBreakpoint(String mod_name, String condition, int line, int state, int istemp, int hitcount, int skiphits, int bpno, int isunderhit) throws IOException { int modNo= 0; PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST); PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_BPS); PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA); modNo= getModByName(mod_name); if(modNo >= 0) { DBGFrame1.addInt(modNo); // mod number } else { DBGFrame1.addInt(0); // mod number (0 use file name) } DBGFrame1.addInt(line); // line number if(modNo >= 0) { DBGFrame1.addInt(0); // use mod number } else { rawCounter++; DBGFrame1.addInt(rawCounter); // ID of FRAME_RAWDATA to send file name } DBGFrame1.addInt(state); // state BPS_* DBGFrame1.addInt(istemp); // istemp DBGFrame1.addInt(hitcount); // hit count DBGFrame1.addInt(skiphits); // skip hits DBGFrame1.addInt(0); // ID of condition DBGFrame1.addInt(bpno); // breakpoint number DBGFrame1.addInt(isunderhit); // is under hit if(modNo < 0) { DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID DBGFrame2.addInt(mod_name.length() + 1); // length of rawdata (+ null char) DBGFrame2.addString(mod_name); // file name DBGFrame2.addChar('\0'); // null char // First add file name data DBGPacket.addFrame(DBGFrame2); } // Second add command data DBGPacket.addFrame(DBGFrame1); DBGPacket.sendPacket(os); clearLastBP(); // Wait response (1 second) and read response waitResponse(1000); flushAllPackets(); return LastBPRead[8]; } private void clearLastBP() { int i; for(i=0; i < LastBPRead.length; i++) LastBPRead[i]= 0; } private void copyToLastBP(int[] BPBody) { int i; for(i=0; i < LastBPRead.length; i++) LastBPRead[i]= BPBody[i]; } public void continueExecution() throws IOException { BPUnderHit= 0; PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_CONTINUE); DBGPacket.sendPacket(os); } private int getBPUnderHit() { int i, BPUnder=0; int[] dbg_bpl_body= new int[10]; // look for bp under hit for(i=0; i < DBGBPList.size(); i++) { dbg_bpl_body= (int[]) DBGBPList.get(i); if(dbg_bpl_body[9] == 1) { BPUnder= dbg_bpl_body[8]; } } return BPUnder; } public void stepInto() throws IOException { BPUnderHit= 0; PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_STEPINTO); DBGPacket.sendPacket(os); } public void stepOver() throws IOException { BPUnderHit= 0; PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_STEPOVER); DBGPacket.sendPacket(os); } public void stepOut() throws IOException { BPUnderHit= 0; PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_STEPOUT); DBGPacket.sendPacket(os); } public void stopExecution() throws IOException { BPUnderHit= 0; PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_STOP); DBGPacket.sendPacket(os); } public PHPVariable[] getVariables(PHPStackFrame stack) throws IOException, DebugException { PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST); PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL); //PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA); DBGFrame1.addInt(0); // istr = raw data ID DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth /* String evalBlock= new String("$GLOBALS"); DBGFrame2.addInt(1); // FRAME_RAWDATA ID DBGFrame2.addInt(evalBlock.length() + 1); // length of rawdata (+ null char) DBGFrame2.addString(evalBlock); // eval block DBGFrame2.addChar('\0'); // null char */ // Add command data DBGPacket.addFrame(DBGFrame1); DBGPacket.sendPacket(os); waitResponse(1000); flushAllPackets(); // Process serialized variables DBGVariableList= procVars(stack); return DBGVariableList; } public void evalBlock(String evalString) throws IOException, DebugException { PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST); PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL); PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA); rawCounter++; DBGFrame1.addInt(rawCounter); // istr = raw data ID DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID DBGFrame2.addInt(evalString.length() + 1); // length of rawdata (+ null char) DBGFrame2.addString(evalString); // eval block DBGFrame2.addChar('\0'); // null char // Add raw data first DBGPacket.addFrame(DBGFrame2); // Add command data DBGPacket.addFrame(DBGFrame1); DBGPacket.sendPacket(os); waitResponse(1000); flushAllPackets(); } public void flushAllPackets() throws IOException { while(readResponse() != 0); } public String getModByNo(int modNo) { int i; PHPDBGMod dbg_mod; // look for mod for(i=0; i < DBGMods.size(); i++) { dbg_mod= (PHPDBGMod) DBGMods.get(i); if(dbg_mod.getNo() == modNo) { return dbg_mod.getName(); } } return ""; } private int getModByName(String modName) { int i; PHPDBGMod dbg_mod; // look for mod for(i=0; i < DBGMods.size(); i++) { dbg_mod= (PHPDBGMod) DBGMods.get(i); if(dbg_mod.getName().equalsIgnoreCase(modName)) { return dbg_mod.getNo(); } } return -1; } private String getRawFrameData(char[] framesInfo, int frameNo) { int nextFrame= 0; int[] dbg_frame= new int[2]; while(nextFrame < framesInfo.length) { dbg_frame[0] = PHPDBGBase.Char4ToInt(framesInfo, nextFrame); // frame name dbg_frame[1] = PHPDBGBase.Char4ToInt(framesInfo, nextFrame + 4); // frame size nextFrame += 8; if(dbg_frame[1] == 0) return ""; switch(dbg_frame[0]) { case PHPDBGBase.FRAME_RAWDATA: if(frameNo == PHPDBGBase.Char4ToInt(framesInfo, nextFrame)) { int toRead= PHPDBGBase.Char4ToInt(framesInfo, nextFrame + 4); return String.copyValueOf(framesInfo, nextFrame + 8, toRead); } break; } // go to next frame nextFrame += dbg_frame[1]; } return ""; } public PHPVariable[] getInstVars(PHPVariable phpVar) throws DebugException { Vector vecVars= new Vector(); PHPVariable localPHPVar; int i=0; // already unserialized for(i=0; i < DBGVars.size(); i++) { localPHPVar= (PHPVariable)DBGVars.get(i); if(localPHPVar.getParent() == phpVar) { vecVars.add(localPHPVar); } } PHPVariable[] arrVars= new PHPVariable[vecVars.size()]; arrVars= (PHPVariable[]) vecVars.toArray(arrVars); return arrVars; } private PHPVariable[] procVars(PHPStackFrame stack) throws DebugException { Vector vecVars= new Vector(); // unserialize finalPos= 0; refCounter= 0; doUnserialize(stack, vecVars, null); DBGVars= vecVars; return(getInstVars(null)); } private String readValue(String serialVars) throws DebugException { int startPos=0, endPos=0, lenStr=0, i=0, elements=0; String ret= new String(""); switch(serialVars.charAt(0)) { case 'a': // associative array, a:elements:{[index][value]...} typeRead= "hash"; startPos= 1; endPos= serialVars.indexOf(':', startPos + 1); if(endPos == -1) return ""; finalPos += endPos + 2; ret= new String(serialVars.substring(startPos + 1, endPos)); hasChildren= true; break; case 'O': // object, O:name_len:"name":elements:{[attribute][value]...} typeRead= "object"; startPos= 1; endPos= serialVars.indexOf(':', startPos + 1); if(endPos == -1) return ""; // get object class lenStr= Integer.parseInt(serialVars.substring(startPos + 1, endPos)); startPos= endPos + 2; endPos= lenStr + startPos; className= new String(serialVars.substring(startPos, endPos).toString()); // get num of elements startPos= endPos + 1; endPos= serialVars.indexOf(':', startPos + 1); if(endPos == -1) return ""; finalPos += endPos + 2; ret= new String(serialVars.substring(startPos + 1, endPos)); isObject= true; hasChildren= true; break; case 's': // string, s:length:"data"; typeRead= "string"; startPos= 1; endPos= serialVars.indexOf(':', startPos + 1); if(endPos == -1) return ""; lenStr= Integer.parseInt(serialVars.substring(startPos + 1, endPos)); startPos= endPos + 2; endPos= lenStr + startPos; ret= new String(serialVars.substring(startPos, endPos).toString()); finalPos += endPos + 2; break; case 'i': // integer, i:123; typeRead= "integer"; startPos= 1; endPos= serialVars.indexOf(';', startPos + 1); if(endPos == -1) return ""; ret= new String(serialVars.substring(startPos + 1, endPos).toString()); finalPos += endPos + 1; break; case 'd': // double (float), d:1.23; typeRead= "double"; startPos= 1; endPos= serialVars.indexOf(';', startPos + 1); if(endPos == -1) return ""; ret= new String(serialVars.substring(startPos + 1, endPos).toString()); finalPos += endPos + 1; break; case 'N': // NULL, N; typeRead= "null"; ret= "nil"; finalPos += 2; break; case 'b': // bool, b:0 or 1 typeRead= "boolean"; ret= (serialVars.charAt(2) == '1')?"true":"false"; finalPos += endPos + 4; break; case 'z': // resource, z:typename_len:"typename":valres; typeRead= "resource"; startPos= 1; endPos= serialVars.indexOf(':', startPos + 1); if(endPos == -1) return ""; // get resource type name lenStr= Integer.parseInt(serialVars.substring(startPos + 1, endPos)); startPos= endPos + 2; endPos= lenStr + startPos; className= new String(serialVars.substring(startPos, endPos).toString()); // get resource value startPos= endPos + 1; endPos= serialVars.indexOf(';', startPos + 1); if(endPos == -1) return ""; ret= new String(serialVars.substring(startPos + 1, endPos)); finalPos += endPos + 1; break; case 'r': case 'R': typeRead= "reference"; startPos= 1; endPos= serialVars.indexOf(';', startPos + 1); if(endPos == -1) return "0"; ret= new String(serialVars.substring(startPos + 1, endPos)); finalPos += endPos + 1; isRef= true; break; case ';': typeRead= "unknown"; finalPos+= 1; break; case '?': finalPos+= 1; default: finalPos+= 1; typeRead= "unknown"; break; } return ret; } private void doUnserialize(PHPStackFrame stack, Vector vecVars, PHPVariable parent) throws DebugException { int i, elements= 0; PHPVariable newVar= null; String value= new String(""); String name= new String(""); String tmp= new String(""); String[] tmpSplit; if(finalPos > serGlobals.length() || serGlobals.equals("") || serGlobals.substring(finalPos).equals("")) return; isRef= false; hasChildren= false; isObject= false; name= readValue(serGlobals.substring(finalPos)); if(hasChildren) { // main array if(refCounter == 0) { value= name; name= ""; } } else { hasChildren= false; isRef= false; value= readValue(serGlobals.substring(finalPos)); // replaceAll doesn't work, why??? tmpSplit= value.split("\\\\"); value= ""; for(i= 0; i < tmpSplit.length; i++) { value= value + tmpSplit[i]; if(!tmpSplit[i].equals("")) { if(i < (tmpSplit.length - 1)) { value= value + "\\"; } } } } if(!name.equals("")) { if(isRef) { PHPVariable varPHP; for(i=0; i < vecVars.size(); i++) { varPHP= (PHPVariable) vecVars.get(i); if(varPHP.getObjectId().equals(value)) { newVar= new PHPVariable(stack, name, "local", true, (PHPValue)varPHP.getValue()); break; } } if(newVar == null) { newVar= new PHPVariable(stack, name, "local", false, null); } } else { refCounter++; newVar= new PHPVariable(stack, name, "local", value, typeRead, hasChildren, Integer.toString(refCounter), className); } newVar.setParent(parent); vecVars.add(newVar); } if(hasChildren) { elements= Integer.parseInt(value); for(i=0; i < elements; i++) doUnserialize(stack, vecVars, newVar); // skip "}" finalPos += 1; } } public int readResponse() throws IOException { int bytesToRead=0, nextFrame=0, i=0, cmdReceived=0, stackIndex=0; char[] dbg_header_struct_read= new char[16]; int[] dbg_header_struct= new int[4]; int[] dbg_bpl_tmp= new int[10]; int[] dbg_frame= new int[2]; int[] dbg_eval_tmp= new int[3]; Vector rawList= new Vector(); Vector stackList= new Vector(); PHPStackFrame[] newStackList; rawList.clear(); stackList.clear(); // Read from input while(readInput(dbg_header_struct_read, 16) != 0) { dbg_header_struct[0] = PHPDBGBase.Char4ToInt(dbg_header_struct_read, 0); dbg_header_struct[1] = PHPDBGBase.Char4ToInt(dbg_header_struct_read, 4); dbg_header_struct[2] = PHPDBGBase.Char4ToInt(dbg_header_struct_read, 8); dbg_header_struct[3] = PHPDBGBase.Char4ToInt(dbg_header_struct_read, 12); // Check DBG sync bytes if(dbg_header_struct[0] != 0x5953) return 0; cmdReceived= dbg_header_struct[1]; bytesToRead= dbg_header_struct[3]; //System.out.println("Response Received: " + cmdReceived); char[] entirePack= new char[bytesToRead]; if(bytesToRead > 0) { if(readInput(entirePack, bytesToRead) < bytesToRead) return 0; } // First process frames nextFrame= 0; while(nextFrame < bytesToRead) { dbg_frame[0] = PHPDBGBase.Char4ToInt(entirePack, nextFrame); // frame name dbg_frame[1] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 4); // frame size nextFrame += 8; if(dbg_frame[1] == 0) return 0; switch(dbg_frame[0]) { case PHPDBGBase.FRAME_STACK: int[] dbg_stack_new= new int[4]; dbg_stack_new[0] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0); // line no dbg_stack_new[1] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 4); // mod no dbg_stack_new[2] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 8); // scope id dbg_stack_new[3] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 12); // id of description string stackIndex++; if(dbg_stack_new[1] != 0) { PHPStackFrame newStack= new PHPStackFrame(null, getModByNo(dbg_stack_new[1]), dbg_stack_new[0], stackIndex, getRawFrameData(entirePack, dbg_stack_new[3]), dbg_stack_new[1]); stackList.add(newStack); } break; case PHPDBGBase.FRAME_SOURCE: break; case PHPDBGBase.FRAME_SRC_TREE: break; case PHPDBGBase.FRAME_RAWDATA: break; case PHPDBGBase.FRAME_ERROR: break; case PHPDBGBase.FRAME_EVAL: String evalString= new String(""); dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0); // istr dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 4); // iresult dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 8); // ierror evalRet= getRawFrameData(entirePack, dbg_eval_tmp[1]); evalString= getRawFrameData(entirePack, dbg_eval_tmp[0]); serGlobals= evalRet; break; case PHPDBGBase.FRAME_BPS: break; case PHPDBGBase.FRAME_BPL: int[] dbg_bpl_new= new int[10]; dbg_bpl_new[0] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0); dbg_bpl_new[1] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 4); dbg_bpl_new[2] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 8); dbg_bpl_new[3] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 12); dbg_bpl_new[4] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 16); dbg_bpl_new[5] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 20); dbg_bpl_new[6] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 24); dbg_bpl_new[7] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 28); dbg_bpl_new[8] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 32); dbg_bpl_new[9] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 36); // look if breakpoint already exists in vector for(i=0; i < DBGBPList.size(); i++) { dbg_bpl_tmp= (int[]) DBGBPList.get(i); if(dbg_bpl_tmp[8] == dbg_bpl_new[8]) { DBGBPList.remove(i); break; } } // add breakpoint to vector DBGBPList.add(dbg_bpl_new); copyToLastBP(dbg_bpl_new); // mod no returned? if(getModByNo(dbg_bpl_new[0]).equals("")) { String fileName= new String(getRawFrameData(entirePack, dbg_bpl_new[2])); // Remove '\0' char if(fileName.length() > 0) fileName= fileName.substring(0, fileName.length() - 1); if(dbg_bpl_new[0] != 0) { PHPDBGMod modNew= new PHPDBGMod(dbg_bpl_new[0], fileName); DBGMods.add(modNew); } } break; case PHPDBGBase.FRAME_VER: break; case PHPDBGBase.FRAME_SID: break; case PHPDBGBase.FRAME_SRCLINESINFO: break; case PHPDBGBase.FRAME_SRCCTXINFO: break; case PHPDBGBase.FRAME_LOG: break; case PHPDBGBase.FRAME_PROF: break; case PHPDBGBase.FRAME_PROF_C: break; case PHPDBGBase.FRAME_SET_OPT: break; } // go to next frame nextFrame += dbg_frame[1]; } // Now process command switch(cmdReceived) { case PHPDBGBase.DBGC_REPLY: break; case PHPDBGBase.DBGC_STARTUP: break; case PHPDBGBase.DBGC_END: sessionEnded= true; break; case PHPDBGBase.DBGC_BREAKPOINT: newStackList= new PHPStackFrame[stackList.size()]; newStackList= (PHPStackFrame[]) stackList.toArray(newStackList); DBGStackList= newStackList; BPUnderHit= getBPUnderHit(); break; case PHPDBGBase.DBGC_STEPINTO_DONE: case PHPDBGBase.DBGC_STEPOVER_DONE: case PHPDBGBase.DBGC_STEPOUT_DONE: case PHPDBGBase.DBGC_EMBEDDED_BREAK: BPUnderHit= 1; newStackList= new PHPStackFrame[stackList.size()]; newStackList= (PHPStackFrame[]) stackList.toArray(newStackList); DBGStackList= newStackList; break; case PHPDBGBase.DBGC_ERROR: newStackList= new PHPStackFrame[stackList.size()]; newStackList= (PHPStackFrame[]) stackList.toArray(newStackList); DBGStackList= newStackList; break; case PHPDBGBase.DBGC_LOG: break; case PHPDBGBase.DBGC_SID: break; case PHPDBGBase.DBGC_PAUSE: break; } } return cmdReceived; } public PHPStackFrame[] getStackList() { return DBGStackList; } private int readInput(char[] buffer, int bytes) throws IOException { int bytesRead= 0; for(int i=0; i < bytes; i++) { if(in.ready()) { buffer[i]= (char) (in.read() & 0x00FF); bytesRead++; } else break; } return bytesRead; } public void setShouldStop() { this.shouldStop= true; } public void waitResponse(long milliseconds) throws IOException { long timeout= System.currentTimeMillis() + milliseconds; while(System.currentTimeMillis() < timeout) { if(in.ready() || shouldStop) { break; } } } }