/* 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"
#include "command.h"
#include "gdbcmd.h"
#include "observer.h"
+#include "objfiles.h"
+#include "exceptions.h"
static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
moment leave this as speculation. */
int level;
- /* For each register, address of where it was saved on entry to the
- frame, or zero if it was not saved on entry to this frame. This
- includes special registers such as pc and fp saved in special
- ways in the stack frame. The SP_REGNUM is even more special, the
- address here is the sp for the previous frame, not the address
- where the sp was saved. */
- /* Allocated by frame_saved_regs_zalloc () which is called /
- initialized by DEPRECATED_FRAME_INIT_SAVED_REGS(). */
- CORE_ADDR *saved_regs; /*NUM_REGS + NUM_PSEUDO_REGS*/
-
- /* Anything extra for this structure that may have been defined in
- the machine dependent files. */
- /* Allocated by frame_extra_info_zalloc () which is called /
- initialized by DEPRECATED_INIT_EXTRA_FRAME_INFO */
- struct frame_extra_info *extra_info;
-
/* The frame's low-level unwinder and corresponding cache. The
low-level unwinder is responsible for unwinding register values
for the previous frame. The low-level unwind methods are
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. */
static int frame_debug;
+static void
+show_frame_debug (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Frame debugging is %s.\n"), value);
+}
/* Flag to indicate whether backtraces should stop at main et.al. */
static int backtrace_past_main;
-static unsigned int backtrace_limit = UINT_MAX;
+static void
+show_backtrace_past_main (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("\
+Whether backtraces should continue past \"main\" is %s.\n"),
+ value);
+}
+
+static int backtrace_past_entry;
+static void
+show_backtrace_past_entry (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("\
+Whether backtraces should continue past the entry point of a program is %s.\n"),
+ value);
+}
+
+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)
+{
+ fprintf_filtered (file, _("\
+An upper bound on the number of backtrace levels is %s.\n"),
+ value);
+}
+
static void
fprint_field (struct ui_file *file, const char *name, int p, CORE_ADDR addr)
if (!this_frame->prev_pc.p)
{
CORE_ADDR pc;
- if (gdbarch_unwind_pc_p (current_gdbarch))
+ if (this_frame->unwind == NULL)
+ this_frame->unwind
+ = frame_unwind_find_by_frame (this_frame->next,
+ &this_frame->prologue_cache);
+ if (this_frame->unwind->prev_pc != NULL)
+ /* A per-frame unwinder, prefer it. */
+ pc = this_frame->unwind->prev_pc (this_frame->next,
+ &this_frame->prologue_cache);
+ else if (gdbarch_unwind_pc_p (current_gdbarch))
{
/* The right way. The `pure' way. The one true way. This
method depends solely on the register-unwind code to
different ways that a PC could be unwound. */
pc = gdbarch_unwind_pc (current_gdbarch, this_frame);
}
- else if (this_frame->level < 0)
- {
- /* FIXME: cagney/2003-03-06: Old code and a sentinel
- frame. Do like was always done. Fetch the PC's value
- directly from the global registers array (via read_pc).
- This assumes that this frame belongs to the current
- global register cache. The assumption is dangerous. */
- pc = read_pc ();
- }
- else if (DEPRECATED_FRAME_SAVED_PC_P ())
- {
- /* FIXME: cagney/2003-03-06: Old code, but not a sentinel
- frame. Do like was always done. Note that this method,
- unlike unwind_pc(), tries to handle all the different
- frame cases directly. It fails. */
- pc = DEPRECATED_FRAME_SAVED_PC (this_frame);
- }
else
- internal_error (__FILE__, __LINE__, "No gdbarch_unwind_pc method");
+ internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
this_frame->prev_pc.value = pc;
this_frame->prev_pc.p = 1;
if (frame_debug)
}
static int
-do_frame_unwind_register (void *src, int regnum, void *buf)
+do_frame_register_read (void *src, int regnum, gdb_byte *buf)
{
- frame_unwind_register (src, regnum, buf);
+ frame_register_read (src, regnum, buf);
return 1;
}
+struct regcache *
+frame_save_as_regcache (struct frame_info *this_frame)
+{
+ struct regcache *regcache = regcache_xmalloc (current_gdbarch);
+ struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
+ regcache_save (regcache, do_frame_register_read, this_frame);
+ discard_cleanups (cleanups);
+ return regcache;
+}
+
void
frame_pop (struct frame_info *this_frame)
{
Save them in a scratch buffer so that there isn't a race between
trying to extract the old values from the current_regcache while
at the same time writing new values into that same cache. */
- struct regcache *scratch = regcache_xmalloc (current_gdbarch);
+ struct regcache *scratch
+ = frame_save_as_regcache (get_prev_frame_1 (this_frame));
struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch);
- regcache_save (scratch, do_frame_unwind_register, 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
void
frame_register_unwind (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
- CORE_ADDR *addrp, int *realnump, void *bufferp)
+ CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
{
struct frame_unwind_cache *cache;
void
frame_register (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
- CORE_ADDR *addrp, int *realnump, void *bufferp)
+ CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
{
/* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
that the value proper does not need to be fetched. */
gdb_assert (realnump != NULL);
/* gdb_assert (bufferp != NULL); */
- /* Ulgh! Old code that, for lval_register, sets ADDRP to the offset
- of the register in the register cache. It should instead return
- the REGNUM corresponding to that register. Translate the . */
- if (DEPRECATED_GET_SAVED_REGISTER_P ())
- {
- DEPRECATED_GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame,
- regnum, lvalp);
- /* Compute the REALNUM if the caller wants it. */
- if (*lvalp == lval_register)
- {
- int regnum;
- for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
- {
- if (*addrp == register_offset_hack (current_gdbarch, regnum))
- {
- *realnump = regnum;
- return;
- }
- }
- internal_error (__FILE__, __LINE__,
- "Failed to compute the register number corresponding"
- " to 0x%s", paddr_d (*addrp));
- }
- *realnump = -1;
- return;
- }
-
/* Obtain the register value by unwinding the register from the next
(more inner frame). */
gdb_assert (frame != NULL && frame->next != NULL);
}
void
-frame_unwind_register (struct frame_info *frame, int regnum, void *buf)
+frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf)
{
int optimized;
CORE_ADDR addr;
void
get_frame_register (struct frame_info *frame,
- int regnum, void *buf)
+ int regnum, gdb_byte *buf)
{
frame_unwind_register (frame->next, regnum, buf);
}
LONGEST
frame_unwind_register_signed (struct frame_info *frame, int regnum)
{
- char buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[MAX_REGISTER_SIZE];
frame_unwind_register (frame, regnum, buf);
- return extract_signed_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
+ return extract_signed_integer (buf, register_size (get_frame_arch (frame),
+ regnum));
}
LONGEST
ULONGEST
frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
{
- char buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[MAX_REGISTER_SIZE];
frame_unwind_register (frame, regnum, buf);
- return extract_unsigned_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
+ return extract_unsigned_integer (buf, register_size (get_frame_arch (frame),
+ regnum));
}
ULONGEST
frame_unwind_unsigned_register (struct frame_info *frame, int regnum,
ULONGEST *val)
{
- char buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[MAX_REGISTER_SIZE];
frame_unwind_register (frame, regnum, buf);
- (*val) = extract_unsigned_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
+ (*val) = extract_unsigned_integer (buf,
+ register_size (get_frame_arch (frame),
+ regnum));
}
void
-put_frame_register (struct frame_info *frame, int regnum, const void *buf)
+put_frame_register (struct frame_info *frame, int regnum,
+ const gdb_byte *buf)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
int realnum;
CORE_ADDR addr;
frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
if (optim)
- error ("Attempt to assign to a value that was optimized out.");
+ error (_("Attempt to assign to a value that was optimized out."));
switch (lval)
{
case lval_memory:
{
/* FIXME: write_memory doesn't yet take constant buffers.
Arrrg! */
- char tmp[MAX_REGISTER_SIZE];
+ gdb_byte tmp[MAX_REGISTER_SIZE];
memcpy (tmp, buf, register_size (gdbarch, regnum));
write_memory (addr, tmp, register_size (gdbarch, regnum));
break;
regcache_cooked_write (current_regcache, realnum, buf);
break;
default:
- error ("Attempt to assign to an unmodifiable value.");
+ error (_("Attempt to assign to an unmodifiable value."));
}
}
/* frame_register_read ()
Find and return the value of REGNUM for the specified stack frame.
- The number of bytes copied is DEPRECATED_REGISTER_RAW_SIZE
- (REGNUM).
+ The number of bytes copied is REGISTER_SIZE (REGNUM).
Returns 0 if the register value could not be found. */
int
-frame_register_read (struct frame_info *frame, int regnum, void *myaddr)
+frame_register_read (struct frame_info *frame, int regnum,
+ gdb_byte *myaddr)
{
int optimized;
enum lval_type lval;
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
return data;
}
-CORE_ADDR *
-frame_saved_regs_zalloc (struct frame_info *fi)
-{
- fi->saved_regs = (CORE_ADDR *)
- frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
- return fi->saved_regs;
-}
-
-CORE_ADDR *
-deprecated_get_frame_saved_regs (struct frame_info *fi)
-{
- return fi->saved_regs;
-}
-
/* Return the innermost (currently executing) stack frame. This is
split into two functions. The function unwind_to_current_frame()
is wrapped in catch exceptions so that, even when the unwind of the
explicitly checks that ``print $pc'' with no registers prints "No
registers". */
if (!target_has_registers)
- error ("No registers.");
+ error (_("No registers."));
if (!target_has_stack)
- error ("No stack.");
+ error (_("No stack."));
if (!target_has_memory)
- error ("No memory.");
+ error (_("No memory."));
if (current_frame == NULL)
{
struct frame_info *sentinel_frame =
create_sentinel_frame (current_regcache);
if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
- NULL, RETURN_MASK_ERROR) != 0)
+ RETURN_MASK_ERROR) != 0)
{
/* Oops! Fake a current frame? Is this useful? It has a PC
of zero, for instance. */
thrown. */
struct frame_info *
-get_selected_frame (void)
+get_selected_frame (const char *message)
{
if (deprecated_selected_frame == NULL)
- /* Hey! Don't trust this. It should really be re-finding the
- last selected frame of the currently selected thread. This,
- though, is better than nothing. */
- select_frame (get_current_frame ());
+ {
+ if (message != NULL && (!target_has_registers
+ || !target_has_stack
+ || !target_has_memory))
+ error (("%s"), message);
+ /* Hey! Don't trust this. It should really be re-finding the
+ last selected frame of the currently selected thread. This,
+ though, is better than nothing. */
+ select_frame (get_current_frame ());
+ }
/* There is always a frame. */
gdb_assert (deprecated_selected_frame != NULL);
return deprecated_selected_frame;
{
if (!target_has_registers || !target_has_stack || !target_has_memory)
return NULL;
- return get_selected_frame ();
+ return get_selected_frame (NULL);
}
/* Select frame FI (or NULL - to invalidate the current frame). */
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);
deprecated_update_frame_base_hack (fi, addr);
deprecated_update_frame_pc_hack (fi, pc);
- if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
- DEPRECATED_INIT_EXTRA_FRAME_INFO (0, fi);
-
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "-> ");
}
}
+/* 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
}
}
+/* Is this (non-sentinel) frame in the "main"() function? */
+
+static int
+inside_main_func (struct frame_info *this_frame)
+{
+ struct minimal_symbol *msymbol;
+ CORE_ADDR maddr;
+
+ if (symfile_objfile == 0)
+ return 0;
+ msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile);
+ if (msymbol == NULL)
+ return 0;
+ /* Make certain that the code, and not descriptor, address is
+ returned. */
+ maddr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ SYMBOL_VALUE_ADDRESS (msymbol),
+ ¤t_target);
+ return maddr == get_frame_func (this_frame);
+}
+
+/* Test whether THIS_FRAME is inside the process entry point function. */
+
+static int
+inside_entry_func (struct frame_info *this_frame)
+{
+ return (get_frame_func (this_frame) == entry_point_address ());
+}
+
/* Return a structure containing various interesting information about
the frame that called THIS_FRAME. Returns NULL if there is entier
no such frame or the frame fails any of a set of target-independent
get_current_frame(). */
gdb_assert (this_frame != NULL);
- /* Make sure we pass an address within THIS_FRAME's code block to
- inside_main_func(). Otherwise, we might stop unwinding at a
- function which has a call instruction as its last instruction if
- that function immediately precedes main(). */
+ /* tausq/2004-12-07: Dummy frames are skipped because it doesn't make much
+ sense to stop unwinding at a dummy frame. One place where a dummy
+ frame may have an address "inside_main_func" is on HPUX. On HPUX, the
+ pcsqh register (space register for the instruction at the head of the
+ instruction queue) cannot be written directly; the only way to set it
+ is to branch to code that is in the target space. In order to implement
+ frame dummies on HPUX, the called function is made to jump back to where
+ the inferior was when the user function was called. If gdb was inside
+ the main function when we created the dummy frame, the dummy frame will
+ point inside the main function. */
if (this_frame->level >= 0
+ && get_frame_type (this_frame) != DUMMY_FRAME
&& !backtrace_past_main
- && inside_main_func (get_frame_address_in_block (this_frame)))
- /* Don't unwind past main(), but always unwind the sentinel frame.
- Note, this is done _before_ the frame has been marked as
- previously unwound. That way if the user later decides to
- allow unwinds past main(), that just happens. */
+ && inside_main_func (this_frame))
+ /* Don't unwind past main(). Note, this is done _before_ the
+ frame has been marked as previously unwound. That way if the
+ user later decides to enable unwinds past main(), that will
+ automatically happen. */
{
frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside main func");
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,
dummy frame PCs typically land in the entry func. Don't apply
this test to the sentinel frame. Sentinel frames should always
be allowed to unwind. */
- /* NOTE: cagney/2003-02-25: Don't enable until someone has found
- hard evidence that this is needed. */
/* NOTE: cagney/2003-07-07: Fixed a bug in inside_main_func() -
wasn't checking for "main" in the minimal symbols. With that
fixed asm-source tests now stop in "main" instead of halting the
I guess) to determine the address range of the start function.
That should provide a far better stopper than the current
heuristics. */
- /* NOTE: cagney/2003-07-15: Need to add a "set backtrace
- beyond-entry-func" command so that this can be selectively
- disabled. */
- if (0
-#if 0
- && backtrace_beyond_entry_func
-#endif
- && this_frame->unwind->type != DUMMY_FRAME && this_frame->level >= 0
+ /* NOTE: tausq/2004-10-09: this is needed if, for example, the compiler
+ applied tail-call optimizations to main so that a function called
+ from main returns directly to the caller of main. Since we don't
+ stop at main, we should at least stop at the entry point of the
+ application. */
+ if (!backtrace_past_entry
+ && 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");
return NULL;
}
+ /* Assume that the only way to get a zero PC is through something
+ like a SIGSEGV or a dummy frame, and hence that NORMAL frames
+ will never unwind a zero PC. */
+ if (this_frame->level > 0
+ && get_frame_type (this_frame) == NORMAL_FRAME
+ && 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");
+ return NULL;
+ }
+
return get_prev_frame_1 (this_frame);
}
return frame->unwind->type;
}
-struct frame_extra_info *
-get_frame_extra_info (struct frame_info *fi)
-{
- return fi->extra_info;
-}
-
-struct frame_extra_info *
-frame_extra_info_zalloc (struct frame_info *fi, long size)
-{
- fi->extra_info = frame_obstack_zalloc (size);
- return fi->extra_info;
-}
-
void
deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
{
frame->this_id.value.stack_addr = base;
}
-struct frame_info *
-deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs,
- long sizeof_extra_info)
-{
- struct frame_info *frame = XMALLOC (struct frame_info);
- memset (frame, 0, sizeof (*frame));
- frame->this_id.p = 1;
- make_cleanup (xfree, frame);
- if (sizeof_saved_regs > 0)
- {
- frame->saved_regs = xcalloc (1, sizeof_saved_regs);
- make_cleanup (xfree, frame->saved_regs);
- }
- if (sizeof_extra_info > 0)
- {
- frame->extra_info = xcalloc (1, sizeof_extra_info);
- make_cleanup (xfree, frame->extra_info);
- }
- return frame;
-}
-
/* Memory access methods. */
void
-get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr, void *buf,
- int len)
+get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr,
+ gdb_byte *buf, int len)
{
read_memory (addr, buf, len);
}
int
safe_frame_unwind_memory (struct frame_info *this_frame,
- CORE_ADDR addr, void *buf, int len)
+ 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. */
frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp);
return sp;
}
- internal_error (__FILE__, __LINE__, "Missing unwind SP 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 */
observer_attach_target_changed (frame_observer_target_changed);
- add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, "\
+ add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
Set backtrace specific variables.\n\
-Configure backtrace variables such as the backtrace limit",
+Configure backtrace variables such as the backtrace limit"),
&set_backtrace_cmdlist, "set backtrace ",
0/*allow-unknown*/, &setlist);
- add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, "\
+ add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, _("\
Show backtrace specific variables\n\
-Show backtrace variables such as the backtrace limit",
+Show backtrace variables such as the backtrace limit"),
&show_backtrace_cmdlist, "show backtrace ",
0/*allow-unknown*/, &showlist);
add_setshow_boolean_cmd ("past-main", class_obscure,
- &backtrace_past_main, "\
-Set whether backtraces should continue past \"main\".", "\
-Show whether backtraces should continue past \"main\".", "\
+ &backtrace_past_main, _("\
+Set whether backtraces should continue past \"main\"."), _("\
+Show whether backtraces should continue past \"main\"."), _("\
Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
the backtrace at \"main\". Set this variable if you need to see the rest\n\
-of the stack trace.", "\
-Whether backtraces should continue past \"main\" is %s.",
- NULL, NULL, &set_backtrace_cmdlist,
+of the stack trace."),
+ NULL,
+ show_backtrace_past_main,
+ &set_backtrace_cmdlist,
&show_backtrace_cmdlist);
- add_setshow_uinteger_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.", "\
+ add_setshow_boolean_cmd ("past-entry", class_obscure,
+ &backtrace_past_entry, _("\
+Set whether backtraces should continue past the entry point of a program."),
+ _("\
+Show whether backtraces should continue past the entry point of a program."),
+ _("\
+Normally there are no callers beyond the entry point of a program, so GDB\n\
+will terminate the backtrace there. Set this variable if you need to see \n\
+the rest of the stack trace."),
+ NULL,
+ show_backtrace_past_entry,
+ &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
+
+ 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.", "\
-An upper bound on the number of backtrace levels is %s.",
- NULL, NULL, &set_backtrace_cmdlist,
- &show_backtrace_cmdlist);
+Zero is unlimited."),
+ NULL,
+ show_backtrace_limit,
+ &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
/* Debug this files internals. */
- deprecated_add_show_from_set
- (add_set_cmd ("frame", class_maintenance, var_zinteger,
- &frame_debug, "Set frame debugging.\n\
-When non-zero, frame specific internal debugging is enabled.", &setdebuglist),
- &showdebuglist);
+ add_setshow_zinteger_cmd ("frame", class_maintenance, &frame_debug, _("\
+Set frame debugging."), _("\
+Show frame debugging."), _("\
+When non-zero, frame specific internal debugging is enabled."),
+ NULL,
+ show_frame_debug,
+ &setdebuglist, &showdebuglist);
}