aboutsummaryrefslogtreecommitdiff
path: root/gdb/frame.c
diff options
context:
space:
mode:
authorDavid Carlton <carlton@bactrian.org>2003-04-16 19:57:09 +0000
committerDavid Carlton <carlton@bactrian.org>2003-04-16 19:57:09 +0000
commit0bb428781c4782c6236beb58c06052dccd382aa1 (patch)
treec2745e3799c869e29769a81c22cc151fdbe84a97 /gdb/frame.c
parent8ddfa96fcd388fb183d7aac8befd08c138e105dd (diff)
downloadgdb-0bb428781c4782c6236beb58c06052dccd382aa1.zip
gdb-0bb428781c4782c6236beb58c06052dccd382aa1.tar.gz
gdb-0bb428781c4782c6236beb58c06052dccd382aa1.tar.bz2
2003-04-16 David Carlton <carlton@bactrian.org>
* Merge with mainline; tag is carlton_dictionary-20030416-merge.
Diffstat (limited to 'gdb/frame.c')
-rw-r--r--gdb/frame.c1375
1 files changed, 1004 insertions, 371 deletions
diff --git a/gdb/frame.c b/gdb/frame.c
index 5d220c9..3871aa1 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -36,9 +36,101 @@
#include "annotate.h"
#include "language.h"
#include "frame-unwind.h"
+#include "frame-base.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. Unfortunatly, 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;
+
+ /* If dwarf2 unwind frame informations is used, this structure holds
+ all related unwind data. */
+ struct context *context;
+
+ /* 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;
@@ -47,6 +139,77 @@ static int frame_debug;
static int backtrace_below_main;
+static void
+fprint_frame_id (struct ui_file *file, struct frame_id id)
+{
+ fprintf_unfiltered (file, "{stack=0x%s,code=0x%s}",
+ paddr_nz (id.stack_addr),
+ paddr_nz (id.code_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 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. */
@@ -57,52 +220,118 @@ get_frame_id (struct frame_info *fi)
{
return null_frame_id;
}
- else
+ if (!fi->this_id.p)
{
- struct frame_id id;
- id.base = fi->frame;
- id.pc = fi->pc;
- return id;
+ 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_pc (current_gdbarch,
+ get_frame_pc (fi));
+ /* 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 (fi->unwind->type != UNKNOWN_FRAME);
+ 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 fi->this_id.value;
}
const struct frame_id null_frame_id; /* All zeros. */
struct frame_id
-frame_id_build (CORE_ADDR base, CORE_ADDR func_or_pc)
+frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
{
struct frame_id id;
- id.base = base;
- id.pc = func_or_pc;
+ id.stack_addr = stack_addr;
+ id.code_addr = code_addr;
return id;
}
int
frame_id_p (struct frame_id l)
{
- /* The .func can be NULL but the .base cannot. */
- return (l.base != 0);
+ 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;
}
int
frame_id_eq (struct frame_id l, struct frame_id r)
{
- /* If .base is different, the frames are different. */
- if (l.base != r.base)
- return 0;
- /* Add a test to check that the frame ID's are for the same function
- here. */
- return 1;
+ int eq;
+ if (l.stack_addr == 0 || r.stack_addr == 0)
+ /* Like a NaN, if either ID is invalid, the result is false. */
+ eq = 0;
+ else if (l.stack_addr != r.stack_addr)
+ /* If .stack addresses are different, the frames are different. */
+ eq = 0;
+ 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. */
+ 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;
+ 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;
}
int
frame_id_inner (struct frame_id l, struct frame_id r)
{
- /* 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 .base but different
- .func). */
- return INNER_THAN (l.base, r.base);
+ int inner;
+ if (l.stack_addr == 0 || r.stack_addr == 0)
+ /* Like NaN, any operation involving an invalid ID always fails. */
+ inner = 0;
+ else
+ /* 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). */
+ 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;
}
struct frame_info *
@@ -135,26 +364,127 @@ frame_find_by_id (struct frame_id id)
}
CORE_ADDR
-frame_pc_unwind (struct frame_info *frame)
+frame_pc_unwind (struct frame_info *this_frame)
+{
+ if (!this_frame->prev_pc.p)
+ {
+ CORE_ADDR pc;
+ 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
+ determine the value of registers in THIS frame, and hence
+ the value of this frame's PC (resume address). A typical
+ implementation is no more than:
+
+ frame_unwind_register (this_frame, ISA_PC_REGNUM, buf);
+ return extract_address (buf, size of ISA_PC_REGNUM);
+
+ Note: this method is very heavily dependent on a correct
+ register-unwind implementation, it pays to fix that
+ method first; this method is frame type agnostic, since
+ it only deals with register values, it works with any
+ frame. This is all in stark contrast to the old
+ FRAME_SAVED_PC which would try to directly handle all the
+ 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 and a sentinel
+ frame. Do like was always done. Fetch the PC's value
+ direct 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");
+ 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;
+}
+
+CORE_ADDR
+frame_func_unwind (struct frame_info *fi)
{
- if (!frame->pc_unwind_cache_p)
+ if (!fi->prev_func.p)
{
- frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache);
- frame->pc_unwind_cache_p = 1;
+ fi->prev_func.p = 1;
+ fi->prev_func.addr = get_pc_function_start (frame_pc_unwind (fi));
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_func_unwind (fi=%d) -> 0x%s }\n",
+ fi->level, paddr_nz (fi->prev_func.addr));
}
- return frame->pc_unwind_cache;
+ return fi->prev_func.addr;
+}
+
+CORE_ADDR
+get_frame_func (struct frame_info *fi)
+{
+ return frame_func_unwind (fi->next);
+}
+
+static int
+do_frame_unwind_register (void *src, int regnum, void *buf)
+{
+ frame_unwind_register (src, regnum, buf);
+ return 1;
}
void
-frame_pop (struct frame_info *frame)
-{
- /* FIXME: cagney/2003-01-18: There is probably a chicken-egg problem
- with passing in current_regcache. The pop function needs to be
- written carefully so as to not overwrite registers whose [old]
- values are needed to restore other registers. Instead, this code
- should pass in a scratch cache and, as a second step, restore the
- registers using that. */
- frame->unwind->pop (frame, &frame->unwind_cache, current_regcache);
+frame_pop (struct frame_info *this_frame)
+{
+ struct regcache *scratch_regcache;
+ struct cleanup *cleanups;
+
+ if (DEPRECATED_POP_FRAME_P ())
+ {
+ /* A legacy architecture that has implemented a custom pop
+ function. All new architectures should instead be using the
+ generic code below. */
+ DEPRECATED_POP_FRAME;
+ }
+ else
+ {
+ /* Make a copy of all the register values unwound from this
+ frame. Save them in a scratch buffer so that there isn't a
+ race betweening 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 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 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
+ 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.
+ Here, regcache_cpy() calls regcache_restore(). */
+ regcache_cpy (current_regcache, scratch);
+ do_cleanups (cleanups);
+ }
+ /* We've made right mess of GDB's local state, just discard
+ everything. */
flush_cached_frames ();
}
@@ -165,6 +495,13 @@ frame_register_unwind (struct frame_info *frame, int regnum,
{
struct frame_unwind_cache *cache;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_register_unwind (frame=%d,regnum=\"%s\",...) ",
+ frame->level, frame_map_regnum_to_name (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);
@@ -179,9 +516,46 @@ frame_register_unwind (struct frame_info *frame, int regnum,
detected the problem before calling here. */
gdb_assert (frame != NULL);
- /* Ask this frame to unwind its register. */
- frame->unwind->reg (frame, &frame->unwind_cache, regnum,
- optimizedp, lvalp, addrp, realnump, bufferp);
+ /* Find the unwinder. */
+ if (frame->unwind == NULL)
+ {
+ frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
+ get_frame_pc (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 (frame->unwind->type != UNKNOWN_FRAME);
+ 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 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
@@ -200,9 +574,10 @@ frame_register (struct frame_info *frame, int regnum,
/* 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 (GET_SAVED_REGISTER_P ())
+ if (DEPRECATED_GET_SAVED_REGISTER_P ())
{
- GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame, regnum, lvalp);
+ DEPRECATED_GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame,
+ regnum, lvalp);
/* Compute the REALNUM if the caller wants it. */
if (*lvalp == lval_register)
{
@@ -330,23 +705,6 @@ generic_unwind_get_saved_register (char *raw_buffer,
&realnumx, raw_buffer);
}
-void
-get_saved_register (char *raw_buffer,
- int *optimized,
- CORE_ADDR *addrp,
- struct frame_info *frame,
- int regnum,
- enum lval_type *lval)
-{
- if (GET_SAVED_REGISTER_P ())
- {
- GET_SAVED_REGISTER (raw_buffer, optimized, addrp, frame, regnum, lval);
- return;
- }
- generic_unwind_get_saved_register (raw_buffer, optimized, addrp, frame,
- regnum, lval);
-}
-
/* frame_register_read ()
Find and return the value of REGNUM for the specified stack frame.
@@ -431,18 +789,22 @@ create_sentinel_frame (struct regcache *regcache)
/* Explicitly initialize the sentinel frame's cache. Provide it
with the underlying regcache. In the future additional
information, such as the frame's thread will be added. */
- frame->unwind_cache = sentinel_frame_cache (regcache);
+ frame->prologue_cache = sentinel_frame_cache (regcache);
/* For the moment there is only one sentinel frame implementation. */
frame->unwind = sentinel_frame_unwind;
/* Link this frame back to itself. The frame is self referential
(the unwound PC is the same as the pc), so make it so. */
frame->next = frame;
- /* Always unwind the PC as part of creating this frame. This
- ensures that the frame's PC points at something valid. */
- /* FIXME: cagney/2003-01-10: Problem here. Unwinding a sentinel
- frame's PC may require information such as the frame's thread's
- stop reason. Is it possible to get to that? */
- frame->pc = frame_pc_unwind (frame);
+ /* Make the sentinel frame's ID valid, but invalid. That way all
+ 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;
}
@@ -498,10 +860,15 @@ unwind_to_current_frame (struct ui_out *ui_out, void *args)
struct frame_info *
get_current_frame (void)
{
- if (!target_has_stack)
- error ("No stack.");
+ /* First check, and report, the lack of registers. Having GDB
+ report "No stack!" or "No memory" when the target doesn't even
+ have registers is very confusing. Besides, "printcmd.exp"
+ explicitly checks that ``print $pc'' with no registers prints "No
+ registers". */
if (!target_has_registers)
error ("No registers.");
+ if (!target_has_stack)
+ error ("No stack.");
if (!target_has_memory)
error ("No memory.");
if (current_frame == NULL)
@@ -567,7 +934,7 @@ select_frame (struct frame_info *fi)
source language of this frame, and switch to it if desired. */
if (fi)
{
- s = find_pc_symtab (fi->pc);
+ s = find_pc_symtab (get_frame_pc (fi));
if (s
&& s->language != current_language->la_language
&& s->language != language_unknown
@@ -583,19 +950,20 @@ select_frame (struct frame_info *fi)
most frame. */
static void
-frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *bufferp)
+legacy_saved_regs_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
{
- /* There is always a frame at this point. And THIS is the frame
- we're interested in. */
+ /* HACK: New code is passed the next frame and this cache.
+ Unfortunatly, 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.
+
+ Do not try this at home. Professional driver, closed course. */
+ struct frame_info *frame = next_frame->prev;
gdb_assert (frame != NULL);
- /* If we're using generic dummy frames, we'd better not be in a call
- dummy. (generic_call_dummy_register_unwind ought to have been called
- instead.) */
- gdb_assert (!(DEPRECATED_USE_GENERIC_DUMMY_FRAMES
- && (get_frame_type (frame) == DUMMY_FRAME)));
/* Only (older) architectures that implement the
DEPRECATED_FRAME_INIT_SAVED_REGS method should be using this
@@ -633,13 +1001,13 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
#if 1
/* Save each register value, as it is read in, in a
frame based cache. */
- void **regs = (*cache);
+ void **regs = (*this_prologue_cache);
if (regs == NULL)
{
int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS)
* sizeof (void *));
regs = frame_obstack_zalloc (sizeof_cache);
- (*cache) = regs;
+ (*this_prologue_cache) = regs;
}
if (regs[regnum] == NULL)
{
@@ -659,102 +1027,35 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
return;
}
- /* No luck, assume this and the next frame have the same register
- value. Pass the request down the frame chain to the next frame.
- Hopefully that will find the register's location, either in a
- register or in memory. */
- frame_register (frame, regnum, optimizedp, lvalp, addrp, realnump,
- bufferp);
+ /* No luck. Assume this and the next frame have the same register
+ value. Pass the unwind request down the frame chain to the next
+ frame. Hopefully that frame will find the register's location. */
+ frame_register_unwind (next_frame, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
}
-static CORE_ADDR
-frame_saved_regs_pc_unwind (struct frame_info *frame, void **cache)
-{
- gdb_assert (FRAME_SAVED_PC_P ());
- return FRAME_SAVED_PC (frame);
-}
-
static void
-frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache,
- struct frame_id *id)
+legacy_saved_regs_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *id)
{
- int fromleaf;
- CORE_ADDR base;
- CORE_ADDR pc;
-
- /* Start out by assuming it's NULL. */
- (*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 (FRAME_CHAIN_P ());
- base = FRAME_CHAIN (next_frame);
-
- if (!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->pc = pc;
- id->base = base;
+ /* legacy_get_prev_frame() always sets ->this_id.p, hence this is
+ never needed. */
+ internal_error (__FILE__, __LINE__, "legacy_saved_regs_this_id() called");
}
-static void
-frame_saved_regs_pop (struct frame_info *fi, void **cache,
- struct regcache *regcache)
-{
- gdb_assert (POP_FRAME_P ());
- POP_FRAME;
-}
-
-const struct frame_unwind trad_frame_unwinder = {
- frame_saved_regs_pop,
- frame_saved_regs_pc_unwind,
- frame_saved_regs_id_unwind,
- frame_saved_regs_register_unwind
+const struct frame_unwind legacy_saved_regs_unwinder = {
+ /* Not really. It gets overridden by legacy_get_prev_frame. */
+ UNKNOWN_FRAME,
+ legacy_saved_regs_this_id,
+ legacy_saved_regs_prev_register
};
-const struct frame_unwind *trad_frame_unwind = &trad_frame_unwinder;
+const struct frame_unwind *legacy_saved_regs_unwind = &legacy_saved_regs_unwinder;
-/* Function: get_saved_register
+/* Function: deprecated_generic_get_saved_register
Find register number REGNUM relative to FRAME and put its (raw,
- target format) contents in *RAW_BUFFER.
+ target format) contents in *RAW_BUFFER.
Set *OPTIMIZED if the variable was optimized out (and thus can't be
fetched). Note that this is never set to anything other than zero
@@ -770,10 +1071,6 @@ const struct frame_unwind *trad_frame_unwind = &trad_frame_unwinder;
offset into the registers array. If the value is stored in a dummy
frame, set *ADDRP to zero.
- To use this implementation, define a function called
- "get_saved_register" in your target code, which simply passes all
- of its arguments to this function.
-
The argument RAW_BUFFER must point to aligned memory. */
void
@@ -888,31 +1185,51 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
{
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->frame = addr;
- fi->pc = pc;
fi->next = create_sentinel_frame (current_regcache);
- fi->type = frame_type_from_pc (pc);
+
+ /* 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);
+ 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);
- /* Select/initialize an unwind function. */
- fi->unwind = frame_unwind_find_by_pc (current_gdbarch, fi->pc);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, fi);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
return fi;
}
-/* Return the frame that FRAME calls (NULL if FRAME is the innermost
- frame). Be careful to not fall off the bottom of the frame chain
- and onto the sentinel frame. */
+/* Return the frame that THIS_FRAME calls (NULL if THIS_FRAME is the
+ innermost frame). Be careful to not fall off the bottom of the
+ frame chain and onto the sentinel frame. */
struct frame_info *
-get_next_frame (struct frame_info *frame)
+get_next_frame (struct frame_info *this_frame)
{
- if (frame->level > 0)
- return frame->next;
+ if (this_frame->level > 0)
+ return this_frame->next;
else
return NULL;
}
@@ -929,6 +1246,8 @@ flush_cached_frames (void)
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. */
@@ -949,15 +1268,183 @@ reinit_frame_cache (void)
INIT_EXTRA_INFO, INIT_FRAME_PC and INIT_FRAME_PC_FIRST. */
static struct frame_info *
-legacy_get_prev_frame (struct frame_info *next_frame)
+legacy_get_prev_frame (struct frame_info *this_frame)
{
CORE_ADDR address = 0;
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
+ remainder of the function fail. The allocated memory will be
+ quickly reclaimed when the frame cache is flushed, and the `we've
+ been here before' check, in get_prev_frame will stop repeated
+ memory allocation calls. */
+ 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
+ in INIT_FRAME_EXTRA_INFO tries to look along frame->prev to pull
+ some fancy tricks (of course such code is, by definition,
+ recursive).
+
+ On the other hand, methods, such as get_frame_pc() and
+ get_frame_base() rely on being able to walk along the frame
+ chain. Make certain that at least they work by providing that
+ link. Of course things manipulating prev can't go back. */
+ prev->next = this_frame;
+
+ /* NOTE: cagney/2002-11-18: Should have been correctly setting the
+ frame's type here, before anything else, and not last, at the
+ bottom of this function. The various
+ DEPRECATED_INIT_EXTRA_FRAME_INFO, DEPRECATED_INIT_FRAME_PC,
+ 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
+ to NORMAL_FRAME. Ulgh! The new frame code does not have this
+ problem. */
+ prev->type = UNKNOWN_FRAME;
+
+ /* A legacy frame's ID is always computed here. Mark it as valid. */
+ prev->this_id.p = 1;
+
+ /* Handle sentinel frame unwind as a special case. */
+ if (this_frame->level < 0)
+ {
+ /* 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, DEPRECATED_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. */
+
+ deprecated_update_frame_pc_hack (prev, frame_pc_unwind (this_frame));
+ if (get_frame_pc (prev) == 0)
+ {
+ /* The allocated PREV_FRAME will be reclaimed when the frame
+ obstack is next purged. */
+ if (frame_debug)
+ {
+ 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));
+ if (prev->unwind->type == UNKNOWN_FRAME)
+ prev->type = frame_type_from_pc (get_frame_pc (prev));
+ else
+ prev->type = prev->unwind->type;
+
+ /* Find the prev's frame's ID. */
+ if (prev->type == DUMMY_FRAME
+ && gdbarch_unwind_dummy_id_p (current_gdbarch))
+ {
+ /* When unwinding a normal frame, the stack structure is
+ determined by analyzing the frame's function's code (be
+ it using brute force prologue analysis, or the dwarf2
+ CFI). In the case of a dummy frame, that simply isn't
+ possible. The The PC is either the program entry point,
+ 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
+ needed to determine the dummy frame's ID. */
+ prev->this_id.value = gdbarch_unwind_dummy_id (current_gdbarch,
+ this_frame);
+ }
+ else
+ {
+ /* We're 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. 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 ());
+ }
+
+ /* Check that the unwound ID is valid. */
+ if (!frame_id_p (prev->this_id.value))
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // unwound legacy ID invalid }\n");
+ }
+ return NULL;
+ }
+
+ /* Check that the new frame isn't inner to (younger, below,
+ next) the old frame. If that happens the frame unwind is
+ going backwards. */
+ /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since
+ that doesn't have a valid frame ID. Should instead set the
+ sentinel frame's frame ID to a `sentinel'. Leave it until
+ after the switch to storing the frame ID, instead of the
+ frame base, in the frame object. */
+
+ /* Link it in. */
+ this_frame->prev = prev;
+
+ /* 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
+ 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
+ initialize the inner-most frame. */
+ if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
+ {
+ 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;
+ }
+
/* This code only works on normal frames. A sentinel frame, where
the level is -1, should never reach this code. */
- gdb_assert (next_frame->level >= 0);
+ gdb_assert (this_frame->level >= 0);
/* On some machines it is possible to call a function without
setting up a stack frame for it. On these machines, we
@@ -966,14 +1453,14 @@ legacy_get_prev_frame (struct frame_info *next_frame)
or isn't leafless. */
/* Still don't want to worry about this except on the innermost
- frame. This macro will set FROMLEAF if NEXT_FRAME is a frameless
+ frame. This macro will set FROMLEAF if THIS_FRAME is a frameless
function invocation. */
- if (next_frame->level == 0)
+ if (this_frame->level == 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);
+ fromleaf = FRAMELESS_FUNCTION_INVOCATION (this_frame);
else
fromleaf = 0;
@@ -984,7 +1471,7 @@ legacy_get_prev_frame (struct frame_info *next_frame)
/* FIXME: 2002-11-09: There isn't any reason to special case this
edge condition. Instead the per-architecture code should hande
it locally. */
- address = get_frame_base (next_frame);
+ address = get_frame_base (this_frame);
else
{
/* Two macros defined in tm.h specify the machine-dependent
@@ -1002,28 +1489,36 @@ legacy_get_prev_frame (struct frame_info *next_frame)
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 (FRAME_CHAIN_P ());
- address = FRAME_CHAIN (next_frame);
+ gdb_assert (DEPRECATED_FRAME_CHAIN_P ());
+ address = DEPRECATED_FRAME_CHAIN (this_frame);
- if (!frame_chain_valid (address, next_frame))
- return 0;
+ if (!legacy_frame_chain_valid (address, this_frame))
+ {
+ 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;
-
- /* Create an initially zero previous frame. */
- prev = frame_obstack_zalloc (sizeof (struct frame_info));
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog,
+ " // legacy frame chain NULL }\n");
+ }
+ return NULL;
+ }
- /* Link it in. */
- next_frame->prev = prev;
- prev->next = next_frame;
- prev->frame = address;
- prev->level = next_frame->level + 1;
- /* FIXME: cagney/2002-11-18: Should be setting the frame's type
- here, before anything else, and not last. Various INIT functions
- are full of work-arounds for the frames type not being set
- correctly from the word go. Ulgh! */
- prev->type = NORMAL_FRAME;
+ /* Link in the already allocated prev frame. */
+ this_frame->prev = prev;
+ deprecated_update_frame_base_hack (prev, address);
/* This change should not be needed, FIXME! We should determine
whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen
@@ -1059,10 +1554,11 @@ legacy_get_prev_frame (struct frame_info *next_frame)
DEPRECATED_INIT_EXTRA_FRAME_INFO and DEPRECATED_INIT_FRAME_PC.
This should also return a flag saying whether to keep the new
frame, or whether to discard it, because on some machines (e.g.
- mips) it is really awkward to have FRAME_CHAIN_VALID called
- BEFORE DEPRECATED_INIT_EXTRA_FRAME_INFO (there is no good way to
- get information deduced in FRAME_CHAIN_VALID into the extra
- fields of the new frame). std_frame_pc(fromleaf, prev)
+ mips) it is really awkward to have DEPRECATED_FRAME_CHAIN_VALID
+ called BEFORE DEPRECATED_INIT_EXTRA_FRAME_INFO (there is no good
+ way to get information deduced in DEPRECATED_FRAME_CHAIN_VALID
+ into the extra fields of the new frame). std_frame_pc(fromleaf,
+ prev)
This is the default setting for INIT_PREV_FRAME. It just does
what the default DEPRECATED_INIT_FRAME_PC does. Some machines
@@ -1083,21 +1579,24 @@ legacy_get_prev_frame (struct frame_info *next_frame)
inner most and any other case.
Since there is always a frame to unwind from, there is always
- somewhere (NEXT_FRAME) to store all the info needed to construct
+ somewhere (THIS_FRAME) to store all the info needed to construct
a new (previous) frame without having to first create it. This
means that the convolution below - needing to carefully order a
frame's initialization - isn't needed.
- The irony here though, is that FRAME_CHAIN(), at least for a more
- up-to-date architecture, always calls FRAME_SAVED_PC(), and
- FRAME_SAVED_PC() computes the PC but without first needing the
- frame! Instead of the convolution below, we could have simply
- called FRAME_SAVED_PC() and been done with it! Note that
- FRAME_SAVED_PC() is being superseed by frame_pc_unwind() and that
- function does have somewhere to cache that PC value. */
+ The irony here though, is that DEPRECATED_FRAME_CHAIN(), at least
+ for a more up-to-date architecture, always calls
+ FRAME_SAVED_PC(), and FRAME_SAVED_PC() computes the PC but
+ without first needing the frame! Instead of the convolution
+ below, we could have simply called FRAME_SAVED_PC() and been done
+ with it! Note that FRAME_SAVED_PC() is being superseed by
+ frame_pc_unwind() and that function does have somewhere to cache
+ that PC value. */
if (DEPRECATED_INIT_FRAME_PC_FIRST_P ())
- prev->pc = (DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf, prev));
+ deprecated_update_frame_pc_hack (prev,
+ DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf,
+ prev));
if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
DEPRECATED_INIT_EXTRA_FRAME_INFO (fromleaf, prev);
@@ -1106,17 +1605,27 @@ legacy_get_prev_frame (struct frame_info *next_frame)
FRAME_SAVED_PC may use that queue to figure out its value (see
tm-sparc.h). We want the pc saved in the inferior frame. */
if (DEPRECATED_INIT_FRAME_PC_P ())
- prev->pc = DEPRECATED_INIT_FRAME_PC (fromleaf, prev);
+ deprecated_update_frame_pc_hack (prev,
+ DEPRECATED_INIT_FRAME_PC (fromleaf,
+ prev));
/* If ->frame and ->pc are unchanged, we are in the process of
getting ourselves into an infinite backtrace. Some architectures
- check this in FRAME_CHAIN or thereabouts, but it seems like there
- is no reason this can't be an architecture-independent check. */
- if (prev->frame == next_frame->frame
- && prev->pc == next_frame->pc)
+ check this in DEPRECATED_FRAME_CHAIN or thereabouts, but it seems
+ like there is no reason this can't be an architecture-independent
+ check. */
+ if (get_frame_base (prev) == get_frame_base (this_frame)
+ && get_frame_pc (prev) == get_frame_pc (this_frame))
{
- next_frame->prev = NULL;
+ 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;
}
@@ -1124,7 +1633,25 @@ legacy_get_prev_frame (struct frame_info *next_frame)
(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, prev->pc);
+ prev->unwind = frame_unwind_find_by_pc (current_gdbarch,
+ get_frame_pc (prev));
+
+ /* 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)
+ 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;
+ }
/* NOTE: cagney/2002-11-18: The code segments, found in
create_new_frame and get_prev_frame(), that initializes the
@@ -1136,8 +1663,8 @@ legacy_get_prev_frame (struct frame_info *next_frame)
before the INIT function has been called. */
if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
&& (DEPRECATED_PC_IN_CALL_DUMMY_P ()
- ? DEPRECATED_PC_IN_CALL_DUMMY (prev->pc, 0, 0)
- : pc_in_dummy_frame (prev->pc)))
+ ? DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (prev), 0, 0)
+ : pc_in_dummy_frame (get_frame_pc (prev))))
prev->type = DUMMY_FRAME;
else
{
@@ -1148,8 +1675,8 @@ legacy_get_prev_frame (struct frame_info *next_frame)
Unforunatly, its the INIT code that sets the PC (Hmm, catch
22). */
char *name;
- find_pc_partial_function (prev->pc, &name, NULL, NULL);
- if (PC_IN_SIGTRAMP (prev->pc, name))
+ find_pc_partial_function (get_frame_pc (prev), &name, NULL, NULL);
+ if (PC_IN_SIGTRAMP (get_frame_pc (prev), name))
prev->type = SIGTRAMP_FRAME;
/* FIXME: cagney/2002-11-11: Leave prev->type alone. Some
architectures are forcing the frame's type in INIT so we
@@ -1159,18 +1686,39 @@ legacy_get_prev_frame (struct frame_info *next_frame)
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 NEXT_FRAME. Returns NULL
+ about the frame that called THIS_FRAME. Returns NULL
if there is no such frame. */
struct frame_info *
-get_prev_frame (struct frame_info *next_frame)
+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
@@ -1189,7 +1737,7 @@ get_prev_frame (struct frame_info *next_frame)
that a frame isn't possible, rather than checking that the target
has state and then calling get_current_frame() and
get_prev_frame(). This is a guess mind. */
- if (next_frame == NULL)
+ if (this_frame == NULL)
{
/* NOTE: cagney/2002-11-09: There was a code segment here that
would error out when CURRENT_FRAME was NULL. The comment
@@ -1202,34 +1750,42 @@ get_prev_frame (struct frame_info *next_frame)
thing to do.''
Per the above, this code shouldn't even be called with a NULL
- NEXT_FRAME. */
+ THIS_FRAME. */
return current_frame;
}
/* There is always a frame. If this assertion fails, suspect that
something should be calling get_selected_frame() or
get_current_frame(). */
- gdb_assert (next_frame != NULL);
+ gdb_assert (this_frame != NULL);
- if (next_frame->level >= 0
+ if (this_frame->level >= 0
&& !backtrace_below_main
- && inside_main_func (get_frame_pc (next_frame)))
+ && inside_main_func (get_frame_pc (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;
}
/* Only try to do the unwind once. */
- if (next_frame->prev_p)
- return next_frame->prev;
- next_frame->prev_p = 1;
+ if (this_frame->prev_p)
+ {
+ 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.
@@ -1241,14 +1797,27 @@ get_prev_frame (struct frame_info *next_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. */
- if (next_frame->type != DUMMY_FRAME && next_frame->level >= 0
- && inside_entry_file (get_frame_pc (next_frame)))
+ /* 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");
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // 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 -
@@ -1258,32 +1827,61 @@ get_prev_frame (struct frame_info *next_frame)
/* NOTE: cagney/2003-02-25: Don't enable until someone has found
hard evidence that this is needed. */
if (0
- && next_frame->type != DUMMY_FRAME && next_frame->level >= 0
- && inside_entry_func (get_frame_pc (next_frame)))
+ && this_frame->type != DUMMY_FRAME && this_frame->level >= 0
+ && inside_entry_func (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 func }\n");
+ }
return NULL;
}
/* If any of the old frame initialization methods are around, use
- the legacy get_prev_frame method. Just don't try to unwind a
- sentinel frame using that method - it doesn't work. All sentinal
- frames use the new unwind code. */
- if ((DEPRECATED_INIT_FRAME_PC_P ()
- || DEPRECATED_INIT_FRAME_PC_FIRST_P ()
- || DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()
- || FRAME_CHAIN_P ())
- && next_frame->level >= 0)
+ the legacy get_prev_frame method. */
+ if (legacy_frame_p (current_gdbarch))
{
- prev_frame = legacy_get_prev_frame (next_frame);
- if (frame_debug && prev_frame == NULL)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - legacy_get_prev_frame NULL.\n");
+ prev_frame = legacy_get_prev_frame (this_frame);
return prev_frame;
}
+ /* 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
+ the sentinel frame. */
+ if (this_frame->level >= 0 && !frame_id_p (get_frame_id (this_frame)))
+ {
+ if (frame_debug)
+ {
+ 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. */
+ 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
+ && frame_id_eq (get_frame_id (this_frame),
+ get_frame_id (this_frame->next)))
+ error ("This frame identical to next 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
frame->next to pull some fancy tricks (of course such code is, by
@@ -1295,7 +1893,7 @@ get_prev_frame (struct frame_info *next_frame)
been here before' check above will stop repeated memory
allocation calls. */
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
- prev_frame->level = next_frame->level + 1;
+ 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
@@ -1304,88 +1902,58 @@ get_prev_frame (struct frame_info *next_frame)
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 FRAME_CHAIN()) assume
- NEXT_FRAME's data structures have already been initialized (using
+ 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 NEXT_FRAME's frame ID. */
+ using THIS_FRAME's frame ID. */
- prev_frame->pc = frame_pc_unwind (next_frame);
- if (prev_frame->pc == 0)
+ 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;
- }
- prev_frame->type = frame_type_from_pc (prev_frame->pc);
-
- /* Set the unwind functions based on that identified PC. */
- prev_frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
- prev_frame->pc);
-
- /* FIXME: cagney/2003-01-13: A dummy frame doesn't need to unwind
- the frame ID because the frame ID comes from the previous frame.
- The other frames do though. True? */
- /* FIXME: cagney/2003-03-04: The below call isn't right. It should
- instead be doing something like "prev_frame -> unwind -> id
- (next_frame, & prev_frame -> unwind_cache, & prev_frame -> id)"
- but that requires more extensive (pending) changes. */
- next_frame->unwind->id (next_frame, &next_frame->unwind_cache,
- &prev_frame->id);
- /* Check that the unwound ID is valid. As of 2003-02-24 the x86-64
- was returning an invalid frame ID when trying to do an unwind a
- sentinel frame that belonged to a frame dummy. */
- if (!frame_id_p (prev_frame->id))
- {
- if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - unwound frame ID invalid\n");
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // unwound PC zero }\n");
+ }
return NULL;
}
- /* Check that the new frame isn't inner to (younger, below, next)
- the old frame. If that happens the frame unwind is going
- backwards. */
- /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since that
- doesn't have a valid frame ID. Should instead set the sentinel
- frame's frame ID to a `sentinel'. Leave it until after the
- switch to storing the frame ID, instead of the frame base, in the
- frame object. */
- if (next_frame->level >= 0
- && frame_id_inner (prev_frame->id, get_frame_id (next_frame)))
- error ("Unwound frame inner-to selected frame (corrupt stack?)");
- /* Note that, due to frameless functions, the stronger test of the
- new frame being outer to the old frame can't be used - frameless
- functions differ by only their PC value. */
-
- /* FIXME: cagney/2002-12-18: Instead of this hack, should only store
- the frame ID in PREV_FRAME. Unfortunatly, some architectures
- (HP/UX) still reply on EXTRA_FRAME_INFO and, hence, still poke at
- the "struct frame_info" object directly. */
- prev_frame->frame = prev_frame->id.base;
+
+ /* Don't yet compute ->unwind (and hence ->type). It is computed
+ on-demand in get_frame_type, frame_register_unwind, and
+ 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
+ unwound, and not here while the prev frame is being created.
+ 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. */
/* Link it in. */
- next_frame->prev = prev_frame;
- prev_frame->next = next_frame;
-
- /* 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 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 initialize the inner-most
- frame. */
- if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
+ this_frame->prev = prev_frame;
+ prev_frame->next = this_frame;
+
+ if (frame_debug)
{
- gdb_assert (prev_frame->level == 0);
- DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev_frame);
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev_frame);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
}
return prev_frame;
@@ -1394,7 +1962,8 @@ get_prev_frame (struct frame_info *next_frame)
CORE_ADDR
get_frame_pc (struct frame_info *frame)
{
- return frame->pc;
+ gdb_assert (frame->next != NULL);
+ return frame_pc_unwind (frame->next);
}
static int
@@ -1417,7 +1986,7 @@ pc_notcurrent (struct frame_info *frame)
void
find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
{
- (*sal) = find_pc_line (frame->pc, pc_notcurrent (frame));
+ (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
}
/* Per "frame.h", return the ``address'' of the frame. Code should
@@ -1425,7 +1994,59 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
CORE_ADDR
get_frame_base (struct frame_info *fi)
{
- return fi->frame;
+ return get_frame_id (fi).stack_addr;
+}
+
+/* High-level offsets into the frame. Used by the debug info. */
+
+CORE_ADDR
+get_frame_base_address (struct frame_info *fi)
+{
+ 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));
+ /* 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 fi->base->this_base (fi->next, &fi->prologue_cache);
+ return fi->base->this_base (fi->next, &fi->base_cache);
+}
+
+CORE_ADDR
+get_frame_locals_address (struct frame_info *fi)
+{
+ void **cache;
+ if (get_frame_type (fi) != NORMAL_FRAME)
+ 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));
+ /* 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)
+ cache = &fi->prologue_cache;
+ else
+ cache = &fi->base_cache;
+ return fi->base->this_locals (fi->next, cache);
+}
+
+CORE_ADDR
+get_frame_args_address (struct frame_info *fi)
+{
+ void **cache;
+ if (get_frame_type (fi) != NORMAL_FRAME)
+ 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));
+ /* 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)
+ cache = &fi->prologue_cache;
+ else
+ cache = &fi->base_cache;
+ return fi->base->this_args (fi->next, cache);
}
/* Level of the selected frame: 0 for innermost, 1 for its caller, ...
@@ -1448,7 +2069,24 @@ get_frame_type (struct frame_info *frame)
if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES
&& deprecated_frame_in_dummy (frame))
return DUMMY_FRAME;
- return frame->type;
+ if (frame->unwind == NULL)
+ {
+ /* Initialize the frame's unwinder because it is that which
+ provides the frame's type. */
+ frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
+ get_frame_pc (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 (frame->unwind->type != UNKNOWN_FRAME);
+ frame->type = frame->unwind->type;
+ }
+ if (frame->type == UNKNOWN_FRAME)
+ return NORMAL_FRAME;
+ else
+ return frame->type;
}
void
@@ -1458,34 +2096,6 @@ deprecated_set_frame_type (struct frame_info *frame, enum frame_type type)
frame->type = type;
}
-#ifdef FRAME_FIND_SAVED_REGS
-/* XXX - deprecated. This is a compatibility function for targets
- that do not yet implement DEPRECATED_FRAME_INIT_SAVED_REGS. */
-/* Find the addresses in which registers are saved in FRAME. */
-
-void
-deprecated_get_frame_saved_regs (struct frame_info *frame,
- struct frame_saved_regs *saved_regs_addr)
-{
- if (frame->saved_regs == NULL)
- {
- frame->saved_regs = (CORE_ADDR *)
- frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
- }
- if (saved_regs_addr == NULL)
- {
- struct frame_saved_regs saved_regs;
- FRAME_FIND_SAVED_REGS (frame, saved_regs);
- memcpy (frame->saved_regs, &saved_regs, SIZEOF_FRAME_SAVED_REGS);
- }
- else
- {
- FRAME_FIND_SAVED_REGS (frame, *saved_regs_addr);
- memcpy (frame->saved_regs, saved_regs_addr, SIZEOF_FRAME_SAVED_REGS);
- }
-}
-#endif
-
struct frame_extra_info *
get_frame_extra_info (struct frame_info *fi)
{
@@ -1502,21 +2112,33 @@ frame_extra_info_zalloc (struct frame_info *fi, long size)
void
deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
{
- /* See comment in "frame.h". */
- frame->pc = pc;
- /* While we're at it, update this frame's cached PC value, found in
- the next frame. Oh, for the day when "struct frame_info" is
- opaque and this hack on hack can go. */
- gdb_assert (frame->next != NULL);
- frame->next->pc_unwind_cache = pc;
- frame->next->pc_unwind_cache_p = 1;
+ 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
+ frame has a next. Sigh. */
+ if (frame->next != NULL)
+ {
+ /* While we're at it, update this frame's cached PC value, found
+ in the next frame. Oh for the day when "struct frame_info"
+ is opaque and this hack on hack can just go away. */
+ frame->next->prev_pc.value = pc;
+ frame->next->prev_pc.p = 1;
+ }
}
void
deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base)
{
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ deprecated_update_frame_base_hack (frame=%d,base=0x%s) }\n",
+ frame->level, paddr_nz (base));
/* See comment in "frame.h". */
- frame->frame = base;
+ frame->this_id.value.stack_addr = base;
}
void
@@ -1563,8 +2185,8 @@ deprecated_set_frame_context (struct frame_info *fi,
struct frame_info *
deprecated_frame_xmalloc (void)
{
- struct frame_info *frame = XMALLOC (struct frame_info);
- memset (frame, 0, sizeof (struct frame_info));
+ struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+ frame->this_id.p = 1;
return frame;
}
@@ -1587,6 +2209,17 @@ deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs,
return frame;
}
+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 ());
+}
+
void
_initialize_frame (void)
{