103 |
103 |
104 # frames, where we want to stop or release debugger |
104 # frames, where we want to stop or release debugger |
105 self.stopframe = None |
105 self.stopframe = None |
106 self.returnframe = None |
106 self.returnframe = None |
107 self.stop_everywhere = False |
107 self.stop_everywhere = False |
|
108 |
|
109 # frame, where opcode tracing could start |
|
110 self.enterframe = None |
|
111 self.traceOpcodes = False |
108 |
112 |
109 self.__recursionDepth = -1 |
113 self.__recursionDepth = -1 |
110 self.setRecursionDepth(inspect.currentframe()) |
114 self.setRecursionDepth(inspect.currentframe()) |
111 |
115 |
112 # background task to periodicaly check for client interactions |
116 # background task to periodicaly check for client interactions |
325 raise SystemExit |
329 raise SystemExit |
326 |
330 |
327 # check if we are still managing all exceptions |
331 # check if we are still managing all exceptions |
328 self._dbgClient.checkExceptionHook() |
332 self._dbgClient.checkExceptionHook() |
329 |
333 |
330 if event == "line": |
334 if event in ("line", "opcode"): # handle both events identically |
331 if self.stop_here(frame) or self.break_here(frame): |
335 if self.stop_here(frame) or self.break_here(frame): |
332 if ( |
336 if ( |
333 self.stop_everywhere |
337 self.stop_everywhere |
334 and frame.f_back |
338 and frame.f_back |
335 and frame.f_back.f_code.co_name == "prepareJsonCommand" |
339 and frame.f_back.f_code.co_name == "prepareJsonCommand" |
391 and arg[0] in (StopIteration, GeneratorExit) |
395 and arg[0] in (StopIteration, GeneratorExit) |
392 ): |
396 ): |
393 self.user_exception(arg) |
397 self.user_exception(arg) |
394 return None |
398 return None |
395 |
399 |
396 if event == "c_call": |
400 if event in ("c_call", "c_exception", "c_return"): |
397 return None |
401 # ignore C events |
398 if event == "c_exception": |
|
399 return None |
|
400 if event == "c_return": |
|
401 return None |
402 return None |
402 |
403 |
403 print( # __IGNORE_WARNING_M801__ |
404 print( # __IGNORE_WARNING_M801__ |
404 "DebugBase.trace_dispatch: unknown debugging event: ", |
405 "DebugBase.trace_dispatch: unknown debugging event: ", |
405 repr(event), |
406 repr(event), |
421 if frame is None: |
422 if frame is None: |
422 frame = sys._getframe().f_back # Skip set_trace method |
423 frame = sys._getframe().f_back # Skip set_trace method |
423 |
424 |
424 stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ |
425 stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ |
425 |
426 |
426 frame.f_trace = self.trace_dispatch |
427 self.enterframe = frame |
427 while frame.f_back is not None: |
428 while frame is not None: |
428 # stop at eric's debugger frame or a threading bootstrap |
429 frame.f_trace = self.trace_dispatch |
429 if frame.f_back.f_code == stopOnHandleCommand: |
430 # We need f_trace_lines == True for the debugger to work. This should |
430 frame.f_trace = self.trace_dispatch |
431 # already be the case per default, but play it safe. |
|
432 frame.f_trace_lines = True |
|
433 frame = frame.f_back |
|
434 if frame and frame.f_code is stopOnHandleCommand: |
|
435 # stop at eric's debugger frame or a threading bootstrap |
431 break |
436 break |
432 |
437 |
433 frame = frame.f_back |
|
434 |
|
435 self.stop_everywhere = True |
438 self.stop_everywhere = True |
|
439 self.set_stepinstr() |
436 sys.settrace(self.trace_dispatch) |
440 sys.settrace(self.trace_dispatch) |
437 sys.setprofile(self._dbgClient.callTraceEnabled) |
441 sys.setprofile(self._dbgClient.callTraceEnabled) |
438 |
442 |
439 def bootstrap(self, target, args, kwargs): |
443 def bootstrap(self, target, args, kwargs): |
440 """ |
444 """ |
520 finally: |
524 finally: |
521 self.quitting = True |
525 self.quitting = True |
522 sys.settrace(None) |
526 sys.settrace(None) |
523 return exitcode |
527 return exitcode |
524 |
528 |
525 def _set_stopinfo(self, stopframe, returnframe, stoplineno=0): |
529 def _set_trace_opcodes(self, traceOpcodes): |
|
530 """ |
|
531 Protected method to set tracing on opcode level enabled or disabled. |
|
532 |
|
533 @param traceOpcodes opcode tracing state |
|
534 @type bool |
|
535 """ |
|
536 if traceOpcodes != self.traceOpcodes: |
|
537 stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ |
|
538 |
|
539 self.traceOpcodes = traceOpcodes |
|
540 frame = self.enterframe |
|
541 while frame is not None: |
|
542 frame.f_trace_opcodes = traceOpcodes |
|
543 frame = frame.f_back |
|
544 if frame and frame.f_code is stopOnHandleCommand: |
|
545 # stop at eric's debugger frame or a threading bootstrap |
|
546 break |
|
547 |
|
548 def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, traceOpcodes=False): |
526 """ |
549 """ |
527 Protected method to update the frame pointers. |
550 Protected method to update the frame pointers. |
528 |
551 |
529 @param stopframe the frame object where to stop |
552 @param stopframe the frame object where to stop |
530 @type frame object |
553 @type frame object |
531 @param returnframe the frame object where to stop on a function return |
554 @param returnframe the frame object where to stop on a function return |
532 @type frame object |
555 @type frame object |
533 @param stoplineno line number to stop at. If stoplineno is greater than |
556 @param stoplineno line number to stop at. If stoplineno is greater than |
534 or equal to 0, then stop at line greater than or equal to the |
557 or equal to 0, then stop at line greater than or equal to the |
535 stopline. If stoplineno is -1, then don't stop at all. |
558 stopline. If stoplineno is -1, then don't stop at all. (defaults to 0) |
536 @type int |
559 @type int (optional) |
|
560 @param traceOpcodes opcode tracing state (defaults to False) |
|
561 @type bool (optional) |
537 """ |
562 """ |
538 self.stopframe = stopframe |
563 self.stopframe = stopframe |
539 self.returnframe = returnframe |
564 self.returnframe = returnframe |
540 # stoplineno >= 0 means: stop at line >= the stoplineno |
565 # stoplineno >= 0 means: stop at line >= the stoplineno |
541 # stoplineno -1 means: don't stop at all |
566 # stoplineno -1 means: don't stop at all |
543 |
568 |
544 if returnframe is not None: |
569 if returnframe is not None: |
545 # Ensure to be able to stop on the return frame |
570 # Ensure to be able to stop on the return frame |
546 returnframe.f_trace = self.trace_dispatch |
571 returnframe.f_trace = self.trace_dispatch |
547 self.stop_everywhere = False |
572 self.stop_everywhere = False |
|
573 |
|
574 self._set_trace_opcodes(traceOpcodes) |
548 |
575 |
549 def set_continue(self, special): |
576 def set_continue(self, special): |
550 """ |
577 """ |
551 Public method to stop only on next breakpoint. |
578 Public method to stop only on next breakpoint. |
552 |
579 |
583 """ |
610 """ |
584 Public method to stop after one line of code. |
611 Public method to stop after one line of code. |
585 """ |
612 """ |
586 self._set_stopinfo(None, None) |
613 self._set_stopinfo(None, None) |
587 self.stop_everywhere = True |
614 self.stop_everywhere = True |
|
615 |
|
616 def set_stepinstr(self): |
|
617 """ |
|
618 Public method to stop before the next instruction. |
|
619 """ |
|
620 self._set_stopinfo(None, None, opcode=True) |
588 |
621 |
589 def set_next(self, frame): |
622 def set_next(self, frame): |
590 """ |
623 """ |
591 Public method to stop on the next line in or below the given frame. |
624 Public method to stop on the next line in or below the given frame. |
592 |
625 |