/* Cache and manage frames for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
- 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001,
+ 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "frame.h"
struct frame_info *next; /* down, inner, younger */
int prev_p;
struct frame_info *prev; /* up, outer, older */
+
+ /* The reason why we could not set PREV, or UNWIND_NO_REASON if we
+ could. Only valid when PREV_P is set. */
+ enum unwind_stop_reason stop_reason;
};
/* Flag to control debugging. */
value);
}
-static unsigned int backtrace_limit = UINT_MAX;
+static int backtrace_limit = INT_MAX;
static void
show_backtrace_limit (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
return !optimized;
}
+int
+get_frame_register_bytes (struct frame_info *frame, int regnum,
+ CORE_ADDR offset, int len, gdb_byte *myaddr)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+
+ /* Skip registers wholly inside of OFFSET. */
+ while (offset >= register_size (gdbarch, regnum))
+ {
+ offset -= register_size (gdbarch, regnum);
+ regnum++;
+ }
+
+ /* Copy the data. */
+ while (len > 0)
+ {
+ int curr_len = register_size (gdbarch, regnum) - offset;
+ if (curr_len > len)
+ curr_len = len;
+
+ if (curr_len == register_size (gdbarch, regnum))
+ {
+ if (!frame_register_read (frame, regnum, myaddr))
+ return 0;
+ }
+ else
+ {
+ gdb_byte buf[MAX_REGISTER_SIZE];
+ if (!frame_register_read (frame, regnum, buf))
+ return 0;
+ memcpy (myaddr, buf + offset, curr_len);
+ }
+
+ myaddr += curr_len;
+ len -= curr_len;
+ offset = 0;
+ regnum++;
+ }
+
+ return 1;
+}
+
+void
+put_frame_register_bytes (struct frame_info *frame, int regnum,
+ CORE_ADDR offset, int len, const gdb_byte *myaddr)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+
+ /* Skip registers wholly inside of OFFSET. */
+ while (offset >= register_size (gdbarch, regnum))
+ {
+ offset -= register_size (gdbarch, regnum);
+ regnum++;
+ }
+
+ /* Copy the data. */
+ while (len > 0)
+ {
+ int curr_len = register_size (gdbarch, regnum) - offset;
+ if (curr_len > len)
+ curr_len = len;
+
+ if (curr_len == register_size (gdbarch, regnum))
+ {
+ put_frame_register (frame, regnum, myaddr);
+ }
+ else
+ {
+ gdb_byte buf[MAX_REGISTER_SIZE];
+ frame_register_read (frame, regnum, buf);
+ memcpy (buf + offset, myaddr, curr_len);
+ put_frame_register (frame, regnum, buf);
+ }
+
+ myaddr += curr_len;
+ len -= curr_len;
+ offset = 0;
+ regnum++;
+ }
+}
/* Map between a frame register number and its name. A frame register
space is a superset of the cooked register space --- it also
paddr_nz (addr), paddr_nz (pc));
}
- fi = frame_obstack_zalloc (sizeof (struct frame_info));
+ fi = FRAME_OBSTACK_ZALLOC (struct frame_info);
fi->next = create_sentinel_frame (current_regcache);
}
}
+/* Find where a register is saved (in memory or another register).
+ The result of frame_register_unwind is just where it is saved
+ relative to this particular frame. */
+
+static void
+frame_register_unwind_location (struct frame_info *this_frame, int regnum,
+ int *optimizedp, enum lval_type *lvalp,
+ CORE_ADDR *addrp, int *realnump)
+{
+ gdb_assert (this_frame == NULL || this_frame->level >= 0);
+
+ while (this_frame != NULL)
+ {
+ frame_register_unwind (this_frame, regnum, optimizedp, lvalp,
+ addrp, realnump, NULL);
+
+ if (*optimizedp)
+ break;
+
+ if (*lvalp != lval_register)
+ break;
+
+ regnum = *realnump;
+ this_frame = get_next_frame (this_frame);
+ }
+}
+
/* Return a "struct frame_info" corresponding to the frame that called
THIS_FRAME. Returns NULL if there is no such frame.
return this_frame->prev;
}
this_frame->prev_p = 1;
+ this_frame->stop_reason = UNWIND_NO_REASON;
/* Check that this frame's ID was valid. If it wasn't, don't try to
unwind to the prev frame. Be careful to not apply this test to
fprint_frame (gdb_stdlog, NULL);
fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
}
+ this_frame->stop_reason = UNWIND_NULL_ID;
return NULL;
}
if (this_frame->next->level >= 0
&& this_frame->next->unwind->type != SIGTRAMP_FRAME
&& frame_id_inner (this_id, get_frame_id (this_frame->next)))
- error (_("Previous frame inner to this frame (corrupt stack?)"));
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // this frame ID is inner }\n");
+ }
+ this_frame->stop_reason = UNWIND_INNER_ID;
+ return NULL;
+ }
/* Check that this and the next frame are not identical. If they
are, there is most likely a stack cycle. As with the inner-than
test above, avoid comparing the inner-most and sentinel frames. */
if (this_frame->level > 0
&& frame_id_eq (this_id, get_frame_id (this_frame->next)))
- error (_("Previous frame identical to this frame (corrupt stack?)"));
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+ }
+ this_frame->stop_reason = UNWIND_SAME_ID;
+ return NULL;
+ }
+
+ /* Check that this and the next frame do not unwind the PC register
+ to the same memory location. If they do, then even though they
+ have different frame IDs, the new frame will be bogus; two
+ functions can't share a register save slot for the PC. This can
+ happen when the prologue analyzer finds a stack adjustment, but
+ no PC save.
+
+ This check does assume that the "PC register" is roughly a
+ traditional PC, even if the gdbarch_unwind_pc method adjusts
+ it (we do not rely on the value, only on the unwound PC being
+ dependent on this value). A potential improvement would be
+ to have the frame prev_pc method and the gdbarch unwind_pc
+ method set the same lval and location information as
+ frame_register_unwind. */
+ if (this_frame->level > 0
+ && PC_REGNUM >= 0
+ && get_frame_type (this_frame) == NORMAL_FRAME
+ && get_frame_type (this_frame->next) == NORMAL_FRAME)
+ {
+ int optimized, realnum;
+ enum lval_type lval, nlval;
+ CORE_ADDR addr, naddr;
+
+ frame_register_unwind_location (this_frame, PC_REGNUM, &optimized,
+ &lval, &addr, &realnum);
+ frame_register_unwind_location (get_next_frame (this_frame), PC_REGNUM,
+ &optimized, &nlval, &naddr, &realnum);
+
+ if (lval == lval_memory && lval == nlval && addr == naddr)
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // no saved PC }\n");
+ }
+
+ this_frame->stop_reason = UNWIND_NO_SAVED_PC;
+ this_frame->prev = NULL;
+ return NULL;
+ }
+ }
/* Allocate the new frame but do not wire it in to the frame chain.
Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along
return NULL;
}
- if (this_frame->level > backtrace_limit)
+ /* If the user's backtrace limit has been exceeded, stop. We must
+ add two to the current level; one of those accounts for backtrace_limit
+ being 1-based and the level being 0-based, and the other accounts for
+ the level of the new frame instead of the level of the current
+ frame. */
+ if (this_frame->level + 2 > backtrace_limit)
{
- error (_("Backtrace limit of %d exceeded"), backtrace_limit);
+ frame_debug_got_null_frame (gdb_stdlog, this_frame,
+ "backtrace limit exceeded");
+ return NULL;
}
/* If we're already inside the entry function for the main objfile,
safe_frame_unwind_memory (struct frame_info *this_frame,
CORE_ADDR addr, gdb_byte *buf, int len)
{
- /* NOTE: deprecated_read_memory_nobpt returns zero on success! */
- return !deprecated_read_memory_nobpt (addr, buf, len);
+ /* NOTE: read_memory_nobpt returns zero on success! */
+ return !read_memory_nobpt (addr, buf, len);
}
/* Architecture method. */
internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
}
+/* Return the reason why we can't unwind past FRAME. */
+
+enum unwind_stop_reason
+get_frame_unwind_stop_reason (struct frame_info *frame)
+{
+ /* If we haven't tried to unwind past this point yet, then assume
+ that unwinding would succeed. */
+ if (frame->prev_p == 0)
+ return UNWIND_NO_REASON;
+
+ /* Otherwise, we set a reason when we succeeded (or failed) to
+ unwind. */
+ return frame->stop_reason;
+}
+
+/* Return a string explaining REASON. */
+
+const char *
+frame_stop_reason_string (enum unwind_stop_reason reason)
+{
+ switch (reason)
+ {
+ case UNWIND_NULL_ID:
+ return _("unwinder did not report frame ID");
+
+ case UNWIND_INNER_ID:
+ return _("previous frame inner to this frame (corrupt stack?)");
+
+ case UNWIND_SAME_ID:
+ return _("previous frame identical to this frame (corrupt stack?)");
+
+ case UNWIND_NO_SAVED_PC:
+ return _("frame did not save the PC");
+
+ case UNWIND_NO_REASON:
+ case UNWIND_FIRST_ERROR:
+ default:
+ internal_error (__FILE__, __LINE__,
+ "Invalid frame stop reason");
+ }
+}
+
extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
static struct cmd_list_element *set_backtrace_cmdlist;
&set_backtrace_cmdlist,
&show_backtrace_cmdlist);
- add_setshow_uinteger_cmd ("limit", class_obscure,
- &backtrace_limit, _("\
+ add_setshow_integer_cmd ("limit", class_obscure,
+ &backtrace_limit, _("\
Set an upper bound on the number of backtrace levels."), _("\
Show the upper bound on the number of backtrace levels."), _("\
No more than the specified number of frames can be displayed or examined.\n\
Zero is unlimited."),
- NULL,
- show_backtrace_limit,
- &set_backtrace_cmdlist,
- &show_backtrace_cmdlist);
+ NULL,
+ show_backtrace_limit,
+ &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
/* Debug this files internals. */
add_setshow_zinteger_cmd ("frame", class_maintenance, &frame_debug, _("\