aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2002-11-08 19:42:00 +0000
committerAndrew Cagney <cagney@redhat.com>2002-11-08 19:42:00 +0000
commit9c1412c1a1a5e1fe7ffadb8a2e4cefe8bf7c4e9f (patch)
treeacbd8bc9c24d451908ffb00d46bda885793ffb8e
parent208d818701644f3d9582d264412485793e627492 (diff)
downloadgdb-9c1412c1a1a5e1fe7ffadb8a2e4cefe8bf7c4e9f.zip
gdb-9c1412c1a1a5e1fe7ffadb8a2e4cefe8bf7c4e9f.tar.gz
gdb-9c1412c1a1a5e1fe7ffadb8a2e4cefe8bf7c4e9f.tar.bz2
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.
-rw-r--r--gdb/ChangeLog21
-rw-r--r--gdb/Makefile.in11
-rw-r--r--gdb/blockframe.c304
-rw-r--r--gdb/dummy-frame.c308
-rw-r--r--gdb/dummy-frame.h66
5 files changed, 404 insertions, 306 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 166ac5b..7985ef7 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index afcca56..696bfef 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -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) \
diff --git a/gdb/blockframe.c b/gdb/blockframe.c
index 2b789e6..c34d3e0 100644
--- a/gdb/blockframe.c
+++ b/gdb/blockframe.c
@@ -35,17 +35,10 @@
#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
index 0000000..1a2a315
--- /dev/null
+++ b/gdb/dummy-frame.c
@@ -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
index 0000000..6bdebee
--- /dev/null
+++ b/gdb/dummy-frame.h
@@ -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) */