This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[commit] Fix internal errors on setting $pc to the start of an inlined function


In order to hide inlined functions - to display their call sites, and
let "step" appear to step into the function - the inline frame
unwinder keeps a cache of where each thread is stopped and a bit of
state for that thread.  In one place where we read from the cache, we
stopped to check whether the $pc had changed since the cache was
stored.  This can happen in a lot of different ways; the most common
are "set $pc" and "load".

Somehow I didn't consider the fact that there are two other places we
retrieve state from the cache, though :-(  And one of them can be
reached before the frame sniffer.  So this patch pushes the check
into the cache lookup routine, where we can't miss it.

Tested on arm-none-eabi and x86_64-linux, checked in.

2009-11-13  Daniel Jacobowitz  <dan@codesourcery.com>

	* inline-frame.c (find_inline_frame_state): Check for changed PC
	here...
	(inline_frame_sniffer): ... not here.

Index: gdb/inline-frame.c
===================================================================
--- gdb/inline-frame.c	(revision 265230)
+++ gdb/inline-frame.c	(revision 265231)
@@ -22,6 +22,7 @@
 #include "block.h"
 #include "frame-unwind.h"
 #include "inferior.h"
+#include "regcache.h"
 #include "symtab.h"
 #include "vec.h"
 
@@ -59,7 +60,8 @@ DEF_VEC_O(inline_state_s);
 
 static VEC(inline_state_s) *inline_states;
 
-/* Locate saved inlined frame state for PTID, if it exists.  */
+/* Locate saved inlined frame state for PTID, if it exists
+   and is valid.  */
 
 static struct inline_state *
 find_inline_frame_state (ptid_t ptid)
@@ -70,7 +72,19 @@ find_inline_frame_state (ptid_t ptid)
   for (ix = 0; VEC_iterate (inline_state_s, inline_states, ix, state); ix++)
     {
       if (ptid_equal (state->ptid, ptid))
-	return state;
+	{
+	  struct regcache *regcache = get_thread_regcache (ptid);
+	  CORE_ADDR current_pc = regcache_read_pc (regcache);
+	  if (current_pc != state->saved_pc)
+	    {
+	      /* PC has changed - this context is invalid.  Use the
+		 default behavior.  */
+	      VEC_unordered_remove (inline_state_s, inline_states, ix);
+	      return NULL;
+	    }
+	  else
+	    return state;
+	}
     }
 
   return NULL;
@@ -225,13 +239,8 @@ inline_frame_sniffer (const struct frame
      can be stepped into later).  */
   if (state != NULL && state->skipped_frames > 0 && next_frame == NULL)
     {
-      if (this_pc != state->saved_pc)
-	state->skipped_frames = 0;
-      else
-	{
-	  gdb_assert (depth >= state->skipped_frames);
-	  depth -= state->skipped_frames;
-	}
+      gdb_assert (depth >= state->skipped_frames);
+      depth -= state->skipped_frames;
     }
 
   /* If all the inlined functions here already have frames, then pass

-- 
Daniel Jacobowitz
CodeSourcery


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]