blob: b4cf585e5cc2315ec62184abf55b804f1ae2593f [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001''' pydevd - a debugging daemon
2This is the daemon you launch for python remote debugging.
3
4Protocol:
5each command has a format:
6 id\tsequence-num\ttext
7 id: protocol command number
8 sequence-num: each request has a sequence number. Sequence numbers
9 originating at the debugger are odd, sequence numbers originating
10 at the daemon are even. Every response uses the same sequence number
11 as the request.
12 payload: it is protocol dependent. When response is a complex structure, it
13 is returned as XML. Each attribute value is urlencoded, and then the whole
14 payload is urlencoded again to prevent stray characters corrupting protocol/xml encodings
15
16 Commands:
17
18 NUMBER NAME FROM* ARGUMENTS RESPONSE NOTE
19100 series: program execution
20 101 RUN JAVA - -
21 102 LIST_THREADS JAVA RETURN with XML listing of all threads
22 103 THREAD_CREATE PYDB - XML with thread information
23 104 THREAD_KILL JAVA id (or * to exit) kills the thread
24 PYDB id nofies JAVA that thread was killed
25 105 THREAD_SUSPEND JAVA XML of the stack, suspends the thread
26 reason for suspension
27 PYDB id notifies JAVA that thread was suspended
28
29 106 CMD_THREAD_RUN JAVA id resume the thread
30 PYDB id \t reason notifies JAVA that thread was resumed
31
32 107 STEP_INTO JAVA thread_id
33 108 STEP_OVER JAVA thread_id
34 109 STEP_RETURN JAVA thread_id
35
36 110 GET_VARIABLE JAVA thread_id \t frame_id \t GET_VARIABLE with XML of var content
37 FRAME|GLOBAL \t attributes*
38
39 111 SET_BREAK JAVA file/line of the breakpoint
40 112 REMOVE_BREAK JAVA file/line of the return
41 113 CMD_EVALUATE_EXPRESSION JAVA expression result of evaluating the expression
42 114 CMD_GET_FRAME JAVA request for frame contents
43 115 CMD_EXEC_EXPRESSION JAVA
44 116 CMD_WRITE_TO_CONSOLE PYDB
45 117 CMD_CHANGE_VARIABLE
46 118 CMD_RUN_TO_LINE
47 119 CMD_RELOAD_CODE
48 120 CMD_GET_COMPLETIONS JAVA
49
50500 series diagnostics/ok
51 501 VERSION either Version string (1.0) Currently just used at startup
52 502 RETURN either Depends on caller -
53
54900 series: errors
55 901 ERROR either - This is reserved for unexpected errors.
56
57 * JAVA - remote debugger, the java end
58 * PYDB - pydevd, the python end
59'''
60from pydevd_constants import * #@UnusedWildImport
61
62import sys
63
64if USE_LIB_COPY:
65 import _pydev_time as time
66 import _pydev_threading as threading
67 try:
68 import _pydev_thread as thread
69 except ImportError:
70 import _thread as thread #Py3K changed it.
71 import _pydev_Queue as _queue
72 from _pydev_socket import socket
73 from _pydev_socket import AF_INET, SOCK_STREAM
74 from _pydev_socket import SHUT_RD, SHUT_WR
75else:
76 import time
77 import threading
78 try:
79 import thread
80 except ImportError:
81 import _thread as thread #Py3K changed it.
82
83 try:
84 import Queue as _queue
85 except ImportError:
86 import queue as _queue
87 from socket import socket
88 from socket import AF_INET, SOCK_STREAM
89 from socket import SHUT_RD, SHUT_WR
90
91try:
Tor Norbyec667c1f2014-05-28 17:06:51 -070092 from urllib import quote, quote_plus, unquote, unquote_plus
Tor Norbye3a2425a2013-11-04 10:16:08 -080093except:
Tor Norbyec667c1f2014-05-28 17:06:51 -070094 from urllib.parse import quote, quote_plus, unquote, unquote_plus #@Reimport @UnresolvedImport
95import pydevconsole
Tor Norbye3a2425a2013-11-04 10:16:08 -080096import pydevd_vars
Tor Norbye3a2425a2013-11-04 10:16:08 -080097import pydevd_tracing
98import pydevd_vm_type
99import pydevd_file_utils
100import traceback
Tor Norbyec667c1f2014-05-28 17:06:51 -0700101from pydevd_utils import quote_smart as quote, compare_object_attrs, cmp_to_key, to_string
Tor Norbye92584642014-04-17 08:39:25 -0700102import pydev_log
Tor Norbyec667c1f2014-05-28 17:06:51 -0700103import _pydev_completer
Tor Norbye3a2425a2013-11-04 10:16:08 -0800104
105from pydevd_tracing import GetExceptionTracebackStr
Tor Norbyec667c1f2014-05-28 17:06:51 -0700106
Tor Norbye3a2425a2013-11-04 10:16:08 -0800107
Tor Norbye3a2425a2013-11-04 10:16:08 -0800108
109CMD_RUN = 101
110CMD_LIST_THREADS = 102
111CMD_THREAD_CREATE = 103
112CMD_THREAD_KILL = 104
113CMD_THREAD_SUSPEND = 105
114CMD_THREAD_RUN = 106
115CMD_STEP_INTO = 107
116CMD_STEP_OVER = 108
117CMD_STEP_RETURN = 109
118CMD_GET_VARIABLE = 110
119CMD_SET_BREAK = 111
120CMD_REMOVE_BREAK = 112
121CMD_EVALUATE_EXPRESSION = 113
122CMD_GET_FRAME = 114
123CMD_EXEC_EXPRESSION = 115
124CMD_WRITE_TO_CONSOLE = 116
125CMD_CHANGE_VARIABLE = 117
126CMD_RUN_TO_LINE = 118
127CMD_RELOAD_CODE = 119
128CMD_GET_COMPLETIONS = 120
129CMD_CONSOLE_EXEC = 121
130CMD_ADD_EXCEPTION_BREAK = 122
131CMD_REMOVE_EXCEPTION_BREAK = 123
132CMD_LOAD_SOURCE = 124
133CMD_ADD_DJANGO_EXCEPTION_BREAK = 125
134CMD_REMOVE_DJANGO_EXCEPTION_BREAK = 126
135CMD_SET_NEXT_STATEMENT = 127
136CMD_SMART_STEP_INTO = 128
137CMD_EXIT = 129
138CMD_SIGNATURE_CALL_TRACE = 130
139CMD_VERSION = 501
140CMD_RETURN = 502
141CMD_ERROR = 901
142
143ID_TO_MEANING = {
144 '101':'CMD_RUN',
145 '102':'CMD_LIST_THREADS',
146 '103':'CMD_THREAD_CREATE',
147 '104':'CMD_THREAD_KILL',
148 '105':'CMD_THREAD_SUSPEND',
149 '106':'CMD_THREAD_RUN',
150 '107':'CMD_STEP_INTO',
151 '108':'CMD_STEP_OVER',
152 '109':'CMD_STEP_RETURN',
153 '110':'CMD_GET_VARIABLE',
154 '111':'CMD_SET_BREAK',
155 '112':'CMD_REMOVE_BREAK',
156 '113':'CMD_EVALUATE_EXPRESSION',
157 '114':'CMD_GET_FRAME',
158 '115':'CMD_EXEC_EXPRESSION',
159 '116':'CMD_WRITE_TO_CONSOLE',
160 '117':'CMD_CHANGE_VARIABLE',
161 '118':'CMD_RUN_TO_LINE',
162 '119':'CMD_RELOAD_CODE',
163 '120':'CMD_GET_COMPLETIONS',
164 '121':'CMD_CONSOLE_EXEC',
165 '122':'CMD_ADD_EXCEPTION_BREAK',
166 '123':'CMD_REMOVE_EXCEPTION_BREAK',
167 '124':'CMD_LOAD_SOURCE',
168 '125':'CMD_ADD_DJANGO_EXCEPTION_BREAK',
169 '126':'CMD_REMOVE_DJANGO_EXCEPTION_BREAK',
170 '127':'CMD_SET_NEXT_STATEMENT',
171 '128':'CMD_SMART_STEP_INTO',
172 '129': 'CMD_EXIT',
173 '130': 'CMD_SIGNATURE_CALL_TRACE',
174 '501':'CMD_VERSION',
175 '502':'CMD_RETURN',
176 '901':'CMD_ERROR',
177 }
178
179MAX_IO_MSG_SIZE = 1000 #if the io is too big, we'll not send all (could make the debugger too non-responsive)
180#this number can be changed if there's need to do so
181
182VERSION_STRING = "@@BUILD_NUMBER@@"
183
Tor Norbyec667c1f2014-05-28 17:06:51 -0700184from _pydev_filesystem_encoding import getfilesystemencoding
185file_system_encoding = getfilesystemencoding()
Tor Norbye3a2425a2013-11-04 10:16:08 -0800186
187#--------------------------------------------------------------------------------------------------- UTILITIES
188
189#=======================================================================================================================
190# PydevdLog
191#=======================================================================================================================
192def PydevdLog(level, *args):
193 """ levels are:
194 0 most serious warnings/errors
195 1 warnings/significant events
196 2 informational trace
197 """
198 if level <= DebugInfoHolder.DEBUG_TRACE_LEVEL:
199 #yes, we can have errors printing if the console of the program has been finished (and we're still trying to print something)
200 try:
201 sys.stderr.write('%s\n' % (args,))
202 except:
203 pass
204
205#=======================================================================================================================
206# GlobalDebuggerHolder
207#=======================================================================================================================
208class GlobalDebuggerHolder:
209 '''
210 Holder for the global debugger.
211 '''
212 globalDbg = None
213
214#=======================================================================================================================
215# GetGlobalDebugger
216#=======================================================================================================================
217def GetGlobalDebugger():
218 return GlobalDebuggerHolder.globalDbg
219
220#=======================================================================================================================
221# SetGlobalDebugger
222#=======================================================================================================================
223def SetGlobalDebugger(dbg):
224 GlobalDebuggerHolder.globalDbg = dbg
225
226
227#------------------------------------------------------------------- ACTUAL COMM
228
229#=======================================================================================================================
230# PyDBDaemonThread
231#=======================================================================================================================
232class PyDBDaemonThread(threading.Thread):
233
234 def __init__(self):
235 threading.Thread.__init__(self)
236 self.setDaemon(True)
237 self.killReceived = False
238 self.dontTraceMe = True
239
240 def run(self):
241 if sys.platform.startswith("java"):
242 import org.python.core as PyCore #@UnresolvedImport
243 ss = PyCore.PySystemState()
244 # Note: Py.setSystemState() affects only the current thread.
245 PyCore.Py.setSystemState(ss)
246
247 self.OnRun()
248
249 def OnRun(self):
250 raise NotImplementedError('Should be reimplemented by: %s' % self.__class__)
251
252 def doKillPydevThread(self):
253 #that was not working very well because jython gave some socket errors
254 self.killReceived = True
255
Tor Norbye3a2425a2013-11-04 10:16:08 -0800256 def stopTrace(self):
257 if self.dontTraceMe:
258 pydevd_tracing.SetTrace(None) # no debugging on this thread
259
260
261#=======================================================================================================================
262# ReaderThread
263#=======================================================================================================================
264class ReaderThread(PyDBDaemonThread):
265 """ reader thread reads and dispatches commands in an infinite loop """
266
267 def __init__(self, sock):
268 PyDBDaemonThread.__init__(self)
269 self.sock = sock
270 self.setName("pydevd.Reader")
271
272
273 def doKillPydevThread(self):
274 #We must close the socket so that it doesn't stay halted there.
275 self.killReceived = True
276 try:
277 self.sock.shutdown(SHUT_RD) #shotdown the socket for read
278 except:
279 #just ignore that
280 pass
281
282 def OnRun(self):
283 self.stopTrace()
284 buffer = ""
285 try:
286
287 while not self.killReceived:
288 try:
289 r = self.sock.recv(1024)
290 except:
291 if not self.killReceived:
292 self.handleExcept()
293 return #Finished communication.
Tor Norbyec667c1f2014-05-28 17:06:51 -0700294
295 #Note: the java backend is always expected to pass utf-8 encoded strings. We now work with unicode
296 #internally and thus, we may need to convert to the actual encoding where needed (i.e.: filenames
297 #on python 2 may need to be converted to the filesystem encoding).
298 if hasattr(r, 'decode'):
Tor Norbye3a2425a2013-11-04 10:16:08 -0800299 r = r.decode('utf-8')
300
301 buffer += r
302 if DebugInfoHolder.DEBUG_RECORD_SOCKET_READS:
303 pydev_log.debug('received >>%s<<\n' % (buffer,))
304
305 if len(buffer) == 0:
306 self.handleExcept()
307 break
308 while buffer.find('\n') != -1:
309 command, buffer = buffer.split('\n', 1)
Tor Norbye1fff8e22014-03-10 13:13:45 -0700310
Tor Norbye3a2425a2013-11-04 10:16:08 -0800311 args = command.split('\t', 2)
312 try:
Tor Norbye1fff8e22014-03-10 13:13:45 -0700313 cmd_id = int(args[0])
314 pydev_log.debug('Received command: %s %s\n' % (ID_TO_MEANING.get(str(cmd_id), '???'), command,))
315 self.processCommand(cmd_id, int(args[1]), args[2])
Tor Norbye3a2425a2013-11-04 10:16:08 -0800316 except:
317 traceback.print_exc()
318 sys.stderr.write("Can't process net command: %s\n" % command)
319 sys.stderr.flush()
320
321 except:
322 traceback.print_exc()
323 self.handleExcept()
324
325
326 def handleExcept(self):
327 GlobalDebuggerHolder.globalDbg.FinishDebuggingSession()
328
329 def processCommand(self, cmd_id, seq, text):
330 GlobalDebuggerHolder.globalDbg.processNetCommand(cmd_id, seq, text)
331
332
333#----------------------------------------------------------------------------------- SOCKET UTILITIES - WRITER
334#=======================================================================================================================
335# WriterThread
336#=======================================================================================================================
337class WriterThread(PyDBDaemonThread):
338 """ writer thread writes out the commands in an infinite loop """
339 def __init__(self, sock):
340 PyDBDaemonThread.__init__(self)
341 self.setDaemon(False) #writer isn't daemon to be able to deliver all messages after main thread terminated
342 self.sock = sock
343 self.setName("pydevd.Writer")
344 self.cmdQueue = _queue.Queue()
345 if pydevd_vm_type.GetVmType() == 'python':
346 self.timeout = 0
347 else:
348 self.timeout = 0.1
349
350 def addCommand(self, cmd):
351 """ cmd is NetCommand """
352 if not self.killReceived: #we don't take new data after everybody die
353 self.cmdQueue.put(cmd)
354
355 def OnRun(self):
356 """ just loop and write responses """
357
358 self.stopTrace()
359 try:
360 while True:
361 try:
362 try:
363 cmd = self.cmdQueue.get(1, 0.1)
364 except _queue.Empty:
365 if self.killReceived:
366 try:
367 self.sock.shutdown(SHUT_WR)
368 self.sock.close()
369 except:
370 pass
Tor Norbye3a2425a2013-11-04 10:16:08 -0800371
372 return #break if queue is empty and killReceived
373 else:
374 continue
375 except:
376 #PydevdLog(0, 'Finishing debug communication...(1)')
377 #when liberating the thread here, we could have errors because we were shutting down
378 #but the thread was still not liberated
379 return
380 out = cmd.getOutgoing()
381
382 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1:
Tor Norbyec667c1f2014-05-28 17:06:51 -0700383 out_message = 'sending cmd --> '
384 out_message += "%20s" % ID_TO_MEANING.get(out[:3], 'UNKNOWN')
Tor Norbye3a2425a2013-11-04 10:16:08 -0800385 out_message += ' '
Tor Norbyec667c1f2014-05-28 17:06:51 -0700386 out_message += unquote(unquote(out)).replace('\n', ' ')
Tor Norbye3a2425a2013-11-04 10:16:08 -0800387 try:
388 sys.stderr.write('%s\n' % (out_message,))
389 except:
390 pass
391
392 if IS_PY3K:
393 out = bytearray(out, 'utf-8')
394 self.sock.send(out) #TODO: this does not guarantee that all message are sent (and jython does not have a send all)
395 if cmd.id == CMD_EXIT:
396 break
397 if time is None:
398 break #interpreter shutdown
399 time.sleep(self.timeout)
400 except Exception:
401 GlobalDebuggerHolder.globalDbg.FinishDebuggingSession()
402 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 0:
403 traceback.print_exc()
404
405
406
407
408#--------------------------------------------------- CREATING THE SOCKET THREADS
409
410#=======================================================================================================================
411# StartServer
412#=======================================================================================================================
413def StartServer(port):
414 """ binds to a port, waits for the debugger to connect """
415 s = socket(AF_INET, SOCK_STREAM)
416 s.bind(('', port))
417 s.listen(1)
418 newSock, _addr = s.accept()
419 return newSock
420
421#=======================================================================================================================
422# StartClient
423#=======================================================================================================================
424def StartClient(host, port):
425 """ connects to a host/port """
426 PydevdLog(1, "Connecting to ", host, ":", str(port))
427
428 s = socket(AF_INET, SOCK_STREAM)
429
Tor Norbye2e5965e2014-07-25 12:24:15 -0700430 MAX_TRIES = 100
Tor Norbye3a2425a2013-11-04 10:16:08 -0800431 i = 0
432 while i<MAX_TRIES:
433 try:
434 s.connect((host, port))
435 except:
436 i+=1
437 time.sleep(0.2)
438 continue
439 PydevdLog(1, "Connected.")
440 return s
441
442 sys.stderr.write("Could not connect to %s: %s\n" % (host, port))
443 sys.stderr.flush()
444 traceback.print_exc()
445 sys.exit(1) #TODO: is it safe?
446
447
448
449#------------------------------------------------------------------------------------ MANY COMMUNICATION STUFF
450
451#=======================================================================================================================
452# NetCommand
453#=======================================================================================================================
454class NetCommand:
455 """ Commands received/sent over the network.
456
457 Command can represent command received from the debugger,
458 or one to be sent by daemon.
459 """
460 next_seq = 0 # sequence numbers
461
462 def __init__(self, id, seq, text):
463 """ smart handling of paramaters
464 if sequence is 0, new sequence will be generated
465 if text has carriage returns they'll be replaced"""
466 self.id = id
467 if (seq == 0): seq = self.getNextSeq()
468 self.seq = seq
469 self.text = text
470 self.outgoing = self.makeMessage(id, seq, text)
471
472 def getNextSeq(self):
473 """ returns next sequence number """
474 NetCommand.next_seq += 2
475 return NetCommand.next_seq
476
477 def getOutgoing(self):
478 """ returns the outgoing message"""
479 return self.outgoing
480
481 def makeMessage(self, cmd, seq, payload):
482 encoded = quote(to_string(payload), '/<>_=" \t')
483 return str(cmd) + '\t' + str(seq) + '\t' + encoded + "\n"
484
485#=======================================================================================================================
486# NetCommandFactory
487#=======================================================================================================================
488class NetCommandFactory:
489
490 def __init_(self):
491 self.next_seq = 0
492
493 def threadToXML(self, thread):
494 """ thread information as XML """
495 name = pydevd_vars.makeValidXmlValue(thread.getName())
496 cmdText = '<thread name="%s" id="%s" />' % (quote(name), GetThreadId(thread))
497 return cmdText
498
499 def makeErrorMessage(self, seq, text):
500 cmd = NetCommand(CMD_ERROR, seq, text)
501 if DebugInfoHolder.DEBUG_TRACE_LEVEL > 2:
502 sys.stderr.write("Error: %s" % (text,))
503 return cmd
504
505 def makeThreadCreatedMessage(self, thread):
506 cmdText = "<xml>" + self.threadToXML(thread) + "</xml>"
507 return NetCommand(CMD_THREAD_CREATE, 0, cmdText)
508
Tor Norbyec667c1f2014-05-28 17:06:51 -0700509
510 def makeCustomFrameCreatedMessage(self, frameId, frameDescription):
511 frameDescription = pydevd_vars.makeValidXmlValue(frameDescription)
512 cmdText = '<xml><thread name="%s" id="%s"/></xml>' % (frameDescription, frameId)
513 return NetCommand(CMD_THREAD_CREATE, 0, cmdText)
514
515
Tor Norbye3a2425a2013-11-04 10:16:08 -0800516 def makeListThreadsMessage(self, seq):
517 """ returns thread listing as XML """
518 try:
519 t = threading.enumerate()
520 cmdText = "<xml>"
521 for i in t:
522 if t.isAlive():
523 cmdText += self.threadToXML(i)
524 cmdText += "</xml>"
525 return NetCommand(CMD_RETURN, seq, cmdText)
526 except:
527 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
528
529 def makeVariableChangedMessage(self, seq, payload):
530 # notify debugger that value was changed successfully
531 return NetCommand(CMD_RETURN, seq, payload)
532
533 def makeIoMessage(self, v, ctx, dbg=None):
534 '''
535 @param v: the message to pass to the debug server
536 @param ctx: 1 for stdio 2 for stderr
537 @param dbg: If not none, add to the writer
538 '''
539
540 try:
541 if len(v) > MAX_IO_MSG_SIZE:
542 v = v[0:MAX_IO_MSG_SIZE]
543 v += '...'
544
545 v = pydevd_vars.makeValidXmlValue(quote(v, '/>_= \t'))
546 net = NetCommand(str(CMD_WRITE_TO_CONSOLE), 0, '<xml><io s="%s" ctx="%s"/></xml>' % (v, ctx))
547 except:
548 net = self.makeErrorMessage(0, GetExceptionTracebackStr())
549
550 if dbg:
551 dbg.writer.addCommand(net)
552
553 return net
554
555 def makeVersionMessage(self, seq):
556 try:
557 return NetCommand(CMD_VERSION, seq, VERSION_STRING)
558 except:
559 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
560
561 def makeThreadKilledMessage(self, id):
562 try:
563 return NetCommand(CMD_THREAD_KILL, 0, str(id))
564 except:
565 return self.makeErrorMessage(0, GetExceptionTracebackStr())
566
567 def makeThreadSuspendMessage(self, thread_id, frame, stop_reason, message):
568
569 """ <xml>
570 <thread id="id" stop_reason="reason">
571 <frame id="id" name="functionName " file="file" line="line">
572 <var variable stuffff....
573 </frame>
574 </thread>
575 """
576 try:
577 cmdTextList = ["<xml>"]
578
579 if message:
580 message = pydevd_vars.makeValidXmlValue(str(message))
581
582 cmdTextList.append('<thread id="%s" stop_reason="%s" message="%s">' % (thread_id, stop_reason, message))
583
584 curFrame = frame
585 try:
586 while curFrame:
587 #print cmdText
588 myId = str(id(curFrame))
589 #print "id is ", myId
590
591 if curFrame.f_code is None:
592 break #Iron Python sometimes does not have it!
593
594 myName = curFrame.f_code.co_name #method name (if in method) or ? if global
595 if myName is None:
596 break #Iron Python sometimes does not have it!
597
598 #print "name is ", myName
599
600 filename, base = pydevd_file_utils.GetFilenameAndBase(curFrame)
601
602 myFile = pydevd_file_utils.NormFileToClient(filename)
Tor Norbyec667c1f2014-05-28 17:06:51 -0700603 if file_system_encoding.lower() != "utf-8" and hasattr(myFile, "decode"):
604 # myFile is a byte string encoded using the file system encoding
605 # convert it to utf8
606 myFile = myFile.decode(file_system_encoding).encode("utf-8")
Tor Norbye3a2425a2013-11-04 10:16:08 -0800607
608 #print "file is ", myFile
609 #myFile = inspect.getsourcefile(curFrame) or inspect.getfile(frame)
610
611 myLine = str(curFrame.f_lineno)
612 #print "line is ", myLine
613
614 #the variables are all gotten 'on-demand'
615 #variables = pydevd_vars.frameVarsToXML(curFrame.f_locals)
616
617 variables = ''
618 cmdTextList.append('<frame id="%s" name="%s" ' % (myId , pydevd_vars.makeValidXmlValue(myName)))
619 cmdTextList.append('file="%s" line="%s">"' % (quote(myFile, '/>_= \t'), myLine))
620 cmdTextList.append(variables)
621 cmdTextList.append("</frame>")
622 curFrame = curFrame.f_back
623 except :
624 traceback.print_exc()
625
626 cmdTextList.append("</thread></xml>")
627 cmdText = ''.join(cmdTextList)
628 return NetCommand(CMD_THREAD_SUSPEND, 0, cmdText)
629 except:
630 return self.makeErrorMessage(0, GetExceptionTracebackStr())
631
632 def makeThreadRunMessage(self, id, reason):
633 try:
634 return NetCommand(CMD_THREAD_RUN, 0, str(id) + "\t" + str(reason))
635 except:
636 return self.makeErrorMessage(0, GetExceptionTracebackStr())
637
638 def makeGetVariableMessage(self, seq, payload):
639 try:
640 return NetCommand(CMD_GET_VARIABLE, seq, payload)
641 except Exception:
642 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
643
644 def makeGetFrameMessage(self, seq, payload):
645 try:
646 return NetCommand(CMD_GET_FRAME, seq, payload)
647 except Exception:
648 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
649
650
651 def makeEvaluateExpressionMessage(self, seq, payload):
652 try:
653 return NetCommand(CMD_EVALUATE_EXPRESSION, seq, payload)
654 except Exception:
655 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
656
657 def makeGetCompletionsMessage(self, seq, payload):
658 try:
659 return NetCommand(CMD_GET_COMPLETIONS, seq, payload)
660 except Exception:
661 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
662
663 def makeLoadSourceMessage(self, seq, source, dbg=None):
664 try:
665 net = NetCommand(CMD_LOAD_SOURCE, seq, '%s' % source)
666
667 except:
668 net = self.makeErrorMessage(0, GetExceptionTracebackStr())
669
670 if dbg:
671 dbg.writer.addCommand(net)
672 return net
673
674 def makeExitMessage(self):
675 try:
676 net = NetCommand(CMD_EXIT, 0, '')
677
678 except:
679 net = self.makeErrorMessage(0, GetExceptionTracebackStr())
680
681 return net
682
683INTERNAL_TERMINATE_THREAD = 1
684INTERNAL_SUSPEND_THREAD = 2
685
686
687#=======================================================================================================================
688# InternalThreadCommand
689#=======================================================================================================================
690class InternalThreadCommand:
691 """ internal commands are generated/executed by the debugger.
692
693 The reason for their existence is that some commands have to be executed
694 on specific threads. These are the InternalThreadCommands that get
695 get posted to PyDB.cmdQueue.
696 """
697
698 def canBeExecutedBy(self, thread_id):
699 '''By default, it must be in the same thread to be executed
700 '''
701 return self.thread_id == thread_id
702
703 def doIt(self, dbg):
704 raise NotImplementedError("you have to override doIt")
705
Tor Norbyec667c1f2014-05-28 17:06:51 -0700706
707class ReloadCodeCommand(InternalThreadCommand):
708
709
710 def __init__(self, module_name, thread_id):
711 self.thread_id = thread_id
712 self.module_name = module_name
713 self.executed = False
714 self.lock = threading.Lock()
715
716
717 def canBeExecutedBy(self, thread_id):
718 if self.thread_id == '*':
719 return True #Any thread can execute it!
720
721 return InternalThreadCommand.canBeExecutedBy(self, thread_id)
722
723
724 def doIt(self, dbg):
725 self.lock.acquire()
726 try:
727 if self.executed:
728 return
729 self.executed = True
730 finally:
731 self.lock.release()
732
733 module_name = self.module_name
734 if not DictContains(sys.modules, module_name):
735 if '.' in module_name:
736 new_module_name = module_name.split('.')[-1]
737 if DictContains(sys.modules, new_module_name):
738 module_name = new_module_name
739
740 if not DictContains(sys.modules, module_name):
741 sys.stderr.write('pydev debugger: Unable to find module to reload: "' + module_name + '".\n')
742 # Too much info...
743 # sys.stderr.write('pydev debugger: This usually means you are trying to reload the __main__ module (which cannot be reloaded).\n')
744
745 else:
746 sys.stderr.write('pydev debugger: Start reloading module: "' + module_name + '" ... \n')
747 import pydevd_reload
748 if pydevd_reload.xreload(sys.modules[module_name]):
749 sys.stderr.write('pydev debugger: reload finished\n')
750 else:
751 sys.stderr.write('pydev debugger: reload finished without applying any change\n')
752
753
Tor Norbye3a2425a2013-11-04 10:16:08 -0800754#=======================================================================================================================
755# InternalTerminateThread
756#=======================================================================================================================
757class InternalTerminateThread(InternalThreadCommand):
758 def __init__(self, thread_id):
759 self.thread_id = thread_id
760
761 def doIt(self, dbg):
762 PydevdLog(1, "killing ", str(self.thread_id))
763 cmd = dbg.cmdFactory.makeThreadKilledMessage(self.thread_id)
764 dbg.writer.addCommand(cmd)
765
766
767#=======================================================================================================================
768# InternalRunThread
769#=======================================================================================================================
770class InternalRunThread(InternalThreadCommand):
771 def __init__(self, thread_id):
772 self.thread_id = thread_id
773
774 def doIt(self, dbg):
775 t = PydevdFindThreadById(self.thread_id)
776 if t:
777 t.additionalInfo.pydev_step_cmd = None
778 t.additionalInfo.pydev_step_stop = None
779 t.additionalInfo.pydev_state = STATE_RUN
780
781
782#=======================================================================================================================
783# InternalStepThread
784#=======================================================================================================================
785class InternalStepThread(InternalThreadCommand):
786 def __init__(self, thread_id, cmd_id):
787 self.thread_id = thread_id
788 self.cmd_id = cmd_id
789
790 def doIt(self, dbg):
791 t = PydevdFindThreadById(self.thread_id)
792 if t:
793 t.additionalInfo.pydev_step_cmd = self.cmd_id
794 t.additionalInfo.pydev_state = STATE_RUN
795
796#=======================================================================================================================
797# InternalSetNextStatementThread
798#=======================================================================================================================
799class InternalSetNextStatementThread(InternalThreadCommand):
800 def __init__(self, thread_id, cmd_id, line, func_name):
801 self.thread_id = thread_id
802 self.cmd_id = cmd_id
803 self.line = line
804 self.func_name = func_name
805
806 def doIt(self, dbg):
807 t = PydevdFindThreadById(self.thread_id)
808 if t:
809 t.additionalInfo.pydev_step_cmd = self.cmd_id
810 t.additionalInfo.pydev_next_line = int(self.line)
811 t.additionalInfo.pydev_func_name = self.func_name
812 t.additionalInfo.pydev_state = STATE_RUN
813
814
815#=======================================================================================================================
816# InternalGetVariable
817#=======================================================================================================================
818class InternalGetVariable(InternalThreadCommand):
819 """ gets the value of a variable """
820 def __init__(self, seq, thread_id, frame_id, scope, attrs):
821 self.sequence = seq
822 self.thread_id = thread_id
823 self.frame_id = frame_id
824 self.scope = scope
825 self.attributes = attrs
826
827 def doIt(self, dbg):
828 """ Converts request into python variable """
829 try:
830 xml = "<xml>"
831 valDict = pydevd_vars.resolveCompoundVariable(self.thread_id, self.frame_id, self.scope, self.attributes)
832 if valDict is None:
833 valDict = {}
834
835 keys = valDict.keys()
836 if hasattr(keys, 'sort'):
837 keys.sort(compare_object_attrs) #Python 3.0 does not have it
838 else:
839 if IS_PY3K:
840 keys = sorted(keys, key=cmp_to_key(compare_object_attrs)) #Jython 2.1 does not have it (and all must be compared as strings).
841 else:
842 keys = sorted(keys, cmp=compare_object_attrs) #Jython 2.1 does not have it (and all must be compared as strings).
843
844 for k in keys:
845 xml += pydevd_vars.varToXML(valDict[k], to_string(k))
846
847 xml += "</xml>"
848 cmd = dbg.cmdFactory.makeGetVariableMessage(self.sequence, xml)
849 dbg.writer.addCommand(cmd)
850 except Exception:
851 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error resolving variables " + GetExceptionTracebackStr())
852 dbg.writer.addCommand(cmd)
853
854
855#=======================================================================================================================
856# InternalChangeVariable
857#=======================================================================================================================
858class InternalChangeVariable(InternalThreadCommand):
859 """ changes the value of a variable """
860 def __init__(self, seq, thread_id, frame_id, scope, attr, expression):
861 self.sequence = seq
862 self.thread_id = thread_id
863 self.frame_id = frame_id
864 self.scope = scope
865 self.attr = attr
866 self.expression = expression
867
868 def doIt(self, dbg):
869 """ Converts request into python variable """
870 try:
871 result = pydevd_vars.changeAttrExpression(self.thread_id, self.frame_id, self.attr, self.expression)
872 xml = "<xml>"
873 xml += pydevd_vars.varToXML(result, "")
874 xml += "</xml>"
875 cmd = dbg.cmdFactory.makeVariableChangedMessage(self.sequence, xml)
876 dbg.writer.addCommand(cmd)
877 except Exception:
878 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error changing variable attr:%s expression:%s traceback:%s" % (self.attr, self.expression, GetExceptionTracebackStr()))
879 dbg.writer.addCommand(cmd)
880
881
882#=======================================================================================================================
883# InternalGetFrame
884#=======================================================================================================================
885class InternalGetFrame(InternalThreadCommand):
886 """ gets the value of a variable """
887 def __init__(self, seq, thread_id, frame_id):
888 self.sequence = seq
889 self.thread_id = thread_id
890 self.frame_id = frame_id
891
892 def doIt(self, dbg):
893 """ Converts request into python variable """
894 try:
895 frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
896 if frame is not None:
897 xml = "<xml>"
898 xml += pydevd_vars.frameVarsToXML(frame.f_locals)
899 del frame
900 xml += "</xml>"
901 cmd = dbg.cmdFactory.makeGetFrameMessage(self.sequence, xml)
902 dbg.writer.addCommand(cmd)
903 else:
904 #pydevd_vars.dumpFrames(self.thread_id)
905 #don't print this error: frame not found: means that the client is not synchronized (but that's ok)
906 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Frame not found: %s from thread: %s" % (self.frame_id, self.thread_id))
907 dbg.writer.addCommand(cmd)
908 except:
909 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error resolving frame: %s from thread: %s" % (self.frame_id, self.thread_id))
910 dbg.writer.addCommand(cmd)
911
912
913#=======================================================================================================================
914# InternalEvaluateExpression
915#=======================================================================================================================
916class InternalEvaluateExpression(InternalThreadCommand):
917 """ gets the value of a variable """
918
919 def __init__(self, seq, thread_id, frame_id, expression, doExec, doTrim):
920 self.sequence = seq
921 self.thread_id = thread_id
922 self.frame_id = frame_id
923 self.expression = expression
924 self.doExec = doExec
925 self.doTrim = doTrim
926
927 def doIt(self, dbg):
928 """ Converts request into python variable """
929 try:
930 result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec)
931 xml = "<xml>"
932 xml += pydevd_vars.varToXML(result, "", self.doTrim)
933 xml += "</xml>"
934 cmd = dbg.cmdFactory.makeEvaluateExpressionMessage(self.sequence, xml)
935 dbg.writer.addCommand(cmd)
936 except:
937 exc = GetExceptionTracebackStr()
938 sys.stderr.write('%s\n' % (exc,))
939 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating expression " + exc)
940 dbg.writer.addCommand(cmd)
941
942#=======================================================================================================================
Tor Norbyec667c1f2014-05-28 17:06:51 -0700943# InternalGetCompletions
944#=======================================================================================================================
945class InternalGetCompletions(InternalThreadCommand):
946 """ Gets the completions in a given scope """
947
948 def __init__(self, seq, thread_id, frame_id, act_tok):
949 self.sequence = seq
950 self.thread_id = thread_id
951 self.frame_id = frame_id
952 self.act_tok = act_tok
953
954
955 def doIt(self, dbg):
956 """ Converts request into completions """
957 try:
958 remove_path = None
959 try:
960
961 frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
962 if frame is not None:
963
964
965 msg = _pydev_completer.GenerateCompletionsAsXML(frame, self.act_tok)
966
967 cmd = dbg.cmdFactory.makeGetCompletionsMessage(self.sequence, msg)
968 dbg.writer.addCommand(cmd)
969 else:
970 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "InternalGetCompletions: Frame not found: %s from thread: %s" % (self.frame_id, self.thread_id))
971 dbg.writer.addCommand(cmd)
972
973
974 finally:
975 if remove_path is not None:
976 sys.path.remove(remove_path)
977
978 except:
979 exc = GetExceptionTracebackStr()
980 sys.stderr.write('%s\n' % (exc,))
981 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating expression " + exc)
982 dbg.writer.addCommand(cmd)
983
984
985#=======================================================================================================================
Tor Norbye3a2425a2013-11-04 10:16:08 -0800986# InternalConsoleExec
987#=======================================================================================================================
988class InternalConsoleExec(InternalThreadCommand):
989 """ gets the value of a variable """
990
991 def __init__(self, seq, thread_id, frame_id, expression):
992 self.sequence = seq
993 self.thread_id = thread_id
994 self.frame_id = frame_id
995 self.expression = expression
996
997 def doIt(self, dbg):
998 """ Converts request into python variable """
999 pydev_start_new_thread = None
1000 try:
1001 try:
1002 pydev_start_new_thread = thread.start_new_thread
1003
1004 thread.start_new_thread = thread._original_start_new_thread #don't trace new threads created by console command
1005 thread.start_new = thread._original_start_new_thread
1006
1007 result = pydevconsole.consoleExec(self.thread_id, self.frame_id, self.expression)
1008 xml = "<xml>"
1009 xml += pydevd_vars.varToXML(result, "")
1010 xml += "</xml>"
1011 cmd = dbg.cmdFactory.makeEvaluateExpressionMessage(self.sequence, xml)
1012 dbg.writer.addCommand(cmd)
1013 except:
1014 exc = GetExceptionTracebackStr()
1015 sys.stderr.write('%s\n' % (exc,))
1016 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating console expression " + exc)
1017 dbg.writer.addCommand(cmd)
1018 finally:
1019 thread.start_new_thread = pydev_start_new_thread
1020 thread.start_new = pydev_start_new_thread
1021 sys.stderr.flush()
1022 sys.stdout.flush()
1023
Tor Norbye3a2425a2013-11-04 10:16:08 -08001024
1025#=======================================================================================================================
1026# PydevdFindThreadById
1027#=======================================================================================================================
1028def PydevdFindThreadById(thread_id):
1029 try:
1030 # there was a deadlock here when I did not remove the tracing function when thread was dead
1031 threads = threading.enumerate()
1032 for i in threads:
Tor Norbyec667c1f2014-05-28 17:06:51 -07001033 tid = GetThreadId(i)
1034 if thread_id == tid or thread_id.endswith('|' + tid):
Tor Norbye3a2425a2013-11-04 10:16:08 -08001035 return i
1036
1037 sys.stderr.write("Could not find thread %s\n" % thread_id)
1038 sys.stderr.write("Available: %s\n" % [GetThreadId(t) for t in threads])
1039 sys.stderr.flush()
1040 except:
1041 traceback.print_exc()
1042
1043 return None
1044