]>
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
)