[PATCH 2/2] Report stop locations in inlined functions.

Keith Seitz keiths@redhat.com
Fri Oct 20 19:21:00 GMT 2017


On 07/18/2017 10:46 AM, Pedro Alves wrote:

> Maybe we need to move this bit in infrun.c:
> 
>   /* See if there is a breakpoint/watchpoint/catchpoint/etc. that
>      handles this event.  */
>   ecs->event_thread->control.stop_bpstat
>     = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
> 			  stop_pc, ecs->ptid, &ecs->ws, stop_chain);
> 
> a bit above, before the skip_inline_frames call, and then
> you don't even need to pass down the bpstat to skip_inline_frames,
> as you can then access it from the thread directly?

I've tried this approach, and it causes a single test regression in gdb.python/py-finish-breakpoint.exp.

It's taken me quite some time to figure out what was happening, but the key is that the regressing test involved a breakpoint condition that was an inferior function call (which failed). In that case, the global inline frame state was left with a stray inline frame and the assertion in skip_inline_frames was triggered.

There are two ways to fix this. The easy way is to call clear_inline_frame_state sometime after the exception occurred, such as where the exception is caught in bpstat_check_breakpoint_conditions(*1). I'm not entirely confident that doing this every time is safe, so I'm leaning toward option #2.

The "more" complex option is to only create the stop_chain, later passing it to bpstat_stop_status(*2). This avoids checking the breakpoint condition before calling skip_inline_frames, avoiding the exception problem altogether.

If you've a preference, I'd like to hear it.

Keith

*1 The "simpler" solution (for illustration only)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 32ceea7..4d2ebd8 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -68,6 +68,7 @@
 #include "format.h"
 #include "thread-fsm.h"
 #include "tid-parse.h"
+#include "inline-frame.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -5359,6 +5360,7 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
            }
          CATCH (ex, RETURN_MASK_ALL)
            {
+             clear_inline_frame_state (ptid);
              exception_fprintf (gdb_stderr, ex,
                                 "Error in testing breakpoint condition:\n");
            }
diff --git a/gdb/infrun.c b/gdb/infrun.c
index d00c5f6..60fd166 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -5864,6 +5864,12 @@ handle_signal_stop (struct execution_control_state *ecs)
   stop_print_frame = 1;
   stopped_by_random_signal = 0;
 
+  /* See if there is a breakpoint/watchpoint/catchpoint/etc. that
+     handles this event.  */
+  ecs->event_thread->control.stop_bpstat
+    = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+			  stop_pc, ecs->ptid, &ecs->ws);
+
   /* Hide inlined functions starting here, unless we just performed stepi or
      nexti.  After stepi and nexti, always show the innermost frame (not any
      inline function call sites).  */
@@ -5894,7 +5900,12 @@ handle_signal_stop (struct execution_control_state *ecs)
 					     ecs->event_thread->prev_pc,
 					     &ecs->ws)))
 	{
-	  skip_inline_frames (ecs->ptid);
+	  struct breakpoint *bpt = NULL;
+
+	  if (ecs->event_thread->control.stop_bpstat != NULL)
+	    bpt = ecs->event_thread->control.stop_bpstat->breakpoint_at;
+
+	  skip_inline_frames (ecs->ptid, bpt);
 
 	  /* Re-fetch current thread's frame in case that invalidated
 	     the frame cache.  */
@@ -5939,12 +5950,6 @@ handle_signal_stop (struct execution_control_state *ecs)
 	}
     }
 
-  /* See if there is a breakpoint/watchpoint/catchpoint/etc. that
-     handles this event.  */
-  ecs->event_thread->control.stop_bpstat
-    = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
-			  stop_pc, ecs->ptid, &ecs->ws);
-
   /* Following in case break condition called a
      function.  */
   stop_print_frame = 1;



*2 The more "complex," safer solution (for illustration only)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index d00c5f6..8c70aba 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -5863,6 +5863,7 @@ handle_signal_stop (struct execution_control_state *ecs)
   ecs->event_thread->control.stop_step = 0;
   stop_print_frame = 1;
   stopped_by_random_signal = 0;
+  bpstat stop_chain = NULL;
 
   /* Hide inlined functions starting here, unless we just performed stepi or
      nexti.  After stepi and nexti, always show the innermost frame (not any
@@ -5894,7 +5895,13 @@ handle_signal_stop (struct execution_control_state *ecs)
                                             ecs->event_thread->prev_pc,
                                             &ecs->ws)))
        {
-         skip_inline_frames (ecs->ptid);
+         struct breakpoint *bpt = NULL;
+
+         stop_chain = build_bpstat_chain (aspace, stop_pc, &ecs->ws);
+         if (stop_chain != NULL)
+           bpt = stop_chain->breakpoint_at;
+
+         skip_inline_frames (ecs->ptid, bpt);
 
          /* Re-fetch current thread's frame in case that invalidated
             the frame cache.  */
@@ -5943,7 +5950,7 @@ handle_signal_stop (struct execution_control_state *ecs)
      handles this event.  */
   ecs->event_thread->control.stop_bpstat
     = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
-                         stop_pc, ecs->ptid, &ecs->ws);
+                         stop_pc, ecs->ptid, &ecs->ws, stop_chain);
 
   /* Following in case break condition called a
      function.  */



More information about the Gdb-patches mailing list