307 if self.quitting: |
316 if self.quitting: |
308 raise SystemExit |
317 raise SystemExit |
309 |
318 |
310 if event == 'line': |
319 if event == 'line': |
311 if self.stop_here(frame) or self.break_here(frame): |
320 if self.stop_here(frame) or self.break_here(frame): |
312 if (self.stop_everywhere and frame.f_back and |
321 if ( |
313 frame.f_back.f_code.co_name == "prepareJsonCommand"): |
322 self.stop_everywhere and |
|
323 frame.f_back and |
|
324 frame.f_back.f_code.co_name == "prepareJsonCommand" |
|
325 ): |
314 # Just stepped into print statement, so skip these frames |
326 # Just stepped into print statement, so skip these frames |
315 self._set_stopinfo(None, frame.f_back) |
327 self._set_stopinfo(None, frame.f_back) |
316 else: |
328 else: |
317 self.user_line(frame) |
329 self.user_line(frame) |
318 return self.trace_dispatch |
330 return self.trace_dispatch |
319 |
331 |
320 if event == 'call': |
332 if event == 'call': |
321 if (self.stop_here(frame) or |
333 if ( |
322 self.__checkBreakInFrame(frame) or |
334 self.stop_here(frame) or |
323 Watch.watches != []): |
335 self.__checkBreakInFrame(frame) or |
|
336 Watch.watches != [] |
|
337 ): |
|
338 return self.trace_dispatch |
|
339 elif ( |
|
340 self.stopframe and |
|
341 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS |
|
342 ): |
324 return self.trace_dispatch |
343 return self.trace_dispatch |
325 else: |
344 else: |
326 # No need to trace this function |
345 # No need to trace this function |
327 return None |
346 return None |
328 |
347 |
329 if event == 'return': |
348 if event == 'return': |
330 if frame == self.returnframe: |
349 if self.stop_here(frame) or frame == self.returnframe: |
331 # Only true if we didn't stopped in this frame, because it's |
350 # Ignore return events in generator except when stepping. |
|
351 if ( |
|
352 self.stopframe and |
|
353 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS |
|
354 ): |
|
355 return self.trace_dispatch |
|
356 # Only true if we didn't stop in this frame, because it's |
332 # belonging to the eric debugger. |
357 # belonging to the eric debugger. |
333 self._set_stopinfo(None, frame.f_back) |
358 if self.stopframe is frame and self.stoplineno != -1: |
|
359 self._set_stopinfo(None, frame.f_back) |
334 return None |
360 return None |
335 |
361 |
336 if event == 'exception': |
362 if event == 'exception': |
337 if not self.__skipFrame(frame): |
363 if not self.__skipFrame(frame): |
338 # When stepping with next/until/return in a generator frame, |
364 # When stepping with next/until/return in a generator frame, |
339 # skip the internal StopIteration exception (with no traceback) |
365 # skip the internal StopIteration exception (with no traceback) |
340 # triggered by a subiterator run with the 'yield from' |
366 # triggered by a subiterator run with the 'yield from' |
341 # statement. |
367 # statement. |
342 if not (frame.f_code.co_flags & CO_GENERATOR and |
368 if not ( |
343 arg[0] is StopIteration and arg[2] is None): |
369 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS and |
|
370 arg[0] is StopIteration and |
|
371 arg[2] is None |
|
372 ): |
344 self.user_exception(arg) |
373 self.user_exception(arg) |
345 # Stop at the StopIteration or GeneratorExit exception when the |
374 # Stop at the StopIteration or GeneratorExit exception when the |
346 # user has set stopframe in a generator by issuing a return |
375 # user has set stopframe in a generator by issuing a return |
347 # command, or a next/until command at the last statement in the |
376 # command, or a next/until command at the last statement in the |
348 # generator before the exception. |
377 # generator before the exception. |
349 elif (self.stopframe and frame is not self.stopframe and |
378 elif ( |
350 self.stopframe.f_code.co_flags & CO_GENERATOR and |
379 self.stopframe and |
351 arg[0] in (StopIteration, GeneratorExit)): |
380 frame is not self.stopframe and |
|
381 (self.stopframe.f_code.co_flags & |
|
382 GENERATOR_AND_COROUTINE_FLAGS) and |
|
383 arg[0] in (StopIteration, GeneratorExit) |
|
384 ): |
352 self.user_exception(arg) |
385 self.user_exception(arg) |
353 return None |
386 return None |
354 |
387 |
355 if event == 'c_call': |
388 if event == 'c_call': |
356 return None |
389 return None |
360 return None |
393 return None |
361 |
394 |
362 print('DebugBase.trace_dispatch:' # __IGNORE_WARNING_M801__ |
395 print('DebugBase.trace_dispatch:' # __IGNORE_WARNING_M801__ |
363 ' unknown debugging event: ', |
396 ' unknown debugging event: ', |
364 repr(event)) |
397 repr(event)) |
|
398 |
365 return self.trace_dispatch |
399 return self.trace_dispatch |
366 |
400 |
367 def set_trace(self, frame=None): |
401 def set_trace(self, frame=None): |
368 """ |
402 """ |
369 Public method to start debugging from 'frame'. |
403 Public method to start debugging from 'frame'. |
370 |
404 |
371 If frame is not specified, debugging starts from caller's frame. |
405 If frame is not specified, debugging starts from caller's frame. |
372 Because of jump optimizations it's not possible to use sys.breakpoint() |
406 Because of jump optimizations it's not possible to use sys.breakpoint() |
373 as last instruction in a function or method. |
407 as last instruction in a function or method. |
374 |
408 |
375 @keyparam frame frame to start debugging from |
409 @param frame frame to start debugging from |
376 @type frame object |
410 @type frame object |
377 """ |
411 """ |
378 if frame is None: |
412 if frame is None: |
379 frame = sys._getframe().f_back # Skip set_trace method |
413 frame = sys._getframe().f_back # Skip set_trace method |
380 |
414 |
381 stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ |
415 stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ |
382 |
416 |
383 frame.f_trace = self.trace_dispatch |
417 frame.f_trace = self.trace_dispatch |
384 while frame.f_back is not None: |
418 while frame.f_back is not None: |
385 # stop at eric's debugger frame or a threading bootstrap |
419 # stop at eric's debugger frame or a threading bootstrap |
386 if (frame.f_back.f_code == stopOnHandleCommand): |
420 if frame.f_back.f_code == stopOnHandleCommand: |
387 frame.f_trace = self.trace_dispatch |
421 frame.f_trace = self.trace_dispatch |
388 break |
422 break |
389 |
423 |
390 frame = frame.f_back |
424 frame = frame.f_back |
391 |
425 |
418 self.user_exception(excinfo, True) |
452 self.user_exception(excinfo, True) |
419 finally: |
453 finally: |
420 sys.settrace(None) |
454 sys.settrace(None) |
421 sys.setprofile(None) |
455 sys.setprofile(None) |
422 |
456 |
423 def run(self, cmd, globalsDict=None, localsDict=None, debug=True): |
457 def run(self, cmd, globalsDict=None, localsDict=None, debug=True, |
|
458 closeSession=True): |
424 """ |
459 """ |
425 Public method to start a given command under debugger control. |
460 Public method to start a given command under debugger control. |
426 |
461 |
427 @param cmd command / code to execute under debugger control |
462 @param cmd command / code to execute under debugger control |
428 @type str or CodeType |
463 @type str or CodeType |
429 @keyparam globalsDict dictionary of global variables for cmd |
464 @param globalsDict dictionary of global variables for cmd |
430 @type dict |
465 @type dict |
431 @keyparam localsDict dictionary of local variables for cmd |
466 @param localsDict dictionary of local variables for cmd |
432 @type dict |
467 @type dict |
433 @keyparam debug flag if command should run under debugger control |
468 @param debug flag if command should run under debugger control |
|
469 @type bool |
|
470 @return exit code of the program |
|
471 @rtype int |
|
472 @param closeSession flag indicating to close the debugger session |
|
473 at exit |
434 @type bool |
474 @type bool |
435 """ |
475 """ |
436 if globalsDict is None: |
476 if globalsDict is None: |
437 import __main__ |
477 import __main__ |
438 globalsDict = __main__.__dict__ |
478 globalsDict = __main__.__dict__ |
451 sys.settrace(self.trace_dispatch) |
491 sys.settrace(self.trace_dispatch) |
452 |
492 |
453 try: |
493 try: |
454 exec(cmd, globalsDict, localsDict) # secok |
494 exec(cmd, globalsDict, localsDict) # secok |
455 atexit._run_exitfuncs() |
495 atexit._run_exitfuncs() |
456 self._dbgClient.progTerminated(0) |
496 self._dbgClient.progTerminated(0, closeSession=closeSession) |
|
497 exitcode = 0 |
457 except SystemExit: |
498 except SystemExit: |
458 atexit._run_exitfuncs() |
499 atexit._run_exitfuncs() |
459 excinfo = sys.exc_info() |
500 excinfo = sys.exc_info() |
460 exitcode, message = self.__extractSystemExitMessage(excinfo) |
501 exitcode, message = self.__extractSystemExitMessage(excinfo) |
461 self._dbgClient.progTerminated(exitcode, message) |
502 self._dbgClient.progTerminated(exitcode, message=message, |
|
503 closeSession=closeSession) |
462 except Exception: |
504 except Exception: |
463 excinfo = sys.exc_info() |
505 excinfo = sys.exc_info() |
464 self.user_exception(excinfo, True) |
506 self.user_exception(excinfo, True) |
|
507 exitcode = 242 |
465 finally: |
508 finally: |
466 self.quitting = True |
509 self.quitting = True |
467 sys.settrace(None) |
510 sys.settrace(None) |
468 |
511 return exitcode |
469 def _set_stopinfo(self, stopframe, returnframe): |
512 |
|
513 def _set_stopinfo(self, stopframe, returnframe, stoplineno=0): |
470 """ |
514 """ |
471 Protected method to update the frame pointers. |
515 Protected method to update the frame pointers. |
472 |
516 |
473 @param stopframe the frame object where to stop |
517 @param stopframe the frame object where to stop |
474 @type frame object |
518 @type frame object |
475 @param returnframe the frame object where to stop on a function return |
519 @param returnframe the frame object where to stop on a function return |
476 @type frame object |
520 @type frame object |
|
521 @param stoplineno line number to stop at. If stoplineno is greater than |
|
522 or equal to 0, then stop at line greater than or equal to the |
|
523 stopline. If stoplineno is -1, then don't stop at all. |
|
524 @type int |
477 """ |
525 """ |
478 self.stopframe = stopframe |
526 self.stopframe = stopframe |
479 self.returnframe = returnframe |
527 self.returnframe = returnframe |
|
528 # stoplineno >= 0 means: stop at line >= the stoplineno |
|
529 # stoplineno -1 means: don't stop at all |
|
530 self.stoplineno = stoplineno |
|
531 |
480 if returnframe is not None: |
532 if returnframe is not None: |
481 # Ensure to be able to stop on the return frame |
533 # Ensure to be able to stop on the return frame |
482 returnframe.f_trace = self.trace_dispatch |
534 returnframe.f_trace = self.trace_dispatch |
483 self.stop_everywhere = False |
535 self.stop_everywhere = False |
484 |
536 |
489 @param special flag indicating a special continue operation |
541 @param special flag indicating a special continue operation |
490 @type bool |
542 @type bool |
491 """ |
543 """ |
492 # Here we only set a new stop frame if it is a normal continue. |
544 # Here we only set a new stop frame if it is a normal continue. |
493 if not special: |
545 if not special: |
494 self._set_stopinfo(None, None) |
546 self._set_stopinfo(None, None, -1) |
495 |
547 |
496 # Disable tracing if not started in debug mode |
548 # Disable tracing if not started in debug mode |
497 if not self._dbgClient.debugging: |
549 if not self._dbgClient.debugging: |
498 sys.settrace(None) |
550 sys.settrace(None) |
499 sys.setprofile(None) |
551 sys.setprofile(None) |
500 |
552 |
|
553 def set_until(self, frame=None, lineno=None): |
|
554 """ |
|
555 Public method to stop when the line with the lineno greater than the |
|
556 current one is reached or when returning from current frame. |
|
557 |
|
558 @param frame reference to the frame object |
|
559 @type frame object |
|
560 @param lineno line number to continue to |
|
561 @type int |
|
562 """ |
|
563 # the name "until" is borrowed from gdb |
|
564 if frame is None: |
|
565 frame = self.currentFrame |
|
566 if lineno is None: |
|
567 lineno = frame.f_lineno + 1 |
|
568 self._set_stopinfo(frame, frame, lineno) |
|
569 |
501 def set_step(self): |
570 def set_step(self): |
502 """ |
571 """ |
503 Public method to stop after one line of code. |
572 Public method to stop after one line of code. |
504 """ |
573 """ |
505 self._set_stopinfo(None, None) |
574 self._set_stopinfo(None, None) |
690 |
759 |
691 def getStack(self, frame=None, applyTrace=False): |
760 def getStack(self, frame=None, applyTrace=False): |
692 """ |
761 """ |
693 Public method to get the stack. |
762 Public method to get the stack. |
694 |
763 |
695 @keyparam frame frame object to inspect |
764 @param frame frame object to inspect |
696 @type frame object or list |
765 @type frame object or list |
697 @keyparam applyTrace flag to assign trace function to fr.f_trace |
766 @param applyTrace flag to assign trace function to fr.f_trace |
698 @type bool |
767 @type bool |
699 @return list of lists with file name (string), line number (integer) |
768 @return list of lists with file name (string), line number (integer) |
700 and function name (string) |
769 and function name (string) |
701 """ |
770 """ |
702 tb_lineno = None |
771 tb_lineno = None |
718 fr.f_trace = self.trace_dispatch |
787 fr.f_trace = self.trace_dispatch |
719 |
788 |
720 fname = self._dbgClient.absPath(self.fix_frame_filename(fr)) |
789 fname = self._dbgClient.absPath(self.fix_frame_filename(fr)) |
721 # Always show at least one stack frame, even if it's from eric. |
790 # Always show at least one stack frame, even if it's from eric. |
722 if stack and os.path.basename(fname).startswith( |
791 if stack and os.path.basename(fname).startswith( |
723 ("DebugBase.py", "DebugClientBase.py", |
792 ("DebugBase.py", "DebugClientBase.py", |
724 "ThreadExtension.py", "threading.py")): |
793 "ThreadExtension.py", "threading.py") |
|
794 ): |
725 break |
795 break |
726 |
796 |
727 fline = tb_lineno or fr.f_lineno |
797 fline = tb_lineno or fr.f_lineno |
728 ffunc = fr.f_code.co_name |
798 ffunc = fr.f_code.co_name |
729 |
799 |
771 |
841 |
772 self._dbgClient.lockClient() |
842 self._dbgClient.lockClient() |
773 self._dbgClient.currentThread = self |
843 self._dbgClient.currentThread = self |
774 self._dbgClient.currentThreadExec = self |
844 self._dbgClient.currentThreadExec = self |
775 |
845 |
776 self._dbgClient.sendResponseLine(stack) |
846 self._dbgClient.sendResponseLine(stack, self.name) |
777 self._dbgClient.eventLoop() |
847 self._dbgClient.eventLoop() |
778 |
848 |
779 self.isBroken = False |
849 self.isBroken = False |
780 self._dbgClient.unlockClient() |
850 self._dbgClient.unlockClient() |
781 |
851 |
|
852 self._dbgClient.dumpThreadList() |
|
853 |
782 def user_exception(self, excinfo, unhandled=False): |
854 def user_exception(self, excinfo, unhandled=False): |
783 """ |
855 """ |
784 Public method reimplemented to report an exception to the debug server. |
856 Public method reimplemented to report an exception to the debug server. |
785 |
857 |
786 @param excinfo details about the exception |
858 @param excinfo details about the exception |
787 @type tuple(Exception, excval object, traceback frame object) |
859 @type tuple(Exception, excval object, traceback frame object) |
788 @keyparam unhandled flag indicating an uncaught exception |
860 @param unhandled flag indicating an uncaught exception |
789 @type bool |
861 @type bool |
790 """ |
862 """ |
791 exctype, excval, exctb = excinfo |
863 exctype, excval, exctb = excinfo |
792 |
864 |
793 if ((exctype in [GeneratorExit, StopIteration] and |
865 if ((exctype in [GeneratorExit, StopIteration] and |
877 stack = self.getStack(frlist[self.skipFrames:]) |
950 stack = self.getStack(frlist[self.skipFrames:]) |
878 |
951 |
879 self._dbgClient.lockClient() |
952 self._dbgClient.lockClient() |
880 self._dbgClient.currentThread = self |
953 self._dbgClient.currentThread = self |
881 self._dbgClient.currentThreadExec = self |
954 self._dbgClient.currentThreadExec = self |
882 self._dbgClient.sendException(exctypetxt, excvaltxt, stack) |
955 self._dbgClient.sendException(exctypetxt, excvaltxt, stack, self.name) |
883 self._dbgClient.setDisassembly(disassembly) |
956 self._dbgClient.setDisassembly(disassembly) |
884 self._dbgClient.dumpThreadList() |
957 self._dbgClient.dumpThreadList() |
885 |
958 |
886 if exctb is not None: |
959 if exctb is not None: |
887 # When polling kept enabled, it isn't possible to resume after an |
960 # When polling kept enabled, it isn't possible to resume after an |
889 self._dbgClient.eventLoop(True) |
962 self._dbgClient.eventLoop(True) |
890 |
963 |
891 self.skipFrames = 0 |
964 self.skipFrames = 0 |
892 |
965 |
893 self.isBroken = False |
966 self.isBroken = False |
|
967 self.isException = False |
894 stop_everywhere = self.stop_everywhere |
968 stop_everywhere = self.stop_everywhere |
895 self.stop_everywhere = False |
969 self.stop_everywhere = False |
896 self.eventPollFlag = False |
970 self.eventPollFlag = False |
897 self._dbgClient.unlockClient() |
971 self._dbgClient.unlockClient() |
898 self.stop_everywhere = stop_everywhere |
972 self.stop_everywhere = stop_everywhere |
|
973 |
|
974 self._dbgClient.dumpThreadList() |
899 |
975 |
900 def __extractExceptionName(self, exctype): |
976 def __extractExceptionName(self, exctype): |
901 """ |
977 """ |
902 Private method to extract the exception name given the exception |
978 Private method to extract the exception name given the exception |
903 type object. |
979 type object. |