summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2003-01-10 21:56:44 +0000
committerAndrew Cagney <cagney@redhat.com>2003-01-10 21:56:44 +0000
commit46c2fdb8b75e20f54bfe86eeecd57bd4ebdbad24 (patch)
tree5888b58afa7f8a1c8ab81b9a5bc5072865b68b2e
parenta62552ff4c38daf8ed32707b05b834972adfc6f2 (diff)
downloadgdb-46c2fdb8b75e20f54bfe86eeecd57bd4ebdbad24.tar.gz
Move legacy frame code to legacy-frame.[hc].
-rw-r--r--gdb/ChangeLog36
-rw-r--r--gdb/Makefile.in12
-rw-r--r--gdb/frame.c356
-rw-r--r--gdb/legacy-frame.c301
-rw-r--r--gdb/legacy-frame.h61
5 files changed, 459 insertions, 307 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ec827624f82..7f562ccd1ed 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,9 +1,35 @@
2003-01-10 Andrew Cagney <ac131313@redhat.com>
- * sentinel-frame.c (sentinel_frame_register_unwind): Correctly set
- LVALP and ADDRP.
+ * frame.c (create_sentinel_frame): Initialize sentinel frame's PC.
- * frame.c: Include "ui-out.h".
+ * sentinel-frame.c (struct frame_unwind_cache): Add pc field.
+
+ * sentinel-frame.h (sentinel_frame_cache): Add a pc parameter.
+
+ * frame.c (deprecated_generic_get_saved_register): Move from here.
+ * legacy-frame.c (deprecated_generic_get_saved_register): to here.
+
+ * legacy-frame.c: Include "regcache.h", "dummy-frame.h", and
+ "target.h".
+
+ * frame.c (set_unwind_by_pc): Update.
+ (frame_saved_regs_id_unwind): Delete function.
+ (frame_saved_regs_register_unwind): Delete function.
+ (frame_saved_regs_pc_unwind): Delete function.
+ (legacy_get_prev_frame): Rename deprecated_get_prev_frame.
+ (get_prev_frame): Update call.
+ (get_prev_frame): Move check for inside_main_func to before
+ setting of prev_p. Add check for inside_entry_file, but after
+ prev_p.
+
+ * Makefile.in (frame.o): Update dependencies.
+
+ * frame.c: Include "legacy-frame.h".
+
+ * Makefile.in (SFILES): Add legacy-frame.c.
+ (legacy_frame_h): Define.
+ (COMMON_OBS): Add legacy-frame.o.
+ (legacy-frame.o): Specify dependencies.
2003-01-09 Andrew Cagney <ac131313@redhat.com>
@@ -14,6 +40,10 @@
(get_prev_frame): Rewrite. Unwind the PC first. Use
frame_id_unwind.
+ * sentinel-frame.c (sentinel_frame_register_unwind): Correctly set
+ LVALP and ADDRP.
+ * frame.c: Include "ui-out.h".
+
2003-01-09 Andrew Cagney <ac131313@redhat.com>
* dummy-frame.h (dummy_frame_id_unwind): Update.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 84f1d74eab0..7fb480f8ed6 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -512,7 +512,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
inf-loop.c infcmd.c inflow.c infrun.c \
jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \
kod.c kod-cisco.c \
- language.c linespec.c \
+ language.c legacy-frame.c linespec.c \
m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \
macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \
mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c \
@@ -649,6 +649,7 @@ inferior_h = inferior.h $(breakpoint_h) $(target_h) $(frame_h)
jv_lang_h = jv-lang.h
kod_h = kod.h
language_h = language.h
+legacy_frame_h = legacy-frame.h
linespec_h = linespec.h
m2_lang_h = m2-lang.h
m68k_tdep_h = m68k-tdep.h
@@ -834,7 +835,7 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \
frame.o doublest.o \
gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o \
sentinel-frame.o \
- reggroups.o
+ reggroups.o legacy-frame.o
OBS = $(COMMON_OBS) $(ANNOTATE_OBS)
@@ -1681,8 +1682,9 @@ fork-child.o: fork-child.c $(defs_h) $(gdb_string_h) $(frame_h) \
$(terminal_h) $(gdbthread_h) $(command_h)
frame.o: frame.c $(defs_h) $(frame_h) $(target_h) $(value_h) $(inferior_h) \
$(regcache_h) $(gdb_assert_h) $(gdb_string_h) $(builtin_regs_h) \
- $(gdb_obstack_h) $(dummy_frame_h) $(gdbcore_h) $(annotate_h) \
- $(language_h) $(sentinel_frame_h) $(ui_out_h)
+ $(gdb_obstack_h) $(dummy_frame_h) $(sentinel_frame_h) \
+ $(legacy_frame_h) $(gdbcore_h) $(annotate_h) $(language_h) \
+ $(ui_out_h)
frv-tdep.o: frv-tdep.c $(defs_h) $(inferior_h) $(symfile_h) $(gdbcore_h) \
$(arch_utils_h) $(regcache_h)
gcore.o: gcore.c $(defs_h) $(cli_decode_h) $(inferior_h) $(gdbcore_h) \
@@ -1832,6 +1834,8 @@ language.o: language.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
$(parser_defs_h) $(jv_lang_h)
lin-lwp.o: lin-lwp.c $(defs_h) $(gdb_assert_h) $(gdb_string_h) $(gdb_wait_h) \
$(gdbthread_h) $(inferior_h) $(target_h) $(regcache_h) $(gdbcmd_h)
+legacy-frame.o: legacy-frame.c $(defs_h) $(legacy_frame_h) $(gdb_assert_h) \
+ $(frame_h) $(gdbcore_h) $(regcache_h) $(target_h) $(dummy_frame_h)
linespec.o: linespec.c $(defs_h) $(symtab_h) $(frame_h) $(command_h) \
$(symfile_h) $(objfiles_h) $(demangle_h) $(value_h) $(completer_h) \
$(cp_abi_h) $(source_h) $(parser_defs_h)
diff --git a/gdb/frame.c b/gdb/frame.c
index 79d0ee64171..0bac5808a2d 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -32,6 +32,7 @@
#include "gdb_obstack.h"
#include "dummy-frame.h"
#include "sentinel-frame.h"
+#include "legacy-frame.h"
#include "gdbcore.h"
#include "annotate.h"
#include "language.h"
@@ -410,6 +411,12 @@ create_sentinel_frame (struct regcache *regcache)
frame->pc_unwind = sentinel_frame_pc_unwind;
frame->id_unwind = sentinel_frame_id_unwind;
frame->register_unwind = sentinel_frame_register_unwind;
+ /* Always unwind the PC as part of creating this frame. This
+ ensures that the frame's PC points into something valid. */
+ /* FIXME: cagney/2003-01-10: Problem here. Unwinding a sentinel
+ frame's PC may require information such as the frame thread's
+ stop reason. Is it possible to get to that? */
+ frame->pc = frame_pc_unwind (frame);
return frame;
}
@@ -450,7 +457,12 @@ get_frame_saved_regs (struct frame_info *fi)
static int
unwind_to_current_frame (struct ui_out *ui_out, void *args)
{
- current_frame = get_prev_frame (args);
+ struct frame_info *frame = get_prev_frame (args);
+ /* A sentinel frame can fail to unwind, eg, because it's PC value
+ lands in somewhere like start. */
+ if (frame == NULL)
+ return 1;
+ current_frame = frame;
return 0;
}
@@ -468,7 +480,7 @@ get_current_frame (void)
struct frame_info *sentinel_frame =
create_sentinel_frame (current_regcache);
if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
- NULL, RETURN_MASK_ERROR) < 0)
+ NULL, RETURN_MASK_ERROR) != 0)
{
/* Oops! Fake a current frame? Is this useful? It has a PC
of zero, for instance. */
@@ -537,271 +549,6 @@ select_frame (struct frame_info *fi)
}
}
-/* Return the register saved in the simplistic ``saved_regs'' cache.
- If the value isn't here AND a value is needed, try the next inner
- most frame. */
-
-struct frame_unwind_cache
-{
- void *regs[1];
-};
-
-static void
-frame_saved_regs_register_unwind (struct frame_info *frame,
- struct frame_unwind_cache **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. */
- 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)));
-
- /* Load the saved_regs register cache. */
- if (frame->saved_regs == NULL)
- FRAME_INIT_SAVED_REGS (frame);
-
- if (frame->saved_regs != NULL
- && frame->saved_regs[regnum] != 0)
- {
- if (regnum == SP_REGNUM)
- {
- /* SP register treated specially. */
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (bufferp != NULL)
- store_address (bufferp, REGISTER_RAW_SIZE (regnum),
- frame->saved_regs[regnum]);
- }
- else
- {
- /* Any other register is saved in memory, fetch it but cache
- a local copy of its value. */
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = frame->saved_regs[regnum];
- *realnump = -1;
- if (bufferp != NULL)
- {
-#if 1
- /* Save each register value, as it is read in, in a
- frame based cache. */
- if ((*cache) == NULL)
- {
- int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS)
- * sizeof (void *));
- (*cache) = frame_obstack_zalloc (sizeof_cache);
- }
- if ((*cache)->regs[regnum] == NULL)
- {
- (*cache)->regs[regnum]
- = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum));
- read_memory (frame->saved_regs[regnum],
- (*cache)->regs[regnum],
- REGISTER_RAW_SIZE (regnum));
- }
- memcpy (bufferp, (*cache)->regs[regnum],
- REGISTER_RAW_SIZE (regnum));
-#else
- /* Read the value in from memory. */
- read_memory (frame->saved_regs[regnum], bufferp,
- REGISTER_RAW_SIZE (regnum));
-#endif
- }
- }
- return;
- }
-
- /* No luck, assume this and the next frame have the same register
- value. If a value is needed, pass the request on down the chain;
- otherwise just return an indication that the value is in the same
- register as the next frame. */
- if (bufferp == NULL)
- {
- *optimizedp = 0;
- *lvalp = lval_register;
- *addrp = 0;
- *realnump = regnum;
- }
- else
- {
- frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
- realnump, bufferp);
- }
-}
-
-static CORE_ADDR
-frame_saved_regs_pc_unwind (struct frame_info *frame,
- struct frame_unwind_cache **cache)
-{
- return FRAME_SAVED_PC (frame);
-}
-
-static void
-frame_saved_regs_id_unwind (struct frame_info *next_frame,
- struct frame_unwind_cache **cache,
- struct frame_id *id)
-{
- int fromleaf;
-
- if (next_frame->next == NULL)
- /* 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. */
- id->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. */
- id->base = FRAME_CHAIN (next_frame);
-
- if (!frame_chain_valid (id->base, next_frame))
- {
- *id = null_frame_id;
- return;
- }
- }
- if (id->base == 0)
- {
- *id = null_frame_id;
- return;
- }
-
- /* FIXME: cagney/2002-06-08: This should probably return the frame's
- function and not the PC (a.k.a. resume address). */
- id->pc = frame_pc_unwind (next_frame);
- return;
-}
-
-/* Function: get_saved_register
- Find register number REGNUM relative to FRAME and put its (raw,
- 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
- in this implementation.
-
- Set *LVAL to lval_memory, lval_register, or not_lval, depending on
- whether the value was fetched from memory, from a register, or in a
- strange and non-modifiable way (e.g. a frame pointer which was
- 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.
-
- 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
-deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
- CORE_ADDR *addrp,
- struct frame_info *frame, int regnum,
- enum lval_type *lval)
-{
- if (!target_has_registers)
- error ("No registers.");
-
- /* Normal systems don't optimize out things with register numbers. */
- if (optimized != NULL)
- *optimized = 0;
-
- if (addrp) /* default assumption: not found in memory */
- *addrp = 0;
-
- /* Note: since the current frame's registers could only have been
- saved by frames INTERIOR TO the current frame, we skip examining
- the current frame itself: otherwise, we would be getting the
- previous frame's registers which were saved by the current frame. */
-
- while (frame && ((frame = frame->next) != NULL))
- {
- if (get_frame_type (frame) == DUMMY_FRAME)
- {
- if (lval) /* found it in a CALL_DUMMY frame */
- *lval = not_lval;
- if (raw_buffer)
- /* FIXME: cagney/2002-06-26: This should be via the
- gdbarch_register_read() method so that it, on the fly,
- constructs either a raw or pseudo register from the raw
- register cache. */
- regcache_raw_read (generic_find_dummy_frame (frame->pc,
- frame->frame),
- regnum, raw_buffer);
- return;
- }
-
- FRAME_INIT_SAVED_REGS (frame);
- if (frame->saved_regs != NULL
- && frame->saved_regs[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),
- frame->saved_regs[regnum]);
- }
- else
- {
- if (addrp) /* any other register */
- *addrp = frame->saved_regs[regnum];
- if (raw_buffer)
- read_memory (frame->saved_regs[regnum], raw_buffer,
- REGISTER_RAW_SIZE (regnum));
- }
- return;
- }
- }
-
- /* If we get thru the loop to this point, it means the register was
- not saved in any frame. Return the actual live-register value. */
-
- if (lval) /* found it in a live register */
- *lval = lval_register;
- if (addrp)
- *addrp = REGISTER_BYTE (regnum);
- if (raw_buffer)
- deprecated_read_register_gen (regnum, raw_buffer);
-}
-
/* Using the PC, select a mechanism for unwinding a frame returning
the previous frame. The register unwind function should, on
demand, initialize the ->context object. */
@@ -818,9 +565,9 @@ set_unwind_by_pc (CORE_ADDR pc,
calls this function to find out where the saved registers are.
Hopefully this is robust enough to stop any core dumps and
return vaguely correct values.. */
- *unwind_register = frame_saved_regs_register_unwind;
- *unwind_pc = frame_saved_regs_pc_unwind;
- *unwind_id = frame_saved_regs_id_unwind;
+ *unwind_register = legacy_frame_register_unwind;
+ *unwind_pc = legacy_frame_pc_unwind;
+ *unwind_id = legacy_frame_id_unwind;
}
else if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
@@ -832,9 +579,9 @@ set_unwind_by_pc (CORE_ADDR pc,
}
else
{
- *unwind_register = frame_saved_regs_register_unwind;
- *unwind_pc = frame_saved_regs_pc_unwind;
- *unwind_id = frame_saved_regs_id_unwind;
+ *unwind_register = legacy_frame_register_unwind;
+ *unwind_pc = legacy_frame_pc_unwind;
+ *unwind_id = legacy_frame_id_unwind;
}
}
@@ -933,17 +680,12 @@ reinit_frame_cache (void)
method. */
static struct frame_info *
-deprecated_get_prev_frame (struct frame_info *next_frame)
+legacy_get_prev_frame (struct frame_info *next_frame)
{
CORE_ADDR address = 0;
struct frame_info *prev;
int fromleaf;
- /* Only try to do the unwind once. */
- if (next_frame->prev_p)
- return next_frame->prev;
- next_frame->prev_p = 1;
-
/* On some machines it is possible to call a function without
setting up a stack frame for it. On these machines, we
define this macro to take two args; a frameinfo pointer
@@ -1080,7 +822,7 @@ deprecated_get_prev_frame (struct frame_info *next_frame)
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 (INIT_EXTRA_FRAME_INFO_P ())
INIT_EXTRA_FRAME_INFO (fromleaf, prev);
@@ -1089,14 +831,14 @@ deprecated_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)
+ if (get_frame_base (prev) == get_frame_base (next_frame)
+ && get_frame_pc (prev) == get_frame_pc (next_frame))
{
next_frame->prev = NULL;
obstack_free (&frame_cache_obstack, prev);
@@ -1107,8 +849,8 @@ deprecated_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. */
- set_unwind_by_pc (prev->pc, &prev->register_unwind, &prev->pc_unwind,
- &prev->id_unwind);
+ set_unwind_by_pc (get_frame_pc (prev), &prev->register_unwind,
+ &prev->pc_unwind, &prev->id_unwind);
/* NOTE: cagney/2002-11-18: The code segments, found in
create_new_frame and get_prev_frame(), that initializes the
@@ -1120,8 +862,8 @@ deprecated_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
{
@@ -1132,8 +874,8 @@ deprecated_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
@@ -1182,27 +924,41 @@ get_prev_frame (struct frame_info *next_frame)
return current_frame;
}
- if ((DEPRECATED_INIT_FRAME_PC_P ()
- || DEPRECATED_INIT_FRAME_PC_FIRST_P ())
- && next_frame->level >= 0)
- /* Don't try to unwind the sentinal frame using the old code. */
- return deprecated_get_prev_frame (next_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);
+ if (next_frame->level >= 0
+ /* && !backtrace_below_main */
+ && inside_main_func (get_frame_pc (next_frame)))
+ /* Don't unwind past main(), 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(), they can just happen. */
+ return 0;
+
/* Only try to do the unwind once. */
if (next_frame->prev_p)
return next_frame->prev;
next_frame->prev_p = 1;
- if (next_frame->level >= 0
- /* && !backtrace_below_main */
- && inside_main_func (next_frame->pc))
- /* Don't unwind past main(), always unwind the sentinel frame. */
- return 0;
+ /* If we're inside the entry file, it isn't valid. */
+ /* NOTE: drow/2002-12-25: should there be a way to disable this
+ check? It assumes a single small entry file, and the way some
+ debug readers (e.g. dbxread) figure out which object is the
+ entry file is somewhat hokey. */
+ /* 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 (inside_entry_file (get_frame_pc (next_frame)))
+ return NULL;
+
+ if ((DEPRECATED_INIT_FRAME_PC_P ()
+ || DEPRECATED_INIT_FRAME_PC_FIRST_P ())
+ && next_frame->level >= 0)
+ /* Don't try to unwind the sentinal frame using the old code. */
+ return legacy_get_prev_frame (next_frame);
/* Allocate the new frame but do not wire it in. Some (bad) code in
INIT_EXTRA_FRAME_INFO tries to look along frame->next to pull
diff --git a/gdb/legacy-frame.c b/gdb/legacy-frame.c
new file mode 100644
index 00000000000..99227806961
--- /dev/null
+++ b/gdb/legacy-frame.c
@@ -0,0 +1,301 @@
+/* Code dealing with legacy frames, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+
+#include "defs.h"
+#include "legacy-frame.h"
+#include "gdb_assert.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "target.h"
+#include "dummy-frame.h" /* For generic_find_dummy_frame. */
+
+/* Legacy frame. This saves the processor state just prior to setting
+ up the inferior function call. Older targets save the registers
+ on the target stack (but that really slows down function calls). */
+
+struct frame_unwind_cache
+{
+ void *regs[1];
+};
+
+/* Given a legacy-frame, return the register register saved in the
+ simplistic ``saved_regs'' cache. If the value isn't here AND a
+ value is needed, try the next inner most frame. */
+
+void
+legacy_frame_register_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **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. */
+ 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)));
+
+ /* Load the saved_regs register cache. */
+ if (get_frame_saved_regs (frame) == NULL)
+ FRAME_INIT_SAVED_REGS (frame);
+
+ if (get_frame_saved_regs (frame) != NULL
+ && get_frame_saved_regs (frame)[regnum] != 0)
+ {
+ if (regnum == SP_REGNUM)
+ {
+ /* SP register treated specially. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (bufferp != NULL)
+ store_address (bufferp, REGISTER_RAW_SIZE (regnum),
+ get_frame_saved_regs (frame)[regnum]);
+ }
+ else
+ {
+ /* Any other register is saved in memory, fetch it but cache
+ a local copy of its value. */
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = get_frame_saved_regs (frame)[regnum];
+ *realnump = -1;
+ if (bufferp != NULL)
+ {
+#if 1
+ /* Save each register value, as it is read in, in a
+ frame based cache. */
+ if ((*cache) == NULL)
+ {
+ int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS)
+ * sizeof (void *));
+ (*cache) = frame_obstack_zalloc (sizeof_cache);
+ }
+ if ((*cache)->regs[regnum] == NULL)
+ {
+ (*cache)->regs[regnum]
+ = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum));
+ read_memory (get_frame_saved_regs (frame)[regnum],
+ (*cache)->regs[regnum],
+ REGISTER_RAW_SIZE (regnum));
+ }
+ memcpy (bufferp, (*cache)->regs[regnum],
+ REGISTER_RAW_SIZE (regnum));
+#else
+ /* Read the value in from memory. */
+ read_memory (get_frame_saved_regs (frame)[regnum], bufferp,
+ REGISTER_RAW_SIZE (regnum));
+#endif
+ }
+ }
+ return;
+ }
+
+ /* No luck, assume this and the next frame have the same register
+ value. If a value is needed, pass the request on down the chain;
+ otherwise just return an indication that the value is in the same
+ register as the next frame. */
+ if (bufferp == NULL)
+ {
+ *optimizedp = 0;
+ *lvalp = lval_register;
+ *addrp = REGISTER_BYTE (regnum);
+ *realnump = regnum;
+ }
+ else
+ {
+ frame_register (frame, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
+ }
+}
+
+CORE_ADDR
+legacy_frame_pc_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **cache)
+{
+ return FRAME_SAVED_PC (frame);
+}
+
+void
+legacy_frame_id_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **cache,
+ struct frame_id *id)
+{
+ int fromleaf;
+
+ if (get_next_frame (frame) == NULL)
+ /* 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 (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. */
+ id->base = get_frame_base (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. */
+ id->base = FRAME_CHAIN (frame);
+
+ if (!frame_chain_valid (id->base, frame))
+ {
+ *id = null_frame_id;
+ return;
+ }
+ }
+ if (id->base == 0)
+ {
+ *id = null_frame_id;
+ return;
+ }
+
+ /* FIXME: cagney/2002-06-08: This should probably return the frame's
+ function and not the PC (a.k.a. resume address). */
+ id->pc = frame_pc_unwind (frame);
+ return;
+}
+
+/* Function: deprecated_generic_get_saved_register.
+
+ Find register number REGNUM relative to FRAME and put its (raw,
+ 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
+ in this implementation.
+
+ Set *LVAL to lval_memory, lval_register, or not_lval, depending on
+ whether the value was fetched from memory, from a register, or in a
+ strange and non-modifiable way (e.g. a frame pointer which was
+ 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.
+
+ 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
+deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
+ CORE_ADDR *addrp,
+ struct frame_info *frame, int regnum,
+ enum lval_type *lval)
+{
+ if (!target_has_registers)
+ error ("No registers.");
+
+ /* Normal systems don't optimize out things with register numbers. */
+ if (optimized != NULL)
+ *optimized = 0;
+
+ if (addrp) /* default assumption: not found in memory */
+ *addrp = 0;
+
+ /* Note: since the current frame's registers could only have been
+ saved by frames INTERIOR TO the current frame, we skip examining
+ the current frame itself: otherwise, we would be getting the
+ previous frame's registers which were saved by the current frame. */
+
+ while (frame && ((frame = get_next_frame (frame)) != NULL))
+ {
+ if (get_frame_type (frame) == DUMMY_FRAME)
+ {
+ if (lval) /* found it in a CALL_DUMMY frame */
+ *lval = not_lval;
+ if (raw_buffer)
+ /* FIXME: cagney/2002-06-26: This should be via the
+ gdbarch_register_read() method so that it, on the 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)),
+ regnum, raw_buffer);
+ return;
+ }
+
+ FRAME_INIT_SAVED_REGS (frame);
+ if (frame->saved_regs != NULL
+ && frame->saved_regs[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),
+ frame->saved_regs[regnum]);
+ }
+ else
+ {
+ if (addrp) /* any other register */
+ *addrp = frame->saved_regs[regnum];
+ if (raw_buffer)
+ read_memory (frame->saved_regs[regnum], raw_buffer,
+ REGISTER_RAW_SIZE (regnum));
+ }
+ return;
+ }
+ }
+
+ /* If we get thru the loop to this point, it means the register was
+ not saved in any frame. Return the actual live-register value. */
+
+ if (lval) /* found it in a live register */
+ *lval = lval_register;
+ if (addrp)
+ *addrp = REGISTER_BYTE (regnum);
+ if (raw_buffer)
+ deprecated_read_register_gen (regnum, raw_buffer);
+}
diff --git a/gdb/legacy-frame.h b/gdb/legacy-frame.h
new file mode 100644
index 00000000000..999e76afdc3
--- /dev/null
+++ b/gdb/legacy-frame.h
@@ -0,0 +1,61 @@
+/* Code dealing with legacy frames, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if !defined (LEGACY_FRAME_H)
+#define LEGACY_FRAME_H 1
+
+struct frame_info;
+struct regcache;
+struct frame_id;
+struct frame_unwind_cache;
+
+/* LEGACY FRAMES
+
+ The original extra frame info implementation of the`struct
+ frame_info' object. These frames always initialize the entire
+ frame object using extra frame info. */
+
+/* Assuming that FRAME is a legacy, return a register value for the
+ previous frame. */
+
+extern void legacy_frame_register_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **unwind_cache,
+ int regnum,
+ int *optimized,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump,
+ void *valuep);
+
+/* Assuming that FRAME is a legacy, return the resume address for the
+ previous frame. */
+
+extern CORE_ADDR legacy_frame_pc_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **unwind_cache);
+
+/* Assuming that FRAME is a legacy, return the ID of the calling frame
+ (the frame that the legacy has the saved state of). */
+
+extern void legacy_frame_id_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **unwind_cache,
+ struct frame_id *id);
+
+#endif