2003-01-27 Andrew Cagney <ac131313@redhat.com>
authorAndrew Cagney <cagney@redhat.com>
Mon, 27 Jan 2003 21:41:41 +0000 (21:41 +0000)
committerAndrew Cagney <cagney@redhat.com>
Mon, 27 Jan 2003 21:41:41 +0000 (21:41 +0000)
* 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.

gdb/ChangeLog
gdb/Makefile.in
gdb/frame.c
gdb/sentinel-frame.c [new file with mode: 0644]
gdb/sentinel-frame.h [new file with mode: 0644]

index 24424a1..216b34f 100644 (file)
@@ -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.
index 229c66b..63a6496 100644 (file)
@@ -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) \
index d252d8a..a0cfc6f 100644 (file)
@@ -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 (file)
index 0000000..fe11d8a
--- /dev/null
@@ -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 (file)
index 0000000..9b69f42
--- /dev/null
@@ -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)  */