]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/PHPDebugger.py
   1 #--------------------------------------------------------------------------- 
   3 # Purpose:      php dbg client and supporting code 
   4 # Author:       Matt Fryer, Kevin Wang 
   6 # Copyright:    (c) 2006 ActiveGrid, Inc. 
   7 # License:      wxWindows License 
   8 #--------------------------------------------------------------------------- 
  17 import DebuggerService
 
  18 import activegrid
.util
.sysutils 
as sysutils
 
  21 DBGC_REPLY                              
= 0x0               # reply to previous DBGA_REQUEST request 
  22 DBGC_STARTUP                            
= 0x0001            # script startup 
  23 DBGC_END                                
= 0x0002            # script done 
  24 DBGC_BREAKPOINT                         
= 0x0003            # user definded breakpoint occured 
  25 DBGC_STEPINTO_DONE                      
= 0x0004            # step to the next statement is completed 
  26 DBGC_STEPOVER_DONE                      
= 0x0005            # step to the next statement is completed 
  27 DBGC_STEPOUT_DONE                       
= 0x0006            # step to the next statement is completed 
  28 DBGC_EMBEDDED_BREAK                     
= 0x0007            # breakpoint caused by DebugBreak() function 
  29 DBGC_ERROR                              
= 0x0010            # error occured 
  30 DBGC_LOG                                
= 0x0011            # logging support 
  31 DBGC_SID                                
= 0x0012            # send SID 
  32 DBGC_PAUSE                              
= 0x0013            # pause current session as soon as possible 
  33 DBGC_AG_SHUTDOWN_REQ                    
= 0x0201            # special ActiveGrid UI shutdown listening thread command 
  36 FRAME_STACK                             
= 100000            # "call:stack" - e.g. backtrace 
  37 FRAME_SOURCE                            
= 100100            # source text 
  38 FRAME_SRC_TREE                          
= 100200            # tree of source files 
  39 FRAME_RAWDATA                           
= 100300            # raw data or string 
  40 FRAME_ERROR                             
= 100400            # error notification 
  41 FRAME_EVAL                              
= 100500            # evaluating/watching 
  42 FRAME_BPS                               
= 100600            # set/remove breakpoint 
  43 FRAME_BPL                               
= 100700            # breakpoint(s) request = get the list 
  44 FRAME_VER                               
= 100800            # version request 
  45 FRAME_SID                               
= 100900            # session id info 
  46 FRAME_SRCLINESINFO                      
= 101000            # source lines info 
  47 FRAME_SRCCTXINFO                        
= 101100            # source contexts info 
  48 FRAME_LOG                               
= 101200            # logging 
  49 FRAME_PROF                              
= 101300            # profiler 
  50 FRAME_PROF_C                            
= 101400            # profiler counter/accuracy 
  51 FRAME_SET_OPT                           
= 101500            # set/update options 
  54 DBGF_STARTED                            
= 0x0001            # debugger has been started 
  55 DBGF_FINISHED                           
= 0x0002            # DBGC_END notification has been sent 
  56 DBGF_WAITACK                            
= 0x0004            # awaiting replay|request 
  57 DBGF_UNSYNC                             
= 0x0008            # protocol has been unsynchronized 
  58 DBGF_REQUESTPENDING                     
= 0x0010            # Debug session request pending 
  59 DBGF_REQUESTFOUND                       
= 0x0020            # Debug session request found 
  60 DBGF_REJECTIONFOUND                     
= 0x0040            # DBGSESSID=-1 found - session rejection 
  68 E_CORE_WARNING                          
= 1 << 5 
  69 E_COMPILE_ERROR                         
= 1 << 6 
  70 E_COMPILE_WARNING                       
= 1 << 7 
  72 E_USER_WARNING                          
= 1 << 9 
  73 E_USER_NOTICE                           
= 1 << 10 
  79 BPS_UNRESOLVED                          
= 0x100 
  83 DBG_SYNC2_STR                           
= chr(0) + chr(0) + chr(89) + chr(83) 
  84 RESPONSE_HEADER_SIZE                    
= 16 
  88 def myprint(format
, vlist
=None): 
  97 # 4 Char's to an Integer 
  99 def C4ToInt(ch
, startPos
): 
 103     retval 
= retval 
+ (CharToInt(ch
[pos
]) << 24) 
 105     retval 
= retval 
+ (CharToInt(ch
[pos
]) << 16) 
 107     retval 
= retval 
+ (CharToInt(ch
[pos
]) << 8) 
 109     retval 
= retval 
+ (CharToInt(ch
[pos
]) << 0) 
 115     return int((ord(ch
) & 0x00FF)); 
 119 # An Integer to 4 Char's 
 122     retval  
= chr((num 
>> 24) & 0x00FF) 
 123     retval 
+= chr((num 
>> 16) & 0x00FF) 
 124     retval 
+= chr((num 
>> 8 ) & 0x00FF) 
 125     retval 
+= chr((num 
>> 0 ) & 0x00FF) 
 130 DBGA_CONTINUE                           
= IntToC4(0x8001) 
 131 DBGA_STOP                               
= IntToC4(0x8002) 
 132 DBGA_STEPINTO                           
= IntToC4(0x8003) 
 133 DBGA_STEPOVER                           
= IntToC4(0x8004) 
 134 DBGA_STEPOUT                            
= IntToC4(0x8005) 
 135 DBGA_IGNORE                             
= IntToC4(0x8006) 
 136 DBGA_REQUEST                            
= IntToC4(0x8010) 
 139 def getCommandString(code
): 
 140     if code 
== DBGC_REPLY
: 
 142     elif code 
== DBGC_STARTUP
: 
 144     elif code 
== DBGC_END
: 
 146     elif code 
== DBGC_BREAKPOINT
: 
 148     elif code 
== DBGC_STEPINTO_DONE
: 
 149         return "STEPINTO DONE" 
 150     elif code 
== DBGC_STEPOVER_DONE
: 
 151         return "STEPOVER DONE" 
 152     elif code 
== DBGC_STEPOUT_DONE
: 
 153         return "STEPOUT DONE" 
 154     elif code 
== DBGC_EMBEDDED_BREAK
: 
 155         return "EMBEDDED BREAK" 
 156     elif code 
== DBGC_PAUSE
: 
 158     elif code 
== DBGC_ERROR
: 
 160     elif code 
== DBGC_LOG
: 
 162     elif code 
== DBGC_SID
: 
 164     elif code 
== DBGC_AG_SHUTDOWN_REQ
: 
 165         return "AG SHUTDOWN REQ" 
 168 def reportFlags(flagsValue
): 
 170     if flagsValue 
& DBGF_STARTED
:                  # debugger has been started 
 171         flagsRetVal 
+= "started+" 
 172     if flagsValue 
& DBGF_FINISHED
:                 # DBGC_END notification has been sent 
 173         flagsRetVal 
+= "finished+" 
 174     if flagsValue 
& DBGF_WAITACK
:                  # awaiting replay|request 
 175         flagsRetVal 
+= "awaiting ack+" 
 176     if flagsValue 
& DBGF_UNSYNC
:                   # protocol has been unsynchronized 
 177         flagsRetVal 
+= "protocol unsynchronized+" 
 178     if flagsValue 
& DBGF_REQUESTPENDING
:           # Debug session request pending 
 179         flagsRetVal 
+= "request pending+" 
 180     if flagsValue 
& DBGF_REQUESTFOUND
:             # Debug session request found 
 181         flagsRetVal 
+= "request found+" 
 182     if flagsValue 
& DBGF_REJECTIONFOUND 
:          # DBGSESSID=-1 found - session rejection 
 183         flagsRetVal 
+= "session rejection+" 
 187 def getErrorTypeString(code
): 
 190     elif code 
== E_WARNING
: 
 192     elif code 
== E_PARSE
: 
 193          return "[Parse Error]" 
 194     elif code 
== E_NOTICE
: 
 196     elif code 
== E_CORE_ERROR
: 
 197         return "[Core Error]" 
 198     elif code 
== E_CORE_WARNING
: 
 199         return "[Core Warning]" 
 200     elif code 
== E_COMPILE_ERROR
: 
 201         return  "[Compile Error]" 
 202     elif code 
== E_COMPILE_WARNING
: 
 203         return  "[Compile Warning]" 
 204     elif code 
== E_USER_ERROR
: 
 205         return  "[User Error]" 
 206     elif code 
== E_USER_WARNING
: 
 207         return  "[User Warning]" 
 208     elif code 
== E_USER_NOTICE
: 
 209         return  "[User Notice]" 
 211         return "[Unexpected Error]" 
 214 class ResponseHeader(object): 
 215     def __init__(self
, conn
, blocking 
= False): 
 217         receivedData 
= conn
.recv(RESPONSE_HEADER_SIZE
, blocking
) 
 220             myprint("Tried to get %d bytes of PHP DBG header, got None\n" % RESPONSE_HEADER_SIZE
) 
 222         elif len(receivedData
) != RESPONSE_HEADER_SIZE
: 
 223             myprint("Tried to get %d bytes of PHP DBG header, got %d\n" % (RESPONSE_HEADER_SIZE
, len(receivedData
))) 
 226         self
.sync    
= C4ToInt(receivedData
, 0) 
 227         self
.command 
= C4ToInt(receivedData
, 4) 
 228         self
.flags   
= C4ToInt(receivedData
, 8) 
 229         self
.toRead  
= C4ToInt(receivedData
, 12) 
 231         myprint("ResponseHeader: sync=%x, command=%s, flags=(%s), toRead=%s\n", (self
.sync
, getCommandString(self
.command
), reportFlags(self
.flags
), self
.toRead
)) 
 232         if self
.sync 
!= DBG_SYNC
: 
 233             myprint("Sync wrong for header! Expected %x, got %s\n" % (DBG_SYNC
, self
.sync
)) 
 239 class ResponsePacketFrame(object): 
 240     def __init__(self
, conn
, size
, data
, blocking 
= False): 
 247             newlyReceived 
= False 
 253                 oneChunk  
= conn
.recv(sizeToReceive
, blocking
) 
 254                 sizeReceived 
= len(oneChunk
) 
 256                     self
.data 
= self
.data 
+ oneChunk
 
 258                 if sizeReceived 
< sizeToReceive
: 
 259                     sizeToReceive 
= sizeToReceive 
- sizeReceived
 
 264             if len(self
.data
) != size
: 
 265                 myprint("Expected to get %d bytes of a PHP DBG packet, got %d\n" % (size
, len(self
.data
))) 
 270         self
.frameName 
= C4ToInt(self
.data
, 0) 
 271         self
.frameSize 
= C4ToInt(self
.data
, 4) 
 273             myprint("Newly received ResponsePacketFrame: frameName=%d, frameSize=%d", (self
.frameName
, self
.frameSize
)) 
 275             myprint("Created from existing ResponsePacketFrame: frameName=%d, frameSize=%d", (self
.frameName
, self
.frameSize
)) 
 277         if self
.frameSize 
== 0: 
 281         self
.totalDataLen 
= len(self
.data
) 
 282         self
.length       
= 8 + self
.frameSize
 
 284         myprint("new ResponsePacketFrame: currPos=%s, totalDataLen=%s, length=%s", (repr(self
.currPos
), repr(self
.totalDataLen
), repr(self
.length
))) 
 287     def getNextInt(self
): 
 288         myprint("getNextInt(): currPos=%s, totalDataLen=%s, length=%s", (repr(self
.currPos
), repr(self
.totalDataLen
), repr(self
.length
))) 
 289         if self
.isValid 
and self
.currPos 
+ 4 <= self
.length
: 
 290             val 
= C4ToInt(self
.data
, self
.currPos
) 
 291             self
.currPos 
= self
.currPos 
+ 4 
 292             myprint("getNextInt(): got an integar: %s", repr(val
)) 
 295             return self
._errorReturn
("getNextInt(): no more integar available with current frame: ") 
 297     def getNextString(self
, strLen
): 
 298         endPos 
= self
.currPos 
+ strLen
 
 299         if self
.isValid 
and endPos 
<= self
.length
: 
 301             # Trim the ending '\0'.  TODO: confirm this applies to all raw string data. 
 303             str          = self
.data
[self
.currPos
:endPos 
- 1] 
 304             self
.currPos 
= endPos
 
 305             myprint("getNextString(): got a string: %s", str) 
 308             return self
._errorReturn
("getNextString(): no more string available with current frame: ") 
 310     def getNextFrame(self
, useAbsolutePos 
= False): 
 313             # Skip this frame's header (8 bytes for frameSize and frameSize) and frame data (frameSize). 
 315             self
.currPos 
= self
.length
 
 317         if self
.isValid 
and self
.currPos 
< self
.totalDataLen
: 
 318             return ResponsePacketFrame(None, None, self
.data
[self
.currPos
:]) 
 320             return self
._errorReturn
("getNextFrame(): no more frame available with current frame: ") 
 322     def _errorReturn(self
, preMsg 
= ''): 
 323         myprint(preMsg 
+ "frameName=%s, frameSize=%s, totalDataLen=%s, length=%s, currPos:%s", (repr(self
.frameName
), repr(self
.frameSize
), repr(self
.totalDataLen
), repr(self
.length
), repr(self
.currPos
))) 
 328 class PHPDBGFrame(object): 
 329     FRAME_HEADER_SIZE 
= 8 
 330     def __init__(self
, frameType
): 
 331         self
.frameType 
= IntToC4(frameType
) 
 334     def addInt(self
, intVal
): 
 335         self
.frameData 
= self
.frameData 
+ IntToC4(intVal
) 
 337     def addChar(self
, charVal
): 
 338         self
.frameData 
= self
.frameData 
+ charVal
 
 340     def addStr(self
, string
): 
 342         # Add the trailing '\0'. 
 344         self
.frameData 
= self
.frameData 
+ string 
+ '\0' 
 347         return len(self
.frameData
) + PHPDBGFrame
.FRAME_HEADER_SIZE
 
 349     def writeFrame(self
, conn
): 
 350         header 
= self
.frameType 
+ IntToC4(len(self
.frameData
)) 
 352         conn
.sendall(self
.frameData
) 
 355 class PHPDBGPacket(object): 
 356     def __init__(self
, packetType
): 
 357         self
.header     
= DBG_SYNC2_STR 
+ packetType
 
 361     def addFrame(self
, frame
): 
 362         self
.frames
.append(frame
) 
 363         self
.packetSize 
+= frame
.getSize() 
 365     def sendPacket(self
, conn
, flags 
= 0): 
 366         self
.header 
+= IntToC4(flags
) 
 367         self
.header 
+= IntToC4(self
.packetSize
) 
 368         conn
.sendall(self
.header
) 
 369         for frame 
in self
.frames
: 
 370             frame
.writeFrame(conn
) 
 373 class PHPDBGException(Exception): 
 374     def __init__(self
, msg 
= None, cause 
= None): 
 376             Exception.__init
__(self
) 
 377         elif (cause 
== None): 
 378             Exception.__init
__(self
, msg
) 
 380             Exception.__init
__(self
, "PHPDBGException: message:%s\n, cause:%s" % (msg
, cause
)) 
 383 class PHPDBGConnException(PHPDBGException
): 
 387 class PHPDebuggerCallback(object): 
 392     def __init__(self
, ui
, service
, lsnrHosti
, lsnrPorti
): 
 394         self
.service         
= service
 
 395         self
.lsnrHost        
= lsnrHosti
 
 396         self
.lsnrPort        
= lsnrPorti
 
 398         self
.lsnrAction      
= PHPDebuggerCallback
.ACTION_NONE
 
 399         self
.clearInternals() 
 403     ############################################################################ 
 404     #                      Public callback functions begin 
 409     def ShutdownServer(self
, stopLsnr 
= True): 
 411         # First to tell php debugger to stop execution of the current PHP 
 412         # program.  Disconnect with php dbg module too. 
 417         # Stop debug listener. 
 422     def BreakExecution(self
): 
 423         reqPacket 
= PHPDBGPacket(IntToC4(DBGC_PAUSE
)) 
 426             reqPacket
.sendPacket(self
.lsnrThr
) 
 427             self
.awaitAndHandleResponse() 
 428         except PHPDBGConnException
: 
 429             self
.currConnFinished() 
 432         self
.ui
.LoadPHPFramesList(self
.stackList
) 
 435     def SingleStep(self
): 
 436         reqPacket 
= PHPDBGPacket(DBGA_STEPINTO
) 
 439             reqPacket
.sendPacket(self
.lsnrThr
) 
 440             self
.lastCommand 
= DBGA_STEPINTO
 
 441             self
.awaitAndHandleResponse(blocking 
= True) 
 442         except PHPDBGConnException
: 
 443             self
.currConnFinished() 
 446         self
.ui
.LoadPHPFramesList(self
.stackList
) 
 450         reqPacket 
= PHPDBGPacket(DBGA_STEPOVER
) 
 453             reqPacket
.sendPacket(self
.lsnrThr
) 
 454             self
.lastCommand 
= DBGA_STEPOVER
 
 455             self
.awaitAndHandleResponse(blocking 
= True) 
 456         except PHPDBGConnException
: 
 457             self
.currConnFinished() 
 460         self
.ui
.LoadPHPFramesList(self
.stackList
) 
 464         reqPacket 
= PHPDBGPacket(DBGA_CONTINUE
) 
 467             reqPacket
.sendPacket(self
.lsnrThr
) 
 468             self
.lastCommand 
= DBGA_CONTINUE
 
 469             self
.awaitAndHandleResponse(blocking 
= True) 
 470         except PHPDBGConnException
: 
 471             self
.currConnFinished() 
 474         self
.ui
.LoadPHPFramesList(self
.stackList
) 
 478         reqPacket 
= PHPDBGPacket(DBGA_STEPOUT
) 
 481             reqPacket
.sendPacket(self
.lsnrThr
) 
 482             self
.lastCommand 
= DBGA_STEPOUT
 
 483             self
.awaitAndHandleResponse(blocking 
= True) 
 484         except PHPDBGConnException
: 
 485             self
.currConnFinished() 
 488         self
.ui
.LoadPHPFramesList(self
.stackList
) 
 491     def PushBreakpoints(self
, noRemove 
= False): 
 493         bps     
= self
.service
.GetMasterBreakpointDict() 
 494         for fileName 
in bps
.keys(): 
 495             if fileName
.endswith('.php'): 
 496                 lines 
= bps
[fileName
] 
 501                             # A tuple (fileName, lineNo) is an item which is 
 502                             # used as a key in self.bpDict. 
 504                             tmpList
.append(self
.createBpKey(fileName
, lineNo
)) 
 505                             myprint("PushBreakpoints(): global breakpoint \'%s:%i\'", (fileName
, lineNo
)) 
 508         # Check to see if we have any new breakpoints added. 
 510         for oneKey 
in tmpList
: 
 511             if not self
.bpDict
.has_key(oneKey
): 
 515                 newBp 
= BreakPoint(self
, oneKey
[0], oneKey
[1]) 
 517                 self
.bpDict
[oneKey
] = newBp
 
 518                 myprint("PushBreakpoints(): newly added global breakpoint \'%s:%i\'", (oneKey
[0], oneKey
[1])) 
 524         # Check to see if any bp that is in our list, but not in the latest 
 525         # global list.  If so, it must have been removed recently in the 
 526         # global one.  Remove it from our list and tell php debugger to do 
 530         for oneKey 
in self
.bpDict
.keys(): 
 531             if tmpList
.count(oneKey
) == 0: 
 532                 toRemoveList
.append((oneKey
, self
.bpDict
[oneKey
])) 
 533                 myprint("PushBreakpoints(): recently removed global breakpoint \'%s:%i\'", (oneKey
[0], oneKey
[1])) 
 535         for bp 
in toRemoveList
: 
 537             del self
.bpDict
[bp
[0]] 
 538             myprint("PushBreakpoints(): successfully removed breakpoint \'%s:%i\' from both our local list and php debugger", (bp
[0][0], bp
[0][1])) 
 542     #                      Public callback functions end 
 543     ############################################################################ 
 546     def newConnEventHandler(self
): 
 548         # Ok, we've got a connection from the php debugger, and some initial 
 549         # frame data from it.  Everything is ready and let's make some initial 
 552         self
.clearInternals() 
 555             self
.awaitAndHandleResponse(self
.lsnrThr
.getConnHeader()) 
 556         except PHPDBGConnException
: 
 557             self
.currConnFinished() 
 560         self
.PushBreakpoints(True) 
 561         self
.ui
.LoadPHPFramesList(self
.stackList
) 
 564     # This could be called when this object is constructed or when self is 
 565     # re-initialized after getting a new dbg module connection as a new 
 568     def clearInternals(self
): 
 570         self
.errStackList    
= [] 
 571         self
.stackFrameIndex 
= 0 
 572         self
.isErrStack      
= False 
 575         self
.stopOnError     
= True 
 576         self
.lastCommand     
= None 
 580         self
.rawDataDict     
= {} 
 583         self
.sessEnded       
= False 
 584         self
.frameCounter    
= 1000 
 585         self
.variableList    
= [] 
 590     def initLsnrThr(self
): 
 591         self
.actionEvent 
= threading
.Event() 
 592         self
.lsnrThr     
= PHPDBGLsnrThr(self
, self
.lsnrHost
, self
.lsnrPort
, self
.actionEvent
, self
.ui
) 
 594     def awaitAndHandleResponse(self
, header 
= None, blocking 
= False, disable 
= True, stopping 
= False): 
 596             self
.ui
.DisableWhileDebuggerRunning() 
 598         while self
.readResponse(header
, blocking
) != 0: 
 599             myprint("Waiting for response") 
 602             self
.ui
.DisableAfterStop() 
 604             self
.ui
.EnableWhileDebuggerStopped() 
 606     def requestDBGVersion(self
): 
 610     def getSourceTree(self
): 
 614     def addDBGModName(self
): 
 618     def getNextFrameCounter(self
): 
 619         self
.frameCounter 
= self
.frameCounter 
+ 1 
 620         return self
.frameCounter
 
 622     def getVariables(self
, stack
): 
 623         self
.variableList 
= [] 
 625         reqPacket 
= PHPDBGPacket(DBGA_REQUEST
) 
 626         reqFrame  
= PHPDBGFrame(FRAME_EVAL
) 
 629         reqFrame
.addInt(stack
.getFrameScopeId()) 
 630         reqPacket
.addFrame(reqFrame
) 
 631         myprint("PHPDebuggerCallback::getVariables(): about to send eval request") 
 634             reqPacket
.sendPacket(self
.lsnrThr
) 
 635             self
.awaitAndHandleResponse(disable 
= False) 
 636         except PHPDBGConnException
: 
 637             self
.currConnFinished() 
 638             return self
.variableList
 
 640         myprint("PHPDebuggerCallback::getVariables(): evalRet=%s", self
.evalRet
) 
 641         evalStr 
= PHPDBGEvalString(stack
, self
.evalRet
) 
 643             self
.variableList 
= evalStr
.getVars() 
 644         myprint("PHPDebuggerCallback::getVariables(): about to return") 
 646         return self
.variableList
 
 648     def evalBlock(self
, stack
, evalStr
): 
 649         reqPacket 
= PHPDBGPacket(DBGA_REQUEST
) 
 650         reqFrame1 
= PHPDBGFrame(FRAME_EVAL
) 
 651         reqFrame2 
= PHPDBGFrame(FRAME_RAWDATA
) 
 653         frameID 
= self
.getNextFrameCounter() 
 654         reqFrame1
.addInt(frameID
) 
 657         reqFrame2
.addInt(frameID
) 
 658         reqFrame2
.addInt(len(evalStr
) + 1) 
 659         reqFrame2
.addStr(evalString
) 
 661         reqPacket
.addFrame(reqFrame2
) 
 662         reqPacket
.addFrame(reqFrame1
) 
 665             reqPacket
.sendPacket(self
.lsnrThr
) 
 666             self
.awaitAndHandleResponse(disable 
= False) 
 667         except PHPDBGConnException
: 
 668             self
.currConnFinished() 
 671         evalStr 
= PHPDBGEvalString(stack
, self
.evalRet
) 
 673         return evalStr
.getVars() 
 675     def getBPUnderHit(self
): 
 676         for bp 
in self
.bpDict
.values(): 
 682     def getRawFrameData(self
, frameNo
): 
 683         if self
.rawDataDict
.has_key(frameNo
): 
 685             # Once the frameData is consumed, remove it from rawDataDict. 
 687             return self
.rawDataDict
.pop(frameNo
) 
 690             # TODO: do we need to handle the case when the raw frame data hasn't 
 691             # been received before? 
 695     def getModByNum(self
, modNum
): 
 696         if self
.modDict
.has_key(modNum
): 
 697             return self
.modDict
[modNum
] 
 701     def getModByFileName(self
, fileName
): 
 702         for mn
, fn 
in self
.modDict
.iteritems(): 
 708     def setMod(self
, modNum
, fileName
): 
 709         if modNum 
!= 0 and fileName
: 
 710             self
.modDict
[modNum
] = fileName
 
 714     def readResponse(self
, headeri 
= None, blockingi 
= False): 
 720         self
.isErrStack 
= False 
 721         self
.rawDataDict
.clear() 
 725             # If we have already received the first packet, we can't block any 
 728             if not isFirstPacket
: 
 732             # If this is the first loop and we have a non-empty header passed in, use it.  Otherwise, 
 733             # read in a new header.  For subsequent loops, inHeader is None so we always read a new 
 734             # header from the wire. 
 740                 header   
= ResponseHeader(self
.lsnrThr
, blocking
) 
 742             if not header
.isValid
: 
 745             cmdReceived 
= header
.command
 
 746             frame       
= ResponsePacketFrame(self
.lsnrThr
, header
.toRead
, None, blocking
) 
 747             if not frame
.isValid
: 
 750             isFirstPacket     
= False 
 751             isFirstStackFrame 
= True 
 752             while frame 
and frame
.isValid
: 
 753                 frameName 
= frame
.frameName
 
 754                 if frameName 
== FRAME_STACK
: 
 756                         self
.errStackList 
= self
.handleRespFrameStack(self
.errStackList
, frame
, isFirstStackFrame
) 
 758                         self
.stackList 
= self
.handleRespFrameStack(self
.stackList
, frame
, isFirstStackFrame
) 
 760                     if isFirstStackFrame
: 
 761                         isFirstStackFrame 
= False 
 762                 elif frameName 
== FRAME_SOURCE
: 
 763                     self
.handleRespFrameSource(frame
) 
 764                 elif frameName 
== FRAME_SRC_TREE
: 
 765                     self
.handleRespFrameSrcTree(frame
) 
 766                 elif frameName 
== FRAME_RAWDATA
: 
 767                     self
.handleRespFrameRawdata(frame
) 
 768                 elif frameName 
== FRAME_ERROR
: 
 769                     self
.handleRespFrameError(frame
) 
 770                 elif frameName 
== FRAME_EVAL
: 
 771                     self
.handleRespFrameEval(frame
) 
 772                 elif frameName 
== FRAME_BPS
: 
 773                     self
.handleRespFrameBps(frame
) 
 774                 elif frameName 
== FRAME_BPL
: 
 775                     self
.handleRespFrameBpl(frame
) 
 776                 elif frameName 
== FRAME_VER
: 
 777                     self
.handleRespFrameVer(frame
) 
 778                 elif frameName 
== FRAME_SID
: 
 779                     self
.handleRespFrameSid(frame
) 
 780                 elif frameName 
== FRAME_SRCLINESINFO
: 
 781                     self
.handleRespFrameSrclinesinfo(frame
) 
 782                 elif frameName 
== FRAME_SRCCTXINFO
: 
 783                     self
.handleRespFrameSrcctxinfo(frame
) 
 784                 elif frameName 
== FRAME_LOG
: 
 785                     self
.handleRespFrameLog(frame
) 
 786                 elif frameName 
== FRAME_PROF
: 
 787                     self
.handleRespFrameProf(frame
) 
 788                 elif frameName 
== FRAME_PROF_C
: 
 789                     self
.handleRespFrameProfC(frame
) 
 790                 elif frameName 
== FRAME_SET_OPT
: 
 791                     self
.handleRespFrameSetOpt(frame
) 
 793                     self
.handleRespFrameUnknown(frame
) 
 797                 # After handling of this frame, force frame to point to the 
 798                 # next one based on current frame's absolute size. 
 800                 frame 
= frame
.getNextFrame(True) 
 802             if cmdReceived 
== DBGC_REPLY
: 
 803                 self
.handleRespCmdReply() 
 804             elif cmdReceived 
== DBGC_STARTUP
: 
 805                 self
.handleRespCmdStartup() 
 806             elif cmdReceived 
== DBGC_END
: 
 807                 self
.handleRespCmdEnd() 
 808             elif cmdReceived 
== DBGC_BREAKPOINT
: 
 809                 self
.handleRespCmdBreakpoint() 
 811             elif cmdReceived 
== DBGC_STEPINTO_DONE
: 
 812                 self
.handleRespCmdStepintoDone() 
 813             elif cmdReceived 
== DBGC_STEPOVER_DONE
: 
 814                 self
.handleRespCmdStepoverDone() 
 815             elif cmdReceived 
== DBGC_STEPOUT_DONE
: 
 816                 self
.handleRespCmdStepoutDone() 
 817             elif cmdReceived 
== DBGC_EMBEDDED_BREAK
: 
 818                 self
.handleRespCmdEmbeddedBreak() 
 819             elif cmdReceived 
== DBGC_PAUSE
: 
 820                 self
.handleRespCmdPause() 
 821             elif cmdReceived 
== DBGC_ERROR
: 
 822                 self
.handleRespCmdError() 
 823             elif cmdReceived 
== DBGC_LOG
: 
 824                 self
.handleRespCmdLog() 
 825             elif cmdReceived 
== DBGC_SID
: 
 826                 self
.handleRespCmdSid() 
 828                 self
.handleRespCmdUnknown() 
 832     def handleRespFrameStack(self
, stackList
, frame
, isFirst
): 
 835             self
.stackFrameIndex 
= 0 
 837         lineNo  
= frame
.getNextInt() 
 838         modNo   
= frame
.getNextInt() 
 839         scopeId 
= frame
.getNextInt() 
 840         frameId 
= frame
.getNextInt() 
 842             newStackFrame 
= PHPStackFrame(self
, self
.getModByNum(modNo
), lineNo
, self
.stackFrameIndex
, scopeId
, self
.getRawFrameData(frameId
), modNo
) 
 843             stackList
.append(newStackFrame
) 
 844             self
.stackFrameIndex 
= self
.stackFrameIndex 
+ 1 
 848     def handleRespFrameSource(self
, frame
): 
 849         modNo           
= frame
.getNextInt() 
 850         fromFilePos     
= frame
.getNextInt() 
 851         error           
= frame
.getNextInt() 
 852         fullSize        
= frame
.getNextInt() 
 853         fileNameFrameId 
= frame
.getNextInt() 
 854         textFrameId     
= frame
.getNextInt() 
 856         fileName 
= self
.getModByNum(modNo
) 
 858             self
.setFileMod(modNo
, fileNameFrameId
) 
 861         # TODO: fullSize string and textFrameId are not handled here. 
 865     def handleRespFrameSrcTree(self
, frame
): 
 866         parentModNo     
= frame
.getNextInt() 
 867         parentLineNo    
= frame
.getNextInt() 
 868         modNo           
= frame
.getNextInt() 
 869         fileNameFrameId 
= frame
.getNextInt() 
 871         fileName 
= self
.getModByNum(modNo
) 
 873             self
.setFileMod(modNo
, fileNameFrameId
) 
 877     def handleRespFrameRawdata(self
, frame
): 
 878         frameNo 
= frame
.getNextInt() 
 880             toRead 
= frame
.getNextInt() 
 882                 str = frame
.getNextString(toRead
) 
 883                 self
.rawDataDict
[frameNo
] = str 
 884                 myprint("handleRespFrameRawdata(): added \'%d\'=\'%s\' to rawDataDict.", (frameNo
, str)) 
 888     def handleRespFrameError(self
, frame
): 
 889         self
.isErrStack 
= True 
 894         errInt0         
= frame
.getNextInt() 
 896         # ID of error message. 
 898         errInt1         
= frame
.getNextInt() 
 900         if errInt0 
== E_ERROR
: 
 902         elif errInt0 
== E_WARNING
: 
 903             errIdStr 
= "[Warning]" 
 904         elif errInt0 
== E_PARSE
: 
 905             errIdStr 
= "[Parse Error]" 
 906         elif errInt0 
== E_NOTICE
: 
 907             errIdStr 
= "[Notice]" 
 908         elif errInt0 
== E_CORE_ERROR
: 
 909             errIdStr 
= "[Core Error]" 
 910         elif errInt0 
== E_CORE_WARNING
: 
 911             errIdStr 
= "[Core Warning]" 
 912         elif errInt0 
== E_COMPILE_ERROR
: 
 913             errIdStr 
= "[Compile Error]" 
 914         elif errInt0 
== E_COMPILE_WARNING
: 
 915             errIdStr 
= "[Compile Warning]" 
 916         elif errInt0 
== E_USER_ERROR
: 
 917             errIdStr 
= "[User Error]" 
 918         elif errInt0 
== E_USER_WARNING
: 
 919             errIdStr 
= "[User Warning]" 
 920         elif errInt0 
== E_USER_NOTICE
: 
 921             errIdStr 
= "[User Notice]" 
 923             errIdStr 
= "[Unexpected Error]" 
 925         errMsg 
= self
.getRawFrameData(errInt1
) 
 926         if errMsg 
and len(errMsg
) > 0: 
 927             self
.errStr 
= errIdStr 
+ ": " + errMsg 
+ "\n" 
 929             self
.errStr 
= errIdStr 
+ ": <Invalid Error Message>\n" 
 931         if not self
.stopOnError
: 
 932             if self
.lastCommand 
== DBGA_CONTINUE
: 
 934             elif self
.lastCommand 
== DBGA_STEPINTO
: 
 936             elif self
.lastCommand 
== DBGA_STEPOUT
: 
 938             elif self
.lastCommand 
== DBGA_STEPOVER
: 
 943     def handleRespFrameEval(self
, frame
): 
 944         evalInt0        
= frame
.getNextInt() 
 945         evalInt1        
= frame
.getNextInt() 
 946         evalInt2        
= frame
.getNextInt() 
 947         self
.evalRet    
= self
.getRawFrameData(evalInt1
) 
 948         #TODO: is the following necessary? 
 949         evalStr         
= self
.getRawFrameData(evalInt0
) 
 953     def handleRespFrameBps(self
, frame
): 
 956     def handleRespFrameBpl(self
, frame
): 
 958         # Get this breakpoint. 
 962             dbgBp
.append(frame
.getNextInt()) 
 966             # If filename is sent, get it from the rawDataDict. 
 968             fileName 
= self
.getRawFrameData(dbgBp
[2]) 
 973             # If this filename comes with a mod number, store this 
 974             # modNum/fileName into this session's modDict.  Notice it might 
 975             # overwrite previous value. 
 978                 self
.setMod(dbgBp
[0], fileName
) 
 981             # Use modNum to get the fileName. 
 983             fileName 
= self
.getModByNum(dbgBp
[0]) 
 988             # Couldn't get the filename; nothing we can do with. 
 992         bpKey 
= self
.createBpKey(fileName
, dbgBp
[1]) 
 993         if not self
.bpDict
.has_key(bpKey
): 
 995             # Not in our bp list?  Anyway, create one for it. 
 997             ourBp              
= BreakPoint(self
, fileName
, dbgBp
[1], dbgBp
[0], dbgBp
[3], dbgBp
[4], dbgBp
[5], dbgBp
[6], dbgBp
[7], dbgBp
[8], dbgBp
[9]) 
 998             self
.bpDict
[bpKey
] = ourBp
 
1001             ourBp              
= self
.bpDict
[bpKey
] 
1002             newlyCreated       
= False 
1005         # Update with the latest bp information. 
1007         if not newlyCreated
: 
1012     def handleRespFrameVer(self
, frame
): 
1013         self
.verMajor 
= frame
.getNextInt() 
1014         self
.verMinor 
= frame
.getNextInt() 
1015         verFrameNo    
= frame
.getNextInt() 
1016         self
.verDesc  
= self
.getRawFrameData(verFrameNo
) 
1017         myprint("respFrameVer: verMajor=%s, verMinor=%s, verDesc=%s", (repr(self
.verMajor
), repr(self
.verMinor
), repr(self
.verDesc
))) 
1021     def handleRespFrameSid(self
, frame
): 
1022         self
.sessID   
= frame
.getNextInt() 
1023         self
.sessType 
= frame
.getNextInt() 
1024         myprint("respFrameSid: sessID=%s, sessType=%s", (self
.sessID
, self
.sessType
)) 
1028     def handleRespFrameSrclinesinfo(self
, frame
): 
1031     def handleRespFrameSrcctxinfo(self
, frame
): 
1034     def handleRespFrameLog(self
, frame
): 
1037         # Now we don't do much here besides following the protocol to retrieve 
1040         logId           
= frame
.getNextInt() 
1041         logType         
= frame
.getNextInt() 
1042         modNo           
= frame
.getNextInt() 
1043         lineNo          
= frame
.getNextInt() 
1044         fileNameFrameId 
= frame
.getNextInt() 
1045         extInfo         
= frame
.getNextInt() 
1047         fileName 
= self
.getModByNum(modNo
) 
1049             self
.setFileMod(modNo
, fileNameFrameId
) 
1053     def handleRespFrameProf(self
, frame
): 
1056     def handleRespFrameProfC(self
, frame
): 
1059     def handleRespFrameSetOpt(self
, frame
): 
1062     def handleRespCmdReply(self
): 
1065     def handleRespCmdStartup(self
): 
1068     def handleRespCmdEnd(self
): 
1069         self
.sessEnded 
= True 
1072     def handleRespCmdBreakpoint(self
): 
1075     def handleRespCmdStepintoDone(self
): 
1078     def handleRespCmdStepoverDone(self
): 
1081     def handleRespCmdStepoutDone(self
): 
1084     def handleRespCmdEmbeddedBreak(self
): 
1087     def handleRespCmdPause(self
): 
1090     def handleRespCmdError(self
): 
1093         if len(self
.errStackList
) > 0: 
1094             self
.errStr 
= self
.errStr 
+ "Stack Trace:\n" 
1096         while len(self
.errStackList
) > 0: 
1097             oneStack 
= self
.errStackList
.pop() 
1098             self
.errStr 
= self
.errStr 
+ "%s\n" % oneStack
.getLongDisplayStr() 
1100         self
.ui
.showErrorDialog(self
.errStr
, "PHP Error") 
1101         myprint("Got PHP Error:\n%s", self
.errStr
) 
1105     def handleRespCmdLog(self
): 
1108     def handleRespCmdSid(self
): 
1111     def setFileMod(self
, modNo
, fileNameFrameId
): 
1112         if fileNameFrameId 
!= 0: 
1113             fileName 
= self
.getRawFrameData(fileNameFrameId
) 
1114             if fileName 
and modNo 
!= 0: 
1115                 self
.setMod(modNo
, fileName
) 
1119     def createBpKey(self
, fileName
, lineNo
): 
1121         # This is to work around a bug in dbg module where it changes the path 
1122         # names that we pass to it to lower cases. 
1124         if sysutils
.isWindows(): 
1125             fileName 
= fileName
.lower() 
1127         return (fileName
, lineNo
) 
1129     def setLsnrAction(self
, actioni
): 
1130         self
.lsnrAction 
= actioni
 
1133     def getLsnrAction(self
): 
1134         return self
.lsnrAction
 
1136     def currConnFinished(self
): 
1137         self
.clearInternals() 
1138         self
.setLsnrAction(PHPDebuggerCallback
.ACTION_LISTEN
) 
1139         self
.actionEvent
.set() 
1140         self
.ui
.DisableAfterStop() 
1142     def stopPhpDbg(self
): 
1144         # TODO: should send a request to stop the current running PHP program. 
1145         #       should handle network blocking issue correctly, otherwise, we 
1148         reqPacket 
= PHPDBGPacket(DBGA_STOP
) 
1151             reqPacket
.sendPacket(self
.lsnrThr
) 
1152             self
.awaitAndHandleResponse(stopping 
= True) 
1153         except PHPDBGConnException
: 
1156         self
.currConnFinished() 
1160         if not self
.lsnrThr
: 
1164         # Then we try to stop our listener thread. 
1166         if self
.lsnrThr
.hasBeenConnected(): 
1168             # If the listener thread has already accepted a connection from a 
1169             # php debug module/client, it is sleeping now and wait for this 
1170             # condition object to be set so that it can exit. 
1172             self
.setLsnrAction(PHPDebuggerCallback
.ACTION_STOP
) 
1173             self
.actionEvent
.set() 
1176             # If the listener thread has never been connected from a php debug 
1177             # module/client, it is still blocking on a accept() call.  We 
1178             # connect to it here and send a special shutdown command asking it 
1181             shutdownMessage 
= IntToC4(DBG_SYNC
) + IntToC4(DBGC_AG_SHUTDOWN_REQ
) + IntToC4(0) + IntToC4(0) 
1182             tempSocket      
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
) 
1184                 tempSocket
.connect((self
.lsnrHost
, self
.lsnrPort
)) 
1185                 tempSocket
.sendall(shutdownMessage
) 
1187                 myprint("shutdown connection/send message got exception!") 
1195 class PHPDBGLsnrThr(threading
.Thread
): 
1196     def __init__(self
, interfacei
, hosti
, porti
, actionEventi
, uii
): 
1197         threading
.Thread
.__init
__(self
) 
1198         self
.interface          
= interfacei
 
1199         self
.svrHost            
= hosti
 
1200         self
.svrPort            
= porti
 
1201         self
.actionEvent        
= actionEventi
 
1202         self
.svrSocket          
= None 
1203         self
.clntConn           
= None 
1204         self
.clntAddr           
= None 
1205         self
.nonBlockingTimeout 
= 1 
1206         self
.connHeader         
= None 
1209     def initSvrSocket(self
): 
1210         self
.svrSocket 
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
) 
1211         self
.svrSocket
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_REUSEADDR
, 1) 
1212         self
.svrSocket
.bind((self
.svrHost
, self
.svrPort
)) 
1214     def waitForClntConn(self
): 
1215         self
.svrSocket
.listen(5) 
1216         self
.clntConn
, self
.clntAddr 
= self
.svrSocket
.accept() 
1217         self
.clntConn
.settimeout(self
.nonBlockingTimeout
) 
1221         # Initialize this server socket. 
1223         self
.initSvrSocket() 
1227             # Block until we get a new connection from a php debug client or our 
1228             # debugger ui (with a special shutting down header/command). 
1230             self
.waitForClntConn() 
1233             # Ok, a new connection comes in ...  Read the header to see where it 
1236             self
.connHeader 
= ResponseHeader(self
) 
1237             if self
.connHeader
.command 
== DBGC_AG_SHUTDOWN_REQ
: 
1239                 # This is a special command coming from our UI asking this 
1240                 # thread to exit.  This only happens if after this thread has 
1241                 # been waiting for new connections from PHP debug module, no one 
1242                 # connects, and UI is ready to shutdown this thread. 
1248                 # Tell the main gui thread to handle this new connection. 
1250                 wx
.CallAfter(self
.interface
.newConnEventHandler
) 
1253                 # From now on, PHPDebuggerCallback will communicate with the php 
1254                 # debug module using this thread's clntConn socket.  This thread 
1255                 # itself will keep sleeping until get notified to make some 
1258                 self
.actionEvent
.wait() 
1259                 self
.actionEvent
.clear() 
1261                 action 
= self
.interface
.getLsnrAction() 
1262                 if action 
== PHPDebuggerCallback
.ACTION_STOP
: 
1265                 elif action 
== PHPDebuggerCallback
.ACTION_LISTEN
: 
1267                         self
.clntConn
.shutdown(socket
.SHUT_RDWR
) 
1268                         self
.clntConn
.close() 
1269                         self
.clntConn 
= None 
1277         # Cleanup and ready to exit. 
1279         self
.clntConn
.shutdown(socket
.SHUT_RDWR
) 
1280         self
.clntConn
.close() 
1281         self
.svrSocket
.close() 
1283     def recv(self
, size
, blocking 
= False): 
1285             myprint("recv: trying to receive %d bytes of data ...", size
) 
1287                 self
.clntConn
.settimeout(None) 
1289                 self
.clntConn
.settimeout(self
.nonBlockingTimeout
) 
1292                 rData 
= self
.clntConn
.recv(size
) 
1293             except socket
.timeout
: 
1294                 myprint("recv: got timed out") 
1297                 myprint("recv: got an unexpected exception: %s", sys
.exc_info()[0]) 
1298                 raise PHPDBGConnException
 
1302             raise PHPDBGConnException
 
1304     def sendall(self
, message
): 
1307                 self
.clntConn
.sendall(message
) 
1309                 myprint("sendall: got an unexpected exception: %s", sys
.exc_info()[0]) 
1310                 raise PHPDBGConnException
 
1312             raise PHPDBGConnException
 
1314     def hasBeenConnected(self
): 
1315         return self
.clntConn 
!= None 
1317     def getConnHeader(self
): 
1318         return self
.connHeader
 
1321 class PHPValue(object): 
1322     PEV_NAMES           
= ("undefined", "long", "double", "string", "array", "object", "boolean", "resource", "reference", "soft reference", "null") 
1335     NULL_VALUE_STR      
= "NULL" 
1336     TRUE_VALUE_STR      
= "True" 
1337     FALSE_VALUE_STR     
= "False" 
1338     OBJECT_VALUE_STR    
= "<%s> object" 
1339     STRING_VALUE_STR    
= "\"%s\"" 
1340     REFERENCE_VALUE_STR 
= "<reference><%s>" 
1341     RESOURCE_VALUE_STR  
= "<%s><%s>" 
1343     def __init__(self
, frame
, type, valueList
): 
1344         self
.fStackFrame 
= frame
 
1345         self
.fValueType  
= type 
1347         if type == self
.PEVT_OBJECT
: 
1348             self
.fValueString 
= self
.OBJECT_VALUE_STR 
% valueList
[0] 
1349             self
.fVariables   
= valueList
[1:] 
1350         elif type == self
.PEVT_ARRAY
: 
1351             self
.fValueString 
= '' 
1352             self
.fVariables   
= valueList
 
1354             self
.fVariables 
= [] 
1355             if type == self
.PEVT_STRING
: 
1356                 self
.fValueString 
= self
.STRING_VALUE_STR 
% valueList
[0] 
1357             elif type == self
.PEVT_NULL
: 
1358                 self
.fValueString 
= self
.NULL_VALUE_STR
 
1359             elif type == self
.PEVT_BOOLEAN
: 
1360                 if valueList
[0] == "0": 
1361                     self
.fValueString 
= self
.FALSE_VALUE_STR
 
1363                     self
.fValueString 
= self
.TRUE_VALUE_STR
 
1364             elif type == self
.PEVT_REF 
or type == self
.PEVT_SOFTREF
: 
1365                 self
.fValueString 
= self
.REFERENCE_VALUE_STR 
% valueList
[0] 
1366             elif type == self
.PEVT_RESOURCE
: 
1367                 self
.fValueString 
= self
.RESOURCE_VALUE_STR 
% (valueList
[0], valueList
[1]) 
1369                 self
.fValueString 
= valueList
[0] 
1371     def addVariable(self
, item
): 
1373             self
.fVariables
.append(item
) 
1375         return self
.fVariables
 
1377     def setParent(self
, parent
): 
1378         if self
.fVariables 
!= None and len(self
.fVariables
) > 0: 
1379             for item 
in self
.fVariables
: 
1380                 item
.setParent(parent
) 
1382     def getReferenceType(self
): 
1383         return self
.fValueType
 
1385     def getReferenceTypeName(self
): 
1386         return self
.PEV_NAMES
[self
.fValueType
] 
1388     def setReferenceType(self
, type): 
1389         self
.fValueType 
= type 
1391     def getValueString(self
): 
1392         return self
.fValueString
 
1394     def getChildrenVariables(self
): 
1395         return self
.fVariables
 
1397     def hasVariables(self
): 
1398         return len(self
.fVariables
) > 0 
1400     def childrenIsSortable(self
): 
1402         # TODO: if self.fValueType != self.PEVT_ARRAY: 
1407 class PHPVariable(object): 
1408     def __init__(self
, frame
, parent
, valueType
, name
, valueList
): 
1409         self
.fStackFrame 
= frame
 
1411         self
.fLongName   
= None 
1412         self
.fPureName   
= None 
1413         self
.fValue      
= PHPValue(frame
, valueType
, valueList
) 
1414         self
.fParent     
= parent
 
1416         self
.setChildrensParent(valueList
) 
1418     def setName(self
, name
): 
1419         self
.fPureName 
= name
 
1421         type = self
.getReferenceType() 
1422         if type == PHPValue
.PEVT_ARRAY
: 
1423             numItems 
= len(self
.getChildrenVariables()) 
1424             self
.fName 
= name 
+ "[" + str(numItems
) + "]" 
1428         if not self
.fParent 
or self
.fParent
.getName() == None: 
1429             self
.fLongName 
= name
 
1435     def setLongName(self
): 
1436         parentType 
= self
.fParent
.getReferenceType() 
1437         if parentType 
== PHPValue
.PEVT_ARRAY
: 
1438             self
.fLongName 
= self
.fParent
.getLongName() + "['" + self
.fPureName 
+ "']" 
1439         elif parentType 
== PHPValue
.PEVT_OBJECT
: 
1440             self
.fLongName 
= self
.fParent
.getLongName() + "." + self
.fName
 
1442             self
.fLongName 
= self
.fName
 
1449     def getValueString(self
): 
1450         return self
.fValue
.getValueString() 
1452     def getChildrenVariables(self
): 
1453         return self
.fValue
.getChildrenVariables() 
1458     def getParent(self
): 
1461     def setParent(self
, parent
): 
1462         self
.fParent 
= parent
 
1466     def setChildrensParent(self
, childrenList
): 
1467         if self
.fValue
.hasVariables(): 
1468             for child 
in self
.fValue
.getChildrenVariables(): 
1469                 child
.setParent(self
) 
1471     def getLongName(self
): 
1472         return self
.fLongName
 
1474     def getReferenceTypeName(self
): 
1475         return self
.fValue
.getReferenceTypeName() 
1477     def getReferenceType(self
): 
1478         return self
.fValue
.getReferenceType() 
1480     def setReferenceType(self
, type): 
1481         tp 
= self
.getValue
.setReferenceType(type) 
1484     def setValue(self
, expression
): 
1485         if self
.fValue
.getReferenceType() == PHPValue
.PEVT_STRING
: 
1486             evalString 
= self
.fLongName 
+ "=\"" + expression 
+ "\"" 
1488             evalString 
= self
.fLongName 
+ "=" + expression
 
1490         vars = self
.fStackFrame
.getPHPDBGInterface().evalBlock(self
.fStackFrame
, evalString
) 
1491         self
.fValue 
= vars[0].fValue
 
1494         rtype 
= self
.getReferenceType() 
1495         if rtype 
== PHPValue
.PEVT_ARRAY
: 
1496             elements 
= len(self
.fValue
.getChildrenVariables()) 
1498                 tmpStr 
= self
.getName() + " [no elements]" 
1500                 tmpStr 
= self
.getName() + " [1 element]" 
1502                 tmpStr 
= self
.getName() + " [" + str(elements
) + " elements]" 
1503         elif rtype 
== PHPValue
.PEVT_OBJECT
: 
1504             tmpStr 
= self
.getName() + " [ class: " + self
.fValue
.getValueString() + "]" 
1505         elif rtype 
== PHPValue
.PEVT_STRING
: 
1506             tmpStr 
= self
.getName() + " = \"" + self
.fValue
.getValueString() + "\"" 
1508             tmpStr 
= self
.getName() + " = " + self
.fValue
.getValueString() 
1512     def hasChildren(self
): 
1513         return self
.fValue
.hasVariables() 
1515     def childrenIsSortable(self
): 
1516         return self
.fValue
.childrenIsSortable() 
1519 class PHPStackFrame(object): 
1520     def __init__(self
, interface
, file, line
, frameIndex
, scopeId
, desc
, modNum
): 
1521         self
.interface      
= interface
 
1522         self
.fileName       
= file 
1524         self
.frameIndex     
= frameIndex
 
1525         self
.scopeId        
= scopeId
 
1527         self
.modNum         
= modNum
 
1529         self
.shortFileName  
= None 
1530         self
.shortDesc      
= None 
1531         self
.displayStr     
= None 
1532         self
.longDisplayStr 
= None 
1534         self
._getFileNamesAndShortDesc
() 
1536         myprint("PHPStackFrame::__init__(): new PHPStackFrame: file=%s, lineNo=%s, frameIndex=%s, scopeId=%s, desc=%s, modNum=%s, shortFileName=%s, shortDesc=%s", (repr(file), repr(line
), repr(frameIndex
), repr(scopeId
), repr(desc
), repr(modNum
), repr(self
.shortFileName
), repr(self
.shortDesc
))) 
1538     def _getFileNamesAndShortDesc(self
): 
1541             tmp 
= self
.desc
.split("::") 
1544             self
.shortFileName 
= os
.path
.basename(self
.fileName
) 
1546                 self
.shortDesc 
= tmp
[1] 
1548                 self
.shortDesc 
= tmp
[0] 
1550                 self
.shortDesc 
= None 
1555         # The fileName is None, we will try our best efforts to get it. 
1559             # We retrieved long finename from the description.  If we haven't 
1560             # stored the file mod before, set this one as the new one. 
1561             # Otherwise, we prefer to keep the stored one. 
1563             if self
.modNum 
!= 0: 
1564                 storedFileName 
= self
.interface
.getModByNum(self
.modNum
) 
1565                 if not storedFileName
: 
1566                     self
.interface
.setMod(self
.modNum
, tmp
[0]) 
1568             self
.fileName      
= tmp
[0] 
1569             self
.shortFileName 
= os
.path
.basename(tmp
[0]) 
1570             self
.shortDesc     
= tmp
[1] 
1572             self
.fileName      
= None 
1573             self
.shortFileName 
= None 
1574             self
.shortDesc     
= tmp
[0] 
1576             self
.shortFileName 
= None 
1577             self
.shortDesc     
= None 
1578             myprint("PHPStackFrame::_getFileNamesAndShortDesc(): something wrong with desc: %s?", self
.desc
) 
1582     def getShortFileName(self
): 
1583         return self
.shortFileName
 
1585     def setShortFileName(self
, shortFileName
): 
1586         self
.shortFileName 
= shortFileName
 
1588     def getShortDesc(self
): 
1589         return self
.shortDesc
 
1591     def getLineNo(self
): 
1594     def getInterface(self
): 
1595         return self
.interface
 
1597     def getVariables(self
): 
1598         if len(self
.variables
) == 0: 
1599             self
.variables 
= self
.interface
.getVariables(self
) 
1601         return self
.variables
 
1603     def findVariables(self
, s
): 
1604         if self
.hasVariables(): 
1606             for var 
in self
.variables
: 
1607                 if var
.getName() == name
: 
1612     def hasVariables(self
): 
1613         if len(self
.variables
) == 0: 
1620             return self
.getDesc() + " [line: " + str(self
.getLineNo()) + "]" 
1622             return self
.getFileName() + " [line: " + str(self
.getLineNo()) + "]" 
1624     def getFileName(self
): 
1625         return self
.fileName
 
1627     def setFileName(self
, fileName
): 
1628         self
.fileName 
= fileName
 
1630     def setDesc(self
, desc
): 
1636     def getFrameScopeId(self
): 
1639     def getFrameIndex(self
): 
1640         return self
.frameIndex
 
1642     def getDisplayStr(self
, stackList 
= None): 
1644             return self
.displayStr
 
1646         if not self
.shortFileName
: 
1648                 i 
= stackList
.index(self
) 
1649                 for j 
in range(i 
+ 1, len(stackList
)): 
1650                     self
.shortFileName 
= stackList
[j
].getShortFileName() 
1651                     if self
.shortFileName
: 
1652                         self
.fileName 
= stackList
[j
].getFileName() 
1654         if self
.shortFileName
: 
1656                 self
.displayStr 
= "<%s> at %s:%d" % (self
.shortDesc
, self
.shortFileName
, self
.lineNo
) 
1658                 self
.displayStr 
= "%s:%d" % (self
.shortFileName
, self
.lineNo
) 
1661                 self
.displayStr 
= "<%s>" % self
.shortDesc
 
1663                 self
.displayStr 
= "<internal stack error>" 
1665         return self
.displayStr
 
1667     def getLongDisplayStr(self
): 
1668         if self
.longDisplayStr
: 
1669             return self
.longDisplayStr
 
1673                 self
.longDisplayStr 
= "<%s> at %s:%d" % (self
.shortDesc
, self
.fileName
, self
.lineNo
) 
1675                 self
.longDisplayStr 
= "%s:%d" % (self
.fileName
, self
.lineNo
) 
1678                 self
.longDisplayStr 
= "<%s>" % self
.shortDesc
 
1680                 self
.longDisplayStr 
= "<internal stack error>" 
1682         return self
.longDisplayStr
 
1684 class BreakPoint(object): 
1685     def __init__(self
, interface
, fileName
, lineNo
, modNum 
= 0, state 
= BPS_ENABLED 
+ BPS_UNRESOLVED
, isTemp 
= 0, hitCount 
= 0, skipHits 
= 0, condition 
= 0, bpId 
= 0, isUnderHit 
= 0): 
1686         self
.interface  
= interface
 
1687         self
.fileName   
= fileName
 
1688         self
.lineNo     
= lineNo
 
1691         self
.isTemp     
= isTemp
 
1692         self
.hitCount   
= hitCount
 
1693         self
.skipHits   
= skipHits
 
1694         self
.condition  
= condition
 
1697             self
.modNum 
= self
.interface
.getModByFileName(fileName
) 
1699             self
.modNum 
= modNum
 
1702             self
.fCounterOrZero 
= 0 
1704             self
.fCounterOrZero 
= interface
.getNextFrameCounter() 
1707         reqPacket 
= PHPDBGPacket(DBGA_REQUEST
) 
1708         reqFrame1 
= PHPDBGFrame(FRAME_BPS
) 
1711             reqFrame1
.addInt(self
.modNum
) 
1714             # 0 in modNum to tell to use fileName instead. 
1718         reqFrame1
.addInt(self
.lineNo
)             # lineNo 
1719         reqFrame1
.addInt(self
.fCounterOrZero
)     # fileName frameCounter or 0 
1720         reqFrame1
.addInt(self
.state
)              # state 
1721         reqFrame1
.addInt(self
.isTemp
)             # isTemp 
1722         reqFrame1
.addInt(self
.hitCount
)           # hitCount 
1723         reqFrame1
.addInt(self
.skipHits
)           # skipHits 
1724         reqFrame1
.addInt(self
.condition
)          # condition 
1725         reqFrame1
.addInt(self
.bpID
)               # breakpoint sequence id 
1726         reqFrame1
.addInt(self
.isUnderHit
)         # isUnderHit 
1729             reqFrame2 
= PHPDBGFrame(FRAME_RAWDATA
) 
1730             reqFrame2
.addInt(self
.fCounterOrZero
) 
1731             reqFrame2
.addInt(len(self
.fileName
) + 1) 
1732             reqFrame2
.addStr(self
.fileName
) 
1733             reqPacket
.addFrame(reqFrame2
) 
1735         reqPacket
.addFrame(reqFrame1
) 
1738             reqPacket
.sendPacket(self
.interface
.lsnrThr
) 
1739             self
.interface
.awaitAndHandleResponse() 
1740         except PHPDBGConnException
: 
1741             self
.interface
.currConnFinished() 
1748     def removeSelf(self
): 
1749         self
.state 
= BPS_DISABLED
 
1752     def isUnderHit(self
): 
1753         return self
.isUnderHit 
== 1 
1755     def update(self
, dbgBp
): 
1756         self
.modNum     
= dbgBp
[0] 
1757         self
.state      
= dbgBp
[3] 
1758         self
.isTemp     
= dbgBp
[4] 
1759         self
.hitCount   
= dbgBp
[5] 
1760         self
.skipHits   
= dbgBp
[6] 
1761         self
.condition  
= dbgBp
[7] 
1762         self
.bpID       
= dbgBp
[8] 
1763         self
.isUnderHit 
= dbgBp
[9] 
1766 class PHPDBGEvalString(object): 
1767     def __init__(self
, stackFrame
, dataStr
): 
1768         self
.stackFrame 
= stackFrame
 
1769         self
.dataStr    
= dataStr
 
1772     # Get a list of variables under self.stackFrame. 
1775         return self
.parseAVariable(isRealVar 
= False) 
1779     #    returnList[0] = The Variable 
1781     #    returnList    = list of variables. 
1783     def parseAVariable(self
, isRealVar 
= True): 
1787         # Get the variable name first.  Notice we ignore this entity's data 
1791             nameEntity 
= self
.parseAnEntity() 
1792             if not nameEntity 
or len(nameEntity
) != 2 or type(nameEntity
[1]) != str: 
1793                 myprint("PHPDBGEvalStr::parseAVariable() got a wrong name entity") 
1796                 varName 
= nameEntity
[1] 
1799         # Get the variable's value. 
1801         valueEntity 
= self
.parseAnEntity() 
1802         if not valueEntity 
or len(valueEntity
) < 1: 
1803             myprint("PHPDBGEvalStr::parseAVariable(): couldn't get a variable's value entity.") 
1807         # This variable's data type. 
1809         varType 
= valueEntity
[0] 
1813             # If this is a real variable, return a list which contains only 
1814             # this variable item. 
1816             #valueEntity = valueEntity[1:] 
1817             variable    
= PHPVariable(self
.stackFrame
, None, varType
, varName
, valueEntity
[1:]) 
1818             #myprint("xxxxCreated variable varName=%s, valueEntity=%s", (repr(varName), repr(valueEntity[1]))) 
1819             myprint("xxxxCreated variable: %s", repr(variable
.toString())) 
1820             returnList
.append(variable
) 
1823             # If this is a root variable container, returns a list of 
1824             # variables under the root.  Do a sanity check here. 
1826             if valueEntity
[0] != PHPValue
.PEVT_ARRAY
: 
1827                 myprint("PHPDBGEvalStr::parseAVariable(): failed to parse the root variable container.") 
1829                 returnList 
= valueEntity
[1:] 
1834     # An entity could be a variable's name or its value. 
1836     # returnList[0]  = variable data type 
1837     # returnList[1:] = the real list 
1839     def parseAnEntity(self
): 
1840         if not self
.dataStr 
or len(self
.dataStr
) < 2  or (self
.dataStr
[1] != ':' and self
.dataStr
[1] != ';'): 
1841             myprint("PHPDBGEvalStr::parseAnEntity(): failed to parse %s.", repr(self
.dataStr
)) 
1845         typeChar      
= self
.dataStr
[0] 
1846         self
.dataStr  
= self
.dataStr
[2:] 
1848             returnList
.append(PHPValue
.PEVT_LONG
) 
1849             self
.parseInt(returnList
) 
1850         elif typeChar 
== 'a': 
1851             returnList
.append(PHPValue
.PEVT_ARRAY
) 
1852             self
.parseArray(returnList
) 
1853         elif typeChar 
== 's': 
1854             returnList
.append(PHPValue
.PEVT_STRING
) 
1855             self
.parseString(returnList
) 
1856         elif typeChar 
== 'O': 
1857             returnList
.append(PHPValue
.PEVT_OBJECT
) 
1858             self
.parseObject(returnList
) 
1859         elif typeChar 
== 'r': 
1860             returnList
.append(PHPValue
.PEVT_SOFTREF
) 
1861             self
.parseReference(returnList
, isSoftRef 
= True) 
1862         elif typeChar 
== 'R': 
1863             returnList
.append(PHPValue
.PEVT_REF
) 
1864             self
.parseReference(returnList
, isSoftRef 
= False) 
1865         elif typeChar 
== 'b': 
1866             returnList
.append(PHPValue
.PEVT_BOOLEAN
) 
1867             self
.parseBoolean(returnList
) 
1868         elif typeChar 
== 'd': 
1869             returnList
.append(PHPValue
.PEVT_DOUBLE
) 
1870             self
.parseDouble(returnList
) 
1871         elif typeChar 
== 'z': 
1872             returnList
.append(PHPValue
.PEVT_RESOURCE
) 
1873             self
.parseResource(returnList
) 
1874         elif typeChar 
== 'N': 
1875             returnList
.append(PHPValue
.PEVT_NULL
) 
1876             self
.parseNull(returnList
) 
1878             myprint("PHPDBGEvalStr::parseAnEntity(): unknown data type: %s", typeChar
) 
1882     def parseInt(self
, returnList
): 
1883         myprint("enter parseInt().") 
1884         returnList
.append(self
.getAnIntStr(';')) 
1888     def parseArray(self
, returnList
): 
1889         myprint("enter parseArray().") 
1891         # The shortest array is 'a:0:{}'. 
1893         if len(self
.dataStr
) < 4: 
1894             myprint("PHPDBGEvalStr::parseArray(): failed (1) to parse an array: %s.", repr(self
.dataStr
)) 
1897         expectedNumItems 
= self
.getAnInt(':') 
1898         if len(self
.dataStr
) < 2 or self
.dataStr
[0] != '{': 
1899             myprint("PHPDBGEvalStr::parseArray(): failed (3) to parse an array: %s.", repr(self
.dataStr
)) 
1902         self
.dataStr 
= self
.dataStr
[1:] 
1904         while self
.dataStr 
and len(self
.dataStr
) > 0 and self
.dataStr
[0] != '}': 
1905             tmpList 
= self
.parseAVariable() 
1906             if not tmpList 
or len(tmpList
) != 1 or not tmpList
[0]: 
1907                 myprint("PHPDBGEvalStr::parseArray(): failed (4) to parse an array.  dataStr=%s.", repr(self
.dataStr
)) 
1910                 varList
.append(tmpList
[0]) 
1912         if expectedNumItems 
!= len(varList
): 
1913             myprint("PHPDBGEvalStr::parseArray(): failed (5) expected no. of items=%d, but got %d", (expectedNumItems
, len(varList
))) 
1916         # An array should end with a '}'. 
1918         if self
.dataStr 
and len(self
.dataStr
) > 0 and self
.dataStr
[0] == '}': 
1919             self
.dataStr 
= self
.dataStr
[1:] 
1920             returnList
.extend(varList
) 
1922             myprint("PHPDBGEvalStr::parseArray(): failed (6) to parse an array.  dataStr=%s.", repr(self
.dataStr
)) 
1924         myprint("parseArray() ends.") 
1927     def parseString(self
, returnList
, endChar 
= ';'): 
1928         myprint("enter parseString().") 
1930         # The shortest string is 's:<str_len>:"<str>"<endChar>'. 
1932         if len(self
.dataStr
) < 5: 
1933             myprint("PHPDBGEvalStr::parseString(): failed (1) to parse a string.  dataStr=%s.", repr(self
.dataStr
)) 
1936         expectedStrLen 
= self
.getAnInt(':') 
1937         if len(self
.dataStr
) < expectedStrLen 
+ 3 or self
.dataStr
[0] != '"': 
1938             myprint("PHPDBGEvalStr::parseString(): failed (3) to parse a string.  dataStr=%s.", repr(self
.dataStr
)) 
1941         strValue 
= self
.dataStr
[1:expectedStrLen 
+ 1] 
1942         if self
.dataStr
[expectedStrLen 
+ 1:expectedStrLen 
+ 3] != '"' + endChar
: 
1943             myprint("PHPDBGEvalStr::parseString(): failed (4) to parse a string.  dataStr=%s.", repr(self
.dataStr
)) 
1947         # Skip the starting double quote, real string, ending double quote, and ending semicolon. 
1949         self
.dataStr 
= self
.dataStr
[expectedStrLen 
+ 3:] 
1950         returnList
.append(strValue
) 
1954     def parseObject(self
, returnList
): 
1956         # A simple sanity check.  The shortest object is: 
1957         # 'O:<class_name_len>:"<class_name>":<num_of_items>:{<list_of_items>}' 
1959         if not self
.dataStr 
or len(self
.dataStr
) < 10: 
1960             myprint("PHPDBGEvalStr::parseObject(): failed (1) to parse an object: %s.", repr(self
.dataStr
)) 
1963         # Get the class name in classNameList[0]. 
1966         self
.parseString(classNameList
, ':') 
1968         expectedNumItems 
= self
.getAnInt(':') 
1969         if len(self
.dataStr
) < 2 or self
.dataStr
[0] != '{': 
1970             myprint("PHPDBGEvalStr::parseObject(): failed (2) to parse an object: %s.", repr(self
.dataStr
)) 
1973         self
.dataStr 
= self
.dataStr
[1:] 
1975         while self
.dataStr 
and len(self
.dataStr
) > 0 and self
.dataStr
[0] != '}': 
1976             tmpList 
= self
.parseAVariable() 
1977             if not tmpList 
or len(tmpList
) != 1 or not tmpList
[0]: 
1978                 myprint("PHPDBGEvalStr::parseObject(): failed (3) to parse an object.  dataStr=%s.", repr(self
.dataStr
)) 
1981                 varList
.append(tmpList
[0]) 
1983         if expectedNumItems 
!= len(varList
): 
1984             myprint("PHPDBGEvalStr::parseObject(): failed (4) expected no. of items=%d, but got %d", (expectedNumItems
, len(varList
))) 
1987         # An object should end with a '}'. 
1989         if self
.dataStr 
and len(self
.dataStr
) > 0 and self
.dataStr
[0] == '}': 
1990             self
.dataStr 
= self
.dataStr
[1:] 
1991             returnList
.append(classNameList
[0]) 
1992             returnList
.extend(varList
) 
1994             myprint("PHPDBGEvalStr::parseObject(): failed (6) to parse an object.  dataStr=%s.", repr(self
.dataStr
)) 
1996         myprint("parseObject() ends.") 
1999     def parseReference(self
, returnList
, isSoftRef
): 
2000         myprint("enter parseReference().") 
2001         intStr 
= self
.getAnIntStr(';') 
2003             returnList
.append(intStr
) 
2007     def parseBoolean(self
, returnList
): 
2008         tmpBooleanStr 
= self
.getAnIntStr(';') 
2009         returnList
.append(tmpBooleanStr
) 
2013     def parseDouble(self
, returnList
): 
2014         tmpStr 
= self
.getAStrTillEndChar(';') 
2016             returnList
.append(tmpStr
) 
2020     def parseResource(self
, returnList
): 
2022         self
.parseString(tmpList
, ':') 
2024         if len(tmpList
) == 1: 
2025             returnList
.extend(tmpList
) 
2029         resourceId 
= self
.getAnIntStr(';') 
2031             returnList
.append(resourceId
) 
2035     def parseNull(self
, returnList
): 
2038     def getAStrTillEndChar(self
, endChar
): 
2039         if len(self
.dataStr
) < 1: 
2040             myprint("PHPDBGEvalStr::getAStrTillEndChar(): no more data string to work with.") 
2043         i 
= self
.findNextChar(self
.dataStr
, endChar
) 
2045             myprint("PHPDBGEvalStr::getAStrTillEndChar(): no double/float string supplied.") 
2048         tmpStr       
= self
.dataStr
[:i
] 
2049         self
.dataStr 
= self
.dataStr
[i 
+ 1:] 
2051         if self
.isFloat(tmpStr
): 
2054             myprint("PHPDBGEvalStr::getAStrTillEndChar(): parsing error.  tried to get an float number, but get %s.", tmpStr
) 
2057     def getAnInt(self
, endChar
): 
2058         tmpStr 
= self
.getAnIntStr(endChar
) 
2064     def getAnIntStr(self
, endChar
): 
2065         if len(self
.dataStr
) == 0: 
2066             myprint("PHPDBGEvalStr::getAnIntStr(): no more data string to work with.") 
2069         i 
= self
.findNextChar(self
.dataStr
, endChar
) 
2071             tmpStr 
= self
.dataStr
 
2074             tmpStr 
= self
.dataStr
[:i
] 
2075             self
.dataStr 
= self
.dataStr
[i 
+ 1:] 
2077         if self
.isInt(tmpStr
): 
2080             myprint("PHPDBGEvalStr::getAnIntStr(): parsing error.  tried to get an integer, but get %s.", tmpStr
) 
2083     def isInt(self
, aStr
): 
2091     def isFloat(self
, aStr
): 
2099     def findNextChar(self
, aStr
, aChar
): 
2101             index 
= aStr
.index(aChar
)