/* 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.
return eq;
}
-int
+/* Safety net to check whether frame ID L should be inner to
+ frame ID R, according to their stack addresses.
+
+ This method cannot be used to compare arbitrary frames, as the
+ ranges of valid stack addresses may be discontiguous (e.g. due
+ to sigaltstack).
+
+ However, it can be used as safety net to discover invalid frame
+ IDs in certain circumstances. Assuming that NEXT is the immediate
+ inner frame to THIS and that NEXT and THIS are both NORMAL frames:
+
+ * 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 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.
+
+ 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)
{
int inner;
struct frame_info *
frame_find_by_id (struct frame_id id)
{
- struct frame_info *frame;
+ struct frame_info *frame, *prev_frame;
/* ZERO denotes the null frame, let the caller decide what to do
about it. Should it instead return get_current_frame()? */
if (!frame_id_p (id))
return NULL;
- for (frame = get_current_frame ();
- frame != NULL;
- frame = get_prev_frame (frame))
+ for (frame = get_current_frame (); ; frame = prev_frame)
{
struct frame_id this = get_frame_id (frame);
if (frame_id_eq (id, this))
/* An exact match. */
return frame;
- if (frame_id_inner (get_frame_arch (frame), id, this))
- /* Gone to far. */
+
+ prev_frame = get_prev_frame (frame);
+ if (!prev_frame)
+ return NULL;
+
+ /* As a safety net to avoid unnecessary backtracing while trying
+ to find an invalid ID, we check for a common situation where
+ we can detect from comparing stack addresses that no other
+ frame in the current frame chain can have this ID. See the
+ comment at frame_id_inner for details. */
+ if (get_frame_type (frame) == NORMAL_FRAME
+ && !frame_id_inner (get_frame_arch (frame), id, this)
+ && frame_id_inner (get_frame_arch (prev_frame), id,
+ get_frame_id (prev_frame)))
return NULL;
- /* Either we're not yet gone far enough out along the frame
- chain (inner(this,id)), or we're comparing frameless functions
- (same .base, different .func, no test available). Struggle
- on until we've definitly gone to far. */
}
return NULL;
}
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);
fprintf_unfiltered (gdb_stdlog, "\
{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
frame->level, regnum,
- frame_map_regnum_to_name (frame, regnum));
+ user_reg_map_regnum_to_name
+ (get_frame_arch (frame), regnum));
}
/* Find the unwinder. */
CORE_ADDR offset, int len, gdb_byte *myaddr)
{
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))
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;
+ 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)
+ break; /* This register is not available on this architecture. */
+ maxsize += thissize;
+ }
+ if (len > maxsize)
+ {
+ warning (_("Bad debug information detected: "
+ "Attempt to read %d bytes from registers."), len);
+ return 0;
+ }
+
/* Copy the data. */
while (len > 0)
{
}
}
-/* Map between a frame register number and its name. A frame register
- space is a superset of the cooked register space --- it also
- includes builtin registers. */
-
-int
-frame_map_name_to_regnum (struct frame_info *frame, const char *name, int len)
-{
- return user_reg_map_name_to_regnum (get_frame_arch (frame), name, len);
-}
-
-const char *
-frame_map_regnum_to_name (struct frame_info *frame, int regnum)
-{
- return user_reg_map_regnum_to_name (get_frame_arch (frame), regnum);
-}
-
/* Create a sentinel frame. */
static struct frame_info *
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.
- Exclude signal trampolines (due to sigaltstack the frame ID can
- go backwards) and sentinel frames (the test is meaningless). */
- if (this_frame->next->level >= 0
- && this_frame->next->unwind->type != SIGTRAMP_FRAME
- && frame_id_inner (get_frame_arch (this_frame), this_id,
+ 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)))
{
if (frame_debug)
/* 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_pc_unwind (frame->next);
}
-/* Return an address that falls within NEXT_FRAME's caller's code
- block, assuming that the caller is a THIS_TYPE frame. */
+/* Return an address that falls within THIS_FRAME's code block. */
CORE_ADDR
-frame_unwind_address_in_block (struct frame_info *next_frame,
- enum frame_type this_type)
+get_frame_address_in_block (struct frame_info *this_frame)
{
/* A draft address. */
- CORE_ADDR pc = frame_pc_unwind (next_frame);
-
- /* If NEXT_FRAME was called by a signal frame or dummy frame, then
- we shold not adjust the unwound PC. These frames may not call
- their next frame in the normal way; the operating system or GDB
- may have pushed their resume address manually onto the stack, so
- it may be the very first instruction. Even if the resume address
- was not manually pushed, they expect to be returned to. */
- if (this_type != NORMAL_FRAME)
- return pc;
-
- /* If THIS frame is not inner most (i.e., NEXT isn't the sentinel),
- and NEXT is `normal' (i.e., not a sigtramp, dummy, ....) THIS
- frame's PC ends up pointing at the instruction following the
- "call". Adjust that PC value so that it falls on the call
- instruction (which, hopefully, falls within THIS frame's code
- block). So far it's proved to be a very good approximation. See
- get_frame_type() for why ->type can't be used. */
- if (next_frame->level >= 0
- && get_frame_type (next_frame) == NORMAL_FRAME)
- --pc;
- return pc;
-}
+ CORE_ADDR pc = get_frame_pc (this_frame);
-CORE_ADDR
-get_frame_address_in_block (struct frame_info *this_frame)
-{
- return frame_unwind_address_in_block (this_frame->next,
- get_frame_type (this_frame));
+ struct frame_info *next_frame = this_frame->next;
+
+ /* Calling get_frame_pc returns the resume address for THIS_FRAME.
+ Normally the resume address is inside the body of the function
+ associated with THIS_FRAME, but there is a special case: when
+ calling a function which the compiler knows will never return
+ (for instance abort), the call may be the very last instruction
+ in the calling function. The resume address will point after the
+ call and may be at the beginning of a different function
+ entirely.
+
+ If THIS_FRAME is a signal frame or dummy frame, then we should
+ not adjust the unwound PC. For a dummy frame, GDB pushed the
+ resume address manually onto the stack. For a signal frame, the
+ OS may have pushed the resume address manually and invoked the
+ handler (e.g. GNU/Linux), or invoked the trampoline which called
+ the signal handler - but in either case the signal handler is
+ expected to return to the trampoline. So in both of these
+ cases we know that the resume address is executable and
+ related. So we only need to adjust the PC if THIS_FRAME
+ is a normal function.
+
+ If the program has been interrupted while THIS_FRAME is current,
+ then clearly the resume address is inside the associated
+ function. There are three kinds of interruption: debugger stop
+ (next frame will be SENTINEL_FRAME), operating system
+ signal or exception (next frame will be SIGTRAMP_FRAME),
+ or debugger-induced function call (next frame will be
+ DUMMY_FRAME). So we only need to adjust the PC if
+ NEXT_FRAME is a normal function.
+
+ We check the type of NEXT_FRAME first, since it is already
+ known; frame type is determined by the unwinder, and since
+ we have THIS_FRAME we've already selected an unwinder for
+ NEXT_FRAME. */
+ if (get_frame_type (next_frame) == NORMAL_FRAME
+ && get_frame_type (this_frame) == NORMAL_FRAME)
+ return pc - 1;
+
+ return pc;
}
static int
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;
}
CORE_ADDR
get_frame_sp (struct frame_info *this_frame)
{
- return frame_sp_unwind (this_frame->next);
-}
-
-CORE_ADDR
-frame_sp_unwind (struct frame_info *next_frame)
-{
- struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
/* Normality - an architecture that provides a way of obtaining any
frame inner-most address. */
if (gdbarch_unwind_sp_p (gdbarch))
- return gdbarch_unwind_sp (gdbarch, next_frame);
+ /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to
+ operate on THIS_FRAME now. */
+ return gdbarch_unwind_sp (gdbarch, this_frame->next);
/* Now things are really are grim. Hope that the value returned by
the gdbarch_sp_regnum register is meaningful. */
if (gdbarch_sp_regnum (gdbarch) >= 0)
- return frame_unwind_register_unsigned (next_frame,
- gdbarch_sp_regnum (gdbarch));
+ return get_frame_register_unsigned (this_frame,
+ gdbarch_sp_regnum (gdbarch));
internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
}
/* Clear cached fields dependent on the unwinder.
The previous PC is independent of the unwinder, but the previous
- function is not (see frame_unwind_address_in_block). */
+ function is not (see get_frame_address_in_block). */
frame->prev_func.p = 0;
frame->prev_func.addr = 0;