src/eric7/DebugClients/Python/DebugBase.py

branch
eric7
changeset 11048
aa0123c997cd
parent 10981
e80ffe75107c
child 11090
f5f5f5803935
--- a/src/eric7/DebugClients/Python/DebugBase.py	Sun Nov 10 15:21:04 2024 +0100
+++ b/src/eric7/DebugClients/Python/DebugBase.py	Mon Nov 11 15:00:58 2024 +0100
@@ -106,6 +106,10 @@
         self.returnframe = None
         self.stop_everywhere = False
 
+        # frame, where opcode tracing could start
+        self.enterframe = None
+        self.traceOpcodes = False
+
         self.__recursionDepth = -1
         self.setRecursionDepth(inspect.currentframe())
 
@@ -327,7 +331,7 @@
         # check if we are still managing all exceptions
         self._dbgClient.checkExceptionHook()
 
-        if event == "line":
+        if event in ("line", "opcode"):  # handle both events identically
             if self.stop_here(frame) or self.break_here(frame):
                 if (
                     self.stop_everywhere
@@ -393,11 +397,8 @@
                 self.user_exception(arg)
             return None
 
-        if event == "c_call":
-            return None
-        if event == "c_exception":
-            return None
-        if event == "c_return":
+        if event in ("c_call", "c_exception", "c_return"):
+            # ignore C events
             return None
 
         print(  # __IGNORE_WARNING_M801__
@@ -423,16 +424,19 @@
 
         stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__
 
-        frame.f_trace = self.trace_dispatch
-        while frame.f_back is not None:
-            # stop at eric's debugger frame or a threading bootstrap
-            if frame.f_back.f_code == stopOnHandleCommand:
-                frame.f_trace = self.trace_dispatch
+        self.enterframe = frame
+        while frame is not None:
+            frame.f_trace = self.trace_dispatch
+            # We need f_trace_lines == True for the debugger to work. This should
+            # already be the case per default, but play it safe.
+            frame.f_trace_lines = True
+            frame = frame.f_back
+            if frame and frame.f_code is stopOnHandleCommand:
+                # stop at eric's debugger frame or a threading bootstrap
                 break
 
-            frame = frame.f_back
-
         self.stop_everywhere = True
+        self.set_stepinstr()
         sys.settrace(self.trace_dispatch)
         sys.setprofile(self._dbgClient.callTraceEnabled)
 
@@ -522,7 +526,26 @@
             sys.settrace(None)
         return exitcode
 
-    def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
+    def _set_trace_opcodes(self, traceOpcodes):
+        """
+        Protected method to set tracing on opcode level enabled or disabled.
+
+        @param traceOpcodes opcode tracing state
+        @type bool
+        """
+        if traceOpcodes != self.traceOpcodes:
+            stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__
+
+            self.traceOpcodes = traceOpcodes
+            frame = self.enterframe
+            while frame is not None:
+                frame.f_trace_opcodes = traceOpcodes
+                frame = frame.f_back
+                if frame and frame.f_code is stopOnHandleCommand:
+                    # stop at eric's debugger frame or a threading bootstrap
+                    break
+
+    def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, traceOpcodes=False):
         """
         Protected method to update the frame pointers.
 
@@ -532,8 +555,10 @@
         @type frame object
         @param stoplineno line number to stop at. If stoplineno is greater than
             or equal to 0, then stop at line greater than or equal to the
-            stopline. If stoplineno is -1, then don't stop at all.
-        @type int
+            stopline. If stoplineno is -1, then don't stop at all. (defaults to 0)
+        @type int (optional)
+        @param traceOpcodes opcode tracing state (defaults to False)
+        @type bool (optional)
         """
         self.stopframe = stopframe
         self.returnframe = returnframe
@@ -546,6 +571,8 @@
             returnframe.f_trace = self.trace_dispatch
         self.stop_everywhere = False
 
+        self._set_trace_opcodes(traceOpcodes)
+
     def set_continue(self, special):
         """
         Public method to stop only on next breakpoint.
@@ -586,6 +613,12 @@
         self._set_stopinfo(None, None)
         self.stop_everywhere = True
 
+    def set_stepinstr(self):
+        """
+        Public method to stop before the next instruction.
+        """
+        self._set_stopinfo(None, None, opcode=True)
+
     def set_next(self, frame):
         """
         Public method to stop on the next line in or below the given frame.

eric ide

mercurial