/* Cache and manage frames for GDB, the GNU debugger.
Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
- 2001, 2002, 2003 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
#include "regcache.h"
#include "gdb_assert.h"
#include "gdb_string.h"
-#include "builtin-regs.h"
+#include "user-regs.h"
#include "gdb_obstack.h"
#include "dummy-frame.h"
#include "sentinel-frame.h"
#include "command.h"
#include "gdbcmd.h"
+/* We keep a cache of stack frames, each of which is a "struct
+ frame_info". The innermost one gets allocated (in
+ wait_for_inferior) each time the inferior stops; current_frame
+ points to it. Additional frames get allocated (in get_prev_frame)
+ as needed, and are chained through the next and prev fields. Any
+ time that the frame cache becomes invalid (most notably when we
+ execute something, but also if we change how we interpret the
+ frames (e.g. "set heuristic-fence-post" in mips-tdep.c, or anything
+ which reads new symbols)), we should call reinit_frame_cache. */
+
+struct frame_info
+{
+ /* Level of this frame. The inner-most (youngest) frame is at level
+ 0. As you move towards the outer-most (oldest) frame, the level
+ increases. This is a cached value. It could just as easily be
+ computed by counting back from the selected frame to the inner
+ most frame. */
+ /* NOTE: cagney/2002-04-05: Perhaphs a level of ``-1'' should be
+ reserved to indicate a bogus frame - one that has been created
+ just to keep GDB happy (GDB always needs a frame). For the
+ moment leave this as speculation. */
+ int level;
+
+ /* The frame's type. */
+ /* FIXME: cagney/2003-04-02: Should instead be returning
+ ->unwind->type. Unfortunately, legacy code is still explicitly
+ setting the type using the method deprecated_set_frame_type.
+ Eliminate that method and this field can be eliminated. */
+ enum frame_type type;
+
+ /* 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
+ selected based on the presence, or otherwize, of register unwind
+ information such as CFI. */
+ void *prologue_cache;
+ const struct frame_unwind *unwind;
+
+ /* Cached copy of the previous frame's resume address. */
+ struct {
+ int p;
+ CORE_ADDR value;
+ } prev_pc;
+
+ /* Cached copy of the previous frame's function address. */
+ struct
+ {
+ CORE_ADDR addr;
+ int p;
+ } prev_func;
+
+ /* This frame's ID. */
+ struct
+ {
+ int p;
+ struct frame_id value;
+ } this_id;
+
+ /* The frame's high-level base methods, and corresponding cache.
+ The high level base methods are selected based on the frame's
+ debug info. */
+ const struct frame_base *base;
+ void *base_cache;
+
+ /* Pointers to the next (down, inner, younger) and previous (up,
+ outer, older) frame_info's in the frame cache. */
+ struct frame_info *next; /* down, inner, younger */
+ int prev_p;
+ struct frame_info *prev; /* up, outer, older */
+};
+
/* Flag to control debugging. */
static int frame_debug;
-/* Flag to indicate whether backtraces should stop at main. */
+/* Flag to indicate whether backtraces should stop at main et.al. */
+
+static int backtrace_past_main;
+static unsigned int backtrace_limit = UINT_MAX;
+
+
+void
+fprint_frame_id (struct ui_file *file, struct frame_id id)
+{
+ fprintf_unfiltered (file, "{stack=0x%s,code=0x%s,special=0x%s}",
+ paddr_nz (id.stack_addr),
+ paddr_nz (id.code_addr),
+ paddr_nz (id.special_addr));
+}
+
+static void
+fprint_frame_type (struct ui_file *file, enum frame_type type)
+{
+ switch (type)
+ {
+ case UNKNOWN_FRAME:
+ fprintf_unfiltered (file, "UNKNOWN_FRAME");
+ return;
+ case NORMAL_FRAME:
+ fprintf_unfiltered (file, "NORMAL_FRAME");
+ return;
+ case DUMMY_FRAME:
+ fprintf_unfiltered (file, "DUMMY_FRAME");
+ return;
+ case SIGTRAMP_FRAME:
+ fprintf_unfiltered (file, "SIGTRAMP_FRAME");
+ return;
+ default:
+ fprintf_unfiltered (file, "<unknown type>");
+ return;
+ };
+}
-static int backtrace_below_main;
+static void
+fprint_frame (struct ui_file *file, struct frame_info *fi)
+{
+ if (fi == NULL)
+ {
+ fprintf_unfiltered (file, "<NULL frame>");
+ return;
+ }
+ fprintf_unfiltered (file, "{");
+ fprintf_unfiltered (file, "level=%d", fi->level);
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "type=");
+ fprint_frame_type (file, fi->type);
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "unwind=");
+ if (fi->unwind != NULL)
+ gdb_print_host_address (fi->unwind, file);
+ else
+ fprintf_unfiltered (file, "<unknown>");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "pc=");
+ if (fi->next != NULL && fi->next->prev_pc.p)
+ fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_pc.value));
+ else
+ fprintf_unfiltered (file, "<unknown>");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "id=");
+ if (fi->this_id.p)
+ fprint_frame_id (file, fi->this_id.value);
+ else
+ fprintf_unfiltered (file, "<unknown>");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "func=");
+ if (fi->next != NULL && fi->next->prev_func.p)
+ fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_func.addr));
+ else
+ fprintf_unfiltered (file, "<unknown>");
+ fprintf_unfiltered (file, "}");
+}
/* Return a frame uniq ID that can be used to, later, re-find the
frame. */
if (!fi->this_id.p)
{
gdb_assert (!legacy_frame_p (current_gdbarch));
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ",
+ fi->level);
+ /* Find the unwinder. */
+ if (fi->unwind == NULL)
+ {
+ fi->unwind = frame_unwind_find_by_frame (fi->next);
+ /* FIXME: cagney/2003-04-02: Rather than storing the frame's
+ type in the frame, the unwinder's type should be returned
+ directly. Unfortunately, legacy code, called by
+ legacy_get_prev_frame, explicitly set the frames type
+ using the method deprecated_set_frame_type(). */
+ fi->type = fi->unwind->type;
+ }
/* Find THIS frame's ID. */
fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value);
fi->this_id.p = 1;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame_id (gdb_stdlog, fi->this_id.value);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
}
- return frame_id_build (fi->this_id.value.stack_addr, get_frame_pc (fi));
+ return fi->this_id.value;
}
const struct frame_id null_frame_id; /* All zeros. */
struct frame_id
-frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
+frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
+ CORE_ADDR special_addr)
{
struct frame_id id;
id.stack_addr = stack_addr;
id.code_addr = code_addr;
+ id.special_addr = special_addr;
return id;
}
+struct frame_id
+frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
+{
+ return frame_id_build_special (stack_addr, code_addr, 0);
+}
+
int
frame_id_p (struct frame_id l)
{
int p;
/* The .code can be NULL but the .stack cannot. */
p = (l.stack_addr != 0);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
+ fprint_frame_id (gdb_stdlog, l);
+ fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", p);
+ }
return p;
}
else if (l.code_addr == 0 || r.code_addr == 0)
/* A zero code addr is a wild card, always succeed. */
eq = 1;
- else if (l.code_addr == r.code_addr)
- /* The .stack and .code are identical, the ID's are identical. */
+ else if (l.code_addr != r.code_addr)
+ /* If .code addresses are different, the frames are different. */
+ eq = 0;
+ else if (l.special_addr == 0 || r.special_addr == 0)
+ /* A zero special addr is a wild card (or unused), always succeed. */
+ eq = 1;
+ else if (l.special_addr == r.special_addr)
+ /* Frames are equal. */
eq = 1;
else
- /* FIXME: cagney/2003-04-06: This should be zero. Can't yet do
- this because most frame ID's are not being initialized
- correctly. */
- eq = 1;
+ /* No luck. */
+ eq = 0;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l=");
+ fprint_frame_id (gdb_stdlog, l);
+ fprintf_unfiltered (gdb_stdlog, ",r=");
+ fprint_frame_id (gdb_stdlog, r);
+ fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", eq);
+ }
return eq;
}
/* Only return non-zero when strictly inner than. Note that, per
comment in "frame.h", there is some fuzz here. Frameless
functions are not strictly inner than (same .stack but
- different .code). */
+ different .code and/or .special address). */
inner = INNER_THAN (l.stack_addr, r.stack_addr);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ frame_id_inner (l=");
+ fprint_frame_id (gdb_stdlog, l);
+ fprintf_unfiltered (gdb_stdlog, ",r=");
+ fprint_frame_id (gdb_stdlog, r);
+ fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", inner);
+ }
return inner;
}
implementation is no more than:
frame_unwind_register (this_frame, ISA_PC_REGNUM, buf);
- return extract_address (buf, size of ISA_PC_REGNUM);
+ return extract_unsigned_integer (buf, size of ISA_PC_REGNUM);
Note: this method is very heavily dependent on a correct
register-unwind implementation, it pays to fix that
internal_error (__FILE__, __LINE__, "No gdbarch_unwind_pc method");
this_frame->prev_pc.value = pc;
this_frame->prev_pc.p = 1;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_pc_unwind (this_frame=%d) -> 0x%s }\n",
+ this_frame->level,
+ paddr_nz (this_frame->prev_pc.value));
}
return this_frame->prev_pc.value;
}
{
if (!fi->prev_func.p)
{
+ /* Make certain that this, and not the adjacent, function is
+ found. */
+ CORE_ADDR addr_in_block = frame_unwind_address_in_block (fi);
fi->prev_func.p = 1;
- fi->prev_func.addr = get_pc_function_start (frame_pc_unwind (fi));
+ fi->prev_func.addr = get_pc_function_start (addr_in_block);
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_func_unwind (fi=%d) -> 0x%s }\n",
+ fi->level, paddr_nz (fi->prev_func.addr));
}
return fi->prev_func.addr;
}
burst register transfer and that the sequence of register
writes should be batched. The pair target_prepare_to_store()
and target_store_registers() kind of suggest this
- functionality. Unfortunatly, they don't implement it. Their
+ functionality. Unfortunately, they don't implement it. Their
lack of a formal definition can lead to targets writing back
bogus values (arguably a bug in the target code mind). */
/* Now copy those saved registers into the current regcache.
{
struct frame_unwind_cache *cache;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "\
+{ frame_register_unwind (frame=%d,regnum=%d(%s),...) ",
+ frame->level, regnum,
+ frame_map_regnum_to_name (frame, regnum));
+ }
+
/* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
that the value proper does not need to be fetched. */
gdb_assert (optimizedp != NULL);
detected the problem before calling here. */
gdb_assert (frame != NULL);
+ /* Find the unwinder. */
+ if (frame->unwind == NULL)
+ {
+ frame->unwind = frame_unwind_find_by_frame (frame->next);
+ /* FIXME: cagney/2003-04-02: Rather than storing the frame's
+ type in the frame, the unwinder's type should be returned
+ directly. Unfortunately, legacy code, called by
+ legacy_get_prev_frame, explicitly set the frames type using
+ the method deprecated_set_frame_type(). */
+ frame->type = frame->unwind->type;
+ }
+
/* Ask this frame to unwind its register. See comment in
"frame-unwind.h" for why NEXT frame and this unwind cace are
passed in. */
frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
optimizedp, lvalp, addrp, realnump, bufferp);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "->");
+ fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp));
+ fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp));
+ fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp)));
+ fprintf_unfiltered (gdb_stdlog, " *bufferp=");
+ if (bufferp == NULL)
+ fprintf_unfiltered (gdb_stdlog, "<NULL>");
+ else
+ {
+ int i;
+ const unsigned char *buf = bufferp;
+ fprintf_unfiltered (gdb_stdlog, "[");
+ for (i = 0; i < register_size (current_gdbarch, regnum); i++)
+ fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+ fprintf_unfiltered (gdb_stdlog, "]");
+ }
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
}
void
}
void
-frame_unwind_signed_register (struct frame_info *frame, int regnum,
- LONGEST *val)
+get_frame_register (struct frame_info *frame,
+ int regnum, void *buf)
{
- void *buf = alloca (MAX_REGISTER_RAW_SIZE);
- frame_unwind_register (frame, regnum, buf);
- (*val) = extract_signed_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
+ frame_unwind_register (frame->next, regnum, buf);
}
-void
-frame_unwind_unsigned_register (struct frame_info *frame, int regnum,
- ULONGEST *val)
+LONGEST
+frame_unwind_register_signed (struct frame_info *frame, int regnum)
{
- void *buf = alloca (MAX_REGISTER_RAW_SIZE);
+ char buf[MAX_REGISTER_SIZE];
frame_unwind_register (frame, regnum, buf);
- (*val) = extract_unsigned_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
+ return extract_signed_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
}
-void
-frame_read_register (struct frame_info *frame, int regnum, void *buf)
+LONGEST
+get_frame_register_signed (struct frame_info *frame, int regnum)
{
- gdb_assert (frame != NULL && frame->next != NULL);
- frame_unwind_register (frame->next, regnum, buf);
+ return frame_unwind_register_signed (frame->next, regnum);
}
-void
-frame_read_unsigned_register (struct frame_info *frame, int regnum,
- ULONGEST *val)
-{
- /* NOTE: cagney/2002-10-31: There is a bit of dogma here - there is
- always a frame. Both this, and the equivalent
- frame_read_signed_register() function, can only be called with a
- valid frame. If, for some reason, this function is called
- without a frame then the problem isn't here, but rather in the
- caller. It should of first created a frame and then passed that
- in. */
- /* NOTE: cagney/2002-10-31: As a side bar, keep in mind that the
- ``current_frame'' should not be treated as a special case. While
- ``get_next_frame (current_frame) == NULL'' currently holds, it
- should, as far as possible, not be relied upon. In the future,
- ``get_next_frame (current_frame)'' may instead simply return a
- normal frame object that simply always gets register values from
- the register cache. Consequently, frame code should try to avoid
- tests like ``if get_next_frame() == NULL'' and instead just rely
- on recursive frame calls (like the below code) when manipulating
- a frame chain. */
- gdb_assert (frame != NULL && frame->next != NULL);
- frame_unwind_unsigned_register (frame->next, regnum, val);
+ULONGEST
+frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
+{
+ char buf[MAX_REGISTER_SIZE];
+ frame_unwind_register (frame, regnum, buf);
+ return extract_unsigned_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
}
-void
-frame_read_signed_register (struct frame_info *frame, int regnum,
- LONGEST *val)
+ULONGEST
+get_frame_register_unsigned (struct frame_info *frame, int regnum)
{
- /* See note above in frame_read_unsigned_register(). */
- gdb_assert (frame != NULL && frame->next != NULL);
- frame_unwind_signed_register (frame->next, regnum, val);
+ return frame_unwind_register_unsigned (frame->next, regnum);
}
void
-generic_unwind_get_saved_register (char *raw_buffer,
- int *optimizedp,
- CORE_ADDR *addrp,
- struct frame_info *frame,
- int regnum,
- enum lval_type *lvalp)
-{
- int optimizedx;
- CORE_ADDR addrx;
- int realnumx;
- enum lval_type lvalx;
-
- if (!target_has_registers)
- error ("No registers.");
-
- /* Keep things simple, ensure that all the pointers (except valuep)
- are non NULL. */
- if (optimizedp == NULL)
- optimizedp = &optimizedx;
- if (lvalp == NULL)
- lvalp = &lvalx;
- if (addrp == NULL)
- addrp = &addrx;
+frame_unwind_unsigned_register (struct frame_info *frame, int regnum,
+ ULONGEST *val)
+{
+ char buf[MAX_REGISTER_SIZE];
+ frame_unwind_register (frame, regnum, buf);
+ (*val) = extract_unsigned_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
+}
- gdb_assert (frame != NULL && frame->next != NULL);
- frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
- &realnumx, raw_buffer);
+void
+put_frame_register (struct frame_info *frame, int regnum, const void *buf)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ int realnum;
+ int optim;
+ enum lval_type lval;
+ 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.");
+ switch (lval)
+ {
+ case lval_memory:
+ {
+ /* FIXME: write_memory doesn't yet take constant buffers.
+ Arrrg! */
+ char tmp[MAX_REGISTER_SIZE];
+ memcpy (tmp, buf, register_size (gdbarch, regnum));
+ write_memory (addr, tmp, register_size (gdbarch, regnum));
+ break;
+ }
+ case lval_register:
+ regcache_cooked_write (current_regcache, realnum, buf);
+ break;
+ default:
+ 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 REGISTER_RAW_SIZE (REGNUM).
+ The number of bytes copied is DEPRECATED_REGISTER_RAW_SIZE
+ (REGNUM).
Returns 0 if the register value could not be found. */
includes builtin registers. */
int
-frame_map_name_to_regnum (const char *name, int len)
+frame_map_name_to_regnum (struct frame_info *frame, const char *name, int len)
{
- int i;
-
- if (len < 0)
- len = strlen (name);
-
- /* Search register name space. */
- for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
- if (REGISTER_NAME (i) && len == strlen (REGISTER_NAME (i))
- && strncmp (name, REGISTER_NAME (i), len) == 0)
- {
- return i;
- }
-
- /* Try builtin registers. */
- i = builtin_reg_map_name_to_regnum (name, len);
- if (i >= 0)
- {
- /* A builtin register doesn't fall into the architecture's
- register range. */
- gdb_assert (i >= NUM_REGS + NUM_PSEUDO_REGS);
- return i;
- }
-
- return -1;
+ return user_reg_map_name_to_regnum (get_frame_arch (frame), name, len);
}
const char *
-frame_map_regnum_to_name (int regnum)
+frame_map_regnum_to_name (struct frame_info *frame, int regnum)
{
- if (regnum < 0)
- return NULL;
- if (regnum < NUM_REGS + NUM_PSEUDO_REGS)
- return REGISTER_NAME (regnum);
- return builtin_reg_map_regnum_to_name (regnum);
+ return user_reg_map_regnum_to_name (get_frame_arch (frame), regnum);
}
/* Create a sentinel frame. */
-struct frame_info *
+static struct frame_info *
create_sentinel_frame (struct regcache *regcache)
{
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
comparisons with it should fail. */
frame->this_id.p = 1;
frame->this_id.value = null_frame_id;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ create_sentinel_frame (...) -> ");
+ fprint_frame (gdb_stdlog, frame);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
return frame;
}
}
CORE_ADDR *
-get_frame_saved_regs (struct frame_info *fi)
+deprecated_get_frame_saved_regs (struct frame_info *fi)
{
return fi->saved_regs;
}
return deprecated_selected_frame;
}
+/* This is a variant of get_selected_frame which can be called when
+ the inferior does not have a frame; in that case it will return
+ NULL instead of calling error (). */
+
+struct frame_info *
+deprecated_safe_get_selected_frame (void)
+{
+ if (!target_has_registers || !target_has_stack || !target_has_memory)
+ return NULL;
+ return get_selected_frame ();
+}
+
/* Select frame FI (or NULL - to invalidate the current frame). */
void
select_frame (struct frame_info *fi)
{
- register struct symtab *s;
+ struct symtab *s;
deprecated_selected_frame = fi;
/* NOTE: cagney/2002-05-04: FI can be NULL. This occures when the
source language of this frame, and switch to it if desired. */
if (fi)
{
- s = find_pc_symtab (get_frame_pc (fi));
+ /* We retrieve the frame's symtab by using the frame PC. However
+ we cannot use the frame pc as is, because it usually points to
+ the instruction following the "call", which is sometimes the
+ first instruction of another function. So we rely on
+ get_frame_address_in_block() which provides us with a PC which
+ is guaranteed to be inside the frame's code block. */
+ s = find_pc_symtab (get_frame_address_in_block (fi));
if (s
&& s->language != current_language->la_language
&& s->language != language_unknown
int *realnump, void *bufferp)
{
/* HACK: New code is passed the next frame and this cache.
- Unfortunatly, old code expects this frame. Since this is a
+ Unfortunately, old code expects this frame. Since this is a
backward compatibility hack, cheat by walking one level along the
prologue chain to the frame the old code expects.
struct frame_info *frame = next_frame->prev;
gdb_assert (frame != NULL);
- /* Only (older) architectures that implement the
- DEPRECATED_FRAME_INIT_SAVED_REGS method should be using this
- function. */
- gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
-
- /* Load the saved_regs register cache. */
- if (get_frame_saved_regs (frame) == NULL)
- DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
+ if (deprecated_get_frame_saved_regs (frame) == NULL)
+ {
+ /* If nothing's initialized the saved regs, do it now. */
+ gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
+ DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
+ gdb_assert (deprecated_get_frame_saved_regs (frame) != NULL);
+ }
- if (get_frame_saved_regs (frame) != NULL
- && get_frame_saved_regs (frame)[regnum] != 0)
+ if (deprecated_get_frame_saved_regs (frame) != NULL
+ && deprecated_get_frame_saved_regs (frame)[regnum] != 0)
{
if (regnum == SP_REGNUM)
{
*addrp = 0;
*realnump = -1;
if (bufferp != NULL)
- store_address (bufferp, REGISTER_RAW_SIZE (regnum),
- get_frame_saved_regs (frame)[regnum]);
+ /* NOTE: cagney/2003-05-09: In-lined store_address with
+ it's body - store_unsigned_integer. */
+ store_unsigned_integer (bufferp, DEPRECATED_REGISTER_RAW_SIZE (regnum),
+ deprecated_get_frame_saved_regs (frame)[regnum]);
}
else
{
a local copy of its value. */
*optimizedp = 0;
*lvalp = lval_memory;
- *addrp = get_frame_saved_regs (frame)[regnum];
+ *addrp = deprecated_get_frame_saved_regs (frame)[regnum];
*realnump = -1;
if (bufferp != NULL)
{
if (regs[regnum] == NULL)
{
regs[regnum]
- = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum));
- read_memory (get_frame_saved_regs (frame)[regnum], regs[regnum],
- REGISTER_RAW_SIZE (regnum));
+ = frame_obstack_zalloc (DEPRECATED_REGISTER_RAW_SIZE (regnum));
+ read_memory (deprecated_get_frame_saved_regs (frame)[regnum], regs[regnum],
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
}
- memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum));
+ memcpy (bufferp, regs[regnum], DEPRECATED_REGISTER_RAW_SIZE (regnum));
#else
/* Read the value in from memory. */
- read_memory (get_frame_saved_regs (frame)[regnum], bufferp,
- REGISTER_RAW_SIZE (regnum));
+ read_memory (deprecated_get_frame_saved_regs (frame)[regnum], bufferp,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
#endif
}
}
void **this_prologue_cache,
struct frame_id *id)
{
- int fromleaf;
- CORE_ADDR base;
- CORE_ADDR pc;
-
- if (frame_relative_level (next_frame) < 0)
- {
- /* FIXME: cagney/2003-03-14: We've got the extra special case of
- unwinding a sentinel frame, the PC of which is pointing at a
- stack dummy. Fake up the dummy frame's ID using the same
- sequence as is found a traditional unwinder. */
- (*id) = frame_id_build (read_fp (), read_pc ());
- return;
- }
-
- /* Start out by assuming it's NULL. */
+ /* A developer is trying to bring up a new architecture, help them
+ by providing a default unwinder that refuses to unwind anything
+ (the ID is always NULL). In the case of legacy code,
+ legacy_get_prev_frame() will have previously set ->this_id.p, so
+ this code won't be called. */
(*id) = null_frame_id;
-
- if (frame_relative_level (next_frame) <= 0)
- /* FIXME: 2002-11-09: Frameless functions can occure anywhere in
- the frame chain, not just the inner most frame! The generic,
- per-architecture, frame code should handle this and the below
- should simply be removed. */
- fromleaf = FRAMELESS_FUNCTION_INVOCATION (next_frame);
- else
- fromleaf = 0;
-
- if (fromleaf)
- /* A frameless inner-most frame. The `FP' (which isn't an
- architecture frame-pointer register!) of the caller is the same
- as the callee. */
- /* FIXME: 2002-11-09: There isn't any reason to special case this
- edge condition. Instead the per-architecture code should hande
- it locally. */
- base = get_frame_base (next_frame);
- else
- {
- /* Two macros defined in tm.h specify the machine-dependent
- actions to be performed here.
-
- First, get the frame's chain-pointer.
-
- If that is zero, the frame is the outermost frame or a leaf
- called by the outermost frame. This means that if start
- calls main without a frame, we'll return 0 (which is fine
- anyway).
-
- Nope; there's a problem. This also returns when the current
- routine is a leaf of main. This is unacceptable. We move
- this to after the ffi test; I'd rather have backtraces from
- start go curfluy than have an abort called from main not show
- main. */
- gdb_assert (DEPRECATED_FRAME_CHAIN_P ());
- base = DEPRECATED_FRAME_CHAIN (next_frame);
-
- if (!legacy_frame_chain_valid (base, next_frame))
- return;
- }
- if (base == 0)
- return;
-
- /* FIXME: cagney/2002-06-08: This should probably return the frame's
- function and not the PC (a.k.a. resume address). */
- pc = frame_pc_unwind (next_frame);
- (*id) = frame_id_build (base, pc);
}
const struct frame_unwind legacy_saved_regs_unwinder = {
calculated rather than fetched). We will use not_lval for values
fetched from generic dummy frames.
- Set *ADDRP to the address, either in memory or as a REGISTER_BYTE
- offset into the registers array. If the value is stored in a dummy
- frame, set *ADDRP to zero.
+ Set *ADDRP to the address, either in memory or as a
+ DEPRECATED_REGISTER_BYTE offset into the registers array. If the
+ value is stored in a dummy frame, set *ADDRP to zero.
The argument RAW_BUFFER must point to aligned memory. */
if (!target_has_registers)
error ("No registers.");
- gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
-
/* Normal systems don't optimize out things with register numbers. */
if (optimized != NULL)
*optimized = 0;
fly, constructs either a raw or pseudo register
from the raw register cache. */
regcache_raw_read
- (generic_find_dummy_frame (get_frame_pc (frame),
- get_frame_base (frame)),
+ (deprecated_find_dummy_frame_regcache (get_frame_pc (frame),
+ get_frame_base (frame)),
regnum, raw_buffer);
return;
}
DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
- if (get_frame_saved_regs (frame) != NULL
- && get_frame_saved_regs (frame)[regnum] != 0)
+ if (deprecated_get_frame_saved_regs (frame) != NULL
+ && deprecated_get_frame_saved_regs (frame)[regnum] != 0)
{
if (lval) /* found it saved on the stack */
*lval = lval_memory;
if (regnum == SP_REGNUM)
{
if (raw_buffer) /* SP register treated specially */
- store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
- get_frame_saved_regs (frame)[regnum]);
+ /* NOTE: cagney/2003-05-09: In-line store_address
+ with it's body - store_unsigned_integer. */
+ store_unsigned_integer (raw_buffer,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum),
+ deprecated_get_frame_saved_regs (frame)[regnum]);
}
else
{
if (addrp) /* any other register */
- *addrp = get_frame_saved_regs (frame)[regnum];
+ *addrp = deprecated_get_frame_saved_regs (frame)[regnum];
if (raw_buffer)
- read_memory (get_frame_saved_regs (frame)[regnum], raw_buffer,
- REGISTER_RAW_SIZE (regnum));
+ read_memory (deprecated_get_frame_saved_regs (frame)[regnum], raw_buffer,
+ DEPRECATED_REGISTER_RAW_SIZE (regnum));
}
return;
}
if (lval) /* found it in a live register */
*lval = lval_register;
if (addrp)
- *addrp = REGISTER_BYTE (regnum);
+ *addrp = DEPRECATED_REGISTER_BYTE (regnum);
if (raw_buffer)
deprecated_read_register_gen (regnum, raw_buffer);
}
{
struct frame_info *fi;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "{ create_new_frame (addr=0x%s, pc=0x%s) ",
+ paddr_nz (addr), paddr_nz (pc));
+ }
+
fi = frame_obstack_zalloc (sizeof (struct frame_info));
fi->next = create_sentinel_frame (current_regcache);
/* Select/initialize both the unwind function and the frame's type
based on the PC. */
- fi->unwind = frame_unwind_find_by_pc (current_gdbarch, pc);
+ fi->unwind = frame_unwind_find_by_frame (fi->next);
if (fi->unwind->type != UNKNOWN_FRAME)
fi->type = fi->unwind->type;
else
fi->type = frame_type_from_pc (pc);
+ fi->this_id.p = 1;
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, "-> ");
+ fprint_frame (gdb_stdlog, fi);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+
return fi;
}
current_frame = NULL; /* Invalidate cache */
select_frame (NULL);
annotate_frames_invalid ();
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ flush_cached_frames () }\n");
}
/* Flush the frame cache, and start a new one if necessary. */
struct frame_info *prev;
int fromleaf;
+ /* Don't frame_debug print legacy_get_prev_frame() here, just
+ confuses the output. */
+
/* Allocate the new frame.
There is no reason to worry about memory leaks, should the
prev = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev->level = this_frame->level + 1;
- /* Do not completly wire it in to the frame chain. Some (bad) code
+ /* Do not completely wire it in to the frame chain. Some (bad) code
in INIT_FRAME_EXTRA_INFO tries to look along frame->prev to pull
some fancy tricks (of course such code is, by definition,
recursive).
DEPRECATED_INIT_FRAME_PC_FIRST and
DEPRECATED_FRAME_INIT_SAVED_REGS methods are full of work-arounds
that handle the frame not being correctly set from the start.
- Unfortunatly those same work-arounds rely on the type defaulting
+ Unfortunately those same work-arounds rely on the type defaulting
to NORMAL_FRAME. Ulgh! The new frame code does not have this
problem. */
prev->type = UNKNOWN_FRAME;
/* The allocated PREV_FRAME will be reclaimed when the frame
obstack is next purged. */
if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - unwound PC zero\n");
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // unwound legacy PC zero }\n");
+ }
return NULL;
}
/* Set the unwind functions based on that identified PC. Ditto
for the "type" but strongly prefer the unwinder's frame type. */
- prev->unwind = frame_unwind_find_by_pc (current_gdbarch,
- get_frame_pc (prev));
+ prev->unwind = frame_unwind_find_by_frame (prev->next);
if (prev->unwind->type == UNKNOWN_FRAME)
prev->type = frame_type_from_pc (get_frame_pc (prev));
else
or some random address on the stack. Trying to use that
PC to apply standard frame ID unwind techniques is just
asking for trouble. */
- /* Assume call_function_by_hand(), via SAVE_DUMMY_FRAME_TOS,
- previously saved the dummy frame's ID. Things only work
- if the two return the same value. */
- gdb_assert (SAVE_DUMMY_FRAME_TOS_P ());
/* Use an architecture specific method to extract the prev's
dummy ID from the next frame. Note that this method uses
frame_register_unwind to obtain the register values
using the same sequence as is found a traditional
unwinder. Once all architectures supply the
unwind_dummy_id method, this code can go away. */
- prev->this_id.value = frame_id_build (read_fp (), read_pc ());
+ prev->this_id.value = frame_id_build (deprecated_read_fp (),
+ read_pc ());
}
/* Check that the unwound ID is valid. */
if (!frame_id_p (prev->this_id.value))
{
if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost legacy sentinel frame - unwound frame ID invalid\n");
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // unwound legacy ID invalid }\n");
+ }
return NULL;
}
/* FIXME: cagney/2002-01-19: This call will go away. Instead of
initializing extra info, all frames will use the frame_cache
(passed to the unwind functions) to store additional frame
- info. Unfortunatly legacy targets can't use
+ info. Unfortunately legacy targets can't use
legacy_get_prev_frame() to unwind the sentinel frame and,
consequently, are forced to take this code path and rely on
the below call to DEPRECATED_INIT_EXTRA_FRAME_INFO to
{
DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev);
}
+
+ if (prev->type == NORMAL_FRAME)
+ prev->this_id.value.code_addr
+ = get_pc_function_start (prev->this_id.value.code_addr);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev);
+ fprintf_unfiltered (gdb_stdlog, " } // legacy innermost frame\n");
+ }
return prev;
}
the frame chain, not just the inner most frame! The generic,
per-architecture, frame code should handle this and the below
should simply be removed. */
- fromleaf = FRAMELESS_FUNCTION_INVOCATION (this_frame);
+ fromleaf = (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P ()
+ && DEPRECATED_FRAMELESS_FUNCTION_INVOCATION (this_frame));
else
fromleaf = 0;
/* FIXME: 2002-11-09: There isn't any reason to special case this
edge condition. Instead the per-architecture code should hande
it locally. */
+ /* FIXME: cagney/2003-06-16: This returns the inner most stack
+ address for the previous frame, that, however, is wrong. It
+ should be the inner most stack address for the previous to
+ previous frame. This is because it is the previous to previous
+ frame's innermost stack address that is constant through out
+ the lifetime of the previous frame (trust me :-). */
address = get_frame_base (this_frame);
else
{
this to after the ffi test; I'd rather have backtraces from
start go curfluy than have an abort called from main not show
main. */
- gdb_assert (DEPRECATED_FRAME_CHAIN_P ());
- address = DEPRECATED_FRAME_CHAIN (this_frame);
+ if (DEPRECATED_FRAME_CHAIN_P ())
+ address = DEPRECATED_FRAME_CHAIN (this_frame);
+ else
+ {
+ /* Someone is part way through coverting an old architecture
+ to the new frame code. Implement FRAME_CHAIN the way the
+ new frame will. */
+ /* Find PREV frame's unwinder. */
+ prev->unwind = frame_unwind_find_by_frame (this_frame->next);
+ /* FIXME: cagney/2003-04-02: Rather than storing the frame's
+ type in the frame, the unwinder's type should be returned
+ directly. Unfortunately, legacy code, called by
+ legacy_get_prev_frame, explicitly set the frames type
+ using the method deprecated_set_frame_type(). */
+ prev->type = prev->unwind->type;
+ /* Find PREV frame's ID. */
+ prev->unwind->this_id (this_frame,
+ &prev->prologue_cache,
+ &prev->this_id.value);
+ prev->this_id.p = 1;
+ address = prev->this_id.value.stack_addr;
+ }
if (!legacy_frame_chain_valid (address, this_frame))
- return 0;
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // legacy frame chain invalid }\n");
+ }
+ return NULL;
+ }
}
if (address == 0)
- return 0;
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // legacy frame chain NULL }\n");
+ }
+ return NULL;
+ }
/* Link in the already allocated prev frame. */
this_frame->prev = prev;
DEPRECATED_INIT_EXTRA_FRAME_INFO, one possible scheme:
SETUP_INNERMOST_FRAME(): Default version is just create_new_frame
- (read_fp ()), read_pc ()). Machines with extra frame info would
- do that (or the local equivalent) and then set the extra fields.
+ (deprecated_read_fp ()), read_pc ()). Machines with extra frame
+ info would do that (or the local equivalent) and then set the
+ extra fields.
SETUP_ARBITRARY_FRAME(argc, argv): Only change here is that
create_new_frame would no longer init extra frame info;
{
this_frame->prev = NULL;
obstack_free (&frame_cache_obstack, prev);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // legacy this.id == prev.id }\n");
+ }
return NULL;
}
/* Initialize the code used to unwind the frame PREV based on the PC
(and probably other architectural information). The PC lets you
check things like the debug info at that point (dwarf2cfi?) and
- use that to decide how the frame should be unwound. */
- prev->unwind = frame_unwind_find_by_pc (current_gdbarch,
- get_frame_pc (prev));
+ use that to decide how the frame should be unwound.
+
+ If there isn't a FRAME_CHAIN, the code above will have already
+ done this. */
+ if (prev->unwind == NULL)
+ prev->unwind = frame_unwind_find_by_frame (prev->next);
/* If the unwinder provides a frame type, use it. Otherwize
continue on to that heuristic mess. */
if (prev->unwind->type != UNKNOWN_FRAME)
{
prev->type = prev->unwind->type;
+ if (prev->type == NORMAL_FRAME)
+ /* FIXME: cagney/2003-06-16: would get_frame_pc() be better? */
+ prev->this_id.value.code_addr
+ = get_pc_function_start (prev->this_id.value.code_addr);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev);
+ fprintf_unfiltered (gdb_stdlog, " } // legacy with unwound type\n");
+ }
return prev;
}
go away. */
}
+ if (prev->type == NORMAL_FRAME)
+ prev->this_id.value.code_addr
+ = get_pc_function_start (prev->this_id.value.code_addr);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev);
+ fprintf_unfiltered (gdb_stdlog, " } // legacy with confused type\n");
+ }
+
return prev;
}
/* Return a structure containing various interesting information
about the frame that called THIS_FRAME. Returns NULL
- if there is no such frame. */
+ if there is no such frame.
+
+ This function tests some target-independent conditions that should
+ terminate the frame chain, such as unwinding past main(). It
+ should not contain any target-dependent tests, such as checking
+ whether the program-counter is zero. */
struct frame_info *
get_prev_frame (struct frame_info *this_frame)
{
struct frame_info *prev_frame;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame (this_frame=");
+ if (this_frame != NULL)
+ fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
+ else
+ fprintf_unfiltered (gdb_stdlog, "<NULL>");
+ fprintf_unfiltered (gdb_stdlog, ") ");
+ }
+
/* 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_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(). */
if (this_frame->level >= 0
- && !backtrace_below_main
- && inside_main_func (get_frame_pc (this_frame)))
+ && !backtrace_past_main
+ && inside_main_func (get_frame_address_in_block (this_frame)))
/* Don't unwind past main(), bug 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. */
{
if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - inside main func.\n");
+ fprintf_unfiltered (gdb_stdlog, "-> NULL // inside main func }\n");
+ return NULL;
+ }
+
+ if (this_frame->level > backtrace_limit)
+ {
+ error ("Backtrace limit of %d exceeded", backtrace_limit);
+ }
+
+ /* If we're already inside the entry function for the main objfile,
+ then it isn't valid. Don't apply this test to a dummy frame -
+ dummy frame PC's 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
+ backtrace in wierd and wonderful ways somewhere inside the entry
+ file. Suspect that deprecated_inside_entry_file and
+ inside_entry_func tests were added to work around that (now
+ fixed) case. */
+ /* NOTE: cagney/2003-07-15: danielj (if I'm reading it right)
+ suggested having the inside_entry_func test use the
+ inside_main_func msymbol trick (along with entry_point_address 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->type != DUMMY_FRAME && this_frame->level >= 0
+ && inside_entry_func (this_frame))
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, "// inside entry func }\n");
+ }
return NULL;
}
/* Only try to do the unwind once. */
if (this_frame->prev_p)
- return this_frame->prev;
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, this_frame->prev);
+ fprintf_unfiltered (gdb_stdlog, " // cached \n");
+ }
+ return this_frame->prev;
+ }
this_frame->prev_p = 1;
-#if 0
/* If we're inside the entry file, it isn't valid. Don't apply this
test to a dummy frame - dummy frame PC's typically land in the
entry file. Don't apply this test to the sentinel frame.
/* NOTE: cagney/2003-01-10: If there is a way of disabling this test
then it should probably be moved to before the ->prev_p test,
above. */
- /* NOTE: vinschen/2003-04-01: Disabled. It turns out that the call to
- inside_entry_file destroys a meaningful backtrace under some
- conditions. E. g. the backtrace tests in the asm-source testcase
- are broken for some targets. In this test the functions are all
- implemented as part of one file and the testcase is not necessarily
- linked with a start file (depending on the target). What happens is,
- that the first frame is printed normaly and following frames are
- treated as being inside the enttry file then. This way, only the
- #0 frame is printed in the backtrace output. */
- if (this_frame->type != DUMMY_FRAME && this_frame->level >= 0
- && inside_entry_file (get_frame_pc (this_frame)))
- {
- if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - inside entry file\n");
- return NULL;
- }
-#endif
-
- /* If we're already inside the entry function for the main objfile,
- then it isn't valid. Don't apply this test to a dummy frame -
- dummy frame PC's 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: vinschen/2003-04-01: Disabled. It turns out that the call
+ to deprecated_inside_entry_file destroys a meaningful backtrace
+ under some conditions. E. g. the backtrace tests in the
+ asm-source testcase are broken for some targets. In this test
+ the functions are all implemented as part of one file and the
+ testcase is not necessarily linked with a start file (depending
+ on the target). What happens is, that the first frame is printed
+ normaly and following frames are treated as being inside the
+ enttry file then. This way, only the #0 frame is printed in the
+ backtrace output. */
if (0
&& this_frame->type != DUMMY_FRAME && this_frame->level >= 0
- && inside_entry_func (get_frame_pc (this_frame)))
+ && deprecated_inside_entry_file (get_frame_pc (this_frame)))
{
if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - inside entry func\n");
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // inside entry file }\n");
+ }
return NULL;
}
if (legacy_frame_p (current_gdbarch))
{
prev_frame = legacy_get_prev_frame (this_frame);
- if (frame_debug && prev_frame == NULL)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - legacy_get_prev_frame NULL.\n");
return prev_frame;
}
if (this_frame->level >= 0 && !frame_id_p (get_frame_id (this_frame)))
{
if (frame_debug)
- fprintf_filtered (gdb_stdlog,
- "Outermost frame - this ID is NULL\n");
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
+ }
return NULL;
}
/* Check that this frame's ID isn't inner to (younger, below, next)
- the next frame. This happens when frame unwind goes backwards.
- Since the sentinel frame isn't valid, don't apply this if this
- frame is entier the inner-most or sentinel frame. */
+ the next frame. This happens when a frame unwind goes backwards.
+ Since the sentinel frame doesn't really exist, don't compare the
+ inner-most against that sentinel. */
if (this_frame->level > 0
&& frame_id_inner (get_frame_id (this_frame),
get_frame_id (this_frame->next)))
- error ("This frame inner-to next frame (corrupt stack?)");
-
- /* Check that this and the next frame are different. If they are
- not, there is most likely a stack cycle. As with the inner-than
- test, avoid the inner-most and sentinel frames. */
- /* FIXME: cagney/2003-03-17: Can't yet enable this this check. The
- frame_id_eq() method doesn't yet use function addresses when
- comparing frame IDs. */
- if (0
- && this_frame->level > 0
+ error ("Previous frame inner to this frame (corrupt stack?)");
+
+ /* 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 (get_frame_id (this_frame),
get_frame_id (this_frame->next)))
- error ("This frame identical to next frame (corrupt stack?)");
+ error ("Previous frame identical to this frame (corrupt stack?)");
/* 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
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev_frame->level = this_frame->level + 1;
- /* Try to unwind the PC. If that doesn't work, assume we've reached
- the oldest frame and simply return. Is there a better sentinal
- value? The unwound PC value is then used to initialize the new
- previous frame's type.
-
- Note that the pc-unwind is intentionally performed before the
- frame chain. This is ok since, for old targets, both
- frame_pc_unwind (nee, FRAME_SAVED_PC) and
- DEPRECATED_FRAME_CHAIN()) assume THIS_FRAME's data structures
- have already been initialized (using
- DEPRECATED_INIT_EXTRA_FRAME_INFO) and hence the call order
- doesn't matter.
-
- By unwinding the PC first, it becomes possible to, in the case of
- a dummy frame, avoid also unwinding the frame ID. This is
- because (well ignoring the PPC) a dummy frame can be located
- using THIS_FRAME's frame ID. */
-
- if (frame_pc_unwind (this_frame) == 0)
- {
- /* The allocated PREV_FRAME will be reclaimed when the frame
- obstack is next purged. */
- if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - unwound PC zero\n");
- return NULL;
- }
-
- /* Set the unwind functions based on that identified PC. */
- prev_frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
- frame_pc_unwind (this_frame));
-
- /* FIXME: cagney/2003-04-02: Rather than storing the frame's type in
- the frame, the unwinder's type should be returned directly.
- Unfortunatly, legacy code, called by legacy_get_prev_frame,
- explicitly set the frames type using the method
- deprecated_set_frame_type(). */
- gdb_assert (prev_frame->unwind->type != UNKNOWN_FRAME);
- prev_frame->type = prev_frame->unwind->type;
+ /* Don't yet compute ->unwind (and hence ->type). It is computed
+ on-demand in get_frame_type, frame_register_unwind, and
+ get_frame_id. */
- /* Can the frame's type and unwinder be computed on demand? That
- would make a frame's creation really really lite! */
-
- /* The prev's frame's ID is computed by demand in get_frame_id(). */
+ /* Don't yet compute the frame's ID. It is computed on-demand by
+ get_frame_id(). */
/* The unwound frame ID is validate at the start of this function,
as part of the logic to decide if that frame should be further
Doing this makes it possible for the user to examine a frame that
has an invalid frame ID.
- The very old VAX frame_args_address_correct() method noted: [...]
- For the sake of argument, suppose that the stack is somewhat
- trashed (which is one reason that "info frame" exists). So,
- return 0 (indicating we don't know the address of the arglist) if
- we don't know what frame this frame calls. */
+ Some very old VAX code noted: [...] For the sake of argument,
+ suppose that the stack is somewhat trashed (which is one reason
+ that "info frame" exists). So, return 0 (indicating we don't
+ know the address of the arglist) if we don't know what frame this
+ frame calls. */
/* Link it in. */
this_frame->prev = prev_frame;
prev_frame->next = this_frame;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev_frame);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+
return prev_frame;
}
return frame_pc_unwind (frame->next);
}
+/* Return an address of that falls within the frame's code block. */
+
+CORE_ADDR
+frame_unwind_address_in_block (struct frame_info *next_frame)
+{
+ /* A draft address. */
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+ /* 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 fallowing 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
+get_frame_address_in_block (struct frame_info *this_frame)
+{
+ return frame_unwind_address_in_block (this_frame->next);
+}
+
static int
pc_notcurrent (struct frame_info *frame)
{
if (get_frame_type (fi) != NORMAL_FRAME)
return 0;
if (fi->base == NULL)
- fi->base = frame_base_find_by_pc (current_gdbarch, get_frame_pc (fi));
+ fi->base = frame_base_find_by_frame (fi->next);
/* Sneaky: If the low-level unwind and high-level base code share a
common unwinder, let them share the prologue cache. */
if (fi->base->unwind == fi->unwind)
return 0;
/* If there isn't a frame address method, find it. */
if (fi->base == NULL)
- fi->base = frame_base_find_by_pc (current_gdbarch, get_frame_pc (fi));
+ fi->base = frame_base_find_by_frame (fi->next);
/* Sneaky: If the low-level unwind and high-level base code share a
common unwinder, let them share the prologue cache. */
if (fi->base->unwind == fi->unwind)
return 0;
/* If there isn't a frame address method, find it. */
if (fi->base == NULL)
- fi->base = frame_base_find_by_pc (current_gdbarch, get_frame_pc (fi));
+ fi->base = frame_base_find_by_frame (fi->next);
/* Sneaky: If the low-level unwind and high-level base code share a
common unwinder, let them share the prologue cache. */
if (fi->base->unwind == fi->unwind)
if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES
&& deprecated_frame_in_dummy (frame))
return DUMMY_FRAME;
+
+ /* Some legacy code, e.g, mips_init_extra_frame_info() wants
+ to determine the frame's type prior to it being completely
+ initialized. Don't attempt to lazily initialize ->unwind for
+ legacy code. It will be initialized in legacy_get_prev_frame(). */
+ if (frame->unwind == NULL && !legacy_frame_p (current_gdbarch))
+ {
+ /* Initialize the frame's unwinder because it is that which
+ provides the frame's type. */
+ frame->unwind = frame_unwind_find_by_frame (frame->next);
+ /* FIXME: cagney/2003-04-02: Rather than storing the frame's
+ type in the frame, the unwinder's type should be returned
+ directly. Unfortunately, legacy code, called by
+ legacy_get_prev_frame, explicitly set the frames type using
+ the method deprecated_set_frame_type(). */
+ frame->type = frame->unwind->type;
+ }
if (frame->type == UNKNOWN_FRAME)
return NORMAL_FRAME;
else
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 frame's
are not in the frame chain, it isn't possible to assume that the
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;
}
-void
-deprecated_set_frame_saved_regs_hack (struct frame_info *frame,
- CORE_ADDR *saved_regs)
+struct frame_info *
+deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs,
+ long sizeof_extra_info)
{
- frame->saved_regs = saved_regs;
+ 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;
}
-void
-deprecated_set_frame_extra_info_hack (struct frame_info *frame,
- struct frame_extra_info *extra_info)
-{
- frame->extra_info = extra_info;
-}
+/* Memory access methods. */
void
-deprecated_set_frame_next_hack (struct frame_info *fi,
- struct frame_info *next)
+get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr, void *buf,
+ int len)
{
- fi->next = next;
+ read_memory (addr, buf, len);
}
-void
-deprecated_set_frame_prev_hack (struct frame_info *fi,
- struct frame_info *prev)
+LONGEST
+get_frame_memory_signed (struct frame_info *this_frame, CORE_ADDR addr,
+ int len)
{
- fi->prev = prev;
+ return read_memory_integer (addr, len);
}
-struct context *
-deprecated_get_frame_context (struct frame_info *fi)
+ULONGEST
+get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr,
+ int len)
{
- return fi->context;
+ return read_memory_unsigned_integer (addr, len);
}
-void
-deprecated_set_frame_context (struct frame_info *fi,
- struct context *context)
+/* Architecture method. */
+
+struct gdbarch *
+get_frame_arch (struct frame_info *this_frame)
{
- fi->context = context;
+ return current_gdbarch;
}
-struct frame_info *
-deprecated_frame_xmalloc (void)
+/* Stack pointer methods. */
+
+CORE_ADDR
+get_frame_sp (struct frame_info *this_frame)
{
- struct frame_info *frame = XMALLOC (struct frame_info);
- memset (frame, 0, sizeof (struct frame_info));
- return frame;
+ return frame_sp_unwind (this_frame->next);
}
-struct frame_info *
-deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs,
- long sizeof_extra_info)
-{
- struct frame_info *frame = deprecated_frame_xmalloc ();
- 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)
+CORE_ADDR
+frame_sp_unwind (struct frame_info *next_frame)
+{
+ /* Normality, an architecture that provides a way of obtaining any
+ frame inner-most address. */
+ if (gdbarch_unwind_sp_p (current_gdbarch))
+ return gdbarch_unwind_sp (current_gdbarch, next_frame);
+ /* Things are looking grim. If it's the inner-most frame and there
+ is a TARGET_READ_SP then that can be used. */
+ if (next_frame->level < 0 && TARGET_READ_SP_P ())
+ return TARGET_READ_SP ();
+ /* Now things are really are grim. Hope that the value returned by
+ the SP_REGNUM register is meaningful. */
+ if (SP_REGNUM >= 0)
{
- frame->extra_info = xcalloc (1, sizeof_extra_info);
- make_cleanup (xfree, frame->extra_info);
+ ULONGEST sp;
+ frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp);
+ return sp;
}
- return frame;
+ internal_error (__FILE__, __LINE__, "Missing unwind SP method");
}
+
int
legacy_frame_p (struct gdbarch *current_gdbarch)
{
- return (DEPRECATED_INIT_FRAME_PC_P ()
- || DEPRECATED_INIT_FRAME_PC_FIRST_P ()
- || DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()
- || DEPRECATED_FRAME_CHAIN_P ()
- || !gdbarch_unwind_dummy_id_p (current_gdbarch)
- || !SAVE_DUMMY_FRAME_TOS_P ());
+ if (DEPRECATED_INIT_FRAME_PC_P ()
+ || DEPRECATED_INIT_FRAME_PC_FIRST_P ()
+ || DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()
+ || DEPRECATED_FRAME_CHAIN_P ())
+ /* No question, it's a legacy frame. */
+ return 1;
+ if (gdbarch_unwind_dummy_id_p (current_gdbarch))
+ /* No question, it's not a legacy frame (provided none of the
+ deprecated methods checked above are present that is). */
+ return 0;
+ if (DEPRECATED_TARGET_READ_FP_P ()
+ || DEPRECATED_FP_REGNUM >= 0)
+ /* Assume it's legacy. If you're trying to convert a legacy frame
+ target to the new mechanism, get rid of these. legacy
+ get_prev_frame requires these when unwind_frame_id isn't
+ available. */
+ return 1;
+ /* Default to assuming that it's brand new code, and hence not
+ legacy. Force it down the non-legacy path so that the new code
+ uses the new frame mechanism from day one. Dummy frame's won't
+ work very well but we can live with that. */
+ return 0;
+}
+
+extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
+
+static struct cmd_list_element *set_backtrace_cmdlist;
+static struct cmd_list_element *show_backtrace_cmdlist;
+
+static void
+set_backtrace_cmd (char *args, int from_tty)
+{
+ help_list (set_backtrace_cmdlist, "set backtrace ", -1, gdb_stdout);
+}
+
+static void
+show_backtrace_cmd (char *args, int from_tty)
+{
+ cmd_show_list (show_backtrace_cmdlist, from_tty, "");
}
void
{
obstack_init (&frame_cache_obstack);
- /* FIXME: cagney/2003-01-19: This command needs a rename. Suggest
- `set backtrace {past,beyond,...}-main'. Also suggest adding `set
- backtrace ...-start' to control backtraces past start. The
- problem with `below' is that it stops the `up' command. */
-
- add_setshow_boolean_cmd ("backtrace-below-main", class_obscure,
- &backtrace_below_main, "\
+ add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, "\
+Set backtrace specific variables.\n\
+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, "\
+Show backtrace specific variables\n\
+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\".\n\
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\
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.",
- NULL, NULL, &setlist, &showlist);
-
+ NULL, NULL, &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.\n\
+No more than the specified number of frames can be displayed or examined.\n\
+Zero is unlimited.", "\
+Show the upper bound on the number of backtrace levels.",
+ NULL, NULL, &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
/* Debug this files internals. */
add_show_from_set (add_set_cmd ("frame", class_maintenance, var_zinteger,