This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[unwind-20030108-branch] Convert d10v to unwind mechanims


Hello,

The attached converts the d10v to the new unwind mechanism. It creates a new file:
d10v-frame.[hc]
which implements a d10v specific frame unwinder. The new file contains one obvious hack do_d10v_frame_pop() (that needs to be added to the standard set of unwind functions and purged of deprecated code), and still needs some d10v code cleanup (e.g., shouldn't need to specify the unused init_frame_extra_info).

In implementing this, the code adds frame-unwind.[hc] which implements a mechanims for maintaining registrary of frame unwinders and selecting one (is frame-unwinder, or frame-winder, or ..., better?).

Finally, it contains the change:

get_frame_base (struct frame_info *fi)
{
- return fi->frame;
+ struct frame_id id = frame_id_unwind (fi->next);
+ return id.base;
}

The issue is that, for a dummy frame, the code delays doing an unwind of the previous frame until it's rewuested. This, unfortunatly, leaves the frame's base undefined. A case of duplicating information finally comming back and biteing us. The above is the correct fix. Further, I think it highlights why I need to make `struct frame_info' opaque - so that this redundency can be eliminated.

Now to break this down into digestable chunks that can be reviewed for the mainline.

Andrew
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.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.311.2.2
diff -u -r1.311.2.2 Makefile.in
--- Makefile.in	10 Jan 2003 21:56:43 -0000	1.311.2.2
+++ Makefile.in	13 Jan 2003 17:00:04 -0000
@@ -500,6 +500,7 @@
 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 @@
 	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_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_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 @@
 	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 @@
 	$(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 @@
 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 @@
 	$(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 @@
 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)
Index: d10v-frame.c
===================================================================
RCS file: d10v-frame.c
diff -N d10v-frame.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ d10v-frame.c	13 Jan 2003 17:00:04 -0000
@@ -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;
+}
Index: d10v-frame.h
===================================================================
RCS file: d10v-frame.h
diff -N d10v-frame.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ d10v-frame.h	13 Jan 2003 17:00:04 -0000
@@ -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: d10v-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/d10v-tdep.c,v
retrieving revision 1.69.2.1
diff -u -r1.69.2.1 d10v-tdep.c
--- d10v-tdep.c	12 Jan 2003 20:07:36 -0000	1.69.2.1
+++ d10v-tdep.c	13 Jan 2003 17:00:04 -0000
@@ -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 @@
     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 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 @@
   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 @@
   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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
   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_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 @@
       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 @@
 	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 @@
 {
   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 @@
 		   (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 @@
 	}
       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 @@
 
   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 @@
 
   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 @@
 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 @@
 		     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 @@
       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 @@
       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 @@
   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 @@
   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 @@
   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 @@
   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);
 
@@ -1644,6 +1574,8 @@
 
   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;
 }
Index: d10v-tdep.h
===================================================================
RCS file: d10v-tdep.h
diff -N d10v-tdep.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ d10v-tdep.h	13 Jan 2003 17:00:04 -0000
@@ -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: dummy-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/dummy-frame.c,v
retrieving revision 1.7.2.1
diff -u -r1.7.2.1 dummy-frame.c
--- dummy-frame.c	10 Jan 2003 15:22:39 -0000	1.7.2.1
+++ dummy-frame.c	13 Jan 2003 17:00:04 -0000
@@ -24,6 +24,7 @@
 
 #include "defs.h"
 #include "dummy-frame.h"
+#include "frame-unwind.h"
 #include "regcache.h"
 #include "frame.h"
 #include "inferior.h"
@@ -360,5 +361,23 @@
     *id = null_frame_id;
   else
     *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: dummy-frame.h
===================================================================
RCS file: /cvs/src/src/gdb/dummy-frame.h,v
retrieving revision 1.5.2.1
diff -u -r1.5.2.1 dummy-frame.h
--- dummy-frame.h	10 Jan 2003 15:22:39 -0000	1.5.2.1
+++ dummy-frame.h	13 Jan 2003 17:00:04 -0000
@@ -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;
Index: frame-unwind.c
===================================================================
RCS file: frame-unwind.c
diff -N frame-unwind.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ frame-unwind.c	13 Jan 2003 17:00:04 -0000
@@ -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);
+}
Index: frame-unwind.h
===================================================================
RCS file: frame-unwind.h
diff -N frame-unwind.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ frame-unwind.h	13 Jan 2003 17:00:04 -0000
@@ -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: frame.c
===================================================================
RCS file: /cvs/src/src/gdb/frame.c,v
retrieving revision 1.56.2.3
diff -u -r1.56.2.3 frame.c
--- frame.c	12 Jan 2003 00:06:19 -0000	1.56.2.3
+++ frame.c	13 Jan 2003 17:00:04 -0000
@@ -62,7 +62,7 @@
 {
   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 @@
   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 @@
      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 @@
 {
   /* 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 @@
   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 @@
     }
 }
 
-/* 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 @@
     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 @@
      (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 @@
   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 @@
 {
   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 @@
 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: frame.h
===================================================================
RCS file: /cvs/src/src/gdb/frame.h,v
retrieving revision 1.59.2.2
diff -u -r1.59.2.2 frame.h
--- frame.h	12 Jan 2003 00:06:19 -0000	1.59.2.2
+++ frame.h	13 Jan 2003 17:00:04 -0000
@@ -309,41 +309,9 @@
 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 @@
     /* 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: legacy-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/Attic/legacy-frame.c,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 legacy-frame.c
--- legacy-frame.c	10 Jan 2003 21:56:44 -0000	1.1.2.1
+++ legacy-frame.c	13 Jan 2003 17:00:05 -0000
@@ -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
@@ -298,4 +300,18 @@
     *addrp = REGISTER_BYTE (regnum);
   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: legacy-frame.h
===================================================================
RCS file: /cvs/src/src/gdb/Attic/legacy-frame.h,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 legacy-frame.h
--- legacy-frame.h	10 Jan 2003 21:56:44 -0000	1.1.2.1
+++ legacy-frame.h	13 Jan 2003 17:00:05 -0000
@@ -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;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]