This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[commit] Fix internal errors on setting $pc to the start of an inlined function
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sourceware dot org
- Date: Fri, 13 Nov 2009 18:00:09 -0500
- Subject: [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