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 **********************************************************************/
11 package net.sourceforge.phpdt.internal.debug.core;
13 import java.io.IOException;
14 import java.io.BufferedReader;
15 import java.io.OutputStream;
16 import java.util.Vector;
17 import java.lang.System;
18 import org.eclipse.debug.core.DebugException;
19 import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame;
20 import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable;
21 import net.sourceforge.phpdt.internal.debug.core.model.PHPValue;
22 import net.sourceforge.phpdt.internal.debug.core.PHPDBGMod;
24 public class PHPDBGInterface {
27 public boolean sessionEnded= false;
28 public int sessType= -1;
29 public int BPUnderHit= 0;
30 public String sessID= new String();
33 private int[] LastBPRead= new int[10];
34 private Vector DBGBPList= new Vector();
35 private PHPStackFrame[] DBGStackList;
36 private PHPVariable[] DBGVariableList;
37 private Vector DBGMods= new Vector();
38 private Vector DBGVars= new Vector();
39 private BufferedReader in;
40 private OutputStream os;
41 private boolean shouldStop= false, isRef= false, hasChildren= false, isObject= false;
42 private String evalRet= new String("");
43 private String serGlobals= new String("");
44 private String typeRead= new String("");
45 private String className= new String("");
46 private int finalPos=0, refCounter=0, rawCounter=1000;
48 public PHPDBGInterface(BufferedReader in, OutputStream os) {
54 public int addBreakpoint(String mod_name, int line) throws IOException {
55 return setBreakpoint(mod_name, "", line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, 0, 0, 0, 0);
58 public void removeBreakpoint(String mod_name, int line, int bpNo) throws IOException {
59 setBreakpoint(mod_name, "", line, PHPDBGBase.BPS_DISABLED, 0, 0, 0, bpNo, 0);
62 public void requestDBGVersion() throws IOException {
63 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
64 PHPDBGFrame DBGFrame= new PHPDBGFrame(PHPDBGBase.FRAME_VER);
66 DBGPacket.addFrame(DBGFrame);
68 DBGPacket.sendPacket(os);
71 public void addDBGModName(String modName) throws IOException {
72 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
73 PHPDBGFrame DBGFrame= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
76 DBGFrame.addInt(rawCounter); // FRAME_RAWDATA ID
77 DBGFrame.addInt(modName.length() + 1); // length of rawdata (+ null char)
78 DBGFrame.addString(modName); // file name
79 DBGFrame.addChar('\0'); // null char
81 DBGPacket.addFrame(DBGFrame);
83 DBGPacket.sendPacket(os);
86 // Returns DBG Breakpoint ID
87 private int setBreakpoint(String mod_name, String condition, int line, int state, int istemp, int hitcount, int skiphits, int bpno, int isunderhit) throws IOException {
90 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
91 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_BPS);
92 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
94 modNo= getModByName(mod_name);
97 DBGFrame1.addInt(modNo); // mod number
99 DBGFrame1.addInt(0); // mod number (0 use file name)
102 DBGFrame1.addInt(line); // line number
105 DBGFrame1.addInt(0); // use mod number
108 DBGFrame1.addInt(rawCounter); // ID of FRAME_RAWDATA to send file name
111 DBGFrame1.addInt(state); // state BPS_*
112 DBGFrame1.addInt(istemp); // istemp
113 DBGFrame1.addInt(hitcount); // hit count
114 DBGFrame1.addInt(skiphits); // skip hits
115 DBGFrame1.addInt(0); // ID of condition
116 DBGFrame1.addInt(bpno); // breakpoint number
117 DBGFrame1.addInt(isunderhit); // is under hit
120 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
121 DBGFrame2.addInt(mod_name.length() + 1); // length of rawdata (+ null char)
122 DBGFrame2.addString(mod_name); // file name
123 DBGFrame2.addChar('\0'); // null char
124 // First add file name data
125 DBGPacket.addFrame(DBGFrame2);
128 // Second add command data
129 DBGPacket.addFrame(DBGFrame1);
131 DBGPacket.sendPacket(os);
135 // Wait response (1 second) and read response
139 return LastBPRead[8];
142 private void clearLastBP() {
145 for(i=0; i < LastBPRead.length; i++)
149 private void copyToLastBP(int[] BPBody) {
152 for(i=0; i < LastBPRead.length; i++)
153 LastBPRead[i]= BPBody[i];
156 public void continueExecution() throws IOException {
158 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_CONTINUE);
159 DBGPacket.sendPacket(os);
162 private int getBPUnderHit() {
164 int[] dbg_bpl_body= new int[10];
166 // look for bp under hit
167 for(i=0; i < DBGBPList.size(); i++) {
168 dbg_bpl_body= (int[]) DBGBPList.get(i);
169 if(dbg_bpl_body[9] == 1) {
170 BPUnder= dbg_bpl_body[8];
176 public void stepInto() throws IOException {
178 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_STEPINTO);
179 DBGPacket.sendPacket(os);
182 public void stepOver() throws IOException {
184 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_STEPOVER);
185 DBGPacket.sendPacket(os);
188 public void stepOut() throws IOException {
190 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_STEPOUT);
191 DBGPacket.sendPacket(os);
194 public void stopExecution() throws IOException {
196 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_STOP);
197 DBGPacket.sendPacket(os);
200 public PHPVariable[] getVariables(PHPStackFrame stack) throws IOException, DebugException {
201 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
202 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
203 //PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
205 DBGFrame1.addInt(0); // istr = raw data ID
206 DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth
209 String evalBlock= new String("$GLOBALS");
210 DBGFrame2.addInt(1); // FRAME_RAWDATA ID
211 DBGFrame2.addInt(evalBlock.length() + 1); // length of rawdata (+ null char)
212 DBGFrame2.addString(evalBlock); // eval block
213 DBGFrame2.addChar('\0'); // null char
217 DBGPacket.addFrame(DBGFrame1);
219 DBGPacket.sendPacket(os);
224 // Process serialized variables
225 DBGVariableList= procVars(stack);
227 return DBGVariableList;
230 public void evalBlock(String evalString) throws IOException, DebugException {
231 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
232 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
233 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
236 DBGFrame1.addInt(rawCounter); // istr = raw data ID
237 DBGFrame1.addInt(1); // scope_id = -1 means current location, 0 never used, +1 first depth
239 DBGFrame2.addInt(rawCounter); // FRAME_RAWDATA ID
240 DBGFrame2.addInt(evalString.length() + 1); // length of rawdata (+ null char)
241 DBGFrame2.addString(evalString); // eval block
242 DBGFrame2.addChar('\0'); // null char
244 // Add raw data first
245 DBGPacket.addFrame(DBGFrame2);
247 DBGPacket.addFrame(DBGFrame1);
249 DBGPacket.sendPacket(os);
255 public void flushAllPackets() throws IOException {
256 while(readResponse() != 0);
259 public String getModByNo(int modNo) {
264 for(i=0; i < DBGMods.size(); i++) {
265 dbg_mod= (PHPDBGMod) DBGMods.get(i);
266 if(dbg_mod.getNo() == modNo) {
267 return dbg_mod.getName();
273 private int getModByName(String modName) {
278 for(i=0; i < DBGMods.size(); i++) {
279 dbg_mod= (PHPDBGMod) DBGMods.get(i);
280 if(dbg_mod.getName().equalsIgnoreCase(modName)) {
281 return dbg_mod.getNo();
287 private String getRawFrameData(char[] framesInfo, int frameNo) {
289 int[] dbg_frame= new int[2];
291 while(nextFrame < framesInfo.length) {
292 dbg_frame[0] = PHPDBGBase.Char4ToInt(framesInfo, nextFrame); // frame name
293 dbg_frame[1] = PHPDBGBase.Char4ToInt(framesInfo, nextFrame + 4); // frame size
296 if(dbg_frame[1] == 0) return "";
298 switch(dbg_frame[0]) {
299 case PHPDBGBase.FRAME_RAWDATA:
300 if(frameNo == PHPDBGBase.Char4ToInt(framesInfo, nextFrame)) {
301 int toRead= PHPDBGBase.Char4ToInt(framesInfo, nextFrame + 4);
302 return String.copyValueOf(framesInfo, nextFrame + 8, toRead);
307 nextFrame += dbg_frame[1];
312 public PHPVariable[] getInstVars(PHPVariable phpVar) throws DebugException {
313 Vector vecVars= new Vector();
314 PHPVariable localPHPVar;
317 // already unserialized
318 for(i=0; i < DBGVars.size(); i++) {
319 localPHPVar= (PHPVariable)DBGVars.get(i);
320 if(localPHPVar.getParent() == phpVar) {
321 vecVars.add(localPHPVar);
324 PHPVariable[] arrVars= new PHPVariable[vecVars.size()];
325 arrVars= (PHPVariable[]) vecVars.toArray(arrVars);
330 private PHPVariable[] procVars(PHPStackFrame stack) throws DebugException {
331 Vector vecVars= new Vector();
336 doUnserialize(stack, vecVars, null);
340 return(getInstVars(null));
343 private String readValue(String serialVars) throws DebugException {
344 int startPos=0, endPos=0, lenStr=0, i=0, elements=0;
345 String ret= new String("");
347 switch(serialVars.charAt(0)) {
348 case 'a': // associative array, a:elements:{[index][value]...}
351 endPos= serialVars.indexOf(':', startPos + 1);
352 if(endPos == -1) return "";
353 finalPos += endPos + 2;
354 ret= new String(serialVars.substring(startPos + 1, endPos));
358 case 'O': // object, O:name_len:"name":elements:{[attribute][value]...}
362 endPos= serialVars.indexOf(':', startPos + 1);
363 if(endPos == -1) return "";
366 lenStr= Integer.parseInt(serialVars.substring(startPos + 1, endPos));
367 startPos= endPos + 2;
368 endPos= lenStr + startPos;
369 className= new String(serialVars.substring(startPos, endPos).toString());
371 // get num of elements
372 startPos= endPos + 1;
373 endPos= serialVars.indexOf(':', startPos + 1);
374 if(endPos == -1) return "";
375 finalPos += endPos + 2;
376 ret= new String(serialVars.substring(startPos + 1, endPos));
381 case 's': // string, s:length:"data";
384 endPos= serialVars.indexOf(':', startPos + 1);
385 if(endPos == -1) return "";
387 lenStr= Integer.parseInt(serialVars.substring(startPos + 1, endPos));
388 startPos= endPos + 2;
389 endPos= lenStr + startPos;
390 ret= new String(serialVars.substring(startPos, endPos).toString());
391 finalPos += endPos + 2;
393 case 'i': // integer, i:123;
396 endPos= serialVars.indexOf(';', startPos + 1);
397 if(endPos == -1) return "";
399 ret= new String(serialVars.substring(startPos + 1, endPos).toString());
400 finalPos += endPos + 1;
402 case 'd': // double (float), d:1.23;
405 endPos= serialVars.indexOf(';', startPos + 1);
406 if(endPos == -1) return "";
408 ret= new String(serialVars.substring(startPos + 1, endPos).toString());
409 finalPos += endPos + 1;
411 case 'N': // NULL, N;
416 case 'b': // bool, b:0 or 1
418 ret= (serialVars.charAt(2) == '1')?"true":"false";
419 finalPos += endPos + 4;
421 case 'z': // resource, z:typename_len:"typename":valres;
422 typeRead= "resource";
425 endPos= serialVars.indexOf(':', startPos + 1);
426 if(endPos == -1) return "";
428 // get resource type name
429 lenStr= Integer.parseInt(serialVars.substring(startPos + 1, endPos));
430 startPos= endPos + 2;
431 endPos= lenStr + startPos;
432 className= new String(serialVars.substring(startPos, endPos).toString());
434 // get resource value
435 startPos= endPos + 1;
436 endPos= serialVars.indexOf(';', startPos + 1);
437 if(endPos == -1) return "";
438 ret= new String(serialVars.substring(startPos + 1, endPos));
439 finalPos += endPos + 1;
443 typeRead= "reference";
445 endPos= serialVars.indexOf(';', startPos + 1);
446 if(endPos == -1) return "0";
448 ret= new String(serialVars.substring(startPos + 1, endPos));
449 finalPos += endPos + 1;
466 private void doUnserialize(PHPStackFrame stack, Vector vecVars, PHPVariable parent) throws DebugException {
468 PHPVariable newVar= null;
469 String value= new String("");
470 String name= new String("");
471 String tmp= new String("");
474 if(finalPos > serGlobals.length() || serGlobals.equals("") || serGlobals.substring(finalPos).equals("")) return;
479 name= readValue(serGlobals.substring(finalPos));
483 if(refCounter == 0) {
490 value= readValue(serGlobals.substring(finalPos));
491 // replaceAll doesn't work, why???
492 tmpSplit= value.split("\\\\");
494 for(i= 0; i < tmpSplit.length; i++) {
495 value= value + tmpSplit[i];
496 if(!tmpSplit[i].equals("")) {
497 if(i < (tmpSplit.length - 1)) {
504 if(!name.equals("")) {
507 for(i=0; i < vecVars.size(); i++) {
508 varPHP= (PHPVariable) vecVars.get(i);
509 if(varPHP.getObjectId().equals(value)) {
510 newVar= new PHPVariable(stack, name, "local", true, (PHPValue)varPHP.getValue());
515 newVar= new PHPVariable(stack, name, "local", false, null);
519 newVar= new PHPVariable(stack, name, "local", value, typeRead, hasChildren, Integer.toString(refCounter), className);
521 newVar.setParent(parent);
525 elements= Integer.parseInt(value);
526 for(i=0; i < elements; i++)
527 doUnserialize(stack, vecVars, newVar);
534 public int readResponse() throws IOException {
535 int bytesToRead=0, nextFrame=0, i=0, cmdReceived=0, stackIndex=0;
536 char[] dbg_header_struct_read= new char[16];
537 int[] dbg_header_struct= new int[4];
538 int[] dbg_bpl_tmp= new int[10];
539 int[] dbg_frame= new int[2];
540 int[] dbg_eval_tmp= new int[3];
541 Vector rawList= new Vector();
542 Vector stackList= new Vector();
543 PHPStackFrame[] newStackList;
548 while(readInput(dbg_header_struct_read, 16) != 0) {
549 dbg_header_struct[0] = PHPDBGBase.Char4ToInt(dbg_header_struct_read, 0);
550 dbg_header_struct[1] = PHPDBGBase.Char4ToInt(dbg_header_struct_read, 4);
551 dbg_header_struct[2] = PHPDBGBase.Char4ToInt(dbg_header_struct_read, 8);
552 dbg_header_struct[3] = PHPDBGBase.Char4ToInt(dbg_header_struct_read, 12);
554 // Check DBG sync bytes
555 if(dbg_header_struct[0] != 0x5953) return 0;
557 cmdReceived= dbg_header_struct[1];
558 bytesToRead= dbg_header_struct[3];
560 //System.out.println("Response Received: " + cmdReceived);
561 char[] entirePack= new char[bytesToRead];
563 if(bytesToRead > 0) {
564 if(readInput(entirePack, bytesToRead) < bytesToRead) return 0;
567 // First process frames
569 while(nextFrame < bytesToRead) {
570 dbg_frame[0] = PHPDBGBase.Char4ToInt(entirePack, nextFrame); // frame name
571 dbg_frame[1] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 4); // frame size
573 if(dbg_frame[1] == 0) return 0;
574 switch(dbg_frame[0]) {
575 case PHPDBGBase.FRAME_STACK:
576 int[] dbg_stack_new= new int[4];
577 dbg_stack_new[0] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0); // line no
578 dbg_stack_new[1] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 4); // mod no
579 dbg_stack_new[2] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 8); // scope id
580 dbg_stack_new[3] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 12); // id of description string
583 if(dbg_stack_new[1] != 0) {
584 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]);
585 stackList.add(newStack);
588 case PHPDBGBase.FRAME_SOURCE:
590 case PHPDBGBase.FRAME_SRC_TREE:
592 case PHPDBGBase.FRAME_RAWDATA:
594 case PHPDBGBase.FRAME_ERROR:
596 case PHPDBGBase.FRAME_EVAL:
597 String evalString= new String("");
598 dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0); // istr
599 dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 4); // iresult
600 dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 8); // ierror
602 evalRet= getRawFrameData(entirePack, dbg_eval_tmp[1]);
603 evalString= getRawFrameData(entirePack, dbg_eval_tmp[0]);
606 case PHPDBGBase.FRAME_BPS:
608 case PHPDBGBase.FRAME_BPL:
609 int[] dbg_bpl_new= new int[10];
610 dbg_bpl_new[0] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0);
611 dbg_bpl_new[1] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 4);
612 dbg_bpl_new[2] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 8);
613 dbg_bpl_new[3] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 12);
614 dbg_bpl_new[4] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 16);
615 dbg_bpl_new[5] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 20);
616 dbg_bpl_new[6] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 24);
617 dbg_bpl_new[7] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 28);
618 dbg_bpl_new[8] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 32);
619 dbg_bpl_new[9] = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 36);
621 // look if breakpoint already exists in vector
622 for(i=0; i < DBGBPList.size(); i++) {
623 dbg_bpl_tmp= (int[]) DBGBPList.get(i);
624 if(dbg_bpl_tmp[8] == dbg_bpl_new[8]) {
630 // add breakpoint to vector
631 DBGBPList.add(dbg_bpl_new);
632 copyToLastBP(dbg_bpl_new);
635 if(getModByNo(dbg_bpl_new[0]).equals("")) {
636 String fileName= new String(getRawFrameData(entirePack, dbg_bpl_new[2]));
638 if(fileName.length() > 0) fileName= fileName.substring(0, fileName.length() - 1);
639 if(dbg_bpl_new[0] != 0) {
640 PHPDBGMod modNew= new PHPDBGMod(dbg_bpl_new[0], fileName);
645 case PHPDBGBase.FRAME_VER:
647 case PHPDBGBase.FRAME_SID:
649 case PHPDBGBase.FRAME_SRCLINESINFO:
651 case PHPDBGBase.FRAME_SRCCTXINFO:
653 case PHPDBGBase.FRAME_LOG:
655 case PHPDBGBase.FRAME_PROF:
657 case PHPDBGBase.FRAME_PROF_C:
659 case PHPDBGBase.FRAME_SET_OPT:
663 nextFrame += dbg_frame[1];
666 // Now process command
667 switch(cmdReceived) {
668 case PHPDBGBase.DBGC_REPLY:
670 case PHPDBGBase.DBGC_STARTUP:
672 case PHPDBGBase.DBGC_END:
675 case PHPDBGBase.DBGC_BREAKPOINT:
676 newStackList= new PHPStackFrame[stackList.size()];
677 newStackList= (PHPStackFrame[]) stackList.toArray(newStackList);
678 DBGStackList= newStackList;
679 BPUnderHit= getBPUnderHit();
681 case PHPDBGBase.DBGC_STEPINTO_DONE:
682 case PHPDBGBase.DBGC_STEPOVER_DONE:
683 case PHPDBGBase.DBGC_STEPOUT_DONE:
684 case PHPDBGBase.DBGC_EMBEDDED_BREAK:
686 newStackList= new PHPStackFrame[stackList.size()];
687 newStackList= (PHPStackFrame[]) stackList.toArray(newStackList);
688 DBGStackList= newStackList;
690 case PHPDBGBase.DBGC_ERROR:
691 newStackList= new PHPStackFrame[stackList.size()];
692 newStackList= (PHPStackFrame[]) stackList.toArray(newStackList);
693 DBGStackList= newStackList;
695 case PHPDBGBase.DBGC_LOG:
697 case PHPDBGBase.DBGC_SID:
699 case PHPDBGBase.DBGC_PAUSE:
707 public PHPStackFrame[] getStackList() {
711 private int readInput(char[] buffer, int bytes) throws IOException {
714 for(int i=0; i < bytes; i++) {
716 buffer[i]= (char) (in.read() & 0x00FF);
725 public void setShouldStop() {
726 this.shouldStop= true;
729 public void waitResponse(long milliseconds) throws IOException {
730 long timeout= System.currentTimeMillis() + milliseconds;
731 while(System.currentTimeMillis() < timeout) {
732 if(in.ready() || shouldStop) {