[sdb] Fix step-over with recursive functions. Fixes #5700.
authorZoltan Varga <vargaz@gmail.com>
Sat, 30 Nov 2013 20:05:19 +0000 (21:05 +0100)
committerZoltan Varga <vargaz@gmail.com>
Sat, 30 Nov 2013 20:05:19 +0000 (21:05 +0100)
mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
mcs/class/Mono.Debugger.Soft/Test/dtest.cs
mono/mini/debugger-agent.c

index 176bb8f6bcdf56fade22b409e4ca3713f56441ea..dc4be1371e6eda1e3d9d794365fa95d1ff0671c9 100644 (file)
@@ -360,6 +360,7 @@ public class Tests : TestsBase, ITest2
                ss_nested ();
                ss_regress_654694 ();
                ss_step_through ();
+               ss_recursive (1);
        }
 
        [MethodImplAttribute (MethodImplOptions.NoInlining)]
@@ -477,6 +478,13 @@ public class Tests : TestsBase, ITest2
        public static void step_through_3 () {
        }
 
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static void ss_recursive (int n) {
+               if (n == 10)
+                       return;
+               ss_recursive (n + 1);
+       }
+
        [MethodImplAttribute (MethodImplOptions.NoInlining)]
        public static bool is_even (int i) {
                return i % 2 == 0;
index 6df8ad7af5e0811c9fc6ad047ad860697d1be66c..2b8982b2f1668241c26e27f59bf1a750b6eb726d 100644 (file)
@@ -541,6 +541,18 @@ public class DebuggerTests
                e = step_into ();
                assert_location (e, "step_through_3");
                req.Disable ();
+
+               // Check that step-over doesn't stop at inner frames with recursive functions
+               e = run_until ("ss_recursive");
+               req = create_step (e);
+               e = step_over ();
+               e = step_over ();
+               e = step_over ();
+               var f = e.Thread.GetFrames () [0];
+               assert_location (e, "ss_recursive");
+               AssertValue (1, f.GetValue (f.Method.GetLocal ("n")));
+
+               req.Disable ();
        }
 
        [Test]
index 01ea5eb97bf45e00ca2dce8a031670a3de7daed5..0990efa4281f53db59f03633fe29cfa6c68c2116 100755 (executable)
@@ -559,6 +559,8 @@ typedef struct {
        gboolean global;
        /* The list of breakpoints used to implement step-over */
        GSList *bps;
+       /* The number of frames at the start of a step-over */
+       int nframes;
 } SingleStepReq;
 
 /*
@@ -4461,7 +4463,7 @@ clear_breakpoints_for_domain (MonoDomain *domain)
  * Return FALSE if single stepping needs to continue.
  */
 static gboolean
-ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp)
+ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *tls, MonoContext *ctx)
 {
        MonoDebugMethodInfo *minfo;
        MonoDebugSourceLocation *loc = NULL;
@@ -4476,6 +4478,17 @@ ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp)
                return FALSE;
        }
 
+       if (req->depth == STEP_DEPTH_OVER && hit) {
+               if (!tls->context.valid)
+                       mono_thread_state_init_from_monoctx (&tls->context, ctx);
+               compute_frame_info (tls->thread, tls);
+               if (req->nframes && tls->frame_count && tls->frame_count > req->nframes) {
+                       /* Hit the breakpoint in a recursive call */
+                       DEBUG (1, fprintf (log_file, "[%p] Breakpoint at lower frame while stepping over, continuing single stepping.\n", (gpointer)GetCurrentThreadId ()));
+                       return FALSE;
+               }
+       }
+
        if (req->size != STEP_SIZE_LINE)
                return TRUE;
 
@@ -4597,7 +4610,7 @@ process_breakpoint_inner (DebuggerTlsData *tls)
                if (mono_thread_internal_current () != ss_req->thread)
                        continue;
 
-               hit = ss_update (ss_req, ji, sp);
+               hit = ss_update (ss_req, ji, sp, tls, ctx);
                if (hit)
                        g_ptr_array_add (ss_reqs, req);
 
@@ -4814,7 +4827,7 @@ process_single_step_inner (DebuggerTlsData *tls)
                return;
        il_offset = sp->il_offset;
 
-       if (!ss_update (ss_req, ji, sp))
+       if (!ss_update (ss_req, ji, sp, tls, ctx))
                return;
 
        /* Start single stepping again from the current sequence point */
@@ -5061,6 +5074,8 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                }
 
                if (ss_req->depth == STEP_DEPTH_OVER) {
+                       if (ss_req->nframes == 0)
+                               ss_req->nframes = tls->frame_count;
                        /* Need to stop in catch clauses as well */
                        for (i = 0; i < tls->frame_count; ++i) {
                                StackFrame *frame = tls->frames [i];