aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2003-01-27 21:41:41 +0000
committerAndrew Cagney <cagney@redhat.com>2003-01-27 21:41:41 +0000
commita94dd1fda23661238cac626d1adc7a11c55364b3 (patch)
tree77dfb87f1723e6353de68d2a533f827af9d45ab2
parent5378adc435ea0bce3ecb56bf0f1bc42deb1406f1 (diff)
downloadgdb-a94dd1fda23661238cac626d1adc7a11c55364b3.zip
gdb-a94dd1fda23661238cac626d1adc7a11c55364b3.tar.gz
gdb-a94dd1fda23661238cac626d1adc7a11c55364b3.tar.bz2
2003-01-27 Andrew Cagney <ac131313@redhat.com>
* sentinel-frame.h, sentinel-frame.c: New files. * Makefile.in (frame.o): Update dependencies. (SFILES): Add sentinel-frame.c. (sentinel_frame_h): Define. (COMMON_OBS): Add sentinel-frame.o. (sentinel-frame.o): Specify dependencies. * frame.c: Include "sentinel-frame.h". (frame_register_unwind): Rewrite assuming that there is always a a ->next frame. (frame_register, generic_unwind_get_saved_register): Ditto. (frame_read_unsigned_register, frame_read_signed_register): Ditto. (create_sentinel_frame, unwind_to_current_frame): New functions. (get_current_frame): Rewrite using create_sentinel_frame and unwind_to_current_frame. When possible, always create a frame. (create_new_frame): Set next to the sentinel frame. (get_next_frame): Rewrite. Don't go below the level 0 frame. (deprecated_update_frame_pc_hack): Update the next frame's PC and ID cache when necessary. (frame_saved_regs_id_unwind): Use frame_relative_level. (deprecated_generic_get_saved_register): Use frame_relative_level, get_frame_saved_regs, get_frame_pc, get_frame_base and get_next_frame. (frame_saved_regs_register_unwind): Use get_frame_saved_regs and frame_register.
-rw-r--r--gdb/ChangeLog27
-rw-r--r--gdb/Makefile.in14
-rw-r--r--gdb/frame.c263
-rw-r--r--gdb/sentinel-frame.c113
-rw-r--r--gdb/sentinel-frame.h41
5 files changed, 327 insertions, 131 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 24424a1..216b34f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,30 @@
+2003-01-27 Andrew Cagney <ac131313@redhat.com>
+
+ * sentinel-frame.h, sentinel-frame.c: New files.
+ * Makefile.in (frame.o): Update dependencies.
+ (SFILES): Add sentinel-frame.c.
+ (sentinel_frame_h): Define.
+ (COMMON_OBS): Add sentinel-frame.o.
+ (sentinel-frame.o): Specify dependencies.
+ * frame.c: Include "sentinel-frame.h".
+ (frame_register_unwind): Rewrite assuming that there is always a a
+ ->next frame.
+ (frame_register, generic_unwind_get_saved_register): Ditto.
+ (frame_read_unsigned_register, frame_read_signed_register): Ditto.
+ (create_sentinel_frame, unwind_to_current_frame): New functions.
+ (get_current_frame): Rewrite using create_sentinel_frame and
+ unwind_to_current_frame. When possible, always create a frame.
+ (create_new_frame): Set next to the sentinel frame.
+ (get_next_frame): Rewrite. Don't go below the level 0 frame.
+ (deprecated_update_frame_pc_hack): Update the next frame's PC and
+ ID cache when necessary.
+ (frame_saved_regs_id_unwind): Use frame_relative_level.
+ (deprecated_generic_get_saved_register): Use frame_relative_level,
+ get_frame_saved_regs, get_frame_pc, get_frame_base and
+ get_next_frame.
+ (frame_saved_regs_register_unwind): Use get_frame_saved_regs and
+ frame_register.
+
2003-01-27 Daniel Jacobowitz <drow@mvista.com>
* gdb_indent.sh: Add -T bfd and -T asection to the indent arguments.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 229c66b..63a6496 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -528,7 +528,9 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
objfiles.c osabi.c \
p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
regcache.c reggroups.c remote.c \
- scm-exp.c scm-lang.c scm-valprint.c serial.c ser-unix.c source.c \
+ scm-exp.c scm-lang.c scm-valprint.c \
+ sentinel-frame.c \
+ serial.c ser-unix.c source.c \
stabsread.c stack.c std-regs.c symfile.c symmisc.c symtab.c \
target.c thread.c top.c tracepoint.c typeprint.c \
tui/tui.c tui/tui.h tui/tuiCommand.c tui/tuiCommand.h \
@@ -686,6 +688,7 @@ remote_utils_h = remote-utils.h $(target_h)
remote_h = remote.h
scm_lang_h = scm-lang.h $(scm_tags_h)
scm_tags_h = scm-tags.h
+sentinel_frame_h = sentinel-frame.h
ser_unix_h = ser-unix.h
serial_h = serial.h
sh_tdep_h = sh-tdep.h
@@ -832,7 +835,9 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \
varobj.o wrapper.o \
jv-lang.o jv-valprint.o jv-typeprint.o \
m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
- scm-exp.o scm-lang.o scm-valprint.o complaints.o typeprint.o \
+ scm-exp.o scm-lang.o scm-valprint.o \
+ sentinel-frame.o \
+ complaints.o typeprint.o \
c-typeprint.o f-typeprint.o m2-typeprint.o \
c-valprint.o cp-valprint.o f-valprint.o m2-valprint.o \
nlmread.o serial.o mdebugread.o top.o utils.o \
@@ -1692,7 +1697,8 @@ fork-child.o: fork-child.c $(defs_h) $(gdb_string_h) $(frame_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) $(frame_unwind_h) $(command_h) $(gdbcmd_h)
+ $(language_h) $(frame_unwind_h) $(command_h) $(gdbcmd_h) \
+ $(sentinel_frame_h)
frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_h) \
$(gdb_assert_h) $(dummy_frame_h) $(legacy_frame_h)
frv-tdep.o: frv-tdep.c $(defs_h) $(inferior_h) $(symfile_h) $(gdbcore_h) \
@@ -2125,6 +2131,8 @@ scm-lang.o: scm-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
scm-valprint.o: scm-valprint.c $(defs_h) $(symtab_h) $(gdbtypes_h) \
$(expression_h) $(parser_defs_h) $(language_h) $(value_h) \
$(scm_lang_h) $(valprint_h) $(gdbcore_h)
+sentinel-frame.o: sentinel-frame.c $(defs_h) $(regcache_h) \
+ $(sentinel_frame_h) $(inferior_h) $(frame_unwind_h)
ser-e7kpc.o: ser-e7kpc.c $(defs_h) $(serial_h) $(gdb_string_h)
ser-go32.o: ser-go32.c $(defs_h) $(gdbcmd_h) $(serial_h) $(gdb_string_h)
ser-pipe.o: ser-pipe.c $(defs_h) $(serial_h) $(ser_unix_h) $(gdb_vfork_h) \
diff --git a/gdb/frame.c b/gdb/frame.c
index d252d8a..a0cfc6f 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -31,6 +31,7 @@
#include "builtin-regs.h"
#include "gdb_obstack.h"
#include "dummy-frame.h"
+#include "sentinel-frame.h"
#include "gdbcore.h"
#include "annotate.h"
#include "language.h"
@@ -179,29 +180,11 @@ frame_register_unwind (struct frame_info *frame, int regnum,
gdb_assert (realnump != NULL);
/* gdb_assert (bufferp != NULL); */
- /* NOTE: cagney/2002-04-14: It would be nice if, instead of a
- special case, there was always an inner frame dedicated to the
- hardware registers. Unfortunatly, there is too much unwind code
- around that looks up/down the frame chain while making the
- assumption that each frame level is using the same unwind code. */
-
- if (frame == NULL)
- {
- /* We're in the inner-most frame, get the value direct from the
- register cache. */
- *optimizedp = 0;
- *lvalp = lval_register;
- /* ULGH! Code uses the offset into the raw register byte array
- as a way of identifying a register. */
- *addrp = REGISTER_BYTE (regnum);
- /* Should this code test ``register_cached (regnum) < 0'' and do
- something like set realnum to -1 when the register isn't
- available? */
- *realnump = regnum;
- if (bufferp)
- deprecated_read_register_gen (regnum, bufferp);
- return;
- }
+ /* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame
+ is broken. There is always a frame. If there, for some reason,
+ isn't, there is some pretty busted code as it should have
+ 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,
@@ -247,25 +230,11 @@ frame_register (struct frame_info *frame, int regnum,
return;
}
- /* Reached the the bottom (youngest, inner most) of the frame chain
- (youngest, inner most) frame, go direct to the hardware register
- cache (do not pass go, do not try to cache the value, ...). The
- unwound value would have been cached in frame->next but that
- doesn't exist. This doesn't matter as the hardware register
- cache is stopping any unnecessary accesses to the target. */
-
- /* NOTE: cagney/2002-04-14: It would be nice if, instead of a
- special case, there was always an inner frame dedicated to the
- hardware registers. Unfortunatly, there is too much unwind code
- around that looks up/down the frame chain while making the
- assumption that each frame level is using the same unwind code. */
-
- if (frame == NULL)
- frame_register_unwind (NULL, regnum, optimizedp, lvalp, addrp, realnump,
- bufferp);
- else
- frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
- realnump, bufferp);
+ /* Obtain the register value by unwinding the register from the next
+ (more inner frame). */
+ gdb_assert (frame != NULL && frame->next != NULL);
+ frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
}
void
@@ -317,17 +286,17 @@ frame_read_unsigned_register (struct frame_info *frame, int regnum,
tests like ``if get_next_frame() == NULL'' and instead just rely
on recursive frame calls (like the below code) when manipulating
a frame chain. */
- gdb_assert (frame != NULL);
- frame_unwind_unsigned_register (get_next_frame (frame), regnum, val);
+ gdb_assert (frame != NULL && frame->next != NULL);
+ frame_unwind_unsigned_register (frame->next, regnum, val);
}
void
frame_read_signed_register (struct frame_info *frame, int regnum,
LONGEST *val)
{
- /* See note in frame_read_unsigned_register(). */
- gdb_assert (frame != NULL);
- frame_unwind_signed_register (get_next_frame (frame), regnum, val);
+ /* See note above in frame_read_unsigned_register(). */
+ gdb_assert (frame != NULL && frame->next != NULL);
+ frame_unwind_signed_register (frame->next, regnum, val);
}
static void
@@ -355,25 +324,9 @@ generic_unwind_get_saved_register (char *raw_buffer,
if (addrp == NULL)
addrp = &addrx;
- /* Reached the the bottom (youngest, inner most) of the frame chain
- (youngest, inner most) frame, go direct to the hardware register
- cache (do not pass go, do not try to cache the value, ...). The
- unwound value would have been cached in frame->next but that
- doesn't exist. This doesn't matter as the hardware register
- cache is stopping any unnecessary accesses to the target. */
-
- /* NOTE: cagney/2002-04-14: It would be nice if, instead of a
- special case, there was always an inner frame dedicated to the
- hardware registers. Unfortunatly, there is too much unwind code
- around that looks up/down the frame chain while making the
- assumption that each frame level is using the same unwind code. */
-
- if (frame == NULL)
- frame_register_unwind (NULL, regnum, optimizedp, lvalp, addrp, &realnumx,
- raw_buffer);
- else
- frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
- &realnumx, raw_buffer);
+ gdb_assert (frame != NULL && frame->next != NULL);
+ frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
+ &realnumx, raw_buffer);
}
void
@@ -463,6 +416,32 @@ frame_map_regnum_to_name (int regnum)
return builtin_reg_map_regnum_to_name (regnum);
}
+/* Create a sentinel frame. */
+
+struct frame_info *
+create_sentinel_frame (struct regcache *regcache)
+{
+ struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+ frame->type = NORMAL_FRAME;
+ frame->level = -1;
+ /* 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);
+ /* 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);
+ return frame;
+}
+
/* Info about the innermost stack frame (contents of FP register) */
static struct frame_info *current_frame;
@@ -495,17 +474,43 @@ get_frame_saved_regs (struct frame_info *fi)
return fi->saved_regs;
}
-/* Return the innermost (currently executing) stack frame. */
+/* Return the innermost (currently executing) stack frame. This is
+ split into two functions. The function unwind_to_current_frame()
+ is wrapped in catch exceptions so that, even when the unwind of the
+ sentinel frame fails, the function still returns a stack frame. */
+
+static int
+unwind_to_current_frame (struct ui_out *ui_out, void *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;
+}
struct frame_info *
get_current_frame (void)
{
+ if (!target_has_stack)
+ error ("No stack.");
+ if (!target_has_registers)
+ error ("No registers.");
+ if (!target_has_memory)
+ error ("No memory.");
if (current_frame == NULL)
{
- if (target_has_stack)
- current_frame = create_new_frame (read_fp (), read_pc ());
- else
- error ("No stack.");
+ 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)
+ {
+ /* Oops! Fake a current frame? Is this useful? It has a PC
+ of zero, for instance. */
+ current_frame = sentinel_frame;
+ }
}
return current_frame;
}
@@ -593,11 +598,11 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
gdb_assert (FRAME_INIT_SAVED_REGS_P ());
/* Load the saved_regs register cache. */
- if (frame->saved_regs == NULL)
+ if (get_frame_saved_regs (frame) == NULL)
FRAME_INIT_SAVED_REGS (frame);
- if (frame->saved_regs != NULL
- && frame->saved_regs[regnum] != 0)
+ if (get_frame_saved_regs (frame) != NULL
+ && get_frame_saved_regs (frame)[regnum] != 0)
{
if (regnum == SP_REGNUM)
{
@@ -608,7 +613,7 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
*realnump = -1;
if (bufferp != NULL)
store_address (bufferp, REGISTER_RAW_SIZE (regnum),
- frame->saved_regs[regnum]);
+ get_frame_saved_regs (frame)[regnum]);
}
else
{
@@ -616,7 +621,7 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
a local copy of its value. */
*optimizedp = 0;
*lvalp = lval_memory;
- *addrp = frame->saved_regs[regnum];
+ *addrp = get_frame_saved_regs (frame)[regnum];
*realnump = -1;
if (bufferp != NULL)
{
@@ -635,13 +640,13 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
{
regs[regnum]
= frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum));
- read_memory (frame->saved_regs[regnum], regs[regnum],
+ read_memory (get_frame_saved_regs (frame)[regnum], regs[regnum],
REGISTER_RAW_SIZE (regnum));
}
memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum));
#else
/* Read the value in from memory. */
- read_memory (frame->saved_regs[regnum], bufferp,
+ read_memory (get_frame_saved_regs (frame)[regnum], bufferp,
REGISTER_RAW_SIZE (regnum));
#endif
}
@@ -650,21 +655,11 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
}
/* 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);
- }
+ 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);
}
static CORE_ADDR
@@ -684,7 +679,7 @@ frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache,
/* Start out by assuming it's NULL. */
(*id) = null_frame_id;
- if (next_frame->next == NULL)
+ 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
@@ -797,44 +792,50 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
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 (frame != NULL)
{
- if (get_frame_type (frame) == DUMMY_FRAME)
+ for (frame = get_next_frame (frame);
+ frame_relative_level (frame) >= 0;
+ frame = get_next_frame (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 (get_frame_type (frame) == DUMMY_FRAME)
{
- if (raw_buffer) /* SP register treated specially */
- store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
- frame->saved_regs[regnum]);
+ 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;
}
- else
+
+ FRAME_INIT_SAVED_REGS (frame);
+ if (get_frame_saved_regs (frame) != NULL
+ && get_frame_saved_regs (frame)[regnum] != 0)
{
- 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));
+ if (lval) /* found it saved on the stack */
+ *lval = lval_memory;
+ if (regnum == SP_REGNUM)
+ {
+ if (raw_buffer) /* SP register treated specially */
+ store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
+ get_frame_saved_regs (frame)[regnum]);
+ }
+ else
+ {
+ if (addrp) /* any other register */
+ *addrp = get_frame_saved_regs (frame)[regnum];
+ if (raw_buffer)
+ read_memory (get_frame_saved_regs (frame)[regnum], raw_buffer,
+ REGISTER_RAW_SIZE (regnum));
+ }
+ return;
}
- return;
}
}
@@ -884,6 +885,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
fi->frame = addr;
fi->pc = pc;
+ fi->next = create_sentinel_frame (current_regcache);
fi->type = frame_type_from_pc (pc);
if (INIT_EXTRA_FRAME_INFO_P ())
@@ -896,12 +898,16 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
}
/* Return the frame that FRAME calls (NULL if FRAME is the innermost
- frame). */
+ 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)
{
- return frame->next;
+ if (frame->level > 0)
+ return frame->next;
+ else
+ return NULL;
}
/* Flush the entire frame cache. */
@@ -1415,6 +1421,7 @@ void
deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
{
/* See comment in "frame.h". */
+ gdb_assert (frame->next != NULL);
frame->pc = pc;
}
diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c
new file mode 100644
index 0000000..fe11d8a
--- /dev/null
+++ b/gdb/sentinel-frame.c
@@ -0,0 +1,113 @@
+/* Code dealing with register stack frames, for GDB, the GNU debugger.
+
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 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 "regcache.h"
+#include "sentinel-frame.h"
+#include "inferior.h"
+#include "frame-unwind.h"
+
+struct frame_unwind_cache
+{
+ struct regcache *regcache;
+};
+
+void *
+sentinel_frame_cache (struct regcache *regcache)
+{
+ struct frame_unwind_cache *cache =
+ FRAME_OBSTACK_ZALLOC (struct frame_unwind_cache);
+ cache->regcache = regcache;
+ return cache;
+}
+
+/* Here the register value is taken direct from the register cache. */
+
+void
+sentinel_frame_register_unwind (struct frame_info *frame,
+ void **unwind_cache,
+ int regnum, int *optimized,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnum, void *bufferp)
+{
+ struct frame_unwind_cache *cache = *unwind_cache;
+ /* Describe the register's location. A reg-frame maps all registers
+ onto the corresponding hardware register. */
+ *optimized = 0;
+ *lvalp = lval_register;
+ *addrp = REGISTER_BYTE (regnum);
+ *realnum = regnum;
+
+ /* If needed, find and return the value of the register. */
+ if (bufferp != NULL)
+ {
+ /* Return the actual value. */
+ /* Use the regcache_cooked_read() method so that it, on the fly,
+ constructs either a raw or pseudo register from the raw
+ register cache. */
+ regcache_cooked_read (cache->regcache, regnum, bufferp);
+ }
+}
+
+CORE_ADDR
+sentinel_frame_pc_unwind (struct frame_info *frame,
+ void **cache)
+{
+ /* FIXME: cagney/2003-01-08: This should be using a per-architecture
+ method that doesn't suffer from DECR_PC_AFTER_BREAK problems.
+ Such a method would take unwind_cache, regcache and stop reason
+ parameters. */
+ return read_pc ();
+}
+
+void
+sentinel_frame_id_unwind (struct frame_info *frame,
+ void **cache,
+ struct frame_id *id)
+{
+ /* FIXME: cagney/2003-01-08: This should be using a per-architecture
+ method that doesn't suffer from DECR_PC_AFTER_BREAK problems.
+ Such a method would take unwind_cache, regcache and stop reason
+ parameters. */
+ id->base = read_fp ();
+ id->pc = read_pc ();
+}
+
+static void
+sentinel_frame_pop (struct frame_info *frame,
+ void **cache,
+ struct regcache *regcache)
+{
+ internal_error (__FILE__, __LINE__, "Function sentinal_frame_pop called");
+}
+
+const struct frame_unwind sentinel_frame_unwinder =
+{
+ sentinel_frame_pop,
+ sentinel_frame_pc_unwind,
+ sentinel_frame_id_unwind,
+ sentinel_frame_register_unwind
+};
+
+const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
diff --git a/gdb/sentinel-frame.h b/gdb/sentinel-frame.h
new file mode 100644
index 0000000..9b69f42
--- /dev/null
+++ b/gdb/sentinel-frame.h
@@ -0,0 +1,41 @@
+/* Code dealing with register stack 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 (SENTINEL_FRAME_H)
+#define SENTINEL_FRAME_H 1
+
+struct frame_unwind;
+struct regcache;
+
+/* Implement the sentinel frame. The sentinel frame terminates the
+ inner most end of the frame chain. If unwound, it returns the
+ information need to construct an inner-most frame. */
+
+/* Pump prime the sentinel frame's cache. Since this needs the
+ REGCACHE provide that here. */
+
+extern void *sentinel_frame_cache (struct regcache *regcache);
+
+/* At present there is only one type of sentinel frame. */
+
+extern const struct frame_unwind *const sentinel_frame_unwind;
+
+#endif /* !defined (SENTINEL_FRAME_H) */