/* Cache and manage frames for GDB, the GNU debugger.
Copyright (C) 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001,
- 2002, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GDB.
to sigaltstack).
However, it can be used as safety net to discover invalid frame
- IDs in certain circumstances.
+ IDs in certain circumstances. Assuming that NEXT is the immediate
+ inner frame to THIS and that NEXT and THIS are both NORMAL frames:
- * If frame NEXT is the immediate inner frame to THIS, and NEXT
- is a NORMAL frame, then the stack address of NEXT must be
- inner-than-or-equal to the stack address of THIS.
+ * The stack address of NEXT must be inner-than-or-equal to the stack
+ address of THIS.
Therefore, if frame_id_inner (THIS, NEXT) holds, some unwind
error has occurred.
- * If frame NEXT is the immediate inner frame to THIS, and NEXT
- is a NORMAL frame, and NEXT and THIS have different stack
- addresses, no other frame in the frame chain may have a stack
- address in between.
+ * If NEXT and THIS have different stack addresses, no other frame
+ in the frame chain may have a stack address in between.
Therefore, if frame_id_inner (TEST, THIS) holds, but
frame_id_inner (TEST, NEXT) does not hold, TEST cannot refer
- to a valid frame in the frame chain. */
+ to a valid frame in the frame chain.
+
+ The sanity checks above cannot be performed when a SIGTRAMP frame
+ is involved, because signal handlers might be executed on a different
+ stack than the stack used by the routine that caused the signal
+ to be raised. This can happen for instance when a thread exceeds
+ its maximum stack size. In this case, certain compilers implement
+ a stack overflow strategy that cause the handler to be run on a
+ different stack. */
static int
frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
struct regcache *scratch;
struct cleanup *cleanups;
+ if (get_frame_type (this_frame) == DUMMY_FRAME)
+ {
+ /* Popping a dummy frame involves restoring more than just registers.
+ dummy_frame_pop does all the work. */
+ dummy_frame_pop (get_frame_id (this_frame));
+ return;
+ }
+
/* Ensure that we have a frame to pop to. */
prev_frame = get_prev_frame_1 (this_frame);
scratch = frame_save_as_regcache (prev_frame);
cleanups = make_cleanup_regcache_xfree (scratch);
- /* If we are popping a dummy frame, clean up the associated
- data as well. */
- if (get_frame_type (this_frame) == DUMMY_FRAME)
- dummy_frame_pop (get_frame_id (this_frame));
-
/* FIXME: cagney/2003-03-16: It should be possible to tell the
target's register cache that it is about to be hit with a burst
register transfer and that the sequence of register writes should
*optimizedp = value_optimized_out (value);
*lvalp = VALUE_LVAL (value);
- *addrp = VALUE_ADDRESS (value);
+ *addrp = value_address (value);
*realnump = VALUE_REGNUM (value);
if (bufferp)
VALUE_REGNUM (value));
else if (VALUE_LVAL (value) == lval_memory)
fprintf_unfiltered (gdb_stdlog, " address=0x%s",
- paddr_nz (VALUE_ADDRESS (value)));
+ paddr_nz (value_address (value)));
else
fprintf_unfiltered (gdb_stdlog, " computed");
struct gdbarch *gdbarch = get_frame_arch (frame);
int i;
int maxsize;
+ int numregs;
/* Skip registers wholly inside of OFFSET. */
while (offset >= register_size (gdbarch, regnum))
/* Ensure that we will not read beyond the end of the register file.
This can only ever happen if the debug information is bad. */
maxsize = -offset;
- for (i = regnum;
- i < gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); i++)
+ numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+ for (i = regnum; i < numregs; i++)
{
int thissize = register_size (gdbarch, i);
if (thissize == 0)
error (_("No stack."));
if (!target_has_memory)
error (_("No memory."));
+ if (ptid_equal (inferior_ptid, null_ptid))
+ error (_("No selected thread."));
+ if (is_exited (inferior_ptid))
+ error (_("Invalid selected thread."));
if (is_executing (inferior_ptid))
error (_("Target is executing."));
static struct frame_info *selected_frame;
-static int
+int
has_stack_frames (void)
{
if (!target_has_registers || !target_has_stack || !target_has_memory)
return 0;
- /* If the current thread is executing, don't try to read from
- it. */
+ /* No current inferior, no frame. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return 0;
+
+ /* Don't try to read from a dead thread. */
+ if (is_exited (inferior_ptid))
+ return 0;
+
+ /* ... or from a spinning thread. */
if (is_executing (inferior_ptid))
return 0;
fi->next = create_sentinel_frame (get_current_regcache ());
+ /* Set/update this frame's cached PC value, found in the next frame.
+ Do this before looking for this frame's unwinder. A sniffer is
+ very likely to read this, and the corresponding unwinder is
+ entitled to rely that the PC doesn't magically change. */
+ fi->next->prev_pc.value = pc;
+ fi->next->prev_pc.p = 1;
+
/* Select/initialize both the unwind function and the frame's type
based on the PC. */
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
fi->this_id.p = 1;
- deprecated_update_frame_base_hack (fi, addr);
- deprecated_update_frame_pc_hack (fi, pc);
+ fi->this_id.value = frame_id_build (addr, pc);
if (frame_debug)
{
/* Observer for the target_changed event. */
-void
+static void
frame_observer_target_changed (struct target_ops *target)
{
reinit_frame_cache ();
/* Check that this frame's ID isn't inner to (younger, below, next)
the next frame. This happens when a frame unwind goes backwards.
- This check is valid only if the next frame is NORMAL. See the
- comment at frame_id_inner for details. */
- if (this_frame->next->unwind->type == NORMAL_FRAME
+ This check is valid only if this frame and the next frame are NORMAL.
+ See the comment at frame_id_inner for details. */
+ if (get_frame_type (this_frame) == NORMAL_FRAME
+ && this_frame->next->unwind->type == NORMAL_FRAME
&& frame_id_inner (get_frame_arch (this_frame->next), this_id,
get_frame_id (this_frame->next)))
{
/* Debug routine to print a NULL frame being returned. */
static void
-frame_debug_got_null_frame (struct ui_file *file,
- struct frame_info *this_frame,
+frame_debug_got_null_frame (struct frame_info *this_frame,
const char *reason)
{
if (frame_debug)
{
struct frame_info *prev_frame;
- /* Return the inner-most frame, when the caller passes in NULL. */
- /* NOTE: cagney/2002-11-09: Not sure how this would happen. The
- caller should have previously obtained a valid frame using
- get_selected_frame() and then called this code - only possibility
- I can think of is code behaving badly.
-
- NOTE: cagney/2003-01-10: Talk about code behaving badly. Check
- block_innermost_frame(). It does the sequence: frame = NULL;
- while (1) { frame = get_prev_frame (frame); .... }. Ulgh! Why
- it couldn't be written better, I don't know.
-
- NOTE: cagney/2003-01-11: I suspect what is happening in
- block_innermost_frame() is, when the target has no state
- (registers, memory, ...), it is still calling this function. The
- assumption being that this function will return NULL indicating
- that a frame isn't possible, rather than checking that the target
- has state and then calling get_current_frame() and
- get_prev_frame(). This is a guess mind. */
- if (this_frame == NULL)
- {
- /* NOTE: cagney/2002-11-09: There was a code segment here that
- would error out when CURRENT_FRAME was NULL. The comment
- that went with it made the claim ...
-
- ``This screws value_of_variable, which just wants a nice
- clean NULL return from block_innermost_frame if there are no
- frames. I don't think I've ever seen this message happen
- otherwise. And returning NULL here is a perfectly legitimate
- thing to do.''
-
- Per the above, this code shouldn't even be called with a NULL
- THIS_FRAME. */
- frame_debug_got_null_frame (gdb_stdlog, this_frame, "this_frame NULL");
- return current_frame;
- }
-
/* There is always a frame. If this assertion fails, suspect that
something should be calling get_selected_frame() or
get_current_frame(). */
user later decides to enable unwinds past main(), that will
automatically happen. */
{
- frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside main func");
+ frame_debug_got_null_frame (this_frame, "inside main func");
return NULL;
}
frame. */
if (this_frame->level + 2 > backtrace_limit)
{
- frame_debug_got_null_frame (gdb_stdlog, this_frame,
- "backtrace limit exceeded");
+ frame_debug_got_null_frame (this_frame, "backtrace limit exceeded");
return NULL;
}
&& get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0
&& inside_entry_func (this_frame))
{
- frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside entry func");
+ frame_debug_got_null_frame (this_frame, "inside entry func");
return NULL;
}
&& get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
&& get_frame_pc (this_frame) == 0)
{
- frame_debug_got_null_frame (gdb_stdlog, this_frame, "zero PC");
+ frame_debug_got_null_frame (this_frame, "zero PC");
return NULL;
}
return frame->unwind->type;
}
-void
-deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
-{
- if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "{ deprecated_update_frame_pc_hack (frame=%d,pc=0x%s) }\n",
- frame->level, paddr_nz (pc));
- /* NOTE: cagney/2003-03-11: Some architectures (e.g., Arm) are
- maintaining a locally allocated frame object. Since such frames
- are not in the frame chain, it isn't possible to assume that the
- frame has a next. Sigh. */
- if (frame->next != NULL)
- {
- /* While we're at it, update this frame's cached PC value, found
- in the next frame. Oh for the day when "struct frame_info"
- is opaque and this hack on hack can just go away. */
- frame->next->prev_pc.value = pc;
- frame->next->prev_pc.p = 1;
- }
-}
-
-void
-deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base)
-{
- if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "{ deprecated_update_frame_base_hack (frame=%d,base=0x%s) }\n",
- frame->level, paddr_nz (base));
- /* See comment in "frame.h". */
- frame->this_id.value.stack_addr = base;
-}
-
/* Memory access methods. */
void
struct gdbarch *
get_frame_arch (struct frame_info *this_frame)
{
+ /* In the future, this function will return a per-frame
+ architecture instead of current_gdbarch. Calling the
+ routine with a NULL value of this_frame is a bug! */
+ gdb_assert (this_frame);
+
return current_gdbarch;
}