2002-11-08 Andrew Cagney <ac131313@redhat.com>
authorAndrew Cagney <cagney@redhat.com>
Fri, 8 Nov 2002 19:42:00 +0000 (19:42 +0000)
committerAndrew Cagney <cagney@redhat.com>
Fri, 8 Nov 2002 19:42:00 +0000 (19:42 +0000)
* blockframe.c: Include "dummy-frame.h".
(struct dummy_frame, dummy_frame_stack)
(generic_find_dummy_frame, deprecated_generic_find_dummy_frame)
(generic_pc_in_call_dummy, deprecated_read_register_dummy)
(generic_push_dummy_frame, generic_save_dummy_frame_tos)
(generic_save_call_dummy_addr, generic_pop_current_frame)
(generic_pop_dummy_frame, generic_fix_call_dummy)
(generic_fix_call_dummy, generic_call_dummy_register_unwind): Move
dummy frame code from here...
* dummy-frame.c: ...to here.  New file.
* dummy-frame.h: New file.
(generic_call_dummy_register_unwind): Declare.
(generic_find_dummy_frame): Declare.
* Makefile.in (SFILES): Add dummy-frame.c.
(dummy-frame.o): Specify dependencies.
(dummy_frame_h): Define.
(COMMON_OBS): Add dummy-frame.o.
(blockframe.o): Update dependencies.

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

index 166ac5b..7985ef7 100644 (file)
@@ -1,3 +1,24 @@
+2002-11-08  Andrew Cagney  <ac131313@redhat.com>
+
+       * blockframe.c: Include "dummy-frame.h".
+       (struct dummy_frame, dummy_frame_stack)
+       (generic_find_dummy_frame, deprecated_generic_find_dummy_frame)
+       (generic_pc_in_call_dummy, deprecated_read_register_dummy)
+       (generic_push_dummy_frame, generic_save_dummy_frame_tos)
+       (generic_save_call_dummy_addr, generic_pop_current_frame)
+       (generic_pop_dummy_frame, generic_fix_call_dummy)
+       (generic_fix_call_dummy, generic_call_dummy_register_unwind): Move
+       dummy frame code from here...
+       * dummy-frame.c: ...to here.  New file.
+       * dummy-frame.h: New file.
+       (generic_call_dummy_register_unwind): Declare.
+       (generic_find_dummy_frame): Declare.
+       * Makefile.in (SFILES): Add dummy-frame.c.
+       (dummy-frame.o): Specify dependencies.
+       (dummy_frame_h): Define.
+       (COMMON_OBS): Add dummy-frame.o.
+       (blockframe.o): Update dependencies.
+
 2002-11-08  Jim Blandy  <jimb@redhat.com>
 
        * dwarf2read.c (read_func_scope): Restore local_symbols and
index afcca56..696bfef 100644 (file)
@@ -535,7 +535,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
        c-exp.y c-lang.c c-typeprint.c c-valprint.c \
        charset.c cli-out.c coffread.c complaints.c completer.c corefile.c \
        cp-abi.c cp-support.c cp-valprint.c \
-       dbxread.c demangle.c disasm.c doublest.c dwarfread.c dwarf2read.c \
+       dbxread.c demangle.c disasm.c doublest.c \
+       dummy-frame.c dwarfread.c dwarf2read.c \
        elfread.c environ.c eval.c event-loop.c event-top.c expprint.c \
        f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c frame.c \
        gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
@@ -640,6 +641,7 @@ defs_h = defs.h $(config_h) $(gdb_locale_h) $(gdb_signals_h) $(ansidecl_h) \
 disasm_h = disasm.h
 doublest_h = doublest.h $(floatformat_h)
 dst_h = dst.h
+dummy_frame_h = dummy-frame.h
 dwarf2cfi_h = dwarf2cfi.h
 environ_h = environ.h
 event_loop_h = event-loop.h
@@ -829,7 +831,7 @@ TAGFILES_NO_SRCDIR = $(SFILES) $(HFILES_NO_SRCDIR) $(ALLDEPFILES) \
 TAGFILES_WITH_SRCDIR = $(HFILES_WITH_SRCDIR)
 
 COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \
-       charset.o disasm.o \
+       charset.o disasm.o dummy-frame.o \
        source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o \
        symtab.o symfile.o symmisc.o linespec.o infcmd.o infrun.o \
        expprint.o environ.o stack.o thread.o \
@@ -1532,7 +1534,8 @@ ax-general.o: ax-general.c $(defs_h) $(ax_h) $(value_h) $(gdb_string_h)
 bcache.o: bcache.c $(defs_h) $(gdb_obstack_h) $(bcache_h) $(gdb_string_h)
 blockframe.o: blockframe.c $(defs_h) $(symtab_h) $(bfd_h) $(symfile_h) \
        $(objfiles_h) $(frame_h) $(gdbcore_h) $(value_h) $(target_h) \
-       $(inferior_h) $(annotate_h) $(regcache_h) $(gdb_assert_h)
+       $(inferior_h) $(annotate_h) $(regcache_h) $(gdb_assert_h) \
+       $(dummy_frame_h)
 breakpoint.o: breakpoint.c $(defs_h) $(symtab_h) $(frame_h) $(breakpoint_h) \
        $(gdbtypes_h) $(expression_h) $(gdbcore_h) $(gdbcmd_h) $(value_h) \
        $(command_h) $(inferior_h) $(gdbthread_h) $(target_h) $(language_h) \
@@ -1627,6 +1630,8 @@ doublest.o: doublest.c $(defs_h) $(doublest_h) $(floatformat_h) \
 dpx2-nat.o: dpx2-nat.c $(defs_h) $(gdbcore_h) $(gdb_string_h)
 dsrec.o: dsrec.c $(defs_h) $(serial_h) $(srec_h)
 # OBSOLETE dstread.o: dstread.c
+dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \
+       $(frame_h) $(inferior_h) $(gdb_assert_h)
 dve3900-rom.o: dve3900-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \
        $(serial_h) $(inferior_h) $(command_h) $(gdb_string_h) $(regcache_h)
 dwarf2cfi.o: dwarf2cfi.c $(defs_h) $(gdbcore_h) $(symtab_h) $(symfile_h) \
index 2b789e6..c34d3e0 100644 (file)
 #include "annotate.h"
 #include "regcache.h"
 #include "gdb_assert.h"
+#include "dummy-frame.h"
 
 /* Prototypes for exported functions. */
 
-static void generic_call_dummy_register_unwind (struct frame_info *frame,
-                                               void **cache,
-                                               int regnum,
-                                               int *optimized,
-                                               enum lval_type *lval,
-                                               CORE_ADDR *addrp,
-                                               int *realnum,
-                                               void *raw_buffer);
 static void frame_saved_regs_register_unwind (struct frame_info *frame,
                                              void **cache,
                                              int regnum,
@@ -1107,244 +1100,6 @@ pc_in_call_dummy_at_entry_point (CORE_ADDR pc, CORE_ADDR sp,
 }
 
 
-/*
- * GENERIC DUMMY FRAMES
- * 
- * The following code serves to maintain the dummy stack frames for
- * inferior function calls (ie. when gdb calls into the inferior via
- * call_function_by_hand).  This code saves the machine state before 
- * the call in host memory, so we must maintain an independent stack 
- * and keep it consistant etc.  I am attempting to make this code 
- * generic enough to be used by many targets.
- *
- * The cheapest and most generic way to do CALL_DUMMY on a new target
- * is probably to define CALL_DUMMY to be empty, CALL_DUMMY_LENGTH to
- * zero, and CALL_DUMMY_LOCATION to AT_ENTRY.  Then you must remember
- * to define PUSH_RETURN_ADDRESS, because no call instruction will be
- * being executed by the target.  Also FRAME_CHAIN_VALID as
- * generic_{file,func}_frame_chain_valid and FIX_CALL_DUMMY as
- * generic_fix_call_dummy.  */
-
-/* Dummy 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 dummy_frame
-{
-  struct dummy_frame *next;
-
-  CORE_ADDR pc;
-  CORE_ADDR fp;
-  CORE_ADDR sp;
-  CORE_ADDR top;
-  struct regcache *regcache;
-
-  /* Address range of the call dummy code.  Look for PC in the range
-     [LO..HI) (after allowing for DECR_PC_AFTER_BREAK).  */
-  CORE_ADDR call_lo;
-  CORE_ADDR call_hi;
-};
-
-static struct dummy_frame *dummy_frame_stack = NULL;
-
-/* Function: find_dummy_frame(pc, fp, sp)
-
-   Search the stack of dummy frames for one matching the given PC and
-   FP/SP.  Unlike PC_IN_CALL_DUMMY, this function doesn't need to
-   adjust for DECR_PC_AFTER_BREAK.  This is because it is only legal
-   to call this function after the PC has been adjusted.  */
-
-static struct regcache *
-generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
-{
-  struct dummy_frame *dummyframe;
-
-  for (dummyframe = dummy_frame_stack; dummyframe != NULL;
-       dummyframe = dummyframe->next)
-    {
-      /* Does the PC fall within the dummy frame's breakpoint
-         instruction.  If not, discard this one.  */
-      if (!(pc >= dummyframe->call_lo && pc < dummyframe->call_hi))
-       continue;
-      /* Does the FP match?  */
-      if (dummyframe->top != 0)
-       {
-         /* If the target architecture explicitly saved the
-            top-of-stack before the inferior function call, assume
-            that that same architecture will always pass in an FP
-            (frame base) value that eactly matches that saved TOS.
-            Don't check the saved SP and SP as they can lead to false
-            hits.  */
-         if (fp != dummyframe->top)
-           continue;
-       }
-      else
-       {
-         /* An older target that hasn't explicitly or implicitly
-             saved the dummy frame's top-of-stack.  Try matching the
-             FP against the saved SP and FP.  NOTE: If you're trying
-             to fix a problem with GDB not correctly finding a dummy
-             frame, check the comments that go with FRAME_ALIGN() and
-             SAVE_DUMMY_FRAME_TOS().  */
-         if (fp != dummyframe->fp && fp != dummyframe->sp)
-           continue;
-       }
-      /* The FP matches this dummy frame.  */
-      return dummyframe->regcache;
-    }
-
-  return 0;
-}
-
-char *
-deprecated_generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
-{
-  struct regcache *regcache = generic_find_dummy_frame (pc, fp);
-  if (regcache == NULL)
-    return NULL;
-  return deprecated_grub_regcache_for_registers (regcache);
-}
-
-/* Function: pc_in_call_dummy (pc, sp, fp)
-
-   Return true if the PC falls in a dummy frame created by gdb for an
-   inferior call.  The code below which allows DECR_PC_AFTER_BREAK is
-   for infrun.c, which may give the function a PC without that
-   subtracted out.  */
-
-int
-generic_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR fp)
-{
-  struct dummy_frame *dummyframe;
-  for (dummyframe = dummy_frame_stack;
-       dummyframe != NULL;
-       dummyframe = dummyframe->next)
-    {
-      if ((pc >= dummyframe->call_lo)
-         && (pc < dummyframe->call_hi + DECR_PC_AFTER_BREAK))
-       return 1;
-    }
-  return 0;
-}
-
-/* Function: read_register_dummy 
-   Find a saved register from before GDB calls a function in the inferior */
-
-CORE_ADDR
-deprecated_read_register_dummy (CORE_ADDR pc, CORE_ADDR fp, int regno)
-{
-  struct regcache *dummy_regs = generic_find_dummy_frame (pc, fp);
-
-  if (dummy_regs)
-    {
-      /* NOTE: cagney/2002-08-12: Replaced a call to
-        regcache_raw_read_as_address() with a call to
-        regcache_cooked_read_unsigned().  The old, ...as_address
-        function was eventually calling extract_unsigned_integer (via
-        extract_address) to unpack the registers value.  The below is
-        doing an unsigned extract so that it is functionally
-        equivalent.  The read needs to be cooked as, otherwise, it
-        will never correctly return the value of a register in the
-        [NUM_REGS .. NUM_REGS+NUM_PSEUDO_REGS) range.  */
-      ULONGEST val;
-      regcache_cooked_read_unsigned (dummy_regs, regno, &val);
-      return val;
-    }
-  else
-    return 0;
-}
-
-/* Save all the registers on the dummy frame stack.  Most ports save the
-   registers on the target stack.  This results in lots of unnecessary memory
-   references, which are slow when debugging via a serial line.  Instead, we
-   save all the registers internally, and never write them to the stack.  The
-   registers get restored when the called function returns to the entry point,
-   where a breakpoint is laying in wait.  */
-
-void
-generic_push_dummy_frame (void)
-{
-  struct dummy_frame *dummy_frame;
-  CORE_ADDR fp = (get_current_frame ())->frame;
-
-  /* check to see if there are stale dummy frames, 
-     perhaps left over from when a longjump took us out of a 
-     function that was called by the debugger */
-
-  dummy_frame = dummy_frame_stack;
-  while (dummy_frame)
-    if (INNER_THAN (dummy_frame->fp, fp))      /* stale -- destroy! */
-      {
-       dummy_frame_stack = dummy_frame->next;
-       regcache_xfree (dummy_frame->regcache);
-       xfree (dummy_frame);
-       dummy_frame = dummy_frame_stack;
-      }
-    else
-      dummy_frame = dummy_frame->next;
-
-  dummy_frame = xmalloc (sizeof (struct dummy_frame));
-  dummy_frame->regcache = regcache_xmalloc (current_gdbarch);
-
-  dummy_frame->pc = read_pc ();
-  dummy_frame->sp = read_sp ();
-  dummy_frame->top = 0;
-  dummy_frame->fp = fp;
-  regcache_cpy (dummy_frame->regcache, current_regcache);
-  dummy_frame->next = dummy_frame_stack;
-  dummy_frame_stack = dummy_frame;
-}
-
-void
-generic_save_dummy_frame_tos (CORE_ADDR sp)
-{
-  dummy_frame_stack->top = sp;
-}
-
-/* Record the upper/lower bounds on the address of the call dummy.  */
-
-void
-generic_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi)
-{
-  dummy_frame_stack->call_lo = lo;
-  dummy_frame_stack->call_hi = hi;
-}
-
-/* Restore the machine state from either the saved dummy stack or a
-   real stack frame. */
-
-void
-generic_pop_current_frame (void (*popper) (struct frame_info * frame))
-{
-  struct frame_info *frame = get_current_frame ();
-
-  if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
-    generic_pop_dummy_frame ();
-  else
-    (*popper) (frame);
-}
-
-/* Function: pop_dummy_frame
-   Restore the machine state from a saved dummy stack frame. */
-
-void
-generic_pop_dummy_frame (void)
-{
-  struct dummy_frame *dummy_frame = dummy_frame_stack;
-
-  /* FIXME: what if the first frame isn't the right one, eg..
-     because one call-by-hand function has done a longjmp into another one? */
-
-  if (!dummy_frame)
-    error ("Can't pop dummy frame!");
-  dummy_frame_stack = dummy_frame->next;
-  regcache_cpy (current_regcache, dummy_frame->regcache);
-  flush_cached_frames ();
-
-  regcache_xfree (dummy_frame->regcache);
-  xfree (dummy_frame);
-}
-
 /* Function: frame_chain_valid 
    Returns true for a user frame or a call_function_by_hand dummy frame,
    and false for the CRT0 start-up frame.  Purpose is to terminate backtrace */
@@ -1373,63 +1128,6 @@ generic_func_frame_chain_valid (CORE_ADDR fp, struct frame_info *fi)
            && !inside_entry_func ((fi)->pc));
 }
 
-/* Function: fix_call_dummy
-   Stub function.  Generic dummy frames typically do not need to fix
-   the frame being created */
-
-void
-generic_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
-                       struct value **args, struct type *type, int gcc_p)
-{
-  return;
-}
-
-/* Given a call-dummy dummy-frame, return the registers.  Here the
-   register value is taken from the local copy of the register buffer.  */
-
-static void
-generic_call_dummy_register_unwind (struct frame_info *frame, void **cache,
-                                   int regnum, int *optimized,
-                                   enum lval_type *lvalp, CORE_ADDR *addrp,
-                                   int *realnum, void *bufferp)
-{
-  gdb_assert (frame != NULL);
-  gdb_assert (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame));
-
-  /* Describe the register's location.  Generic dummy frames always
-     have the register value in an ``expression''.  */
-  *optimized = 0;
-  *lvalp = not_lval;
-  *addrp = 0;
-  *realnum = -1;
-
-  /* If needed, find and return the value of the register.  */
-  if (bufferp != NULL)
-    {
-      struct regcache *registers;
-#if 1
-      /* Get the address of the register buffer that contains all the
-        saved registers for this dummy frame.  Cache that address.  */
-      registers = (*cache);
-      if (registers == NULL)
-       {
-         registers = generic_find_dummy_frame (frame->pc, frame->frame);
-         (*cache) = registers;
-       }
-#else
-      /* Get the address of the register buffer that contains the
-         saved registers and then extract the value from that.  */
-      registers = generic_find_dummy_frame (frame->pc, frame->frame);
-#endif
-      gdb_assert (registers != 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 (registers, regnum, bufferp);
-    }
-}
-
 /* 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.  */
diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c
new file mode 100644 (file)
index 0000000..1a2a315
--- /dev/null
@@ -0,0 +1,308 @@
+/* Code dealing with dummy 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 "dummy-frame.h"
+#include "regcache.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdb_assert.h"
+
+/* Dummy 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 dummy_frame
+{
+  struct dummy_frame *next;
+
+  CORE_ADDR pc;
+  CORE_ADDR fp;
+  CORE_ADDR sp;
+  CORE_ADDR top;
+  struct regcache *regcache;
+
+  /* Address range of the call dummy code.  Look for PC in the range
+     [LO..HI) (after allowing for DECR_PC_AFTER_BREAK).  */
+  CORE_ADDR call_lo;
+  CORE_ADDR call_hi;
+};
+
+static struct dummy_frame *dummy_frame_stack = NULL;
+
+/* Function: find_dummy_frame(pc, fp, sp)
+
+   Search the stack of dummy frames for one matching the given PC and
+   FP/SP.  Unlike PC_IN_CALL_DUMMY, this function doesn't need to
+   adjust for DECR_PC_AFTER_BREAK.  This is because it is only legal
+   to call this function after the PC has been adjusted.  */
+
+struct regcache *
+generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
+{
+  struct dummy_frame *dummyframe;
+
+  for (dummyframe = dummy_frame_stack; dummyframe != NULL;
+       dummyframe = dummyframe->next)
+    {
+      /* Does the PC fall within the dummy frame's breakpoint
+         instruction.  If not, discard this one.  */
+      if (!(pc >= dummyframe->call_lo && pc < dummyframe->call_hi))
+       continue;
+      /* Does the FP match?  */
+      if (dummyframe->top != 0)
+       {
+         /* If the target architecture explicitly saved the
+            top-of-stack before the inferior function call, assume
+            that that same architecture will always pass in an FP
+            (frame base) value that eactly matches that saved TOS.
+            Don't check the saved SP and SP as they can lead to false
+            hits.  */
+         if (fp != dummyframe->top)
+           continue;
+       }
+      else
+       {
+         /* An older target that hasn't explicitly or implicitly
+             saved the dummy frame's top-of-stack.  Try matching the
+             FP against the saved SP and FP.  NOTE: If you're trying
+             to fix a problem with GDB not correctly finding a dummy
+             frame, check the comments that go with FRAME_ALIGN() and
+             SAVE_DUMMY_FRAME_TOS().  */
+         if (fp != dummyframe->fp && fp != dummyframe->sp)
+           continue;
+       }
+      /* The FP matches this dummy frame.  */
+      return dummyframe->regcache;
+    }
+
+  return 0;
+}
+
+char *
+deprecated_generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
+{
+  struct regcache *regcache = generic_find_dummy_frame (pc, fp);
+  if (regcache == NULL)
+    return NULL;
+  return deprecated_grub_regcache_for_registers (regcache);
+}
+
+/* Function: pc_in_call_dummy (pc, sp, fp)
+
+   Return true if the PC falls in a dummy frame created by gdb for an
+   inferior call.  The code below which allows DECR_PC_AFTER_BREAK is
+   for infrun.c, which may give the function a PC without that
+   subtracted out.  */
+
+int
+generic_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR fp)
+{
+  struct dummy_frame *dummyframe;
+  for (dummyframe = dummy_frame_stack;
+       dummyframe != NULL;
+       dummyframe = dummyframe->next)
+    {
+      if ((pc >= dummyframe->call_lo)
+         && (pc < dummyframe->call_hi + DECR_PC_AFTER_BREAK))
+       return 1;
+    }
+  return 0;
+}
+
+/* Function: read_register_dummy 
+   Find a saved register from before GDB calls a function in the inferior */
+
+CORE_ADDR
+deprecated_read_register_dummy (CORE_ADDR pc, CORE_ADDR fp, int regno)
+{
+  struct regcache *dummy_regs = generic_find_dummy_frame (pc, fp);
+
+  if (dummy_regs)
+    {
+      /* NOTE: cagney/2002-08-12: Replaced a call to
+        regcache_raw_read_as_address() with a call to
+        regcache_cooked_read_unsigned().  The old, ...as_address
+        function was eventually calling extract_unsigned_integer (via
+        extract_address) to unpack the registers value.  The below is
+        doing an unsigned extract so that it is functionally
+        equivalent.  The read needs to be cooked as, otherwise, it
+        will never correctly return the value of a register in the
+        [NUM_REGS .. NUM_REGS+NUM_PSEUDO_REGS) range.  */
+      ULONGEST val;
+      regcache_cooked_read_unsigned (dummy_regs, regno, &val);
+      return val;
+    }
+  else
+    return 0;
+}
+
+/* Save all the registers on the dummy frame stack.  Most ports save the
+   registers on the target stack.  This results in lots of unnecessary memory
+   references, which are slow when debugging via a serial line.  Instead, we
+   save all the registers internally, and never write them to the stack.  The
+   registers get restored when the called function returns to the entry point,
+   where a breakpoint is laying in wait.  */
+
+void
+generic_push_dummy_frame (void)
+{
+  struct dummy_frame *dummy_frame;
+  CORE_ADDR fp = (get_current_frame ())->frame;
+
+  /* check to see if there are stale dummy frames, 
+     perhaps left over from when a longjump took us out of a 
+     function that was called by the debugger */
+
+  dummy_frame = dummy_frame_stack;
+  while (dummy_frame)
+    if (INNER_THAN (dummy_frame->fp, fp))      /* stale -- destroy! */
+      {
+       dummy_frame_stack = dummy_frame->next;
+       regcache_xfree (dummy_frame->regcache);
+       xfree (dummy_frame);
+       dummy_frame = dummy_frame_stack;
+      }
+    else
+      dummy_frame = dummy_frame->next;
+
+  dummy_frame = xmalloc (sizeof (struct dummy_frame));
+  dummy_frame->regcache = regcache_xmalloc (current_gdbarch);
+
+  dummy_frame->pc = read_pc ();
+  dummy_frame->sp = read_sp ();
+  dummy_frame->top = 0;
+  dummy_frame->fp = fp;
+  regcache_cpy (dummy_frame->regcache, current_regcache);
+  dummy_frame->next = dummy_frame_stack;
+  dummy_frame_stack = dummy_frame;
+}
+
+void
+generic_save_dummy_frame_tos (CORE_ADDR sp)
+{
+  dummy_frame_stack->top = sp;
+}
+
+/* Record the upper/lower bounds on the address of the call dummy.  */
+
+void
+generic_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi)
+{
+  dummy_frame_stack->call_lo = lo;
+  dummy_frame_stack->call_hi = hi;
+}
+
+/* Restore the machine state from either the saved dummy stack or a
+   real stack frame. */
+
+void
+generic_pop_current_frame (void (*popper) (struct frame_info * frame))
+{
+  struct frame_info *frame = get_current_frame ();
+
+  if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+    generic_pop_dummy_frame ();
+  else
+    (*popper) (frame);
+}
+
+/* Function: pop_dummy_frame
+   Restore the machine state from a saved dummy stack frame. */
+
+void
+generic_pop_dummy_frame (void)
+{
+  struct dummy_frame *dummy_frame = dummy_frame_stack;
+
+  /* FIXME: what if the first frame isn't the right one, eg..
+     because one call-by-hand function has done a longjmp into another one? */
+
+  if (!dummy_frame)
+    error ("Can't pop dummy frame!");
+  dummy_frame_stack = dummy_frame->next;
+  regcache_cpy (current_regcache, dummy_frame->regcache);
+  flush_cached_frames ();
+
+  regcache_xfree (dummy_frame->regcache);
+  xfree (dummy_frame);
+}
+
+/* Function: fix_call_dummy
+   Stub function.  Generic dummy frames typically do not need to fix
+   the frame being created */
+
+void
+generic_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+                       struct value **args, struct type *type, int gcc_p)
+{
+  return;
+}
+
+/* Given a call-dummy dummy-frame, return the registers.  Here the
+   register value is taken from the local copy of the register buffer.  */
+
+void
+generic_call_dummy_register_unwind (struct frame_info *frame, void **cache,
+                                   int regnum, int *optimized,
+                                   enum lval_type *lvalp, CORE_ADDR *addrp,
+                                   int *realnum, void *bufferp)
+{
+  gdb_assert (frame != NULL);
+  gdb_assert (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame));
+
+  /* Describe the register's location.  Generic dummy frames always
+     have the register value in an ``expression''.  */
+  *optimized = 0;
+  *lvalp = not_lval;
+  *addrp = 0;
+  *realnum = -1;
+
+  /* If needed, find and return the value of the register.  */
+  if (bufferp != NULL)
+    {
+      struct regcache *registers;
+#if 1
+      /* Get the address of the register buffer that contains all the
+        saved registers for this dummy frame.  Cache that address.  */
+      registers = (*cache);
+      if (registers == NULL)
+       {
+         registers = generic_find_dummy_frame (frame->pc, frame->frame);
+         (*cache) = registers;
+       }
+#else
+      /* Get the address of the register buffer that contains the
+         saved registers and then extract the value from that.  */
+      registers = generic_find_dummy_frame (frame->pc, frame->frame);
+#endif
+      gdb_assert (registers != 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 (registers, regnum, bufferp);
+    }
+}
+
diff --git a/gdb/dummy-frame.h b/gdb/dummy-frame.h
new file mode 100644 (file)
index 0000000..6bdebee
--- /dev/null
@@ -0,0 +1,66 @@
+/* Code dealing with dummy stack frames, for GDB, the GNU debugger.
+
+   Copyright 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.  */
+
+#if !defined (DUMMY_FRAME_H)
+#define DUMMY_FRAME_H 1
+
+struct frame_info;
+struct regcache;
+
+/* GENERIC DUMMY FRAMES
+  
+   The following code serves to maintain the dummy stack frames for
+   inferior function calls (ie. when gdb calls into the inferior via
+   call_function_by_hand).  This code saves the machine state before
+   the call in host memory, so we must maintain an independent stack
+   and keep it consistant etc.  I am attempting to make this code
+   generic enough to be used by many targets.
+   The cheapest and most generic way to do CALL_DUMMY on a new target
+   is probably to define CALL_DUMMY to be empty, CALL_DUMMY_LENGTH to
+   zero, and CALL_DUMMY_LOCATION to AT_ENTRY.  Then you must remember
+   to define PUSH_RETURN_ADDRESS, because no call instruction will be
+   being executed by the target.  Also FRAME_CHAIN_VALID as
+   generic_{file,func}_frame_chain_valid and FIX_CALL_DUMMY as
+   generic_fix_call_dummy.  */
+
+/* Assuming that FRAME is a dummy, return a register value for the
+   previous frame.  */
+
+extern void generic_call_dummy_register_unwind (struct frame_info *frame,
+                                               void **unwind_cache,
+                                               int regnum,
+                                               int *optimized,
+                                               enum lval_type *lvalp,
+                                               CORE_ADDR *addrp,
+                                               int *realnump,
+                                               void *valuep);
+
+/* Return the regcache that belongs to the dummy-frame identifed by PC
+   and FP, or NULL if no such frame exists.  */
+/* FIXME: cagney/2002-11-08: The function only exists because of
+   deprecated_generic_get_saved_register.  Eliminate that function and
+   this, to, can go.  */
+
+extern struct regcache *generic_find_dummy_frame (CORE_ADDR pc,
+                                                 CORE_ADDR fp);
+
+#endif /* !defined (DUMMY_FRAME_H)  */