]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
2003-01-13 Andrew Cagney <ac131313@redhat.com>
authorAndrew Cagney <cagney@redhat.com>
Mon, 13 Jan 2003 17:03:53 +0000 (17:03 +0000)
committerAndrew Cagney <cagney@redhat.com>
Mon, 13 Jan 2003 17:03:53 +0000 (17:03 +0000)
* 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.

16 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/d10v-frame.c [new file with mode: 0644]
gdb/d10v-frame.h [new file with mode: 0644]
gdb/d10v-tdep.c
gdb/d10v-tdep.h [new file with mode: 0644]
gdb/dummy-frame.c
gdb/dummy-frame.h
gdb/frame-unwind.c [new file with mode: 0644]
gdb/frame-unwind.h [new file with mode: 0644]
gdb/frame.c
gdb/frame.h
gdb/legacy-frame.c
gdb/legacy-frame.h
gdb/sentinel-frame.c [new file with mode: 0644]
gdb/sentinel-frame.h [new file with mode: 0644]

index 7e4be3e9162028642af1b41a8e4fc224a0777e9b..1ab571050f7c0162fe9c5a6aaa49ebe79613dab5 100644 (file)
@@ -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
index 7fb480f8ed62519a9afd906d34f7d7a48a010097..4f130510c35ebb70d0f30b1891b273e8c565bb46 100644 (file)
@@ -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 (file)
index 0000000..5b29545
--- /dev/null
@@ -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 (file)
index 0000000..c05c4fb
--- /dev/null
@@ -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
index 63efe4c1540468ec2c70aeb6694ec7c9cc095930..e6152e41b4698955403e06a3d3c2b868421b2d05 100644 (file)
 #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 (file)
index 0000000..4535c2a
--- /dev/null
@@ -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
index a1abc29f9444d88455bab7d6f130767591e65025..83748127d07c4149d654203991abc9f7a1299c13 100644 (file)
@@ -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;
+}
+
index 7743c8efc9116683b71bc47df5bfeb5ee4929454..39bf1a9faf65ef2079c6ea27d8f4edcc9b4a8fac 100644 (file)
 #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);
+
+\f
 struct frame_info;
 struct regcache;
 struct frame_id;
diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
new file mode 100644 (file)
index 0000000..a08bcf0
--- /dev/null
@@ -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 (file)
index 0000000..5c82b6d
--- /dev/null
@@ -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
index daa243a84781ed21ae999bf9cd322587954a4e8e..2a35a8cd236f032a5592e72fec6605f2511932a5 100644 (file)
@@ -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, ...
index f77a05edf63874e2253807e574bf5b6dc00836b1..6b80afc31367b21472cd8b8e68f8092acac8c4b3 100644 (file)
@@ -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);
 
 \f
-/* 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;
 
index 99227806961d3d4bcaa961189c1feb8e48a15bad..b22e6a30a6efe1cec262f5f04d8887ea39f6dc7c 100644 (file)
@@ -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;
+}
index 999e76afdc3817f0e352156ad7aa24ee2130908a..909893a440f5ebc06f26dc6628edc1bc995f6e19 100644 (file)
 #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);
+
+\f
 struct frame_info;
 struct regcache;
 struct frame_id;
diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c
new file mode 100644 (file)
index 0000000..036c318
--- /dev/null
@@ -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 (file)
index 0000000..a7d2187
--- /dev/null
@@ -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)  */