summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2003-01-13 17:03:53 +0000
committerAndrew Cagney <cagney@redhat.com>2003-01-13 17:03:53 +0000
commit545659b712fc1d3bae86186677cf30ae9680b29b (patch)
tree5ed48b4e7c07f62ccde3b9cefc8eeea6ef8fe622
parent6647c6d4dab0727e593439e7e5fe182ddd40ee10 (diff)
downloadgdb-545659b712fc1d3bae86186677cf30ae9680b29b.tar.gz
2003-01-13 Andrew Cagney <ac131313@redhat.com>
* d10v-tdep.c: Include "d10v-tdep.h". Update to use D10V_ prefixed enums. (do_d10v_pop_frame): Delete. Use version in d10v-frame.c. * frame.c (frame_read_unsigned_register): Do not use get_next_frame. (frame_read_signed_register): Do not use get_next_frame. (get_frame_base): Use frame_id_unwind. * d10v-tdep.h: New file. * d10v-frame.h: New file. * d10v-frame.c: New file. * frame.c (frame_id_unwind): Update. (create_sentinel_frame): Update. (legacy_get_prev_frame): Use frame_unwind_find_by_pc. (get_prev_frame): Ditto. * frame.h (struct frame_info): Replace pc_unwind, id_unwind and register_unwind with unwind structure. * frame.c (set_unwind_by_pc): Delete function. (create_new_frame): Use frame_unwind_find_by_pc; * Makefile.in (frame_h): Add $(frame_unwind_h). * frame.h: Include "frame-unwind.h". (frame_register_unwind_ftype): Delete. (frame_id_unwind_ftype): Delete. (frame_pc_unwind_ftype): Delete. * Makefile.in (dummy-frame.o): Update dependencies. (legacy-frame.o): Update dependencies. * dummy-frame.c: Include "frame-unwind.h". (dummy_frame_unwind): New static variable. (dummy_frame_p): New function. * legacy-frame.c: Include "frame-unwind.h". (legacy_frame_unwind): New static variable. (legacy_frame_p): New function. * legacy-frame.h (legacy_frame_p): Declare. * dummy-frame.h (dummy_frame_p): Declare. * Makefile.in (frame_unwind_h): Define. * frame-unwind.h: New file. * frame-unwind.c: New file.
-rw-r--r--gdb/ChangeLog48
-rw-r--r--gdb/Makefile.in17
-rw-r--r--gdb/d10v-frame.c392
-rw-r--r--gdb/d10v-frame.h28
-rw-r--r--gdb/d10v-tdep.c222
-rw-r--r--gdb/d10v-tdep.h62
-rw-r--r--gdb/dummy-frame.c19
-rw-r--r--gdb/dummy-frame.h7
-rw-r--r--gdb/frame-unwind.c102
-rw-r--r--gdb/frame-unwind.h92
-rw-r--r--gdb/frame.c66
-rw-r--r--gdb/frame.h50
-rw-r--r--gdb/legacy-frame.c16
-rw-r--r--gdb/legacy-frame.h5
-rw-r--r--gdb/sentinel-frame.c107
-rw-r--r--gdb/sentinel-frame.h65
16 files changed, 1052 insertions, 246 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7e4be3e9162..1ab571050f7 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,51 @@
+2003-01-13 Andrew Cagney <ac131313@redhat.com>
+
+ * d10v-tdep.c: Include "d10v-tdep.h". Update to use D10V_
+ prefixed enums.
+ (do_d10v_pop_frame): Delete. Use version in d10v-frame.c.
+
+ * frame.c (frame_read_unsigned_register): Do not use
+ get_next_frame.
+ (frame_read_signed_register): Do not use get_next_frame.
+ (get_frame_base): Use frame_id_unwind.
+
+ * d10v-tdep.h: New file.
+ * d10v-frame.h: New file.
+ * d10v-frame.c: New file.
+
+ * frame.c (frame_id_unwind): Update.
+ (create_sentinel_frame): Update.
+ (legacy_get_prev_frame): Use frame_unwind_find_by_pc.
+ (get_prev_frame): Ditto.
+
+ * frame.h (struct frame_info): Replace pc_unwind, id_unwind and
+ register_unwind with unwind structure.
+
+ * frame.c (set_unwind_by_pc): Delete function.
+ (create_new_frame): Use frame_unwind_find_by_pc;
+
+ * Makefile.in (frame_h): Add $(frame_unwind_h).
+ * frame.h: Include "frame-unwind.h".
+ (frame_register_unwind_ftype): Delete.
+ (frame_id_unwind_ftype): Delete.
+ (frame_pc_unwind_ftype): Delete.
+
+ * Makefile.in (dummy-frame.o): Update dependencies.
+ (legacy-frame.o): Update dependencies.
+
+ * dummy-frame.c: Include "frame-unwind.h".
+ (dummy_frame_unwind): New static variable.
+ (dummy_frame_p): New function.
+ * legacy-frame.c: Include "frame-unwind.h".
+ (legacy_frame_unwind): New static variable.
+ (legacy_frame_p): New function.
+ * legacy-frame.h (legacy_frame_p): Declare.
+ * dummy-frame.h (dummy_frame_p): Declare.
+
+ * Makefile.in (frame_unwind_h): Define.
+ * frame-unwind.h: New file.
+ * frame-unwind.c: New file.
+
2003-01-12 Andrew Cagney <ac131313@redhat.com>
* d10v-tdep.c (d10v_init_extra_frame_info): Remove checks for a
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 7fb480f8ed6..4f130510c35 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -500,6 +500,7 @@ TARGET_FLAGS_TO_PASS = \
SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
ax-general.c ax-gdb.c \
bcache.c blockframe.c breakpoint.c buildsym.c builtin-regs.c \
+ d10v-frame.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 \
@@ -507,6 +508,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.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 \
+ frame-unwind.c \
gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
hpacc-abi.c \
inf-loop.c infcmd.c inflow.c infrun.c \
@@ -619,7 +621,8 @@ event_loop_h = event-loop.h
event_top_h = event-top.h
expression_h = expression.h $(symtab_h) $(doublest_h)
f_lang_h = f-lang.h
-frame_h = frame.h
+frame_h = frame.h $(frame_unwind_h)
+frame_unwind_h = frame-unwind.h
gdb_events_h = gdb-events.h
gdb_stabs_h = gdb-stabs.h
gdb_h = gdb.h
@@ -807,7 +810,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 dummy-frame.o \
+ charset.o disasm.o dummy-frame.o d10v-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 \
@@ -832,7 +835,7 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \
c-valprint.o cp-valprint.o f-valprint.o m2-valprint.o \
nlmread.o serial.o mdebugread.o top.o utils.o \
ui-file.o \
- frame.o doublest.o \
+ frame.o doublest.o frame-unwind.o \
gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o \
sentinel-frame.o \
reggroups.o legacy-frame.o
@@ -1605,6 +1608,7 @@ cris-tdep.o: cris-tdep.c $(defs_h) $(frame_h) $(symtab_h) $(inferior_h) \
$(gdbtypes_h) $(gdbcore_h) $(gdbcmd_h) $(target_h) $(value_h) \
$(opcode_cris_h) $(arch_utils_h) $(regcache_h) $(symfile_h) \
$(solib_h) $(solib_svr4_h) $(gdb_string_h)
+d10v-frame.o: d10v-frame.c $(defs_h) $(frame_unwind_h)
d10v-tdep.o: d10v-tdep.c $(defs_h) $(frame_h) $(symtab_h) $(gdbtypes_h) \
$(gdbcmd_h) $(gdbcore_h) $(gdb_string_h) $(value_h) $(inferior_h) \
$(dis_asm_h) $(symfile_h) $(objfiles_h) $(language_h) \
@@ -1631,7 +1635,7 @@ 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)
dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \
- $(frame_h) $(inferior_h) $(gdb_assert_h)
+ $(frame_h) $(inferior_h) $(gdb_assert_h) $(frame_unwind_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) \
@@ -1685,6 +1689,8 @@ frame.o: frame.c $(defs_h) $(frame_h) $(target_h) $(value_h) $(inferior_h) \
$(gdb_obstack_h) $(dummy_frame_h) $(sentinel_frame_h) \
$(legacy_frame_h) $(gdbcore_h) $(annotate_h) $(language_h) \
$(ui_out_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) \
$(arch_utils_h) $(regcache_h)
gcore.o: gcore.c $(defs_h) $(cli_decode_h) $(inferior_h) $(gdbcore_h) \
@@ -1835,7 +1841,8 @@ language.o: language.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
lin-lwp.o: lin-lwp.c $(defs_h) $(gdb_assert_h) $(gdb_string_h) $(gdb_wait_h) \
$(gdbthread_h) $(inferior_h) $(target_h) $(regcache_h) $(gdbcmd_h)
legacy-frame.o: legacy-frame.c $(defs_h) $(legacy_frame_h) $(gdb_assert_h) \
- $(frame_h) $(gdbcore_h) $(regcache_h) $(target_h) $(dummy_frame_h)
+ $(frame_h) $(gdbcore_h) $(regcache_h) $(target_h) $(dummy_frame_h) \
+ $(frame_unwind_h)
linespec.o: linespec.c $(defs_h) $(symtab_h) $(frame_h) $(command_h) \
$(symfile_h) $(objfiles_h) $(demangle_h) $(value_h) $(completer_h) \
$(cp_abi_h) $(source_h) $(parser_defs_h)
diff --git a/gdb/d10v-frame.c b/gdb/d10v-frame.c
new file mode 100644
index 00000000000..5b29545c535
--- /dev/null
+++ b/gdb/d10v-frame.c
@@ -0,0 +1,392 @@
+/* Frame unwinder for Mitsubishi D10V, for GDB, the GNU Debugger.
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "d10v-tdep.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "target.h"
+#include "gdb_assert.h"
+
+struct frame_unwind_cache
+{
+ CORE_ADDR return_pc;
+ int frameless;
+ int size;
+ CORE_ADDR *saved_regs;
+ CORE_ADDR next_addr;
+ int uses_frame;
+ void **regs;
+};
+
+
+static int
+prologue_find_regs (unsigned short op, struct frame_unwind_cache *info,
+ CORE_ADDR addr)
+{
+ int n;
+
+ /* st rn, @-sp */
+ if ((op & 0x7E1F) == 0x6C1F)
+ {
+ n = (op & 0x1E0) >> 5;
+ info->next_addr -= 2;
+ info->saved_regs[n] = info->next_addr;
+ return 1;
+ }
+
+ /* st2w rn, @-sp */
+ else if ((op & 0x7E3F) == 0x6E1F)
+ {
+ n = (op & 0x1E0) >> 5;
+ info->next_addr -= 4;
+ info->saved_regs[n] = info->next_addr;
+ info->saved_regs[n + 1] = info->next_addr + 2;
+ return 1;
+ }
+
+ /* subi sp, n */
+ if ((op & 0x7FE1) == 0x01E1)
+ {
+ n = (op & 0x1E) >> 1;
+ if (n == 0)
+ n = 16;
+ info->next_addr -= n;
+ return 1;
+ }
+
+ /* mv r11, sp */
+ if (op == 0x417E)
+ {
+ info->uses_frame = 1;
+ return 1;
+ }
+
+ /* nop */
+ if (op == 0x5E00)
+ return 1;
+
+ /* st rn, @sp */
+ if ((op & 0x7E1F) == 0x681E)
+ {
+ n = (op & 0x1E0) >> 5;
+ info->saved_regs[n] = info->next_addr;
+ return 1;
+ }
+
+ /* st2w rn, @sp */
+ if ((op & 0x7E3F) == 0x3A1E)
+ {
+ n = (op & 0x1E0) >> 5;
+ info->saved_regs[n] = info->next_addr;
+ info->saved_regs[n + 1] = info->next_addr + 2;
+ return 1;
+ }
+
+ return 0;
+}
+
+struct frame_unwind_cache *
+d10v_frame_unwind_cache (struct frame_info *fi,
+ struct frame_unwind_cache **cache)
+{
+ CORE_ADDR fp, pc;
+ unsigned long op;
+ unsigned short op1, op2;
+ int i;
+ struct frame_unwind_cache *info;
+
+ if ((*cache))
+ return (*cache);
+
+ info = FRAME_OBSTACK_ZALLOC (struct frame_unwind_cache);
+ (*cache) = info;
+ info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
+
+ info->frameless = 0;
+ info->size = 0;
+ info->return_pc = 0;
+
+ fp = get_frame_base (fi);
+ info->next_addr = 0;
+
+ pc = get_pc_function_start (get_frame_pc (fi));
+
+ info->uses_frame = 0;
+ while (1)
+ {
+ op = (unsigned long) read_memory_integer (pc, 4);
+ if ((op & 0xC0000000) == 0xC0000000)
+ {
+ /* long instruction */
+ if ((op & 0x3FFF0000) == 0x01FF0000)
+ {
+ /* add3 sp,sp,n */
+ short n = op & 0xFFFF;
+ info->next_addr += n;
+ }
+ else if ((op & 0x3F0F0000) == 0x340F0000)
+ {
+ /* st rn, @(offset,sp) */
+ short offset = op & 0xFFFF;
+ short n = (op >> 20) & 0xF;
+ info->saved_regs[n] = info->next_addr + offset;
+ }
+ else if ((op & 0x3F1F0000) == 0x350F0000)
+ {
+ /* st2w rn, @(offset,sp) */
+ short offset = op & 0xFFFF;
+ short n = (op >> 20) & 0xF;
+ info->saved_regs[n] = info->next_addr + offset;
+ info->saved_regs[n + 1] = info->next_addr + offset + 2;
+ }
+ else
+ break;
+ }
+ else
+ {
+ /* short instructions */
+ if ((op & 0xC0000000) == 0x80000000)
+ {
+ op2 = (op & 0x3FFF8000) >> 15;
+ op1 = op & 0x7FFF;
+ }
+ else
+ {
+ op1 = (op & 0x3FFF8000) >> 15;
+ op2 = op & 0x7FFF;
+ }
+ if (!prologue_find_regs (op1, (*cache), pc)
+ || !prologue_find_regs (op2, (*cache), pc))
+ break;
+ }
+ pc += 4;
+ }
+
+ info->size = -info->next_addr;
+
+ if (!(fp & 0xffff))
+ fp = d10v_read_sp ();
+
+ for (i = 0; i < NUM_REGS - 1; i++)
+ if (info->saved_regs[i])
+ {
+ info->saved_regs[i] = fp - (info->next_addr - info->saved_regs[i]);
+ }
+
+ if (info->saved_regs[D10V_LR_REGNUM])
+ {
+ CORE_ADDR return_pc
+ = read_memory_unsigned_integer (info->saved_regs[D10V_LR_REGNUM],
+ REGISTER_RAW_SIZE (D10V_LR_REGNUM));
+ info->return_pc = d10v_make_iaddr (return_pc);
+ }
+ else
+ {
+ ULONGEST return_pc;
+ frame_read_unsigned_register (fi, D10V_LR_REGNUM, &return_pc);
+ info->return_pc = d10v_make_iaddr (return_pc);
+ }
+
+ /* The SP is not normally (ever?) saved, but check anyway */
+ if (!info->saved_regs[D10V_SP_REGNUM])
+ {
+ /* if the FP was saved, that means the current FP is valid, */
+ /* otherwise, it isn't being used, so we use the SP instead */
+ if (info->uses_frame)
+ info->saved_regs[D10V_SP_REGNUM]
+ = d10v_read_fp () + info->size;
+ else
+ {
+ info->saved_regs[SP_REGNUM] = fp + info->size;
+ info->frameless = 1;
+ info->saved_regs[FP_REGNUM] = 0;
+ }
+ }
+
+ return info;
+}
+
+static CORE_ADDR
+d10v_frame_pc_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **cache)
+{
+ struct frame_unwind_cache *info = d10v_frame_unwind_cache (frame, cache);
+ return info->return_pc;
+}
+
+static void
+d10v_frame_id_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **cache,
+ struct frame_id *id)
+{
+ struct frame_unwind_cache *info = d10v_frame_unwind_cache (frame, cache);
+ CORE_ADDR addr;
+
+ /* Start with a NULL frame ID. */
+ (*id) = null_frame_id;
+
+ if (info->return_pc == D10V_IMEM_START
+ || inside_entry_file (info->return_pc))
+ {
+ /* This is meant to halt the backtrace at "_start".
+ Make sure we don't halt it at a generic dummy frame. */
+ return;
+ }
+
+ if (!info->saved_regs[FP_REGNUM])
+ {
+ if (!info->saved_regs[SP_REGNUM]
+ || info->saved_regs[SP_REGNUM] == D10V_STACK_START)
+ return;
+
+ id->base = info->saved_regs[SP_REGNUM];
+ id->pc = info->return_pc;
+ }
+
+ addr = read_memory_unsigned_integer (info->saved_regs[FP_REGNUM],
+ REGISTER_RAW_SIZE (FP_REGNUM));
+ if (addr == 0)
+ return;
+
+ id->base = d10v_make_daddr (addr);
+ id->pc = info->return_pc;
+}
+
+static void
+saved_regs_unwinder (struct frame_info *frame,
+ CORE_ADDR *saved_regs,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ /* If we're using generic dummy frames, we'd better not be in a call
+ dummy. (generic_call_dummy_register_unwind ought to have been called
+ instead.) */
+ gdb_assert (!(DEPRECATED_USE_GENERIC_DUMMY_FRAMES
+ && (get_frame_type (frame) == DUMMY_FRAME)));
+
+ if (saved_regs[regnum] != 0)
+ {
+ if (regnum == SP_REGNUM)
+ {
+ /* SP register treated specially. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (bufferp != NULL)
+ store_address (bufferp, REGISTER_RAW_SIZE (regnum),
+ saved_regs[regnum]);
+ }
+ else
+ {
+ /* Any other register is saved in memory, fetch it but cache
+ a local copy of its value. */
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = saved_regs[regnum];
+ *realnump = -1;
+ if (bufferp != NULL)
+ {
+ /* Read the value in from memory. */
+ read_memory (get_frame_saved_regs (frame)[regnum], bufferp,
+ REGISTER_RAW_SIZE (regnum));
+ }
+ }
+ return;
+ }
+
+ /* No luck, assume this and the next frame have the same register
+ value. If a value is needed, pass the request on down the chain;
+ otherwise just return an indication that the value is in the same
+ register as the next frame. */
+ frame_register (frame, regnum, optimizedp, lvalp, addrp,
+ realnump, bufferp);
+}
+
+
+static void
+d10v_frame_register_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ struct frame_unwind_cache *info = d10v_frame_unwind_cache (frame, cache);
+ saved_regs_unwinder (frame, info->saved_regs, regnum, optimizedp,
+ lvalp, addrp, realnump, bufferp);
+}
+
+
+void
+do_d10v_pop_frame (struct frame_info *fi)
+{
+ struct frame_unwind_cache *info =
+ d10v_frame_unwind_cache (fi, &fi->unwind_cache);
+ CORE_ADDR fp;
+ int regnum;
+ char raw_buffer[8];
+
+ fp = get_frame_base (fi);
+
+ /* now update the current registers with the old values */
+ for (regnum = d10v_a0_regnum (current_gdbarch); regnum < d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS; regnum++)
+ {
+ if (info->saved_regs[regnum])
+ {
+ read_memory (info->saved_regs[regnum], raw_buffer, REGISTER_RAW_SIZE (regnum));
+ deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer,
+ REGISTER_RAW_SIZE (regnum));
+ }
+ }
+ for (regnum = 0; regnum < D10V_SP_REGNUM; regnum++)
+ {
+ if (info->saved_regs[regnum])
+ {
+ write_register (regnum, read_memory_unsigned_integer (info->saved_regs[regnum], REGISTER_RAW_SIZE (regnum)));
+ }
+ }
+ if (info->saved_regs[D10V_PSW_REGNUM])
+ {
+ write_register (D10V_PSW_REGNUM, read_memory_unsigned_integer (info->saved_regs[D10V_PSW_REGNUM], REGISTER_RAW_SIZE (D10V_PSW_REGNUM)));
+ }
+
+ write_register (D10V_PC_REGNUM, read_register (D10V_LR_REGNUM));
+ write_register (D10V_SP_REGNUM, fp + info->size);
+ target_store_registers (-1);
+ flush_cached_frames ();
+}
+
+static struct frame_unwind d10v_frame_unwind = {
+ d10v_frame_pc_unwind,
+ d10v_frame_id_unwind,
+ d10v_frame_register_unwind
+};
+
+const struct frame_unwind *
+d10v_frame_p (CORE_ADDR pc)
+{
+ return &d10v_frame_unwind;
+}
diff --git a/gdb/d10v-frame.h b/gdb/d10v-frame.h
new file mode 100644
index 00000000000..c05c4fba71d
--- /dev/null
+++ b/gdb/d10v-frame.h
@@ -0,0 +1,28 @@
+/* Definitions for a d10v frame unwinder, 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 (D10V_FRAME_H)
+#define D10V_UNWIND_H 1
+
+struct frame_unwind;
+extern const struct frame_unwind *d10v_frame_p (CORE_ADDR pc);
+
+#endif
diff --git a/gdb/d10v-tdep.c b/gdb/d10v-tdep.c
index 63efe4c1540..e6152e41b46 100644
--- a/gdb/d10v-tdep.c
+++ b/gdb/d10v-tdep.c
@@ -38,10 +38,14 @@
#include "arch-utils.h"
#include "regcache.h"
+#include "d10v-tdep.h"
#include "floatformat.h"
#include "gdb/sim-d10v.h"
#include "sim-regno.h"
+#include "frame-unwind.h"
+#include "d10v-frame.h"
+
#include "gdb_assert.h"
struct frame_extra_info
@@ -59,47 +63,18 @@ struct gdbarch_tdep
unsigned long (*imap_register) (int nr);
};
-/* These are the addresses the D10V-EVA board maps data and
- instruction memory to. */
-
-enum memspace {
- DMEM_START = 0x2000000,
- IMEM_START = 0x1000000,
- STACK_START = 0x200bffe
-};
-
-/* d10v register names. */
-
-enum
- {
- R0_REGNUM = 0,
- R3_REGNUM = 3,
- _FP_REGNUM = 11,
- LR_REGNUM = 13,
- _SP_REGNUM = 15,
- PSW_REGNUM = 16,
- _PC_REGNUM = 18,
- NR_IMAP_REGS = 2,
- NR_A_REGS = 2,
- TS2_NUM_REGS = 37,
- TS3_NUM_REGS = 42,
- /* d10v calling convention. */
- ARG1_REGNUM = R0_REGNUM,
- ARGN_REGNUM = R3_REGNUM,
- RET1_REGNUM = R0_REGNUM,
- };
-
#define NR_DMAP_REGS (gdbarch_tdep (current_gdbarch)->nr_dmap_regs)
-#define A0_REGNUM (gdbarch_tdep (current_gdbarch)->a0_regnum)
+
+int
+d10v_a0_regnum (struct gdbarch *gdbarch)
+{
+ return (gdbarch_tdep (current_gdbarch)->a0_regnum);
+}
/* Local functions */
extern void _initialize_d10v_tdep (void);
-static CORE_ADDR d10v_read_sp (void);
-
-static CORE_ADDR d10v_read_fp (void);
-
static void d10v_eva_prepare_to_trace (void);
static void d10v_eva_get_trace_data (void);
@@ -109,12 +84,12 @@ static int prologue_find_regs (unsigned short op, struct frame_info *fi,
static void d10v_frame_init_saved_regs (struct frame_info *);
-static void do_d10v_pop_frame (struct frame_info *fi);
+void do_d10v_pop_frame (struct frame_info *fi);
static int
d10v_frame_chain_valid (CORE_ADDR chain, struct frame_info *frame)
{
- return (get_frame_pc (frame) > IMEM_START);
+ return (get_frame_pc (frame) > D10V_IMEM_START);
}
static CORE_ADDR
@@ -298,12 +273,12 @@ d10v_ts2_register_sim_regno (int nr)
if (legacy_register_sim_regno (nr) < 0)
return legacy_register_sim_regno (nr);
if (nr >= TS2_IMAP0_REGNUM
- && nr < TS2_IMAP0_REGNUM + NR_IMAP_REGS)
+ && nr < TS2_IMAP0_REGNUM + D10V_NR_IMAP_REGS)
return nr - TS2_IMAP0_REGNUM + SIM_D10V_IMAP0_REGNUM;
if (nr == TS2_DMAP_REGNUM)
return nr - TS2_DMAP_REGNUM + SIM_D10V_TS2_DMAP_REGNUM;
if (nr >= TS2_A0_REGNUM
- && nr < TS2_A0_REGNUM + NR_A_REGS)
+ && nr < TS2_A0_REGNUM + D10V_NR_A_REGS)
return nr - TS2_A0_REGNUM + SIM_D10V_A0_REGNUM;
return nr;
}
@@ -314,13 +289,13 @@ d10v_ts3_register_sim_regno (int nr)
if (legacy_register_sim_regno (nr) < 0)
return legacy_register_sim_regno (nr);
if (nr >= TS3_IMAP0_REGNUM
- && nr < TS3_IMAP0_REGNUM + NR_IMAP_REGS)
+ && nr < TS3_IMAP0_REGNUM + D10V_NR_IMAP_REGS)
return nr - TS3_IMAP0_REGNUM + SIM_D10V_IMAP0_REGNUM;
if (nr >= TS3_DMAP0_REGNUM
&& nr < TS3_DMAP0_REGNUM + TS3_NR_DMAP_REGS)
return nr - TS3_DMAP0_REGNUM + SIM_D10V_DMAP0_REGNUM;
if (nr >= TS3_A0_REGNUM
- && nr < TS3_A0_REGNUM + NR_A_REGS)
+ && nr < TS3_A0_REGNUM + D10V_NR_A_REGS)
return nr - TS3_A0_REGNUM + SIM_D10V_A0_REGNUM;
return nr;
}
@@ -331,15 +306,15 @@ d10v_ts3_register_sim_regno (int nr)
static int
d10v_register_byte (int reg_nr)
{
- if (reg_nr < A0_REGNUM)
+ if (reg_nr < d10v_a0_regnum (current_gdbarch))
return (reg_nr * 2);
- else if (reg_nr < (A0_REGNUM + NR_A_REGS))
- return (A0_REGNUM * 2
- + (reg_nr - A0_REGNUM) * 8);
+ else if (reg_nr < (d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS))
+ return (d10v_a0_regnum (current_gdbarch) * 2
+ + (reg_nr - d10v_a0_regnum (current_gdbarch)) * 8);
else
- return (A0_REGNUM * 2
- + NR_A_REGS * 8
- + (reg_nr - A0_REGNUM - NR_A_REGS) * 2);
+ return (d10v_a0_regnum (current_gdbarch) * 2
+ + D10V_NR_A_REGS * 8
+ + (reg_nr - d10v_a0_regnum (current_gdbarch) - D10V_NR_A_REGS) * 2);
}
/* Number of bytes of storage in the actual machine representation for
@@ -348,9 +323,9 @@ d10v_register_byte (int reg_nr)
static int
d10v_register_raw_size (int reg_nr)
{
- if (reg_nr < A0_REGNUM)
+ if (reg_nr < d10v_a0_regnum (current_gdbarch))
return 2;
- else if (reg_nr < (A0_REGNUM + NR_A_REGS))
+ else if (reg_nr < (d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS))
return 8;
else
return 2;
@@ -362,12 +337,12 @@ d10v_register_raw_size (int reg_nr)
static struct type *
d10v_register_virtual_type (int reg_nr)
{
- if (reg_nr == PC_REGNUM)
+ if (reg_nr == D10V_PC_REGNUM)
return builtin_type_void_func_ptr;
- if (reg_nr == _SP_REGNUM || reg_nr == _FP_REGNUM)
+ if (reg_nr == D10V_SP_REGNUM || reg_nr == D10V_FP_REGNUM)
return builtin_type_void_data_ptr;
- else if (reg_nr >= A0_REGNUM
- && reg_nr < (A0_REGNUM + NR_A_REGS))
+ else if (reg_nr >= d10v_a0_regnum (current_gdbarch)
+ && reg_nr < (d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS))
return builtin_type_int64;
else
return builtin_type_int16;
@@ -376,28 +351,28 @@ d10v_register_virtual_type (int reg_nr)
static int
d10v_daddr_p (CORE_ADDR x)
{
- return (((x) & 0x3000000) == DMEM_START);
+ return (((x) & 0x3000000) == D10V_DMEM_START);
}
static int
d10v_iaddr_p (CORE_ADDR x)
{
- return (((x) & 0x3000000) == IMEM_START);
+ return (((x) & 0x3000000) == D10V_IMEM_START);
}
-static CORE_ADDR
+CORE_ADDR
d10v_make_daddr (CORE_ADDR x)
{
- return ((x) | DMEM_START);
+ return ((x) | D10V_DMEM_START);
}
-static CORE_ADDR
+CORE_ADDR
d10v_make_iaddr (CORE_ADDR x)
{
if (d10v_iaddr_p (x))
return x; /* Idempotency -- x is already in the IMEM space. */
else
- return (((x) << 2) | IMEM_START);
+ return (((x) << 2) | D10V_IMEM_START);
}
static CORE_ADDR
@@ -465,7 +440,7 @@ d10v_integer_to_address (struct type *type, void *buf)
static void
d10v_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
{
- write_register (ARG1_REGNUM, (addr));
+ write_register (D10V_ARG1_REGNUM, (addr));
}
/* Write into appropriate registers a function return value
@@ -531,8 +506,8 @@ d10v_frame_saved_pc (struct frame_info *frame)
static CORE_ADDR
d10v_saved_pc_after_call (struct frame_info *frame)
{
- return ((read_register (LR_REGNUM) << 2)
- | IMEM_START);
+ return ((read_register (D10V_LR_REGNUM) << 2)
+ | D10V_IMEM_START);
}
/* Discard from the stack the innermost frame, restoring all saved
@@ -544,46 +519,6 @@ d10v_pop_frame (void)
generic_pop_current_frame (do_d10v_pop_frame);
}
-static void
-do_d10v_pop_frame (struct frame_info *fi)
-{
- CORE_ADDR fp;
- int regnum;
- char raw_buffer[8];
-
- fp = get_frame_base (fi);
- /* fill out fsr with the address of where each */
- /* register was stored in the frame */
- d10v_frame_init_saved_regs (fi);
-
- /* now update the current registers with the old values */
- for (regnum = A0_REGNUM; regnum < A0_REGNUM + NR_A_REGS; regnum++)
- {
- if (get_frame_saved_regs (fi)[regnum])
- {
- read_memory (get_frame_saved_regs (fi)[regnum], raw_buffer, REGISTER_RAW_SIZE (regnum));
- deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer,
- REGISTER_RAW_SIZE (regnum));
- }
- }
- for (regnum = 0; regnum < SP_REGNUM; regnum++)
- {
- if (get_frame_saved_regs (fi)[regnum])
- {
- write_register (regnum, read_memory_unsigned_integer (get_frame_saved_regs (fi)[regnum], REGISTER_RAW_SIZE (regnum)));
- }
- }
- if (get_frame_saved_regs (fi)[PSW_REGNUM])
- {
- write_register (PSW_REGNUM, read_memory_unsigned_integer (get_frame_saved_regs (fi)[PSW_REGNUM], REGISTER_RAW_SIZE (PSW_REGNUM)));
- }
-
- write_register (PC_REGNUM, read_register (LR_REGNUM));
- write_register (SP_REGNUM, fp + get_frame_extra_info (fi)->size);
- target_store_registers (-1);
- flush_cached_frames ();
-}
-
static int
check_prologue (unsigned short op)
{
@@ -695,7 +630,7 @@ d10v_frame_chain (struct frame_info *fi)
d10v_frame_init_saved_regs (fi);
- if (get_frame_extra_info (fi)->return_pc == IMEM_START
+ if (get_frame_extra_info (fi)->return_pc == D10V_IMEM_START
|| inside_entry_file (get_frame_extra_info (fi)->return_pc))
{
/* This is meant to halt the backtrace at "_start".
@@ -703,17 +638,17 @@ d10v_frame_chain (struct frame_info *fi)
return (CORE_ADDR) 0;
}
- if (!get_frame_saved_regs (fi)[FP_REGNUM])
+ if (!get_frame_saved_regs (fi)[D10V_FP_REGNUM])
{
- if (!get_frame_saved_regs (fi)[SP_REGNUM]
- || get_frame_saved_regs (fi)[SP_REGNUM] == STACK_START)
+ if (!get_frame_saved_regs (fi)[D10V_SP_REGNUM]
+ || get_frame_saved_regs (fi)[D10V_SP_REGNUM] == D10V_STACK_START)
return (CORE_ADDR) 0;
- return get_frame_saved_regs (fi)[SP_REGNUM];
+ return get_frame_saved_regs (fi)[D10V_SP_REGNUM];
}
- addr = read_memory_unsigned_integer (get_frame_saved_regs (fi)[FP_REGNUM],
- REGISTER_RAW_SIZE (FP_REGNUM));
+ addr = read_memory_unsigned_integer (get_frame_saved_regs (fi)[D10V_FP_REGNUM],
+ REGISTER_RAW_SIZE (D10V_FP_REGNUM));
if (addr == 0)
return (CORE_ADDR) 0;
@@ -869,31 +804,31 @@ d10v_frame_init_saved_regs (struct frame_info *fi)
get_frame_saved_regs (fi)[i] = fp - (next_addr - get_frame_saved_regs (fi)[i]);
}
- if (get_frame_saved_regs (fi)[LR_REGNUM])
+ if (get_frame_saved_regs (fi)[D10V_LR_REGNUM])
{
CORE_ADDR return_pc
- = read_memory_unsigned_integer (get_frame_saved_regs (fi)[LR_REGNUM],
- REGISTER_RAW_SIZE (LR_REGNUM));
+ = read_memory_unsigned_integer (get_frame_saved_regs (fi)[D10V_LR_REGNUM],
+ REGISTER_RAW_SIZE (D10V_LR_REGNUM));
get_frame_extra_info (fi)->return_pc = d10v_make_iaddr (return_pc);
}
else
{
- get_frame_extra_info (fi)->return_pc = d10v_make_iaddr (read_register (LR_REGNUM));
+ get_frame_extra_info (fi)->return_pc = d10v_make_iaddr (read_register (D10V_LR_REGNUM));
}
/* The SP is not normally (ever?) saved, but check anyway */
- if (!get_frame_saved_regs (fi)[SP_REGNUM])
+ if (!get_frame_saved_regs (fi)[D10V_SP_REGNUM])
{
/* if the FP was saved, that means the current FP is valid, */
/* otherwise, it isn't being used, so we use the SP instead */
if (uses_frame)
- get_frame_saved_regs (fi)[SP_REGNUM]
+ get_frame_saved_regs (fi)[D10V_SP_REGNUM]
= d10v_read_fp () + get_frame_extra_info (fi)->size;
else
{
- get_frame_saved_regs (fi)[SP_REGNUM] = fp + get_frame_extra_info (fi)->size;
+ get_frame_saved_regs (fi)[D10V_SP_REGNUM] = fp + get_frame_extra_info (fi)->size;
get_frame_extra_info (fi)->frameless = 1;
- get_frame_saved_regs (fi)[FP_REGNUM] = 0;
+ get_frame_saved_regs (fi)[D10V_FP_REGNUM] = 0;
}
}
}
@@ -925,9 +860,9 @@ show_regs (char *args, int from_tty)
{
int a;
printf_filtered ("PC=%04lx (0x%lx) PSW=%04lx RPT_S=%04lx RPT_E=%04lx RPT_C=%04lx\n",
- (long) read_register (PC_REGNUM),
- (long) d10v_make_iaddr (read_register (PC_REGNUM)),
- (long) read_register (PSW_REGNUM),
+ (long) read_register (D10V_PC_REGNUM),
+ (long) d10v_make_iaddr (read_register (D10V_PC_REGNUM)),
+ (long) read_register (D10V_PSW_REGNUM),
(long) read_register (24),
(long) read_register (25),
(long) read_register (23));
@@ -949,7 +884,7 @@ show_regs (char *args, int from_tty)
(long) read_register (13),
(long) read_register (14),
(long) read_register (15));
- for (a = 0; a < NR_IMAP_REGS; a++)
+ for (a = 0; a < D10V_NR_IMAP_REGS; a++)
{
if (a > 0)
printf_filtered (" ");
@@ -965,8 +900,8 @@ show_regs (char *args, int from_tty)
}
printf_filtered ("\n");
}
- printf_filtered ("A0-A%d", NR_A_REGS - 1);
- for (a = A0_REGNUM; a < A0_REGNUM + NR_A_REGS; a++)
+ printf_filtered ("A0-A%d", D10V_NR_A_REGS - 1);
+ for (a = d10v_a0_regnum (current_gdbarch); a < d10v_a0_regnum (current_gdbarch) + D10V_NR_A_REGS; a++)
{
char num[MAX_REGISTER_RAW_SIZE];
int i;
@@ -989,7 +924,7 @@ d10v_read_pc (ptid_t ptid)
save_ptid = inferior_ptid;
inferior_ptid = ptid;
- pc = (int) read_register (PC_REGNUM);
+ pc = (int) read_register (D10V_PC_REGNUM);
inferior_ptid = save_ptid;
retval = d10v_make_iaddr (pc);
return retval;
@@ -1002,26 +937,26 @@ d10v_write_pc (CORE_ADDR val, ptid_t ptid)
save_ptid = inferior_ptid;
inferior_ptid = ptid;
- write_register (PC_REGNUM, d10v_convert_iaddr_to_raw (val));
+ write_register (D10V_PC_REGNUM, d10v_convert_iaddr_to_raw (val));
inferior_ptid = save_ptid;
}
-static CORE_ADDR
+CORE_ADDR
d10v_read_sp (void)
{
- return (d10v_make_daddr (read_register (SP_REGNUM)));
+ return (d10v_make_daddr (read_register (D10V_SP_REGNUM)));
}
static void
d10v_write_sp (CORE_ADDR val)
{
- write_register (SP_REGNUM, d10v_convert_daddr_to_raw (val));
+ write_register (D10V_SP_REGNUM, d10v_convert_daddr_to_raw (val));
}
-static CORE_ADDR
+CORE_ADDR
d10v_read_fp (void)
{
- return (d10v_make_daddr (read_register (FP_REGNUM)));
+ return (d10v_make_daddr (read_register (D10V_FP_REGNUM)));
}
/* Function: push_return_address (pc)
@@ -1031,7 +966,7 @@ d10v_read_fp (void)
static CORE_ADDR
d10v_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
{
- write_register (LR_REGNUM, d10v_convert_iaddr_to_raw (CALL_DUMMY_ADDRESS ()));
+ write_register (D10V_LR_REGNUM, d10v_convert_iaddr_to_raw (CALL_DUMMY_ADDRESS ()));
return sp;
}
@@ -1077,7 +1012,7 @@ d10v_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int i;
- int regnum = ARG1_REGNUM;
+ int regnum = D10V_ARG1_REGNUM;
struct stack_item *si = NULL;
long val;
@@ -1099,13 +1034,13 @@ d10v_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int aligned_regnum = (regnum + 1) & ~1;
/* printf ("push: type=%d len=%d\n", TYPE_CODE (type), len); */
- if (len <= 2 && regnum <= ARGN_REGNUM)
+ if (len <= 2 && regnum <= D10V_ARGN_REGNUM)
/* fits in a single register, do not align */
{
val = extract_unsigned_integer (contents, len);
write_register (regnum++, val);
}
- else if (len <= (ARGN_REGNUM - aligned_regnum + 1) * 2)
+ else if (len <= (D10V_ARGN_REGNUM - aligned_regnum + 1) * 2)
/* value fits in remaining registers, store keeping left
aligned */
{
@@ -1125,7 +1060,7 @@ d10v_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
else
{
/* arg will go onto stack */
- regnum = ARGN_REGNUM + 1;
+ regnum = D10V_ARGN_REGNUM + 1;
si = push_stack_item (si, contents, len);
}
}
@@ -1151,9 +1086,9 @@ d10v_extract_return_value (struct type *type, struct regcache *regcache,
int len;
#if 0
printf("RET: TYPE=%d len=%d r%d=0x%x\n", TYPE_CODE (type),
- TYPE_LENGTH (type), RET1_REGNUM - R0_REGNUM,
- (int) extract_unsigned_integer (regbuf + REGISTER_BYTE(RET1_REGNUM),
- REGISTER_RAW_SIZE (RET1_REGNUM)));
+ TYPE_LENGTH (type), D10V_RET1_REGNUM - R0_REGNUM,
+ (int) extract_unsigned_integer (regbuf + REGISTER_BYTE(D10V_RET1_REGNUM),
+ REGISTER_RAW_SIZE (D10V_RET1_REGNUM)));
#endif
if (TYPE_LENGTH (type) == 1)
{
@@ -1338,7 +1273,7 @@ d10v_eva_prepare_to_trace (void)
if (!tracing)
return;
- last_pc = read_register (PC_REGNUM);
+ last_pc = read_register (D10V_PC_REGNUM);
}
/* Collect trace data from the target board and format it into a form
@@ -1520,10 +1455,6 @@ d10v_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdep = XMALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
- /* NOTE: cagney/2002-12-06: This can be deleted when this arch is
- ready to unwind the PC first (see frame.c:get_prev_frame()). */
- set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
-
switch (info.bfd_arch_info->mach)
{
case bfd_mach_d10v_ts2:
@@ -1620,7 +1551,6 @@ d10v_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_use_struct_convention (gdbarch, d10v_use_struct_convention);
set_gdbarch_frame_init_saved_regs (gdbarch, d10v_frame_init_saved_regs);
- set_gdbarch_init_extra_frame_info (gdbarch, d10v_init_extra_frame_info);
set_gdbarch_pop_frame (gdbarch, d10v_pop_frame);
@@ -1645,6 +1575,8 @@ d10v_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_register_sim_regno (gdbarch, d10v_register_sim_regno);
set_gdbarch_extra_stack_alignment_needed (gdbarch, 0);
+ frame_unwind_append_predicate (gdbarch, d10v_frame_p);
+
return gdbarch;
}
diff --git a/gdb/d10v-tdep.h b/gdb/d10v-tdep.h
new file mode 100644
index 00000000000..4535c2ac245
--- /dev/null
+++ b/gdb/d10v-tdep.h
@@ -0,0 +1,62 @@
+/* Target-dependent code for Mitsubishi D10V, for GDB.
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 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. */
+
+#ifndef D10V_TDEP_H
+#define D10V_TDEP_H
+
+/* d10v register names. */
+
+enum
+{
+ D10V_R0_REGNUM = 0,
+ D10V_R3_REGNUM = 3,
+ D10V_FP_REGNUM = 11,
+ D10V_LR_REGNUM = 13,
+ D10V_SP_REGNUM = 15,
+ D10V_PSW_REGNUM = 16,
+ D10V_PC_REGNUM = 18,
+ D10V_NR_IMAP_REGS = 2,
+ D10V_NR_A_REGS = 2,
+ D10V_TS2_NUM_REGS = 37,
+ D10V_TS3_NUM_REGS = 42,
+ /* d10v calling convention. */
+ D10V_ARG1_REGNUM = D10V_R0_REGNUM,
+ D10V_ARGN_REGNUM = D10V_R3_REGNUM,
+ D10V_RET1_REGNUM = D10V_R0_REGNUM,
+};
+
+/* These are the addresses the D10V-EVA board maps data and
+ instruction memory to. */
+
+enum memspace {
+ D10V_DMEM_START = 0x2000000,
+ D10V_IMEM_START = 0x1000000,
+ D10V_STACK_START = 0x200bffe
+};
+
+extern CORE_ADDR d10v_make_iaddr (CORE_ADDR x);
+extern CORE_ADDR d10v_make_daddr (CORE_ADDR x);
+extern CORE_ADDR d10v_read_sp (void);
+extern CORE_ADDR d10v_read_fp (void);
+extern int d10v_a0_regnum (struct gdbarch *gdbarch);
+
+#endif
diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c
index a1abc29f944..83748127d07 100644
--- a/gdb/dummy-frame.c
+++ b/gdb/dummy-frame.c
@@ -24,6 +24,7 @@
#include "defs.h"
#include "dummy-frame.h"
+#include "frame-unwind.h"
#include "regcache.h"
#include "frame.h"
#include "inferior.h"
@@ -362,3 +363,21 @@ dummy_frame_id_unwind (struct frame_info *frame,
*id = dummy->id;
}
+static struct frame_unwind dummy_frame_unwind =
+{
+ dummy_frame_pc_unwind,
+ dummy_frame_id_unwind,
+ dummy_frame_register_unwind
+};
+
+const struct frame_unwind *
+dummy_frame_p (CORE_ADDR pc)
+{
+ if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
+ ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
+ : pc_in_dummy_frame (pc))
+ return &dummy_frame_unwind;
+ else
+ return NULL;
+}
+
diff --git a/gdb/dummy-frame.h b/gdb/dummy-frame.h
index 7743c8efc91..39bf1a9faf6 100644
--- a/gdb/dummy-frame.h
+++ b/gdb/dummy-frame.h
@@ -22,6 +22,13 @@
#if !defined (DUMMY_FRAME_H)
#define DUMMY_FRAME_H 1
+/* Does the PC belong to a dummy frame? If it does, return a dummy
+ frame unwind descriptor. */
+
+struct frame_unwind;
+extern const struct frame_unwind *dummy_frame_p (CORE_ADDR pc);
+
+
struct frame_info;
struct regcache;
struct frame_id;
diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
new file mode 100644
index 00000000000..a08bcf0df66
--- /dev/null
+++ b/gdb/frame-unwind.c
@@ -0,0 +1,102 @@
+/* Definitions for a frame unwinder, for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "gdb_assert.h"
+#include "dummy-frame.h"
+#include "legacy-frame.h"
+
+static struct gdbarch_data *frame_unwind_data;
+
+struct frame_unwind_table
+{
+ frame_unwind_p_ftype **p;
+ int middle;
+ int nr;
+};
+
+/* Append a predicate to the end of the table. */
+static void
+append_predicate (struct frame_unwind_table *table,
+ frame_unwind_p_ftype *p)
+{
+ table->p = xrealloc (table->p,
+ (table->nr + 1) * sizeof (frame_unwind_p_ftype *));
+ table->p[table->nr] = p;
+ table->nr++;
+}
+
+static void *
+frame_unwind_init (struct gdbarch *gdbarch)
+{
+ struct frame_unwind_table *table = XCALLOC (1, struct frame_unwind_table);
+ append_predicate (table, dummy_frame_p);
+ return table;
+}
+
+static void
+frame_unwind_free (struct gdbarch *gdbarch, void *data)
+{
+ struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
+ xfree (table->p);
+ xfree (table);
+}
+
+void
+frame_unwind_append_predicate (struct gdbarch *gdbarch,
+ frame_unwind_p_ftype *p)
+{
+ struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
+ if (table == NULL)
+ {
+ /* ULGH, called during architecture initialization. Patch
+ things up. */
+ table = frame_unwind_init (gdbarch);
+ set_gdbarch_data (gdbarch, frame_unwind_data, table);
+ }
+ append_predicate (table, p);
+}
+
+const struct frame_unwind *
+frame_unwind_find_by_pc (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ int i;
+ struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
+ /* Seriously old code. Don't even try to use this new mechanism. */
+ if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
+ return legacy_frame_unwind_p (pc);
+ for (i = 0; i < table->nr; i++)
+ {
+ const struct frame_unwind *desc = table->p[i] (pc);
+ if (desc != NULL)
+ return desc;
+ }
+ return legacy_frame_unwind_p (pc);
+}
+
+void
+_initialize_frame_unwind (void)
+{
+ frame_unwind_data = register_gdbarch_data (frame_unwind_init,
+ frame_unwind_free);
+}
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
new file mode 100644
index 00000000000..5c82b6dda28
--- /dev/null
+++ b/gdb/frame-unwind.h
@@ -0,0 +1,92 @@
+/* Definitions for a frame unwinder, 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 (FRAME_UNWIND_H)
+#define FRAME_UNWIND_H 1
+
+struct frame_info;
+struct frame_unwind_cache;
+struct frame_unwind;
+struct frame_id;
+struct gdbarch;
+
+/* Return the corresponding frame descriptor this method is capable of
+ unwinding the frame containing PC. */
+
+typedef const struct frame_unwind *(frame_unwind_p_ftype) (CORE_ADDR pc);
+
+/* Append a descriptor predicate. Descriptors are polled in append
+ order. The list is initialized with just the dummy frame. */
+
+extern void frame_unwind_append_predicate (struct gdbarch *gdbarch,
+ frame_unwind_p_ftype *p);
+
+/* Iterate through the list of frame descriptor predicates for the
+ first one to return a frame descriptor. */
+
+extern const struct frame_unwind *frame_unwind_find_by_pc (struct gdbarch *gdbarch,
+ CORE_ADDR pc);
+
+/* Return the location (and possibly value) of REGNUM for the previous
+ (older, up) frame. All parameters except VALUEP can be assumed to
+ be non NULL. When VALUEP is NULL, just the location of the
+ register should be returned.
+
+ UNWIND_CACHE is provided as mechanism for implementing a per-frame
+ local cache. It's initial value being NULL. Memory for that cache
+ should be allocated using frame_obstack_zalloc().
+
+ Register window architectures (eg SPARC) should note that REGNUM
+ identifies the register for the previous frame. For instance, a
+ request for the value of "o1" for the previous frame would be found
+ in the register "i1" in this FRAME. */
+
+typedef void (frame_register_unwind_ftype) (struct frame_info *frame,
+ struct frame_unwind_cache **unwind_cache,
+ int regnum,
+ int *optimized,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump,
+ void *valuep);
+
+/* Same as for registers above, but return the address at which the
+ calling frame would resume. */
+
+typedef CORE_ADDR (frame_pc_unwind_ftype) (struct frame_info *frame,
+ struct frame_unwind_cache **unwind_cache);
+
+/* Same as for registers above, but return the ID of the frame that
+ called this one. */
+
+typedef void (frame_id_unwind_ftype) (struct frame_info *frame,
+ struct frame_unwind_cache **unwind_cache,
+ struct frame_id *id);
+
+struct frame_unwind
+{
+ /* FIXME: Should the frame's type go here? */
+ frame_pc_unwind_ftype *pc;
+ frame_id_unwind_ftype *id;
+ frame_register_unwind_ftype *reg;
+};
+
+#endif
diff --git a/gdb/frame.c b/gdb/frame.c
index daa243a8478..2a35a8cd236 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -62,7 +62,7 @@ frame_id_unwind (struct frame_info *frame)
{
if (!frame->id_unwind_cache_p)
{
- frame->id_unwind (frame, &frame->unwind_cache, &frame->id_unwind_cache);
+ frame->unwind->id (frame, &frame->unwind_cache, &frame->id_unwind_cache);
frame->id_unwind_cache_p = 1;
}
return frame->id_unwind_cache;
@@ -171,8 +171,8 @@ frame_register_unwind (struct frame_info *frame, int regnum,
gdb_assert (frame != NULL);
/* Ask this frame to unwind its register. */
- frame->register_unwind (frame, &frame->unwind_cache, regnum,
- optimizedp, lvalp, addrp, realnump, bufferp);
+ frame->unwind->reg (frame, &frame->unwind_cache, regnum,
+ optimizedp, lvalp, addrp, realnump, bufferp);
}
void
@@ -271,7 +271,7 @@ frame_read_unsigned_register (struct frame_info *frame, int regnum,
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);
+ frame_unwind_unsigned_register (frame->next, regnum, val);
}
void
@@ -280,7 +280,7 @@ frame_read_signed_register (struct frame_info *frame, int regnum,
{
/* See note in frame_read_unsigned_register(). */
gdb_assert (frame != NULL);
- frame_unwind_signed_register (get_next_frame (frame), regnum, val);
+ frame_unwind_signed_register (frame->next, regnum, val);
}
static void
@@ -409,9 +409,7 @@ create_sentinel_frame (struct regcache *regcache)
frame->type = SENTINEL_FRAME;
frame->level = -1;
frame->unwind_cache = sentinel_frame_cache (regcache);
- frame->pc_unwind = sentinel_frame_pc_unwind;
- frame->id_unwind = sentinel_frame_id_unwind;
- frame->register_unwind = sentinel_frame_register_unwind;
+ frame->unwind = sentinel_frame_unwind_p (0/* dummy value*/);
/* Link this frame back to itself. The frame is self referential
(the unwound PC is the same as the pc for instance, so make it
so. */
@@ -554,42 +552,6 @@ select_frame (struct frame_info *fi)
}
}
-/* Using the PC, select a mechanism for unwinding a frame returning
- the previous frame. The register unwind function should, on
- demand, initialize the ->context object. */
-
-static void
-set_unwind_by_pc (CORE_ADDR pc,
- frame_register_unwind_ftype **unwind_register,
- frame_pc_unwind_ftype **unwind_pc,
- frame_id_unwind_ftype **unwind_id)
-{
- if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
- {
- /* Still need to set this to something. The ``info frame'' code
- calls this function to find out where the saved registers are.
- Hopefully this is robust enough to stop any core dumps and
- return vaguely correct values.. */
- *unwind_register = legacy_frame_register_unwind;
- *unwind_pc = legacy_frame_pc_unwind;
- *unwind_id = legacy_frame_id_unwind;
- }
- else if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
- ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
- : pc_in_dummy_frame (pc))
- {
- *unwind_register = dummy_frame_register_unwind;
- *unwind_pc = dummy_frame_pc_unwind;
- *unwind_id = dummy_frame_id_unwind;
- }
- else
- {
- *unwind_register = legacy_frame_register_unwind;
- *unwind_pc = legacy_frame_pc_unwind;
- *unwind_id = legacy_frame_id_unwind;
- }
-}
-
/* Determine the frame's type based on its PC. */
static enum frame_type
@@ -633,8 +595,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
INIT_EXTRA_FRAME_INFO (0, fi);
/* Select/initialize an unwind function. */
- set_unwind_by_pc (fi->pc, &fi->register_unwind, &fi->pc_unwind,
- &fi->id_unwind);
+ fi->unwind = frame_unwind_find_by_pc (current_gdbarch, fi->pc);
return fi;
}
@@ -857,8 +818,8 @@ legacy_get_prev_frame (struct frame_info *next_frame)
(and probably other architectural information). The PC lets you
check things like the debug info at that point (dwarf2cfi?) and
use that to decide how the frame should be unwound. */
- set_unwind_by_pc (get_frame_pc (prev), &prev->register_unwind,
- &prev->pc_unwind, &prev->id_unwind);
+ prev->unwind = frame_unwind_find_by_pc (current_gdbarch,
+ get_frame_pc (prev));
/* NOTE: cagney/2002-11-18: The code segments, found in
create_new_frame and get_prev_frame(), that initializes the
@@ -1007,8 +968,8 @@ get_prev_frame (struct frame_info *next_frame)
prev_frame->type = frame_type_from_pc (prev_frame->pc);
/* Set the unwind functions based on that identified PC. */
- set_unwind_by_pc (prev_frame->pc, &prev_frame->register_unwind,
- &prev_frame->pc_unwind, &prev_frame->id_unwind);
+ prev_frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
+ prev_frame->pc);
/* Now figure out how to initialize this new frame. Perhaphs one
day, this will too, be selected by set_unwind_by_pc(). */
@@ -1062,7 +1023,7 @@ frame_pc_unwind (struct frame_info *frame)
{
if (!frame->pc_unwind_cache_p)
{
- frame->pc_unwind_cache = frame->pc_unwind (frame, &frame->unwind_cache);
+ frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache);
frame->pc_unwind_cache_p = 1;
}
return frame->pc_unwind_cache;
@@ -1114,7 +1075,8 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
CORE_ADDR
get_frame_base (struct frame_info *fi)
{
- return fi->frame;
+ struct frame_id id = frame_id_unwind (fi->next);
+ return id.base;
}
/* Level of the selected frame: 0 for innermost, 1 for its caller, ...
diff --git a/gdb/frame.h b/gdb/frame.h
index f77a05edf63..6b80afc3136 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -309,41 +309,9 @@ extern CORE_ADDR frame_pc_unwind (struct frame_info *frame);
extern struct frame_id frame_id_unwind (struct frame_info *frame);
-/* Return the location (and possibly value) of REGNUM for the previous
- (older, up) frame. All parameters except VALUEP can be assumed to
- be non NULL. When VALUEP is NULL, just the location of the
- register should be returned.
-
- UNWIND_CACHE is provided as mechanism for implementing a per-frame
- local cache. It's initial value being NULL. Memory for that cache
- should be allocated using frame_obstack_zalloc().
-
- Register window architectures (eg SPARC) should note that REGNUM
- identifies the register for the previous frame. For instance, a
- request for the value of "o1" for the previous frame would be found
- in the register "i1" in this FRAME. */
-
-typedef void (frame_register_unwind_ftype) (struct frame_info *frame,
- struct frame_unwind_cache **unwind_cache,
- int regnum,
- int *optimized,
- enum lval_type *lvalp,
- CORE_ADDR *addrp,
- int *realnump,
- void *valuep);
-
-/* Same as for registers above, but return the address at which the
- calling frame would resume. */
-
-typedef CORE_ADDR (frame_pc_unwind_ftype) (struct frame_info *frame,
- struct frame_unwind_cache **unwind_cache);
-
-/* Same as for registers above, but return the ID of the frame that
- called this one. */
-
-typedef void (frame_id_unwind_ftype) (struct frame_info *frame,
- struct frame_unwind_cache **unwind_cache,
- struct frame_id *id);
+/* FIXME: cagney/2003-01-12: Once `struct frame_info' has been made
+ opaque, this include can go. */
+#include "frame-unwind.h"
/* Describe the saved registers of a frame. */
@@ -431,19 +399,13 @@ struct frame_info
/* Unwind cache shared between the unwind functions - they had
better all agree as to the contents. */
struct frame_unwind_cache *unwind_cache;
+ const struct frame_unwind *unwind;
- /* See description above. The previous frame's registers. */
- frame_register_unwind_ftype *register_unwind;
-
- /* See description above. The previous frame's resume address.
- Save the previous PC in a local cache. */
- frame_pc_unwind_ftype *pc_unwind;
+ /* Cache for the unwound PC value. */
int pc_unwind_cache_p;
CORE_ADDR pc_unwind_cache;
- /* See description above. The previous frame's resume address.
- Save the previous PC in a local cache. */
- frame_id_unwind_ftype *id_unwind;
+ /* Cache for the unwound frame ID value. */
int id_unwind_cache_p;
struct frame_id id_unwind_cache;
diff --git a/gdb/legacy-frame.c b/gdb/legacy-frame.c
index 99227806961..b22e6a30a6e 100644
--- a/gdb/legacy-frame.c
+++ b/gdb/legacy-frame.c
@@ -28,6 +28,8 @@
#include "regcache.h"
#include "target.h"
#include "dummy-frame.h" /* For generic_find_dummy_frame. */
+#include "frame-unwind.h"
+
/* Legacy frame. This saves the processor state just prior to setting
up the inferior function call. Older targets save the registers
@@ -299,3 +301,17 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
if (raw_buffer)
deprecated_read_register_gen (regnum, raw_buffer);
}
+
+
+const struct frame_unwind legacy_frame_unwind =
+{
+ legacy_frame_pc_unwind,
+ legacy_frame_id_unwind,
+ legacy_frame_register_unwind
+};
+
+const struct frame_unwind *
+legacy_frame_unwind_p (CORE_ADDR pc)
+{
+ return &legacy_frame_unwind;
+}
diff --git a/gdb/legacy-frame.h b/gdb/legacy-frame.h
index 999e76afdc3..909893a440f 100644
--- a/gdb/legacy-frame.h
+++ b/gdb/legacy-frame.h
@@ -22,6 +22,11 @@
#if !defined (LEGACY_FRAME_H)
#define LEGACY_FRAME_H 1
+/* Frame unwinder for legacy code. */
+
+const struct frame_unwind *legacy_frame_unwind_p (CORE_ADDR pc);
+
+
struct frame_info;
struct regcache;
struct frame_id;
diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c
new file mode 100644
index 00000000000..036c318b014
--- /dev/null
+++ b/gdb/sentinel-frame.c
@@ -0,0 +1,107 @@
+/* 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"
+
+struct frame_unwind_cache
+{
+ struct regcache *regcache;
+};
+
+struct frame_unwind_cache *
+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,
+ struct frame_unwind_cache **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,
+ struct frame_unwind_cache **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,
+ struct frame_unwind_cache **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 ();
+}
+
+const struct frame_unwind sentinel_frame_unwind =
+{
+ sentinel_frame_pc_unwind,
+ sentinel_frame_id_unwind,
+ sentinel_frame_register_unwind
+};
+
+const struct frame_unwind *
+sentinel_frame_unwind_p (CORE_ADDR pc)
+{
+ return &sentinel_frame_unwind;
+}
diff --git a/gdb/sentinel-frame.h b/gdb/sentinel-frame.h
new file mode 100644
index 00000000000..a7d218731ae
--- /dev/null
+++ b/gdb/sentinel-frame.h
@@ -0,0 +1,65 @@
+/* Code dealing with register 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 (SENTINEL_FRAME_H)
+#define SENTINEL_FRAME_H 1
+
+struct frame_info;
+struct frame_id;
+struct frame_unwind_cache;
+
+/* 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. */
+
+struct frame_unwind_cache *sentinel_frame_cache (struct regcache *regcache);
+
+/* Return the previous frames register value. For a sentinel-frame,
+ it is the value found in the register cache. */
+
+extern void sentinel_frame_register_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **unwind_cache,
+ int regnum,
+ int *optimized,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump,
+ void *valuep);
+
+/* Return the resume address of the previous frame. For the
+ sentinel-frame, it is the threads resume address. */
+
+extern CORE_ADDR sentinel_frame_pc_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **unwind_cache);
+
+/* Return the frame ID of the previous frame. For the sentinel-frame,
+ it is the ID of the inner most frame. */
+
+extern void sentinel_frame_id_unwind (struct frame_info *frame,
+ struct frame_unwind_cache **unwind_cache,
+ struct frame_id *id);
+
+extern const struct frame_unwind *sentinel_frame_unwind_p (CORE_ADDR pc);
+
+#endif /* !defined (SENTINEL_FRAME_H) */