* alpha-linux-tdep.c (alpha_linux_sigtramp_offset_1): New.
authorRichard Henderson <rth@redhat.com>
Thu, 29 May 2003 23:02:53 +0000 (23:02 +0000)
committerRichard Henderson <rth@redhat.com>
Thu, 29 May 2003 23:02:53 +0000 (23:02 +0000)
(alpha_linux_sigtramp_offset): Use it.  Make static.
(alpha_linux_sigcontext_addr): Handle __NR_rt_sigreturn;
update for new frame model.
* alpha-mdebug-tdep.c: New file.
* alpha-osf1-tdep.c (alpha_call_dummy_address): Move from alpha-tdep.c.
(alpha_osf1_init_abi): Install it.
* alpha-tdep.c (PROC_*): Move to alpha-mdebug-tdep.c.
(linked_proc_desc_table): Remove.
(alpha_frame_past_sigtramp_frame): Remove.
(alpha_dynamic_sigtramp_offset): Remove.
(ALPHA_PROC_SIGTRAMP_MAGIC): Remove.
(alpha_proc_desc_is_dyn_sigtramp): Remove.
(alpha_set_proc_desc_is_dyn_sigtramp): Remove.
(push_sigtramp_desc): Remove.
(alpha_cannot_fetch_register): Use ALPHA_FP_REGNUM.
(alpha_cannot_store_register): Likewise.
(alpha_sigcontext_addr): Remove.
(alpha_find_saved_regs): Remove.
(alpha_frame_init_saved_regs): Remove.
(alpha_init_frame_pc_first): Remove.
(read_next_frame_reg): Remove.
(alpha_frame_saved_pc): Remove.
(alpha_saved_pc_after_call): Remove.
(temp_proc_desc, temp_saved_regs): Remove.
(alpha_about_to_return): Remove.
(cached_proc_desc): Remove.
(alpha_frame_chain): Remove.
(alpha_print_extra_frame_info): Remove.
(alpha_init_extra_frame_info): Remove.
(alpha_frame_locals_address): Remove.
(alpha_frame_args_address): Remove.
(alpha_push_arguments): Use ALPHA_REGISTER_BYTES not sizeof CORE_ADDR.
(alpha_push_dummy_frame): Remove.
(alpha_pop_frame): Remove.
(alpha_after_prologue): Rename from after_prologue; remove mdebug bits.
(alpha_read_insn): New.
(alpha_skip_prologue): Merge alpha_skip_prologue_internal; adjust
for different insn encodings.
(alpha_in_lenient_prologue): Remove.
(struct alpha_sigtramp_unwind_cache): New.
(alpha_sigtramp_frame_unwind_cache): New.
(alpha_sigtramp_register_address): New.
(alpha_sigtramp_frame_this_id): New.
(alpha_sigtramp_frame_prev_register): New.
(alpha_sigtramp_frame_unwind): New.
(alpha_sigtramp_frame_p): New.
(struct alpha_heuristic_unwind_cache): New.
(alpha_heuristic_proc_start): Rename from heuristic_proc_start;
don't count nop insns that occur between functions.
(alpha_heuristic_frame_unwind_cache): New; incorporate much of
heuristic_proc_desc, but without the mdebug wrapping.
(alpha_heuristic_frame_this_id): New.
(alpha_heuristic_frame_prev_register): New.
(alpha_heuristic_frame_unwind): New.
(alpha_heuristic_frame_p): New.
(alpha_heuristic_frame_base_address): New.
(alpha_heuristic_frame_base): New.
(alpha_unwind_dummy_id): New.
(alpha_unwind_pc): New.
(alpha_gdbarch_init): Don't set skip_sigtramp_frame.  Kill use of
frame related deprecated initializations; install replacements.
(alpha_dump_tdep): Remove.
* alpha-tdep.h (struct gdbarch_tdep): Remove skip_sigtramp_frame.
(alpha_read_insn, alpha_after_prologue,
alpha_heuristic_frame_unwind_cache, alpha_heuristic_frame_this_id,
alpha_heuristic_frame_prev_register,
alpha_heuristic_frame_base_address, alpha_mdebug_init_abi): Declare.
* config/alpha/alpha-linux.mt (TDEPFILES): Add alpha-mdebug-tdep.o.
* config/alpha/tm-alpha.h (PRINT_EXTRA_FRAME_INFO): Remove.
* config/alpha/tm-alphalinux.h (SIGTRAMP_START, SIGTRAMP_END): Remove.

gdb/ChangeLog
gdb/alpha-linux-tdep.c
gdb/alpha-mdebug-tdep.c [new file with mode: 0644]
gdb/alpha-osf1-tdep.c
gdb/alpha-tdep.c
gdb/alpha-tdep.h
gdb/config/alpha/alpha-linux.mt
gdb/config/alpha/tm-alpha.h
gdb/config/alpha/tm-alphalinux.h

index 0a810e96e1d0a30c52469e8e592539d61a4a1778..61819233b4fc847cbd71be613d649125d9c6f89f 100644 (file)
@@ -1,3 +1,77 @@
+2003-05-29  Richard Henderson  <rth@redhat.com>
+
+       * alpha-linux-tdep.c (alpha_linux_sigtramp_offset_1): New.
+       (alpha_linux_sigtramp_offset): Use it.  Make static.
+       (alpha_linux_sigcontext_addr): Handle __NR_rt_sigreturn;
+       update for new frame model.
+       * alpha-mdebug-tdep.c: New file.
+       * alpha-osf1-tdep.c (alpha_call_dummy_address): Move from alpha-tdep.c.
+       (alpha_osf1_init_abi): Install it.
+       * alpha-tdep.c (PROC_*): Move to alpha-mdebug-tdep.c.
+       (linked_proc_desc_table): Remove.
+       (alpha_frame_past_sigtramp_frame): Remove.
+       (alpha_dynamic_sigtramp_offset): Remove.
+       (ALPHA_PROC_SIGTRAMP_MAGIC): Remove.
+       (alpha_proc_desc_is_dyn_sigtramp): Remove.
+       (alpha_set_proc_desc_is_dyn_sigtramp): Remove.
+       (push_sigtramp_desc): Remove.
+       (alpha_cannot_fetch_register): Use ALPHA_FP_REGNUM.
+       (alpha_cannot_store_register): Likewise.
+       (alpha_sigcontext_addr): Remove.
+       (alpha_find_saved_regs): Remove.
+       (alpha_frame_init_saved_regs): Remove.
+       (alpha_init_frame_pc_first): Remove.
+       (read_next_frame_reg): Remove.
+       (alpha_frame_saved_pc): Remove.
+       (alpha_saved_pc_after_call): Remove.
+       (temp_proc_desc, temp_saved_regs): Remove.
+       (alpha_about_to_return): Remove.
+       (cached_proc_desc): Remove.
+       (alpha_frame_chain): Remove.
+       (alpha_print_extra_frame_info): Remove.
+       (alpha_init_extra_frame_info): Remove.
+       (alpha_frame_locals_address): Remove.
+       (alpha_frame_args_address): Remove.
+       (alpha_push_arguments): Use ALPHA_REGISTER_BYTES not sizeof CORE_ADDR.
+       (alpha_push_dummy_frame): Remove.
+       (alpha_pop_frame): Remove.
+       (alpha_after_prologue): Rename from after_prologue; remove mdebug bits.
+       (alpha_read_insn): New.
+       (alpha_skip_prologue): Merge alpha_skip_prologue_internal; adjust
+       for different insn encodings.
+       (alpha_in_lenient_prologue): Remove.
+       (struct alpha_sigtramp_unwind_cache): New.
+       (alpha_sigtramp_frame_unwind_cache): New.
+       (alpha_sigtramp_register_address): New.
+       (alpha_sigtramp_frame_this_id): New.
+       (alpha_sigtramp_frame_prev_register): New.
+       (alpha_sigtramp_frame_unwind): New.
+       (alpha_sigtramp_frame_p): New.
+       (struct alpha_heuristic_unwind_cache): New.
+       (alpha_heuristic_proc_start): Rename from heuristic_proc_start;
+       don't count nop insns that occur between functions.
+       (alpha_heuristic_frame_unwind_cache): New; incorporate much of
+       heuristic_proc_desc, but without the mdebug wrapping.
+       (alpha_heuristic_frame_this_id): New.
+       (alpha_heuristic_frame_prev_register): New.
+       (alpha_heuristic_frame_unwind): New.
+       (alpha_heuristic_frame_p): New.
+       (alpha_heuristic_frame_base_address): New.
+       (alpha_heuristic_frame_base): New.
+       (alpha_unwind_dummy_id): New.
+       (alpha_unwind_pc): New.
+       (alpha_gdbarch_init): Don't set skip_sigtramp_frame.  Kill use of
+       frame related deprecated initializations; install replacements.
+       (alpha_dump_tdep): Remove.
+       * alpha-tdep.h (struct gdbarch_tdep): Remove skip_sigtramp_frame.
+       (alpha_read_insn, alpha_after_prologue,
+       alpha_heuristic_frame_unwind_cache, alpha_heuristic_frame_this_id,
+       alpha_heuristic_frame_prev_register,
+       alpha_heuristic_frame_base_address, alpha_mdebug_init_abi): Declare.
+       * config/alpha/alpha-linux.mt (TDEPFILES): Add alpha-mdebug-tdep.o.
+       * config/alpha/tm-alpha.h (PRINT_EXTRA_FRAME_INFO): Remove.
+       * config/alpha/tm-alphalinux.h (SIGTRAMP_START, SIGTRAMP_END): Remove.
+
 2003-05-29  Andrew Cagney  <cagney@redhat.com>
 
        * gdb_assert.h (gdb_assert_fail): Provide different definitions
index c5d7481fbf95ef042297031d96dd5cd030e307c1..e89a0fa5fe17bf7391f665d75cda6b823394454f 100644 (file)
 #include "gdbcore.h"
 #include "value.h"
 #include "osabi.h"
+#include "gdb_assert.h"
 
 #include "alpha-tdep.h"
 
-/* Under GNU/Linux, signal handler invocations can be identified by the
-   designated code sequence that is used to return from a signal
+/* Under GNU/Linux, signal handler invocations can be identified by
+   the designated code sequence that is used to return from a signal
    handler.  In particular, the return address of a signal handler
-   points to the following sequence (the first instruction is quadword
-   aligned):
-  
-   bis $30,$30,$16
-   addq $31,0x67,$0
-   call_pal callsys 
-      
-   Each instruction has a unique encoding, so we simply attempt to
-   match the instruction the pc is pointing to with any of the above
-   instructions.  If there is a hit, we know the offset to the start
-   of the designated sequence and can then check whether we really are
-   executing in a designated sequence.  If not, -1 is returned,
-   otherwise the offset from the start of the desingated sequence is
-   returned.
-   
-   There is a slight chance of false hits: code could jump into the
-   middle of the designated sequence, in which case there is no
-   guarantee that we are in the middle of a sigreturn syscall.  Don't
-   think this will be a problem in praxis, though.  */
-LONGEST
-alpha_linux_sigtramp_offset (CORE_ADDR pc)
+   points to a sequence that copies $sp to $16, loads $0 with the
+   appropriate syscall number, and finally enters the kernel.
+
+   This is somewhat complicated in that:
+     (1) the expansion of the "mov" assembler macro has changed over
+         time, from "bis src,src,dst" to "bis zero,src,dst",
+     (2) the kernel has changed from using "addq" to "lda" to load the
+         syscall number,
+     (3) there is a "normal" sigreturn and an "rt" sigreturn which
+         has a different stack layout.
+*/
+
+static long
+alpha_linux_sigtramp_offset_1 (CORE_ADDR pc)
 {
-  unsigned int i[3], w;
-  long off;
+  switch (alpha_read_insn (pc))
+    {
+    case 0x47de0410:           /* bis $30,$30,$16 */
+    case 0x47fe0410:           /* bis $31,$30,$16 */
+      return 0;
 
-  if (read_memory_nobpt (pc, (char *) &w, 4) != 0)
-    return -1;
+    case 0x43ecf400:           /* addq $31,103,$0 */
+    case 0x201f0067:           /* lda $0,103($31) */
+    case 0x201f015f:           /* lda $0,351($31) */
+      return 4;
+
+    case 0x00000083:           /* call_pal callsys */
+      return 8;
 
-  off = -1;
-  switch (w)
-    {
-    case 0x47de0410:
-      off = 0;
-      break;                   /* bis $30,$30,$16 */
-    case 0x43ecf400:
-      off = 4;
-      break;                   /* addq $31,0x67,$0 */
-    case 0x00000083:
-      off = 8;
-      break;                   /* call_pal callsys */
     default:
       return -1;
     }
+}
+
+static LONGEST
+alpha_linux_sigtramp_offset (CORE_ADDR pc)
+{
+  long i, off;
+
+  if (pc & 3)
+    return -1;
+
+  /* Guess where we might be in the sequence.  */
+  off = alpha_linux_sigtramp_offset_1 (pc);
+  if (off < 0)
+    return -1;
+
+  /* Verify that the other two insns of the sequence are as we expect.  */
   pc -= off;
-  if (pc & 0x7)
+  for (i = 0; i < 12; i += 4)
     {
-      /* designated sequence is not quadword aligned */
-      return -1;
+      if (i == off)
+       continue;
+      if (alpha_linux_sigtramp_offset_1 (pc + i) != i)
+       return -1;
     }
-  if (read_memory_nobpt (pc, (char *) i, sizeof (i)) != 0)
-    return -1;
-
-  if (i[0] == 0x47de0410 && i[1] == 0x43ecf400 && i[2] == 0x00000083)
-    return off;
 
-  return -1;
+  return off;
 }
 
 static int
 alpha_linux_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
 {
-  return (alpha_linux_sigtramp_offset (pc) >= 0);
+  return alpha_linux_sigtramp_offset (pc) >= 0;
 }
 
 static CORE_ADDR
-alpha_linux_sigcontext_addr (struct frame_info *frame)
+alpha_linux_sigcontext_addr (struct frame_info *next_frame)
 {
-  return (get_frame_base (frame) - 0x298); /* sizeof(struct sigcontext) */
+  CORE_ADDR pc;
+  ULONGEST sp;
+  long off;
+
+  pc = frame_pc_unwind (next_frame);
+  frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &sp);
+
+  off = alpha_linux_sigtramp_offset (pc);
+  gdb_assert (off >= 0);
+
+  /* __NR_rt_sigreturn has a couple of structures on the stack.  This is:
+
+       struct rt_sigframe {
+         struct siginfo info;
+         struct ucontext uc;
+        };
+
+       offsetof (struct rt_sigframe, uc.uc_mcontext);
+  */
+  if (alpha_read_insn (pc - off + 4) == 0x201f015f)
+    return sp + 176;
+
+  /* __NR_sigreturn has the sigcontext structure at the top of the stack.  */
+  return sp;
 }
 
 static void
 alpha_linux_init_abi (struct gdbarch_info info,
                       struct gdbarch *gdbarch)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct gdbarch_tdep *tdep;
+
+  alpha_mdebug_init_abi (info, gdbarch);
 
   set_gdbarch_pc_in_sigtramp (gdbarch, alpha_linux_pc_in_sigtramp);
 
+  tdep = gdbarch_tdep (gdbarch);
   tdep->dynamic_sigtramp_offset = alpha_linux_sigtramp_offset;
   tdep->sigcontext_addr = alpha_linux_sigcontext_addr;
-
   tdep->jb_pc = 2;
   tdep->jb_elt_size = 8;
 }
diff --git a/gdb/alpha-mdebug-tdep.c b/gdb/alpha-mdebug-tdep.c
new file mode 100644 (file)
index 0000000..2f84d6d
--- /dev/null
@@ -0,0 +1,442 @@
+/* Target-dependent mdebug code for the ALPHA architecture.
+   Copyright 1993, 1994, 1995, 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 "frame-base.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "dis-asm.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb_string.h"
+#include "linespec.h"
+#include "regcache.h"
+#include "doublest.h"
+#include "arch-utils.h"
+#include "osabi.h"
+#include "block.h"
+#include "gdb_assert.h"
+
+#include "elf-bfd.h"
+
+#include "alpha-tdep.h"
+
+/* FIXME: Some of this code should perhaps be merged with mips.  */
+
+/* *INDENT-OFF* */
+/* Layout of a stack frame on the alpha:
+
+                |                              |
+ pdr members:  |  7th ... nth arg,             |
+                |  `pushed' by caller.         |
+                |                              |
+----------------|-------------------------------|<--  old_sp == vfp
+   ^  ^  ^  ^  |                               |
+   |  |  |  |  |                               |
+   |  |localoff        |  Copies of 1st .. 6th         |
+   |  |  |  |  |  argument if necessary.       |
+   |  |  |  v  |                               |
+   |  |  |  ---        |-------------------------------|<-- FRAME_LOCALS_ADDRESS
+   |  |  |      |                              |
+   |  |  |      |  Locals and temporaries.     |
+   |  |  |      |                              |
+   |  |  |      |-------------------------------|
+   |  |  |      |                              |
+   |-fregoffset        |  Saved float registers.       |
+   |  |  |      |  F9                          |
+   |  |  |      |   .                          |
+   |  |  |      |   .                          |
+   |  |  |      |  F2                          |
+   |  |  v      |                              |
+   |  |  -------|-------------------------------|
+   |  |         |                              |
+   |  |         |  Saved registers.            |
+   |  |         |  S6                          |
+   |-regoffset |   .                           |
+   |  |         |   .                          |
+   |  |         |  S0                          |
+   |  |         |  pdr.pcreg                   |
+   |  v         |                              |
+   |  ----------|-------------------------------|
+   |            |                              |
+ frameoffset    |  Argument build area, gets   |
+   |            |  7th ... nth arg for any     |
+   |            |  called procedure.           |
+   v            |                              |
+   -------------|-------------------------------|<-- sp
+                |                              |
+*/
+/* *INDENT-ON* */
+
+#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr)
+#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset)
+#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg)
+#define PROC_REG_MASK(proc) ((proc)->pdr.regmask)
+#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask)
+#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)
+#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)
+#define PROC_PC_REG(proc) ((proc)->pdr.pcreg)
+#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff)
+\f
+/* Locate the mdebug PDR for the given PC.  Return null if one can't
+   be found; you'll have to fall back to other methods in that case.  */
+
+static alpha_extra_func_info_t
+find_proc_desc (CORE_ADDR pc)
+{
+  struct block *b = block_for_pc (pc);
+  alpha_extra_func_info_t proc_desc = NULL;
+  struct symbol *sym = NULL;
+
+  if (b)
+    {
+      CORE_ADDR startaddr;
+      find_pc_partial_function (pc, NULL, &startaddr, NULL);
+
+      if (startaddr > BLOCK_START (b))
+       /* This is the "pathological" case referred to in a comment in
+          print_frame_info.  It might be better to move this check into
+          symbol reading.  */
+       sym = NULL;
+      else
+       sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0, NULL);
+    }
+
+  if (sym)
+    {
+      proc_desc = (alpha_extra_func_info_t) SYMBOL_VALUE (sym);
+
+      /* If we never found a PDR for this function in symbol reading,
+        then examine prologues to find the information.  */
+      if (proc_desc->pdr.framereg == -1)
+       proc_desc = NULL;
+    }
+
+  return proc_desc;
+}
+
+/* This returns the PC of the first inst after the prologue.  If we can't
+   find the prologue, then return 0.  */
+
+static CORE_ADDR
+alpha_mdebug_after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
+{
+  if (proc_desc)
+    {
+      /* If function is frameless, then we need to do it the hard way.  I
+         strongly suspect that frameless always means prologueless... */
+      if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
+         && PROC_FRAME_OFFSET (proc_desc) == 0)
+       return 0;
+    }
+
+  return alpha_after_prologue (pc);
+}
+
+/* Return non-zero if we *might* be in a function prologue.  Return zero
+   if we are definitively *not* in a function prologue.  */
+
+static int
+alpha_mdebug_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
+{
+  CORE_ADDR after_prologue_pc = alpha_mdebug_after_prologue (pc, proc_desc);
+  return (after_prologue_pc == 0 || pc < after_prologue_pc);
+}
+
+\f
+/* Frame unwinder that reads mdebug PDRs.  */
+
+struct alpha_mdebug_unwind_cache
+{
+  alpha_extra_func_info_t proc_desc;
+  CORE_ADDR vfp;
+  CORE_ADDR *saved_regs;
+  void *in_prologue_cache;
+};
+
+/* Extract all of the information about the frame from PROC_DESC
+   and store the resulting register save locations in the structure.  */
+
+static struct alpha_mdebug_unwind_cache *
+alpha_mdebug_frame_unwind_cache (struct frame_info *next_frame, 
+                                void **this_prologue_cache)
+{
+  struct alpha_mdebug_unwind_cache *info;
+  alpha_extra_func_info_t proc_desc;
+  ULONGEST vfp;
+  CORE_ADDR pc, reg_position;
+  unsigned long mask;
+  int ireg, returnreg;
+
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
+
+  info = FRAME_OBSTACK_ZALLOC (struct alpha_mdebug_unwind_cache);
+  *this_prologue_cache = info;
+  pc = frame_pc_unwind (next_frame);
+
+  /* ??? We don't seem to be able to cache the lookup of the PDR
+     from alpha_mdebug_frame_p.  It'd be nice if we could change
+     the arguments to that function.  Oh well.  */
+  proc_desc = find_proc_desc (pc);
+  info->proc_desc = proc_desc;
+  gdb_assert (proc_desc != NULL);
+
+  /* If we're in the prologue, the PDR for this frame is not yet valid.  */
+  /* ??? We could have said "no" in alpha_mdebug_frame_p, and we'd
+     walk down the list of unwinders and try the heuristic unwinder
+     and things would have been fine. However, since we have the PDR,
+     we know how to skip the search for the start of the procedure,
+     and all the uncertainty involved there.  So instead, arrange for
+     us to defer to the heuristic unwinder directly.  */
+  if (alpha_mdebug_in_prologue (pc, proc_desc))
+    {
+      alpha_heuristic_frame_unwind_cache (next_frame,
+                                         &info->in_prologue_cache,
+                                         PROC_LOW_ADDR (proc_desc));
+      return info;
+    }
+
+  info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
+
+  /* The VFP of the frame is at FRAME_REG+FRAME_OFFSET.  */
+  frame_unwind_unsigned_register (next_frame, PROC_FRAME_REG (proc_desc), &vfp);
+  vfp += PROC_FRAME_OFFSET (info->proc_desc);
+  info->vfp = vfp;
+
+  /* Fill in the offsets for the registers which gen_mask says were saved.  */
+
+  reg_position = vfp + PROC_REG_OFFSET (proc_desc);
+  mask = PROC_REG_MASK (proc_desc);
+  returnreg = PROC_PC_REG (proc_desc);
+
+  /* Note that RA is always saved first, regardless of its actual
+     register number.  */
+  if (mask & (1 << returnreg))
+    {
+      /* Clear bit for RA so we don't save it again later. */
+      mask &= ~(1 << returnreg);
+
+      info->saved_regs[returnreg] = reg_position;
+      reg_position += 8;
+    }
+
+  for (ireg = 0; ireg <= 31; ++ireg)
+    if (mask & (1 << ireg))
+      {
+       info->saved_regs[ireg] = reg_position;
+       reg_position += 8;
+      }
+
+  reg_position = vfp + PROC_FREG_OFFSET (proc_desc);
+  mask = PROC_FREG_MASK (proc_desc);
+
+  for (ireg = 0; ireg <= 31; ++ireg)
+    if (mask & (1 << ireg))
+      {
+       info->saved_regs[FP0_REGNUM + ireg] = reg_position;
+       reg_position += 8;
+      }
+
+  return info;
+}
+
+/* Given a GDB frame, determine the address of the calling function's
+   frame.  This will be used to create a new GDB frame struct.  */
+
+static void
+alpha_mdebug_frame_this_id (struct frame_info *next_frame,
+                           void **this_prologue_cache,
+                           struct frame_id *this_id)
+{
+  struct alpha_mdebug_unwind_cache *info
+    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+
+  /* If we're in the prologue, defer to the heuristic unwinder.  */
+  if (info->in_prologue_cache)
+    alpha_heuristic_frame_this_id (next_frame, &info->in_prologue_cache,
+                                  this_id);
+  else
+    *this_id = frame_id_build (info->vfp, frame_func_unwind (next_frame));
+}
+
+/* Retrieve the value of REGNUM in FRAME.  Don't give up!  */
+
+static void
+alpha_mdebug_frame_prev_register (struct frame_info *next_frame,
+                                 void **this_prologue_cache,
+                                 int regnum, int *optimizedp,
+                                 enum lval_type *lvalp, CORE_ADDR *addrp,
+                                 int *realnump, void *bufferp)
+{
+  struct alpha_mdebug_unwind_cache *info
+    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+
+  /* If we're in the prologue, defer to the heuristic unwinder.  */
+  if (info->in_prologue_cache)
+    {
+      alpha_heuristic_frame_prev_register (next_frame,
+                                          &info->in_prologue_cache,
+                                          regnum, optimizedp, lvalp,
+                                          addrp, realnump, bufferp);
+      return;
+    }
+
+  /* The PC of the previous frame is stored in the link register of
+     the current frame.  Frob regnum so that we pull the value from
+     the correct place.  */
+  if (regnum == PC_REGNUM)
+    regnum = PROC_PC_REG (info->proc_desc);
+  
+  /* For all registers known to be saved in the current frame, 
+     do the obvious and pull the value out.  */
+  if (info->saved_regs[regnum])
+    {
+      *optimizedp = 0;
+      *lvalp = lval_memory;
+      *addrp = info->saved_regs[regnum];
+      *realnump = -1;
+      if (bufferp != NULL)
+       read_memory (*addrp, bufferp, ALPHA_REGISTER_SIZE);
+      return;
+    }
+
+  /* The stack pointer of the previous frame is computed by popping
+     the current stack frame.  */
+  if (regnum == SP_REGNUM)
+    {
+      *optimizedp = 0;
+      *lvalp = not_lval;
+      *addrp = 0;
+      *realnump = -1;
+      if (bufferp != NULL)
+       store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp);
+      return;
+    }
+
+  /* Otherwise assume the next frame has the same register value.  */
+  frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
+                 realnump, bufferp);
+}
+
+static const struct frame_unwind alpha_mdebug_frame_unwind = {
+  NORMAL_FRAME,
+  alpha_mdebug_frame_this_id,
+  alpha_mdebug_frame_prev_register
+};
+
+const struct frame_unwind *
+alpha_mdebug_frame_p (CORE_ADDR pc)
+{
+  alpha_extra_func_info_t proc_desc;
+
+  /* If this PC does not map to a PDR, then clearly this isn't an
+     mdebug frame.  */
+  proc_desc = find_proc_desc (pc);
+  if (proc_desc == NULL)
+    return NULL;
+
+  return &alpha_mdebug_frame_unwind;
+}
+
+static CORE_ADDR
+alpha_mdebug_frame_base_address (struct frame_info *next_frame,
+                                void **this_prologue_cache)
+{
+  struct alpha_mdebug_unwind_cache *info
+    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+
+  if (info->in_prologue_cache)
+    return alpha_heuristic_frame_base_address (next_frame,
+                                              &info->in_prologue_cache);
+  else
+    return info->vfp;
+}
+
+static CORE_ADDR
+alpha_mdebug_frame_locals_address (struct frame_info *next_frame,
+                                  void **this_prologue_cache)
+{
+  struct alpha_mdebug_unwind_cache *info
+    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+  CORE_ADDR vfp;
+
+  if (info->in_prologue_cache)
+    vfp = alpha_heuristic_frame_base_address (next_frame,
+                                             &info->in_prologue_cache);
+  else
+    vfp = info->vfp;
+
+  return vfp - PROC_LOCALOFF (info->proc_desc);
+}
+
+static CORE_ADDR
+alpha_mdebug_frame_args_address (struct frame_info *next_frame,
+                                void **this_prologue_cache)
+{
+  struct alpha_mdebug_unwind_cache *info
+    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
+  CORE_ADDR vfp;
+
+  if (info->in_prologue_cache)
+    vfp = alpha_heuristic_frame_base_address (next_frame,
+                                             &info->in_prologue_cache);
+  else
+    vfp = info->vfp;
+
+  return vfp - ALPHA_NUM_ARG_REGS * 8;
+}
+
+static const struct frame_base alpha_mdebug_frame_base = {
+  &alpha_mdebug_frame_unwind,
+  alpha_mdebug_frame_base_address,
+  alpha_mdebug_frame_locals_address,
+  alpha_mdebug_frame_args_address
+};
+
+static const struct frame_base *
+alpha_mdebug_frame_base_p (CORE_ADDR pc)
+{
+  alpha_extra_func_info_t proc_desc;
+
+  /* If this PC does not map to a PDR, then clearly this isn't an
+     mdebug frame.  */
+  proc_desc = find_proc_desc (pc);
+  if (proc_desc == NULL)
+    return NULL;
+
+  return &alpha_mdebug_frame_base;
+}
+
+\f
+void
+alpha_mdebug_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  frame_unwind_append_predicate (gdbarch, alpha_mdebug_frame_p);
+  frame_base_append_predicate (gdbarch, alpha_mdebug_frame_base_p);
+}
index 4eaa3c4013c51be11cef2f917615ad9bf05c886e..26e1790760766d5228253686b32d31da7a88345d 100644 (file)
@@ -53,6 +53,30 @@ alpha_osf1_sigcontext_addr (struct frame_info *frame)
                                           : frame->frame, 8));
 }
 
+/* This is the definition of CALL_DUMMY_ADDRESS.  It's a heuristic that is used
+   to find a convenient place in the text segment to stick a breakpoint to
+   detect the completion of a target function call (ala call_function_by_hand).
+ */
+
+static CORE_ADDR
+alpha_call_dummy_address (void)
+{
+  CORE_ADDR entry;
+  struct minimal_symbol *sym;
+
+  entry = entry_point_address ();
+
+  if (entry != 0)
+    return entry;
+
+  sym = lookup_minimal_symbol ("_Prelude", NULL, symfile_objfile);
+
+  if (!sym || MSYMBOL_TYPE (sym) != mst_text)
+    return 0;
+  else
+    return SYMBOL_VALUE_ADDRESS (sym) + 4;
+}
+
 static void
 alpha_osf1_init_abi (struct gdbarch_info info,
                      struct gdbarch *gdbarch)
@@ -65,6 +89,11 @@ alpha_osf1_init_abi (struct gdbarch_info info,
      instead.  */
   set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
 
+  /* Alpha OSF/1 inhibits execution of code on the stack.  But there is
+     no need for a dummy on the Alpha.  PUSH_ARGUMENTS takes care of all
+     argument handling and bp_call_dummy takes care of stopping the dummy.  */
+  set_gdbarch_call_dummy_address (gdbarch, alpha_call_dummy_address);
+
   tdep->skip_sigtramp_frame = alpha_osf1_skip_sigtramp_frame;
   tdep->sigcontext_addr = alpha_osf1_sigcontext_addr;
 
index ad7ca7475072d74f49d71d04d84801f5fa3c9ce3..66075279eef30b763cea729700a9e6142621daec 100644 (file)
@@ -21,6 +21,8 @@
 
 #include "defs.h"
 #include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
 #include "inferior.h"
 #include "symtab.h"
 #include "value.h"
 
 #include "alpha-tdep.h"
 
-static gdbarch_init_ftype alpha_gdbarch_init;
-
-static gdbarch_register_name_ftype alpha_register_name;
-static gdbarch_register_raw_size_ftype alpha_register_raw_size;
-static gdbarch_register_virtual_size_ftype alpha_register_virtual_size;
-static gdbarch_register_virtual_type_ftype alpha_register_virtual_type;
-static gdbarch_register_byte_ftype alpha_register_byte;
-static gdbarch_cannot_fetch_register_ftype alpha_cannot_fetch_register;
-static gdbarch_cannot_store_register_ftype alpha_cannot_store_register;
-static gdbarch_register_convertible_ftype alpha_register_convertible;
-static gdbarch_register_convert_to_virtual_ftype
-    alpha_register_convert_to_virtual;
-static gdbarch_register_convert_to_raw_ftype alpha_register_convert_to_raw;
-static gdbarch_deprecated_extract_return_value_ftype alpha_extract_return_value;
-static gdbarch_deprecated_extract_struct_value_address_ftype
-    alpha_extract_struct_value_address;
-static gdbarch_use_struct_convention_ftype alpha_use_struct_convention;
-
-static gdbarch_breakpoint_from_pc_ftype alpha_breakpoint_from_pc;
-
-static gdbarch_frame_args_address_ftype alpha_frame_args_address;
-static gdbarch_frame_locals_address_ftype alpha_frame_locals_address;
-
-static gdbarch_skip_prologue_ftype alpha_skip_prologue;
-
-static gdbarch_get_longjmp_target_ftype alpha_get_longjmp_target;
-
-struct frame_extra_info
-  {
-    alpha_extra_func_info_t proc_desc;
-    int localoff;
-    int pc_reg;
-  };
-
-/* FIXME: Some of this code should perhaps be merged with mips-tdep.c.  */
-
-/* Prototypes for local functions. */
-
-static void alpha_find_saved_regs (struct frame_info *);
-
-static alpha_extra_func_info_t push_sigtramp_desc (CORE_ADDR low_addr);
-
-static CORE_ADDR read_next_frame_reg (struct frame_info *, int);
-
-static CORE_ADDR heuristic_proc_start (CORE_ADDR);
-
-static alpha_extra_func_info_t heuristic_proc_desc (CORE_ADDR,
-                                                   CORE_ADDR,
-                                                   struct frame_info *);
-
-static alpha_extra_func_info_t find_proc_desc (CORE_ADDR,
-                                              struct frame_info *);
-
-#if 0
-static int alpha_in_lenient_prologue (CORE_ADDR, CORE_ADDR);
-#endif
-
-static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *);
-
-static CORE_ADDR after_prologue (CORE_ADDR pc,
-                                alpha_extra_func_info_t proc_desc);
-
-static int alpha_in_prologue (CORE_ADDR pc,
-                             alpha_extra_func_info_t proc_desc);
-
-static int alpha_about_to_return (CORE_ADDR pc);
-
-void _initialize_alpha_tdep (void);
-
-/* Heuristic_proc_start may hunt through the text section for a long
-   time across a 2400 baud serial line.  Allows the user to limit this
-   search.  */
-static unsigned int heuristic_fence_post = 0;
-/* *INDENT-OFF* */
-/* Layout of a stack frame on the alpha:
-
-                |                              |
- pdr members:  |  7th ... nth arg,             |
-                |  `pushed' by caller.         |
-                |                              |
-----------------|-------------------------------|<--  old_sp == vfp
-   ^  ^  ^  ^  |                               |
-   |  |  |  |  |                               |
-   |  |localoff        |  Copies of 1st .. 6th         |
-   |  |  |  |  |  argument if necessary.       |
-   |  |  |  v  |                               |
-   |  |  |  ---        |-------------------------------|<-- FRAME_LOCALS_ADDRESS
-   |  |  |      |                              |
-   |  |  |      |  Locals and temporaries.     |
-   |  |  |      |                              |
-   |  |  |      |-------------------------------|
-   |  |  |      |                              |
-   |-fregoffset        |  Saved float registers.       |
-   |  |  |      |  F9                          |
-   |  |  |      |   .                          |
-   |  |  |      |   .                          |
-   |  |  |      |  F2                          |
-   |  |  v      |                              |
-   |  |  -------|-------------------------------|
-   |  |         |                              |
-   |  |         |  Saved registers.            |
-   |  |         |  S6                          |
-   |-regoffset |   .                           |
-   |  |         |   .                          |
-   |  |         |  S0                          |
-   |  |         |  pdr.pcreg                   |
-   |  v         |                              |
-   |  ----------|-------------------------------|
-   |            |                              |
- frameoffset    |  Argument build area, gets   |
-   |            |  7th ... nth arg for any     |
-   |            |  called procedure.           |
-   v            |                              |
-   -------------|-------------------------------|<-- sp
-                |                              |
-*/
-/* *INDENT-ON* */
-
-#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr)  /* least address */
-/* These next two fields are kind of being hijacked.  I wonder if
-   iline is too small for the values it needs to hold, if GDB is
-   running on a 32-bit host.  */
-#define PROC_HIGH_ADDR(proc) ((proc)->pdr.iline)       /* upper address bound */
-#define PROC_DUMMY_FRAME(proc) ((proc)->pdr.cbLineOffset)      /*CALL_DUMMY frame */
-#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset)
-#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg)
-#define PROC_REG_MASK(proc) ((proc)->pdr.regmask)
-#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask)
-#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)
-#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)
-#define PROC_PC_REG(proc) ((proc)->pdr.pcreg)
-#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff)
-#define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym)
-#define _PROC_MAGIC_ 0x0F0F0F0F
-#define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_)
-#define SET_PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym = _PROC_MAGIC_)
-
-struct linked_proc_info
-  {
-    struct alpha_extra_func_info info;
-    struct linked_proc_info *next;
-  }
- *linked_proc_desc_table = NULL;
-\f
-static CORE_ADDR
-alpha_frame_past_sigtramp_frame (struct frame_info *frame, CORE_ADDR pc)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
-  if (tdep->skip_sigtramp_frame != NULL)
-    return (tdep->skip_sigtramp_frame (frame, pc));
-
-  return (0);
-}
-
-static LONGEST
-alpha_dynamic_sigtramp_offset (CORE_ADDR pc)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
-  /* Must be provided by OS/ABI variant code if supported. */
-  if (tdep->dynamic_sigtramp_offset != NULL)
-    return (tdep->dynamic_sigtramp_offset (pc));
-
-  return (-1);
-}
-
-#define ALPHA_PROC_SIGTRAMP_MAGIC 0x0e0f0f0f
-
-/* Return TRUE if the procedure descriptor PROC is a procedure
-   descriptor that refers to a dynamically generated signal
-   trampoline routine.  */
-static int
-alpha_proc_desc_is_dyn_sigtramp (struct alpha_extra_func_info *proc)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
-  if (tdep->dynamic_sigtramp_offset != NULL)
-    return (proc->pdr.isym == ALPHA_PROC_SIGTRAMP_MAGIC);
-
-  return (0);
-}
-
-static void
-alpha_set_proc_desc_is_dyn_sigtramp (struct alpha_extra_func_info *proc)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
-  if (tdep->dynamic_sigtramp_offset != NULL)
-    proc->pdr.isym = ALPHA_PROC_SIGTRAMP_MAGIC;
-}
-
-/* Dynamically create a signal-handler caller procedure descriptor for
-   the signal-handler return code starting at address LOW_ADDR.  The
-   descriptor is added to the linked_proc_desc_table.  */
-
-static alpha_extra_func_info_t
-push_sigtramp_desc (CORE_ADDR low_addr)
-{
-  struct linked_proc_info *link;
-  alpha_extra_func_info_t proc_desc;
-
-  link = (struct linked_proc_info *)
-    xmalloc (sizeof (struct linked_proc_info));
-  link->next = linked_proc_desc_table;
-  linked_proc_desc_table = link;
-
-  proc_desc = &link->info;
-
-  proc_desc->numargs = 0;
-  PROC_LOW_ADDR (proc_desc) = low_addr;
-  PROC_HIGH_ADDR (proc_desc) = low_addr + 3 * 4;
-  PROC_DUMMY_FRAME (proc_desc) = 0;
-  PROC_FRAME_OFFSET (proc_desc) = 0x298;       /* sizeof(struct sigcontext_struct) */
-  PROC_FRAME_REG (proc_desc) = SP_REGNUM;
-  PROC_REG_MASK (proc_desc) = 0xffff;
-  PROC_FREG_MASK (proc_desc) = 0xffff;
-  PROC_PC_REG (proc_desc) = 26;
-  PROC_LOCALOFF (proc_desc) = 0;
-  alpha_set_proc_desc_is_dyn_sigtramp (proc_desc);
-  return (proc_desc);
-}
 \f
-
 static const char *
 alpha_register_name (int regno)
 {
@@ -291,13 +70,13 @@ alpha_register_name (int regno)
 static int
 alpha_cannot_fetch_register (int regno)
 {
-  return (regno == DEPRECATED_FP_REGNUM || regno == ALPHA_ZERO_REGNUM);
+  return (regno == ALPHA_FP_REGNUM || regno == ALPHA_ZERO_REGNUM);
 }
 
 static int
 alpha_cannot_store_register (int regno)
 {
-  return (regno == DEPRECATED_FP_REGNUM || regno == ALPHA_ZERO_REGNUM);
+  return (regno == ALPHA_FP_REGNUM || regno == ALPHA_ZERO_REGNUM);
 }
 
 static int
@@ -330,1228 +109,868 @@ alpha_register_virtual_size (int regno)
 {
   return 8;
 }
-\f
 
-static CORE_ADDR
-alpha_sigcontext_addr (struct frame_info *fi)
+/* The alpha needs a conversion between register and memory format if the
+   register is a floating point register and memory format is float, as the
+   register format must be double or memory format is an integer with 4
+   bytes or less, as the representation of integers in floating point
+   registers is different. */
+
+static void
+alpha_register_convert_to_virtual (int regnum, struct type *valtype,
+                                  char *raw_buffer, char *virtual_buffer)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
+    {
+      memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
+      return;
+    }
+
+  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+    {
+      double d = deprecated_extract_floating (raw_buffer, REGISTER_RAW_SIZE (regnum));
+      deprecated_store_floating (virtual_buffer, TYPE_LENGTH (valtype), d);
+    }
+  else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
+    {
+      ULONGEST l;
+      l = extract_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum));
+      l = ((l >> 32) & 0xc0000000) | ((l >> 29) & 0x3fffffff);
+      store_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype), l);
+    }
+  else
+    error ("Cannot retrieve value from floating point register");
+}
 
-  if (tdep->sigcontext_addr)
-    return (tdep->sigcontext_addr (fi));
+static void
+alpha_register_convert_to_raw (struct type *valtype, int regnum,
+                              char *virtual_buffer, char *raw_buffer)
+{
+  if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
+    {
+      memcpy (raw_buffer, virtual_buffer, REGISTER_RAW_SIZE (regnum));
+      return;
+    }
 
-  return (0);
+  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+    {
+      double d = deprecated_extract_floating (virtual_buffer, TYPE_LENGTH (valtype));
+      deprecated_store_floating (raw_buffer, REGISTER_RAW_SIZE (regnum), d);
+    }
+  else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
+    {
+      ULONGEST l;
+      if (TYPE_UNSIGNED (valtype))
+       l = extract_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype));
+      else
+       l = extract_signed_integer (virtual_buffer, TYPE_LENGTH (valtype));
+      l = ((l & 0xc0000000) << 32) | ((l & 0x3fffffff) << 29);
+      store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), l);
+    }
+  else
+    error ("Cannot store value in floating point register");
 }
 
-/* Guaranteed to set frame->saved_regs to some values (it never leaves it
-   NULL).  */
+\f
+/* The alpha passes the first six arguments in the registers, the rest on
+   the stack. The register arguments are eventually transferred to the
+   argument transfer area immediately below the stack by the called function
+   anyway. So we `push' at least six arguments on the stack, `reload' the
+   argument registers and then adjust the stack pointer to point past the
+   sixth argument. This algorithm simplifies the passing of a large struct
+   which extends from the registers to the stack.
+   If the called function is returning a structure, the address of the
+   structure to be returned is passed as a hidden first argument.  */
 
-static void
-alpha_find_saved_regs (struct frame_info *frame)
+static CORE_ADDR
+alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+                     int struct_return, CORE_ADDR struct_addr)
 {
-  int ireg;
-  CORE_ADDR reg_position;
-  unsigned long mask;
-  alpha_extra_func_info_t proc_desc;
-  int returnreg;
-
-  frame_saved_regs_zalloc (frame);
-
-  /* If it is the frame for __sigtramp, the saved registers are located
-     in a sigcontext structure somewhere on the stack. __sigtramp
-     passes a pointer to the sigcontext structure on the stack.
-     If the stack layout for __sigtramp changes, or if sigcontext offsets
-     change, we might have to update this code.  */
-#ifndef SIGFRAME_PC_OFF
-#define SIGFRAME_PC_OFF                (2 * 8)
-#define SIGFRAME_REGSAVE_OFF   (4 * 8)
-#define SIGFRAME_FPREGSAVE_OFF (SIGFRAME_REGSAVE_OFF + 32 * 8 + 8)
-#endif
-  if ((get_frame_type (frame) == SIGTRAMP_FRAME))
+  int i;
+  int accumulate_size = struct_return ? 8 : 0;
+  int arg_regs_size = ALPHA_NUM_ARG_REGS * 8;
+  struct alpha_arg
     {
-      CORE_ADDR sigcontext_addr;
+      char *contents;
+      int len;
+      int offset;
+    };
+  struct alpha_arg *alpha_args =
+  (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
+  register struct alpha_arg *m_arg;
+  char raw_buffer[ALPHA_REGISTER_BYTES];
+  int required_arg_regs;
 
-      sigcontext_addr = alpha_sigcontext_addr (frame);
-      if (sigcontext_addr == 0)
-       {
-         /* Don't know where the sigcontext is; just bail.  */
-         return;
-       }
-      for (ireg = 0; ireg < 32; ireg++)
-       {
-         reg_position = sigcontext_addr + SIGFRAME_REGSAVE_OFF + ireg * 8;
-         get_frame_saved_regs (frame)[ireg] = reg_position;
-       }
-      for (ireg = 0; ireg < 32; ireg++)
+  for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++)
+    {
+      struct value *arg = args[i];
+      struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+      /* Cast argument to long if necessary as the compiler does it too.  */
+      switch (TYPE_CODE (arg_type))
        {
-         reg_position = sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + ireg * 8;
-         get_frame_saved_regs (frame)[FP0_REGNUM + ireg] = reg_position;
+       case TYPE_CODE_INT:
+       case TYPE_CODE_BOOL:
+       case TYPE_CODE_CHAR:
+       case TYPE_CODE_RANGE:
+       case TYPE_CODE_ENUM:
+         if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long))
+           {
+             arg_type = builtin_type_long;
+             arg = value_cast (arg_type, arg);
+           }
+         break;
+       default:
+         break;
        }
-      get_frame_saved_regs (frame)[PC_REGNUM] = sigcontext_addr + SIGFRAME_PC_OFF;
-      return;
+      m_arg->len = TYPE_LENGTH (arg_type);
+      m_arg->offset = accumulate_size;
+      accumulate_size = (accumulate_size + m_arg->len + 7) & ~7;
+      m_arg->contents = VALUE_CONTENTS (arg);
     }
 
-  proc_desc = get_frame_extra_info (frame)->proc_desc;
-  if (proc_desc == NULL)
-    /* I'm not sure how/whether this can happen.  Normally when we can't
-       find a proc_desc, we "synthesize" one using heuristic_proc_desc
-       and set the saved_regs right away.  */
-    return;
-
-  /* Fill in the offsets for the registers which gen_mask says
-     were saved.  */
+  /* Determine required argument register loads, loading an argument register
+     is expensive as it uses three ptrace calls.  */
+  required_arg_regs = accumulate_size / 8;
+  if (required_arg_regs > ALPHA_NUM_ARG_REGS)
+    required_arg_regs = ALPHA_NUM_ARG_REGS;
 
-  reg_position = get_frame_base (frame) + PROC_REG_OFFSET (proc_desc);
-  mask = PROC_REG_MASK (proc_desc);
+  /* Make room for the arguments on the stack.  */
+  if (accumulate_size < arg_regs_size)
+    accumulate_size = arg_regs_size;
+  sp -= accumulate_size;
 
-  returnreg = PROC_PC_REG (proc_desc);
+  /* Keep sp aligned to a multiple of 16 as the compiler does it too.  */
+  sp &= ~15;
 
-  /* Note that RA is always saved first, regardless of its actual
-     register number.  */
-  if (mask & (1 << returnreg))
+  /* `Push' arguments on the stack.  */
+  for (i = nargs; m_arg--, --i >= 0;)
+    write_memory (sp + m_arg->offset, m_arg->contents, m_arg->len);
+  if (struct_return)
     {
-      get_frame_saved_regs (frame)[returnreg] = reg_position;
-      reg_position += 8;
-      mask &= ~(1 << returnreg);       /* Clear bit for RA so we
-                                          don't save again later. */
+      store_unsigned_integer (raw_buffer, ALPHA_REGISTER_BYTES, struct_addr);
+      write_memory (sp, raw_buffer, ALPHA_REGISTER_BYTES);
     }
 
-  for (ireg = 0; ireg <= 31; ++ireg)
-    if (mask & (1 << ireg))
-      {
-       get_frame_saved_regs (frame)[ireg] = reg_position;
-       reg_position += 8;
-      }
-
-  /* Fill in the offsets for the registers which float_mask says
-     were saved.  */
-
-  reg_position = get_frame_base (frame) + PROC_FREG_OFFSET (proc_desc);
-  mask = PROC_FREG_MASK (proc_desc);
+  /* Load the argument registers.  */
+  for (i = 0; i < required_arg_regs; i++)
+    {
+      LONGEST val;
 
-  for (ireg = 0; ireg <= 31; ++ireg)
-    if (mask & (1 << ireg))
-      {
-       get_frame_saved_regs (frame)[FP0_REGNUM + ireg] = reg_position;
-       reg_position += 8;
-      }
+      val = read_memory_integer (sp + i * 8, ALPHA_REGISTER_BYTES);
+      write_register (ALPHA_A0_REGNUM + i, val);
+      write_register (ALPHA_FPA0_REGNUM + i, val);
+    }
 
-  get_frame_saved_regs (frame)[PC_REGNUM] = get_frame_saved_regs (frame)[returnreg];
+  return sp + arg_regs_size;
 }
 
+/* Given a return value in `regbuf' with a type `valtype', 
+   extract and copy its value into `valbuf'.  */
+
 static void
-alpha_frame_init_saved_regs (struct frame_info *fi)
+alpha_extract_return_value (struct type *valtype,
+                           char regbuf[ALPHA_REGISTER_BYTES], char *valbuf)
 {
-  if (get_frame_saved_regs (fi) == NULL)
-    alpha_find_saved_regs (fi);
-  get_frame_saved_regs (fi)[SP_REGNUM] = get_frame_base (fi);
+  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+    alpha_register_convert_to_virtual (FP0_REGNUM, valtype,
+                                      regbuf + REGISTER_BYTE (FP0_REGNUM),
+                                      valbuf);
+  else
+    memcpy (valbuf, regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
+            TYPE_LENGTH (valtype));
 }
 
-static CORE_ADDR
-alpha_init_frame_pc_first (int fromleaf, struct frame_info *prev)
-{
-  return (fromleaf
-         ? DEPRECATED_SAVED_PC_AFTER_CALL (get_next_frame (prev)) 
-         : get_next_frame (prev)
-         ? DEPRECATED_FRAME_SAVED_PC (get_next_frame (prev))
-         : read_pc ());
-}
+/* Given a return value in `regbuf' with a type `valtype', 
+   write its value into the appropriate register.  */
 
-static CORE_ADDR
-read_next_frame_reg (struct frame_info *fi, int regno)
+static void
+alpha_store_return_value (struct type *valtype, char *valbuf)
 {
-  for (; fi; fi = get_next_frame (fi))
+  char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
+  int regnum = ALPHA_V0_REGNUM;
+  int length = TYPE_LENGTH (valtype);
+
+  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
     {
-      /* We have to get the saved sp from the sigcontext
-         if it is a signal handler frame.  */
-      if (regno == SP_REGNUM && !(get_frame_type (fi) == SIGTRAMP_FRAME))
-       return get_frame_base (fi);
-      else
-       {
-         if (get_frame_saved_regs (fi) == NULL)
-           alpha_find_saved_regs (fi);
-         if (get_frame_saved_regs (fi)[regno])
-           return read_memory_integer (get_frame_saved_regs (fi)[regno], 8);
-       }
+      regnum = FP0_REGNUM;
+      length = REGISTER_RAW_SIZE (regnum);
+      alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer);
     }
-  return read_register (regno);
+  else
+    memcpy (raw_buffer, valbuf, length);
+
+  deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length);
 }
 
-static CORE_ADDR
-alpha_frame_saved_pc (struct frame_info *frame)
+static int
+alpha_use_struct_convention (int gcc_p, struct type *type)
 {
-  alpha_extra_func_info_t proc_desc = get_frame_extra_info (frame)->proc_desc;
-  /* We have to get the saved pc from the sigcontext
-     if it is a signal handler frame.  */
-  int pcreg = ((get_frame_type (frame) == SIGTRAMP_FRAME)
-              ? PC_REGNUM
-              : get_frame_extra_info (frame)->pc_reg);
-
-  if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc))
-    return read_memory_integer  (get_frame_base (frame) - 8, 8);
+  /* Structures are returned by ref in extra arg0.  */
+  return 1;
+}
 
-  return read_next_frame_reg (frame, pcreg);
+static void
+alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+  /* Store the address of the place in which to copy the structure the
+     subroutine will return.  Handled by alpha_push_arguments.  */
 }
 
 static CORE_ADDR
-alpha_saved_pc_after_call (struct frame_info *frame)
+alpha_extract_struct_value_address (char *regbuf)
 {
-  CORE_ADDR pc = get_frame_pc (frame);
-  CORE_ADDR tmp;
-  alpha_extra_func_info_t proc_desc;
-  int pcreg;
-
-  /* Skip over shared library trampoline if necessary.  */
-  tmp = SKIP_TRAMPOLINE_CODE (pc);
-  if (tmp != 0)
-    pc = tmp;
-
-  proc_desc = find_proc_desc (pc, get_next_frame (frame));
-  pcreg = proc_desc ? PROC_PC_REG (proc_desc) : ALPHA_RA_REGNUM;
-
-  if ((get_frame_type (frame) == SIGTRAMP_FRAME))
-    return alpha_frame_saved_pc (frame);
-  else
-    return read_register (pcreg);
+  return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
+                          REGISTER_RAW_SIZE (ALPHA_V0_REGNUM)));
 }
 
-
-static struct alpha_extra_func_info temp_proc_desc;
-static CORE_ADDR temp_saved_regs[ALPHA_NUM_REGS];
-
-/* Nonzero if instruction at PC is a return instruction.  "ret
-   $zero,($ra),1" on alpha. */
-
-static int
-alpha_about_to_return (CORE_ADDR pc)
+\f
+static const unsigned char *
+alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
 {
-  return read_memory_integer (pc, 4) == 0x6bfa8001;
-}
-
+  static const unsigned char alpha_breakpoint[] =
+    { 0x80, 0, 0, 0 }; /* call_pal bpt */
 
+  *lenptr = sizeof(alpha_breakpoint);
+  return (alpha_breakpoint);
+}
 
-/* This fencepost looks highly suspicious to me.  Removing it also
-   seems suspicious as it could affect remote debugging across serial
-   lines.  */
+\f
+/* This returns the PC of the first insn after the prologue.
+   If we can't find the prologue, then return 0.  */
 
-static CORE_ADDR
-heuristic_proc_start (CORE_ADDR pc)
+CORE_ADDR
+alpha_after_prologue (CORE_ADDR pc)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-  CORE_ADDR start_pc = pc;
-  CORE_ADDR fence = start_pc - heuristic_fence_post;
+  struct symtab_and_line sal;
+  CORE_ADDR func_addr, func_end;
 
-  if (start_pc == 0)
+  if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
     return 0;
 
-  if (heuristic_fence_post == UINT_MAX
-      || fence < tdep->vm_min_address)
-    fence = tdep->vm_min_address;
-
-  /* search back for previous return */
-  for (start_pc -= 4;; start_pc -= 4)
-    if (start_pc < fence)
-      {
-       /* It's not clear to me why we reach this point when
-          stop_soon, but with this test, at least we
-          don't print out warnings for every child forked (eg, on
-          decstation).  22apr93 rich@cygnus.com.  */
-       if (stop_soon == NO_STOP_QUIETLY)
-         {
-           static int blurb_printed = 0;
-
-           if (fence == tdep->vm_min_address)
-             warning ("Hit beginning of text section without finding");
-           else
-             warning ("Hit heuristic-fence-post without finding");
-
-           warning ("enclosing function for address 0x%s", paddr_nz (pc));
-           if (!blurb_printed)
-             {
-               printf_filtered ("\
-This warning occurs if you are debugging a function without any symbols\n\
-(for example, in a stripped executable).  In that case, you may wish to\n\
-increase the size of the search with the `set heuristic-fence-post' command.\n\
-\n\
-Otherwise, you told GDB there was a function where there isn't one, or\n\
-(more likely) you have encountered a bug in GDB.\n");
-               blurb_printed = 1;
-             }
-         }
-
-       return 0;
-      }
-    else if (alpha_about_to_return (start_pc))
-      break;
+  sal = find_pc_line (func_addr, 0);
+  if (sal.end < func_end)
+    return sal.end;
 
-  start_pc += 4;               /* skip return */
-  return start_pc;
+  /* The line after the prologue is after the end of the function.  In this
+     case, tell the caller to find the prologue the hard way.  */
+  return 0;
 }
 
-static alpha_extra_func_info_t
-heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc,
-                    struct frame_info *next_frame)
+/* Read an instruction from memory at PC, looking through breakpoints.  */
+
+unsigned int
+alpha_read_insn (CORE_ADDR pc)
 {
-  CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM);
-  CORE_ADDR vfp = sp;
-  CORE_ADDR cur_pc;
-  int frame_size;
-  int has_frame_reg = 0;
-  unsigned long reg_mask = 0;
-  int pcreg = -1;
-  int regno;
+  char buf[4];
+  int status;
 
-  if (start_pc == 0)
-    return NULL;
-  memset (&temp_proc_desc, '\0', sizeof (temp_proc_desc));
-  memset (&temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS);
-  PROC_LOW_ADDR (&temp_proc_desc) = start_pc;
+  status = read_memory_nobpt (pc, buf, 4);
+  if (status)
+    memory_error (status, pc);
+  return extract_unsigned_integer (buf, 4);
+}
 
-  if (start_pc + 200 < limit_pc)
-    limit_pc = start_pc + 200;
-  frame_size = 0;
-  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
-    {
-      char buf[4];
-      unsigned long word;
-      int status;
+/* To skip prologues, I use this predicate.  Returns either PC itself
+   if the code at PC does not look like a function prologue; otherwise
+   returns an address that (if we're lucky) follows the prologue.  If
+   LENIENT, then we must skip everything which is involved in setting
+   up the frame (it's OK to skip more, just so long as we don't skip
+   anything which might clobber the registers which are being saved.  */
 
-      status = read_memory_nobpt (cur_pc, buf, 4);
-      if (status)
-       memory_error (status, cur_pc);
-      word = extract_unsigned_integer (buf, 4);
+static CORE_ADDR
+alpha_skip_prologue (CORE_ADDR pc)
+{
+  unsigned long inst;
+  int offset;
+  CORE_ADDR post_prologue_pc;
+  char buf[4];
 
-      if ((word & 0xffff0000) == 0x23de0000)   /* lda $sp,n($sp) */
-       {
-         if (word & 0x8000)
-          {
-            /* Consider only the first stack allocation instruction
-               to contain the static size of the frame. */
-            if (frame_size == 0)
-               frame_size += (-word) & 0xffff;
-          }
-         else
-           /* Exit loop if a positive stack adjustment is found, which
-              usually means that the stack cleanup code in the function
-              epilogue is reached.  */
-           break;
-       }
-      else if ((word & 0xfc1f0000) == 0xb41e0000       /* stq reg,n($sp) */
-              && (word & 0xffff0000) != 0xb7fe0000)    /* reg != $zero */
-       {
-         int reg = (word & 0x03e00000) >> 21;
-         reg_mask |= 1 << reg;
-
-          /* Do not compute the address where the register was saved yet,
-             because we don't know yet if the offset will need to be
-             relative to $sp or $fp (we can not compute the address relative
-             to $sp if $sp is updated during the execution of the current
-             subroutine, for instance when doing some alloca). So just store
-             the offset for the moment, and compute the address later
-             when we know whether this frame has a frame pointer or not.
-           */
-          temp_saved_regs[reg] = (short) word;
-
-         /* Starting with OSF/1-3.2C, the system libraries are shipped
-            without local symbols, but they still contain procedure
-            descriptors without a symbol reference. GDB is currently
-            unable to find these procedure descriptors and uses
-            heuristic_proc_desc instead.
-            As some low level compiler support routines (__div*, __add*)
-            use a non-standard return address register, we have to
-            add some heuristics to determine the return address register,
-            or stepping over these routines will fail.
-            Usually the return address register is the first register
-            saved on the stack, but assembler optimization might
-            rearrange the register saves.
-            So we recognize only a few registers (t7, t9, ra) within
-            the procedure prologue as valid return address registers.
-            If we encounter a return instruction, we extract the
-            the return address register from it.
-
-            FIXME: Rewriting GDB to access the procedure descriptors,
-            e.g. via the minimal symbol table, might obviate this hack.  */
-         if (pcreg == -1
-             && cur_pc < (start_pc + 80)
-             && (reg == ALPHA_T7_REGNUM || reg == ALPHA_T9_REGNUM
-                 || reg == ALPHA_RA_REGNUM))
-           pcreg = reg;
-       }
-      else if ((word & 0xffe0ffff) == 0x6be08001)      /* ret zero,reg,1 */
-       pcreg = (word >> 16) & 0x1f;
-      else if (word == 0x47de040f || word == 0x47fe040f) /* bis sp,sp fp */
-        {
-          /* ??? I am not sure what instruction is 0x47fe040f, and I
-             am suspecting that there was a typo and should have been
-             0x47fe040f. I'm keeping it in the test above until further
-             investigation */
-           has_frame_reg = 1;
-          vfp = read_next_frame_reg (next_frame, ALPHA_GCC_FP_REGNUM);
-        }
-    }
-  if (pcreg == -1)
-    {
-      /* If we haven't found a valid return address register yet,
-         keep searching in the procedure prologue.  */
-      while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80))
-       {
-         char buf[4];
-         unsigned long word;
+  /* Silently return the unaltered pc upon memory errors.
+     This could happen on OSF/1 if decode_line_1 tries to skip the
+     prologue for quickstarted shared library functions when the
+     shared library is not yet mapped in.
+     Reading target memory is slow over serial lines, so we perform
+     this check only if the target has shared libraries (which all
+     Alpha targets do).  */
+  if (target_read_memory (pc, buf, 4))
+    return pc;
 
-         if (read_memory_nobpt (cur_pc, buf, 4))
-           break;
-         cur_pc += 4;
-         word = extract_unsigned_integer (buf, 4);
+  /* See if we can determine the end of the prologue via the symbol table.
+     If so, then return either PC, or the PC after the prologue, whichever
+     is greater.  */
 
-         if ((word & 0xfc1f0000) == 0xb41e0000         /* stq reg,n($sp) */
-             && (word & 0xffff0000) != 0xb7fe0000)     /* reg != $zero */
-           {
-             int reg = (word & 0x03e00000) >> 21;
-             if (reg == ALPHA_T7_REGNUM || reg == ALPHA_T9_REGNUM
-                 || reg == ALPHA_RA_REGNUM)
-               {
-                 pcreg = reg;
-                 break;
-               }
-           }
-         else if ((word & 0xffe0ffff) == 0x6be08001)   /* ret zero,reg,1 */
-           {
-             pcreg = (word >> 16) & 0x1f;
-             break;
-           }
-       }
-    }
+  post_prologue_pc = alpha_after_prologue (pc);
+  if (post_prologue_pc != 0)
+    return max (pc, post_prologue_pc);
 
-  if (has_frame_reg)
-    PROC_FRAME_REG (&temp_proc_desc) = ALPHA_GCC_FP_REGNUM;
-  else
-    PROC_FRAME_REG (&temp_proc_desc) = SP_REGNUM;
-
-  /* At this point, we know which of the Stack Pointer or the Frame Pointer
-     to use as the reference address to compute the saved registers address.
-     But in both cases, the processing above has set vfp to this reference
-     address, so just need to increment the offset of each saved register
-     by this address. */
-  for (regno = 0; regno < NUM_REGS; regno++)
-    {
-      if (reg_mask & 1 << regno)
-       temp_saved_regs[regno] += vfp;
-    }
+  /* Can't determine prologue from the symbol table, need to examine
+     instructions.  */
 
-  PROC_FRAME_OFFSET (&temp_proc_desc) = frame_size;
-  PROC_REG_MASK (&temp_proc_desc) = reg_mask;
-  PROC_PC_REG (&temp_proc_desc) = (pcreg == -1) ? ALPHA_RA_REGNUM : pcreg;
-  PROC_LOCALOFF (&temp_proc_desc) = 0; /* XXX - bogus */
-  return &temp_proc_desc;
-}
+  /* Skip the typical prologue instructions. These are the stack adjustment
+     instruction and the instructions that save registers on the stack
+     or in the gcc frame.  */
+  for (offset = 0; offset < 100; offset += 4)
+    {
+      inst = alpha_read_insn (pc + offset);
 
-/* This returns the PC of the first inst after the prologue.  If we can't
-   find the prologue, then return 0.  */
+      if ((inst & 0xffff0000) == 0x27bb0000)   /* ldah $gp,n($t12) */
+       continue;
+      if ((inst & 0xffff0000) == 0x23bd0000)   /* lda $gp,n($gp) */
+       continue;
+      if ((inst & 0xffff0000) == 0x23de0000)   /* lda $sp,n($sp) */
+       continue;
+      if ((inst & 0xffe01fff) == 0x43c0153e)   /* subq $sp,n,$sp */
+       continue;
 
-static CORE_ADDR
-after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
-{
-  struct symtab_and_line sal;
-  CORE_ADDR func_addr, func_end;
+      if (((inst & 0xfc1f0000) == 0xb41e0000           /* stq reg,n($sp) */
+          || (inst & 0xfc1f0000) == 0x9c1e0000)        /* stt reg,n($sp) */
+         && (inst & 0x03e00000) != 0x03e00000)         /* reg != $zero */
+       continue;
 
-  if (!proc_desc)
-    proc_desc = find_proc_desc (pc, NULL);
+      if (inst == 0x47de040f)                  /* bis sp,sp,fp */
+       continue;
+      if (inst == 0x47fe040f)                  /* bis zero,sp,fp */
+       continue;
 
-  if (proc_desc)
-    {
-      if (alpha_proc_desc_is_dyn_sigtramp (proc_desc))
-       return PROC_LOW_ADDR (proc_desc);       /* "prologue" is in kernel */
-
-      /* If function is frameless, then we need to do it the hard way.  I
-         strongly suspect that frameless always means prologueless... */
-      if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
-         && PROC_FRAME_OFFSET (proc_desc) == 0)
-       return 0;
+      break;
     }
+  return pc + offset;
+}
 
-  if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
-    return 0;                  /* Unknown */
-
-  sal = find_pc_line (func_addr, 0);
-
-  if (sal.end < func_end)
-    return sal.end;
+\f
+/* Construct an inferior call to FUN.  For Alpha this is as simple as
+   initializing the RA and T12 registers; everything else is set up by
+   generic code.  */
 
-  /* The line after the prologue is after the end of the function.  In this
-     case, tell the caller to find the prologue the hard way.  */
+static void
+alpha_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+                      struct value **args, struct type *type, int gcc_p)
+{
+  CORE_ADDR bp_address = CALL_DUMMY_ADDRESS ();
 
-  return 0;
+  if (bp_address == 0)
+    error ("no place to put call");
+  write_register (ALPHA_RA_REGNUM, bp_address);
+  write_register (ALPHA_T12_REGNUM, fun);
 }
 
-/* Return non-zero if we *might* be in a function prologue.  Return zero if we
-   are definitively *not* in a function prologue.  */
+/* On the Alpha, the call dummy code is never copied to user space
+   (see alpha_fix_call_dummy() above).  The contents of this do not
+   matter.  */
+LONGEST alpha_call_dummy_words[] = { 0 };
+
+\f
+/* Figure out where the longjmp will land.
+   We expect the first arg to be a pointer to the jmp_buf structure from
+   which we extract the PC (JB_PC) that we will land at.  The PC is copied
+   into the "pc".  This routine returns true on success.  */
 
 static int
-alpha_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
+alpha_get_longjmp_target (CORE_ADDR *pc)
 {
-  CORE_ADDR after_prologue_pc;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  CORE_ADDR jb_addr;
+  char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
 
-  after_prologue_pc = after_prologue (pc, proc_desc);
+  jb_addr = read_register (ALPHA_A0_REGNUM);
 
-  if (after_prologue_pc == 0
-      || pc < after_prologue_pc)
-    return 1;
-  else
+  if (target_read_memory (jb_addr + (tdep->jb_pc * tdep->jb_elt_size),
+                         raw_buffer, tdep->jb_elt_size))
     return 0;
+
+  *pc = extract_address (raw_buffer, tdep->jb_elt_size);
+  return 1;
 }
 
-static alpha_extra_func_info_t
-find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame)
+\f
+/* Frame unwinder for signal trampolines.  We use alpha tdep bits that
+   describe the location and shape of the sigcontext structure.  After
+   that, all registers are in memory, so it's easy.  */
+/* ??? Shouldn't we be able to do this generically, rather than with
+   OSABI data specific to Alpha?  */
+
+struct alpha_sigtramp_unwind_cache
 {
-  alpha_extra_func_info_t proc_desc;
-  struct block *b;
-  struct symbol *sym;
-  CORE_ADDR startaddr;
-
-  /* Try to get the proc_desc from the linked call dummy proc_descs
-     if the pc is in the call dummy.
-     This is hairy. In the case of nested dummy calls we have to find the
-     right proc_desc, but we might not yet know the frame for the dummy
-     as it will be contained in the proc_desc we are searching for.
-     So we have to find the proc_desc whose frame is closest to the current
-     stack pointer.  */
-
-  if (DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
-    {
-      struct linked_proc_info *link;
-      CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM);
-      alpha_extra_func_info_t found_proc_desc = NULL;
-      long min_distance = LONG_MAX;
+  CORE_ADDR sigcontext_addr;
+};
 
-      for (link = linked_proc_desc_table; link; link = link->next)
-       {
-         long distance = (CORE_ADDR) PROC_DUMMY_FRAME (&link->info) - sp;
-         if (distance > 0 && distance < min_distance)
-           {
-             min_distance = distance;
-             found_proc_desc = &link->info;
-           }
-       }
-      if (found_proc_desc != NULL)
-       return found_proc_desc;
-    }
+static struct alpha_sigtramp_unwind_cache *
+alpha_sigtramp_frame_unwind_cache (struct frame_info *next_frame,
+                                  void **this_prologue_cache)
+{
+  struct alpha_sigtramp_unwind_cache *info;
+  struct gdbarch_tdep *tdep;
 
-  b = block_for_pc (pc);
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
 
-  find_pc_partial_function (pc, NULL, &startaddr, NULL);
-  if (b == NULL)
-    sym = NULL;
-  else
-    {
-      if (startaddr > BLOCK_START (b))
-       /* This is the "pathological" case referred to in a comment in
-          print_frame_info.  It might be better to move this check into
-          symbol reading.  */
-       sym = NULL;
-      else
-       sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_DOMAIN,
-                            0, NULL);
-    }
+  info = FRAME_OBSTACK_ZALLOC (struct alpha_sigtramp_unwind_cache);
+  *this_prologue_cache = info;
 
-  /* If we never found a PDR for this function in symbol reading, then
-     examine prologues to find the information.  */
-  if (sym && ((mips_extra_func_info_t) SYMBOL_VALUE (sym))->pdr.framereg == -1)
-    sym = NULL;
+  tdep = gdbarch_tdep (current_gdbarch);
+  info->sigcontext_addr = tdep->sigcontext_addr (next_frame);
 
-  if (sym)
-    {
-      /* IF this is the topmost frame AND
-       * (this proc does not have debugging information OR
-       * the PC is in the procedure prologue)
-       * THEN create a "heuristic" proc_desc (by analyzing
-       * the actual code) to replace the "official" proc_desc.
-       */
-      proc_desc = (alpha_extra_func_info_t) SYMBOL_VALUE (sym);
-      if (next_frame == NULL)
-       {
-         if (PROC_DESC_IS_DUMMY (proc_desc) || alpha_in_prologue (pc, proc_desc))
-           {
-             alpha_extra_func_info_t found_heuristic =
-             heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
-                                  pc, next_frame);
-             if (found_heuristic)
-               {
-                 PROC_LOCALOFF (found_heuristic) =
-                   PROC_LOCALOFF (proc_desc);
-                 PROC_PC_REG (found_heuristic) = PROC_PC_REG (proc_desc);
-                 proc_desc = found_heuristic;
-               }
-           }
-       }
-    }
-  else
-    {
-      long offset;
-
-      /* Is linked_proc_desc_table really necessary?  It only seems to be used
-         by procedure call dummys.  However, the procedures being called ought
-         to have their own proc_descs, and even if they don't,
-         heuristic_proc_desc knows how to create them! */
-
-      register struct linked_proc_info *link;
-      for (link = linked_proc_desc_table; link; link = link->next)
-       if (PROC_LOW_ADDR (&link->info) <= pc
-           && PROC_HIGH_ADDR (&link->info) > pc)
-         return &link->info;
-
-      /* If PC is inside a dynamically generated sigtramp handler,
-         create and push a procedure descriptor for that code: */
-      offset = alpha_dynamic_sigtramp_offset (pc);
-      if (offset >= 0)
-       return push_sigtramp_desc (pc - offset);
-
-      /* If heuristic_fence_post is non-zero, determine the procedure
-         start address by examining the instructions.
-         This allows us to find the start address of static functions which
-         have no symbolic information, as startaddr would have been set to
-         the preceding global function start address by the
-         find_pc_partial_function call above.  */
-      if (startaddr == 0 || heuristic_fence_post != 0)
-       startaddr = heuristic_proc_start (pc);
-
-      proc_desc =
-       heuristic_proc_desc (startaddr, pc, next_frame);
-    }
-  return proc_desc;
+  return info;
 }
 
-alpha_extra_func_info_t cached_proc_desc;
-
-static CORE_ADDR
-alpha_frame_chain (struct frame_info *frame)
-{
-  alpha_extra_func_info_t proc_desc;
-  CORE_ADDR saved_pc = DEPRECATED_FRAME_SAVED_PC (frame);
+/* Return the address of REGNO in a sigtramp frame.  Since this is all
+   arithmetic, it doesn't seem worthwhile to cache it.  */
 
-  if (saved_pc == 0 || inside_entry_file (saved_pc))
-    return 0;
+#ifndef SIGFRAME_PC_OFF
+#define SIGFRAME_PC_OFF                (2 * 8)
+#define SIGFRAME_REGSAVE_OFF   (4 * 8)
+#define SIGFRAME_FPREGSAVE_OFF (SIGFRAME_REGSAVE_OFF + 32 * 8 + 8)
+#endif
 
-  proc_desc = find_proc_desc (saved_pc, frame);
-  if (!proc_desc)
-    return 0;
+static CORE_ADDR
+alpha_sigtramp_register_address (CORE_ADDR sigcontext_addr, unsigned int regno)
+{ 
+  if (regno < 32)
+    return sigcontext_addr + SIGFRAME_REGSAVE_OFF + regno * 8;
+  if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
+    return sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + regno * 8;
+  if (regno == PC_REGNUM)
+    return sigcontext_addr + SIGFRAME_PC_OFF; 
 
-  cached_proc_desc = proc_desc;
-
-  /* Fetch the frame pointer for a dummy frame from the procedure
-     descriptor.  */
-  if (PROC_DESC_IS_DUMMY (proc_desc))
-    return (CORE_ADDR) PROC_DUMMY_FRAME (proc_desc);
-
-  /* If no frame pointer and frame size is zero, we must be at end
-     of stack (or otherwise hosed).  If we don't check frame size,
-     we loop forever if we see a zero size frame.  */
-  if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
-      && PROC_FRAME_OFFSET (proc_desc) == 0
-  /* The previous frame from a sigtramp frame might be frameless
-     and have frame size zero.  */
-      && !(get_frame_type (frame) == SIGTRAMP_FRAME))
-    return alpha_frame_past_sigtramp_frame (frame, saved_pc);
-  else
-    return read_next_frame_reg (frame, PROC_FRAME_REG (proc_desc))
-      + PROC_FRAME_OFFSET (proc_desc);
+  return 0;
 }
 
-void
-alpha_print_extra_frame_info (struct frame_info *fi)
-{
-  if (fi
-      && get_frame_extra_info (fi)
-      && get_frame_extra_info (fi)->proc_desc
-      && get_frame_extra_info (fi)->proc_desc->pdr.framereg < NUM_REGS)
-    printf_filtered (" frame pointer is at %s+%s\n",
-                    REGISTER_NAME (get_frame_extra_info (fi)->proc_desc->pdr.framereg),
-                    paddr_d (get_frame_extra_info (fi)->proc_desc->pdr.frameoffset));
-}
+/* Given a GDB frame, determine the address of the calling function's
+   frame.  This will be used to create a new GDB frame struct.  */
 
 static void
-alpha_init_extra_frame_info (int fromleaf, struct frame_info *frame)
+alpha_sigtramp_frame_this_id (struct frame_info *next_frame,
+                             void **this_prologue_cache,
+                             struct frame_id *this_id)
 {
-  /* Use proc_desc calculated in frame_chain */
-  alpha_extra_func_info_t proc_desc =
-    get_next_frame (frame)
-    ? cached_proc_desc
-    : find_proc_desc (get_frame_pc (frame), get_next_frame (frame));
-
-  frame_extra_info_zalloc (frame, sizeof (struct frame_extra_info));
-
-  /* NOTE: cagney/2003-01-03: No need to set saved_regs to NULL,
-     always NULL by default.  */
-  /* frame->saved_regs = NULL; */
-  get_frame_extra_info (frame)->localoff = 0;
-  get_frame_extra_info (frame)->pc_reg = ALPHA_RA_REGNUM;
-  get_frame_extra_info (frame)->proc_desc = proc_desc == &temp_proc_desc ? 0 : proc_desc;
-  if (proc_desc)
+  struct alpha_sigtramp_unwind_cache *info
+    = alpha_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
+  struct gdbarch_tdep *tdep;
+  CORE_ADDR stack_addr, code_addr;
+
+  /* If the OSABI couldn't locate the sigcontext, give up.  */
+  if (info->sigcontext_addr == 0)
+    return;
+
+  /* If we have dynamic signal trampolines, find their start.
+     If we do not, then we must assume there is a symbol record
+     that can provide the start address.  */
+  tdep = gdbarch_tdep (current_gdbarch);
+  if (tdep->dynamic_sigtramp_offset)
     {
-      /* Get the locals offset and the saved pc register from the
-         procedure descriptor, they are valid even if we are in the
-         middle of the prologue.  */
-      get_frame_extra_info (frame)->localoff = PROC_LOCALOFF (proc_desc);
-      get_frame_extra_info (frame)->pc_reg = PROC_PC_REG (proc_desc);
-
-      /* Fixup frame-pointer - only needed for top frame */
-
-      /* Fetch the frame pointer for a dummy frame from the procedure
-         descriptor.  */
-      if (PROC_DESC_IS_DUMMY (proc_desc))
-       deprecated_update_frame_base_hack (frame, (CORE_ADDR) PROC_DUMMY_FRAME (proc_desc));
-
-      /* This may not be quite right, if proc has a real frame register.
-         Get the value of the frame relative sp, procedure might have been
-         interrupted by a signal at it's very start.  */
-      else if (get_frame_pc (frame) == PROC_LOW_ADDR (proc_desc)
-              && !alpha_proc_desc_is_dyn_sigtramp (proc_desc))
-       deprecated_update_frame_base_hack (frame, read_next_frame_reg (get_next_frame (frame), SP_REGNUM));
+      int offset;
+      code_addr = frame_pc_unwind (next_frame);
+      offset = tdep->dynamic_sigtramp_offset (code_addr);
+      if (offset >= 0)
+       code_addr -= offset;
       else
-       deprecated_update_frame_base_hack (frame, read_next_frame_reg (get_next_frame (frame), PROC_FRAME_REG (proc_desc))
-                                          + PROC_FRAME_OFFSET (proc_desc));
-
-      if (proc_desc == &temp_proc_desc)
-       {
-         char *name;
-
-         /* Do not set the saved registers for a sigtramp frame,
-            alpha_find_saved_registers will do that for us.  We can't
-            use (get_frame_type (frame) == SIGTRAMP_FRAME), it is not
-            yet set.  */
-         /* FIXME: cagney/2002-11-18: This problem will go away once
-             frame.c:get_prev_frame() is modified to set the frame's
-             type before calling functions like this.  */
-         find_pc_partial_function (get_frame_pc (frame), &name,
-                                   (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
-         if (!PC_IN_SIGTRAMP (get_frame_pc (frame), name))
-           {
-             frame_saved_regs_zalloc (frame);
-             memcpy (get_frame_saved_regs (frame), temp_saved_regs,
-                     SIZEOF_FRAME_SAVED_REGS);
-             get_frame_saved_regs (frame)[PC_REGNUM]
-               = get_frame_saved_regs (frame)[ALPHA_RA_REGNUM];
-           }
-       }
+       code_addr = 0;
     }
-}
-
-static CORE_ADDR
-alpha_frame_locals_address (struct frame_info *fi)
-{
-  return (get_frame_base (fi) - get_frame_extra_info (fi)->localoff);
-}
-
-static CORE_ADDR
-alpha_frame_args_address (struct frame_info *fi)
-{
-  return (get_frame_base (fi) - (ALPHA_NUM_ARG_REGS * 8));
-}
-
-/* ALPHA stack frames are almost impenetrable.  When execution stops,
-   we basically have to look at symbol information for the function
-   that we stopped in, which tells us *which* register (if any) is
-   the base of the frame pointer, and what offset from that register
-   the frame itself is at.  
-
-   This presents a problem when trying to examine a stack in memory
-   (that isn't executing at the moment), using the "frame" command.  We
-   don't have a PC, nor do we have any registers except SP.
+  else
+    code_addr = frame_func_unwind (next_frame);
 
-   This routine takes two arguments, SP and PC, and tries to make the
-   cached frames look as if these two arguments defined a frame on the
-   cache.  This allows the rest of info frame to extract the important
-   arguments without difficulty.  */
+  /* The stack address is trivially read from the sigcontext.  */
+  stack_addr = alpha_sigtramp_register_address (info->sigcontext_addr,
+                                               ALPHA_SP_REGNUM);
+  stack_addr = read_memory_unsigned_integer (stack_addr, ALPHA_REGISTER_SIZE);
 
-struct frame_info *
-alpha_setup_arbitrary_frame (int argc, CORE_ADDR *argv)
-{
-  if (argc != 2)
-    error ("ALPHA frame specifications require two arguments: sp and pc");
-
-  return create_new_frame (argv[0], argv[1]);
+  *this_id = frame_id_build (stack_addr, code_addr);
 }
 
-/* The alpha passes the first six arguments in the registers, the rest on
-   the stack. The register arguments are eventually transferred to the
-   argument transfer area immediately below the stack by the called function
-   anyway. So we `push' at least six arguments on the stack, `reload' the
-   argument registers and then adjust the stack pointer to point past the
-   sixth argument. This algorithm simplifies the passing of a large struct
-   which extends from the registers to the stack.
-   If the called function is returning a structure, the address of the
-   structure to be returned is passed as a hidden first argument.  */
+/* Retrieve the value of REGNUM in FRAME.  Don't give up!  */
 
-static CORE_ADDR
-alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
-                     int struct_return, CORE_ADDR struct_addr)
+static void
+alpha_sigtramp_frame_prev_register (struct frame_info *next_frame,
+                                   void **this_prologue_cache,
+                                   int regnum, int *optimizedp,
+                                   enum lval_type *lvalp, CORE_ADDR *addrp,
+                                   int *realnump, void *bufferp)
 {
-  int i;
-  int accumulate_size = struct_return ? 8 : 0;
-  int arg_regs_size = ALPHA_NUM_ARG_REGS * 8;
-  struct alpha_arg
-    {
-      char *contents;
-      int len;
-      int offset;
-    };
-  struct alpha_arg *alpha_args =
-  (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
-  register struct alpha_arg *m_arg;
-  char raw_buffer[sizeof (CORE_ADDR)];
-  int required_arg_regs;
+  struct alpha_sigtramp_unwind_cache *info
+    = alpha_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
+  CORE_ADDR addr;
 
-  for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++)
+  if (info->sigcontext_addr != 0)
     {
-      struct value *arg = args[i];
-      struct type *arg_type = check_typedef (VALUE_TYPE (arg));
-      /* Cast argument to long if necessary as the compiler does it too.  */
-      switch (TYPE_CODE (arg_type))
+      /* All integer and fp registers are stored in memory.  */
+      addr = alpha_sigtramp_register_address (info->sigcontext_addr, regnum);
+      if (addr != 0)
        {
-       case TYPE_CODE_INT:
-       case TYPE_CODE_BOOL:
-       case TYPE_CODE_CHAR:
-       case TYPE_CODE_RANGE:
-       case TYPE_CODE_ENUM:
-         if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long))
-           {
-             arg_type = builtin_type_long;
-             arg = value_cast (arg_type, arg);
-           }
-         break;
-       default:
-         break;
+         *optimizedp = 0;
+         *lvalp = lval_memory;
+         *addrp = addr;
+         *realnump = -1;
+         if (bufferp != NULL)
+           read_memory (addr, bufferp, ALPHA_REGISTER_SIZE);
+         return;
        }
-      m_arg->len = TYPE_LENGTH (arg_type);
-      m_arg->offset = accumulate_size;
-      accumulate_size = (accumulate_size + m_arg->len + 7) & ~7;
-      m_arg->contents = VALUE_CONTENTS (arg);
     }
 
-  /* Determine required argument register loads, loading an argument register
-     is expensive as it uses three ptrace calls.  */
-  required_arg_regs = accumulate_size / 8;
-  if (required_arg_regs > ALPHA_NUM_ARG_REGS)
-    required_arg_regs = ALPHA_NUM_ARG_REGS;
-
-  /* Make room for the arguments on the stack.  */
-  if (accumulate_size < arg_regs_size)
-    accumulate_size = arg_regs_size;
-  sp -= accumulate_size;
+  /* This extra register may actually be in the sigcontext, but our
+     current description of it in alpha_sigtramp_frame_unwind_cache
+     doesn't include it.  Too bad.  Fall back on whatever's in the
+     outer frame.  */
+  frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
+                 realnump, bufferp);
+}
 
-  /* Keep sp aligned to a multiple of 16 as the compiler does it too.  */
-  sp &= ~15;
+static const struct frame_unwind alpha_sigtramp_frame_unwind = {
+  SIGTRAMP_FRAME,
+  alpha_sigtramp_frame_this_id,
+  alpha_sigtramp_frame_prev_register
+};
 
-  /* `Push' arguments on the stack.  */
-  for (i = nargs; m_arg--, --i >= 0;)
-    write_memory (sp + m_arg->offset, m_arg->contents, m_arg->len);
-  if (struct_return)
-    {
-      /* NOTE: cagney/2003-05-09: Using sizeof CORE_ADDR here is just
-         wrong.  */
-      store_unsigned_integer (raw_buffer, sizeof (CORE_ADDR), struct_addr);
-      write_memory (sp, raw_buffer, sizeof (CORE_ADDR));
-    }
+static const struct frame_unwind *
+alpha_sigtramp_frame_p (CORE_ADDR pc)
+{
+  char *name;
 
-  /* Load the argument registers.  */
-  for (i = 0; i < required_arg_regs; i++)
-    {
-      LONGEST val;
+  /* We shouldn't even bother to try if the OSABI didn't register
+     a sigcontext_addr handler.  */
+  if (!gdbarch_tdep (current_gdbarch)->sigcontext_addr)
+    return NULL;
 
-      val = read_memory_integer (sp + i * 8, 8);
-      write_register (ALPHA_A0_REGNUM + i, val);
-      write_register (ALPHA_FPA0_REGNUM + i, val);
-    }
+  /* Otherwise we should be in a signal frame.  */
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  if (PC_IN_SIGTRAMP (pc, name))
+    return &alpha_sigtramp_frame_unwind;
 
-  return sp + arg_regs_size;
+  return NULL;
 }
+\f
+/* Fallback alpha frame unwinder.  Uses instruction scanning and knows
+   something about the traditional layout of alpha stack frames.  */
 
-static void
-alpha_push_dummy_frame (void)
+struct alpha_heuristic_unwind_cache
 {
-  int ireg;
-  struct linked_proc_info *link;
-  alpha_extra_func_info_t proc_desc;
-  CORE_ADDR sp = read_register (SP_REGNUM);
-  CORE_ADDR save_address;
-  char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
-  unsigned long mask;
-
-  link = (struct linked_proc_info *) xmalloc (sizeof (struct linked_proc_info));
-  link->next = linked_proc_desc_table;
-  linked_proc_desc_table = link;
-
-  proc_desc = &link->info;
-
-  /*
-   * The registers we must save are all those not preserved across
-   * procedure calls.
-   * In addition, we must save the PC and RA.
-   *
-   * Dummy frame layout:
-   *  (high memory)
-   *    Saved PC
-   *    Saved F30
-   *    ...
-   *    Saved F0
-   *    Saved R29
-   *    ...
-   *    Saved R0
-   *    Saved R26 (RA)
-   *    Parameter build area
-   *  (low memory)
-   */
-
-/* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<31. */
-#define MASK(i,j) ((((LONGEST)1 << ((j)+1)) - 1) ^ (((LONGEST)1 << (i)) - 1))
-#define GEN_REG_SAVE_MASK (MASK(0,8) | MASK(16,29))
-#define GEN_REG_SAVE_COUNT 24
-#define FLOAT_REG_SAVE_MASK (MASK(0,1) | MASK(10,30))
-#define FLOAT_REG_SAVE_COUNT 23
-  /* The special register is the PC as we have no bit for it in the save masks.
-     alpha_frame_saved_pc knows where the pc is saved in a dummy frame.  */
-#define SPECIAL_REG_SAVE_COUNT 1
-
-  PROC_REG_MASK (proc_desc) = GEN_REG_SAVE_MASK;
-  PROC_FREG_MASK (proc_desc) = FLOAT_REG_SAVE_MASK;
-  /* PROC_REG_OFFSET is the offset from the dummy frame to the saved RA,
-     but keep SP aligned to a multiple of 16.  */
-  PROC_REG_OFFSET (proc_desc) =
-    -((8 * (SPECIAL_REG_SAVE_COUNT
-           + GEN_REG_SAVE_COUNT
-           + FLOAT_REG_SAVE_COUNT)
-       + 15) & ~15);
-  PROC_FREG_OFFSET (proc_desc) =
-    PROC_REG_OFFSET (proc_desc) + 8 * GEN_REG_SAVE_COUNT;
-
-  /* Save general registers.
-     The return address register is the first saved register, all other
-     registers follow in ascending order.
-     The PC is saved immediately below the SP.  */
-  save_address = sp + PROC_REG_OFFSET (proc_desc);
-  store_unsigned_integer (raw_buffer, 8, read_register (ALPHA_RA_REGNUM));
-  write_memory (save_address, raw_buffer, 8);
-  save_address += 8;
-  mask = PROC_REG_MASK (proc_desc) & 0xffffffffL;
-  for (ireg = 0; mask; ireg++, mask >>= 1)
-    if (mask & 1)
-      {
-       if (ireg == ALPHA_RA_REGNUM)
-         continue;
-       store_unsigned_integer (raw_buffer, 8, read_register (ireg));
-       write_memory (save_address, raw_buffer, 8);
-       save_address += 8;
-      }
-
-  store_unsigned_integer (raw_buffer, 8, read_register (PC_REGNUM));
-  write_memory (sp - 8, raw_buffer, 8);
-
-  /* Save floating point registers.  */
-  save_address = sp + PROC_FREG_OFFSET (proc_desc);
-  mask = PROC_FREG_MASK (proc_desc) & 0xffffffffL;
-  for (ireg = 0; mask; ireg++, mask >>= 1)
-    if (mask & 1)
-      {
-       store_unsigned_integer (raw_buffer, 8, read_register (ireg + FP0_REGNUM));
-       write_memory (save_address, raw_buffer, 8);
-       save_address += 8;
-      }
-
-  /* Set and save the frame address for the dummy.  
-     This is tricky. The only registers that are suitable for a frame save
-     are those that are preserved across procedure calls (s0-s6). But if
-     a read system call is interrupted and then a dummy call is made
-     (see testsuite/gdb.t17/interrupt.exp) the dummy call hangs till the read
-     is satisfied. Then it returns with the s0-s6 registers set to the values
-     on entry to the read system call and our dummy frame pointer would be
-     destroyed. So we save the dummy frame in the proc_desc and handle the
-     retrieval of the frame pointer of a dummy specifically. The frame register
-     is set to the virtual frame (pseudo) register, it's value will always
-     be read as zero and will help us to catch any errors in the dummy frame
-     retrieval code.  */
-  PROC_DUMMY_FRAME (proc_desc) = sp;
-  PROC_FRAME_REG (proc_desc) = DEPRECATED_FP_REGNUM;
-  PROC_FRAME_OFFSET (proc_desc) = 0;
-  sp += PROC_REG_OFFSET (proc_desc);
-  write_register (SP_REGNUM, sp);
-
-  PROC_LOW_ADDR (proc_desc) = CALL_DUMMY_ADDRESS ();
-  PROC_HIGH_ADDR (proc_desc) = PROC_LOW_ADDR (proc_desc) + 4;
-
-  SET_PROC_DESC_IS_DUMMY (proc_desc);
-  PROC_PC_REG (proc_desc) = ALPHA_RA_REGNUM;
-}
+  CORE_ADDR *saved_regs;
+  CORE_ADDR vfp;
+  CORE_ADDR start_pc;
+  int return_reg;
+};
 
-static void
-alpha_pop_frame (void)
-{
-  register int regnum;
-  struct frame_info *frame = get_current_frame ();
-  CORE_ADDR new_sp = get_frame_base (frame);
+/* Heuristic_proc_start may hunt through the text section for a long
+   time across a 2400 baud serial line.  Allows the user to limit this
+   search.  */
+static unsigned int heuristic_fence_post = 0;
 
-  alpha_extra_func_info_t proc_desc = get_frame_extra_info (frame)->proc_desc;
+/* Attempt to locate the start of the function containing PC.  We assume that
+   the previous function ends with an about_to_return insn.  Not foolproof by
+   any means, since gcc is happy to put the epilogue in the middle of a
+   function.  But we're guessing anyway...  */
 
-  /* we need proc_desc to know how to restore the registers;
-     if it is NULL, construct (a temporary) one */
-  if (proc_desc == NULL)
-    proc_desc = find_proc_desc (get_frame_pc (frame), get_next_frame (frame));
+static CORE_ADDR
+alpha_heuristic_proc_start (CORE_ADDR pc)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  CORE_ADDR last_non_nop = pc;
+  CORE_ADDR fence = pc - heuristic_fence_post;
+  CORE_ADDR orig_pc = pc;
 
-  /* Question: should we copy this proc_desc and save it in
-     frame->proc_desc?  If we do, who will free it?
-     For now, we don't save a copy... */
+  if (pc == 0)
+    return 0;
 
-  write_register (PC_REGNUM, DEPRECATED_FRAME_SAVED_PC (frame));
-  if (get_frame_saved_regs (frame) == NULL)
-    alpha_find_saved_regs (frame);
-  if (proc_desc)
-    {
-      for (regnum = 32; --regnum >= 0;)
-       if (PROC_REG_MASK (proc_desc) & (1 << regnum))
-         write_register (regnum,
-                         read_memory_integer (get_frame_saved_regs (frame)[regnum],
-                                              8));
-      for (regnum = 32; --regnum >= 0;)
-       if (PROC_FREG_MASK (proc_desc) & (1 << regnum))
-         write_register (regnum + FP0_REGNUM,
-          read_memory_integer (get_frame_saved_regs (frame)[regnum + FP0_REGNUM], 8));
-    }
-  write_register (SP_REGNUM, new_sp);
-  flush_cached_frames ();
+  if (heuristic_fence_post == UINT_MAX
+      || fence < tdep->vm_min_address)
+    fence = tdep->vm_min_address;
 
-  if (proc_desc && (PROC_DESC_IS_DUMMY (proc_desc)
-                   || alpha_proc_desc_is_dyn_sigtramp (proc_desc)))
+  /* Search back for previous return; also stop at a 0, which might be
+     seen for instance before the start of a code section.  Don't include
+     nops, since this usually indicates padding between functions.  */
+  for (pc -= 4; pc >= fence; pc -= 4)
     {
-      struct linked_proc_info *pi_ptr, *prev_ptr;
-
-      for (pi_ptr = linked_proc_desc_table, prev_ptr = NULL;
-          pi_ptr != NULL;
-          prev_ptr = pi_ptr, pi_ptr = pi_ptr->next)
+      unsigned int insn = alpha_read_insn (pc);
+      switch (insn)
        {
-         if (&pi_ptr->info == proc_desc)
-           break;
+       case 0:                 /* invalid insn */
+       case 0x6bfa8001:        /* ret $31,($26),1 */
+         return last_non_nop;
+
+       case 0x2ffe0000:        /* unop: ldq_u $31,0($30) */
+       case 0x47ff041f:        /* nop: bis $31,$31,$31 */
+         break;
+
+       default:
+         last_non_nop = pc;
+         break;
        }
+    }
 
-      if (pi_ptr == NULL)
-       error ("Can't locate dummy extra frame info\n");
+  /* It's not clear to me why we reach this point when stopping quietly,
+     but with this test, at least we don't print out warnings for every
+     child forked (eg, on decstation).  22apr93 rich@cygnus.com.  */
+  if (stop_soon == NO_STOP_QUIETLY)
+    {
+      static int blurb_printed = 0;
 
-      if (prev_ptr != NULL)
-       prev_ptr->next = pi_ptr->next;
+      if (fence == tdep->vm_min_address)
+       warning ("Hit beginning of text section without finding");
       else
-       linked_proc_desc_table = pi_ptr->next;
+       warning ("Hit heuristic-fence-post without finding");
+      warning ("enclosing function for address 0x%s", paddr_nz (orig_pc));
 
-      xfree (pi_ptr);
-    }
-}
-\f
-/* To skip prologues, I use this predicate.  Returns either PC itself
-   if the code at PC does not look like a function prologue; otherwise
-   returns an address that (if we're lucky) follows the prologue.  If
-   LENIENT, then we must skip everything which is involved in setting
-   up the frame (it's OK to skip more, just so long as we don't skip
-   anything which might clobber the registers which are being saved.
-   Currently we must not skip more on the alpha, but we might need the
-   lenient stuff some day.  */
+      if (!blurb_printed)
+       {
+         printf_filtered ("\
+This warning occurs if you are debugging a function without any symbols\n\
+(for example, in a stripped executable).  In that case, you may wish to\n\
+increase the size of the search with the `set heuristic-fence-post' command.\n\
+\n\
+Otherwise, you told GDB there was a function where there isn't one, or\n\
+(more likely) you have encountered a bug in GDB.\n");
+         blurb_printed = 1;
+       }
+    }
 
-static CORE_ADDR
-alpha_skip_prologue_internal (CORE_ADDR pc, int lenient)
-{
-  unsigned long inst;
-  int offset;
-  CORE_ADDR post_prologue_pc;
-  char buf[4];
+  return 0;
+}
 
-  /* Silently return the unaltered pc upon memory errors.
-     This could happen on OSF/1 if decode_line_1 tries to skip the
-     prologue for quickstarted shared library functions when the
-     shared library is not yet mapped in.
-     Reading target memory is slow over serial lines, so we perform
-     this check only if the target has shared libraries (which all
-     Alpha targets do).  */
-  if (target_read_memory (pc, buf, 4))
-    return pc;
+struct alpha_heuristic_unwind_cache *
+alpha_heuristic_frame_unwind_cache (struct frame_info *next_frame,
+                                   void **this_prologue_cache,
+                                   CORE_ADDR start_pc)
+{
+  struct alpha_heuristic_unwind_cache *info;
+  ULONGEST val;
+  CORE_ADDR limit_pc, cur_pc;
+  int frame_reg, frame_size, return_reg, reg;
 
-  /* See if we can determine the end of the prologue via the symbol table.
-     If so, then return either PC, or the PC after the prologue, whichever
-     is greater.  */
+  if (*this_prologue_cache)
+    return *this_prologue_cache;
 
-  post_prologue_pc = after_prologue (pc, NULL);
+  info = FRAME_OBSTACK_ZALLOC (struct alpha_heuristic_unwind_cache);
+  *this_prologue_cache = info;
+  info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
 
-  if (post_prologue_pc != 0)
-    return max (pc, post_prologue_pc);
+  limit_pc = frame_pc_unwind (next_frame);
+  if (start_pc == 0)
+    start_pc = alpha_heuristic_proc_start (limit_pc);
+  info->start_pc = start_pc;
 
-  /* Can't determine prologue from the symbol table, need to examine
-     instructions.  */
+  frame_reg = ALPHA_SP_REGNUM;
+  frame_size = 0;
+  return_reg = -1;
 
-  /* Skip the typical prologue instructions. These are the stack adjustment
-     instruction and the instructions that save registers on the stack
-     or in the gcc frame.  */
-  for (offset = 0; offset < 100; offset += 4)
+  /* If we've identified a likely place to start, do code scanning.  */
+  if (start_pc != 0)
     {
-      int status;
-
-      status = read_memory_nobpt (pc + offset, buf, 4);
-      if (status)
-       memory_error (status, pc + offset);
-      inst = extract_unsigned_integer (buf, 4);
+      /* Limit the forward search to 50 instructions.  */
+      if (start_pc + 200 < limit_pc)
+       limit_pc = start_pc + 200;
 
-      /* The alpha has no delay slots. But let's keep the lenient stuff,
-         we might need it for something else in the future.  */
-      if (lenient && 0)
-       continue;
+      for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
+       {
+         unsigned int word = alpha_read_insn (cur_pc);
 
-      if ((inst & 0xffff0000) == 0x27bb0000)   /* ldah $gp,n($t12) */
-       continue;
-      if ((inst & 0xffff0000) == 0x23bd0000)   /* lda $gp,n($gp) */
-       continue;
-      if ((inst & 0xffff0000) == 0x23de0000)   /* lda $sp,n($sp) */
-       continue;
-      if ((inst & 0xffe01fff) == 0x43c0153e)   /* subq $sp,n,$sp */
-       continue;
+         if ((word & 0xffff0000) == 0x23de0000)        /* lda $sp,n($sp) */
+           {
+             if (word & 0x8000)
+               {
+                 /* Consider only the first stack allocation instruction
+                    to contain the static size of the frame. */
+                 if (frame_size == 0)
+                   frame_size = (-word) & 0xffff;
+               }
+             else
+               {
+                 /* Exit loop if a positive stack adjustment is found, which
+                    usually means that the stack cleanup code in the function
+                    epilogue is reached.  */
+                 break;
+               }
+           }
+         else if ((word & 0xfc1f0000) == 0xb41e0000)   /* stq reg,n($sp) */
+           {
+             reg = (word & 0x03e00000) >> 21;
+
+             if (reg == 31)
+               continue;
+
+             /* Do not compute the address where the register was saved yet,
+                because we don't know yet if the offset will need to be
+                relative to $sp or $fp (we can not compute the address
+                relative to $sp if $sp is updated during the execution of
+                the current subroutine, for instance when doing some alloca).
+                So just store the offset for the moment, and compute the
+                address later when we know whether this frame has a frame
+                pointer or not.  */
+             /* Hack: temporarily add one, so that the offset is non-zero
+                and we can tell which registers have save offsets below.  */
+             info->saved_regs[reg] = (word & 0xffff) + 1;
+
+             /* Starting with OSF/1-3.2C, the system libraries are shipped
+                without local symbols, but they still contain procedure
+                descriptors without a symbol reference. GDB is currently
+                unable to find these procedure descriptors and uses
+                heuristic_proc_desc instead.
+                As some low level compiler support routines (__div*, __add*)
+                use a non-standard return address register, we have to
+                add some heuristics to determine the return address register,
+                or stepping over these routines will fail.
+                Usually the return address register is the first register
+                saved on the stack, but assembler optimization might
+                rearrange the register saves.
+                So we recognize only a few registers (t7, t9, ra) within
+                the procedure prologue as valid return address registers.
+                If we encounter a return instruction, we extract the
+                the return address register from it.
+
+                FIXME: Rewriting GDB to access the procedure descriptors,
+                e.g. via the minimal symbol table, might obviate this hack.  */
+             if (return_reg == -1
+                 && cur_pc < (start_pc + 80)
+                 && (reg == ALPHA_T7_REGNUM
+                     || reg == ALPHA_T9_REGNUM
+                     || reg == ALPHA_RA_REGNUM))
+               return_reg = reg;
+           }
+         else if ((word & 0xffe0ffff) == 0x6be08001)   /* ret zero,reg,1 */
+           return_reg = (word >> 16) & 0x1f;
+         else if (word == 0x47de040f)                  /* bis sp,sp,fp */
+           frame_reg = ALPHA_GCC_FP_REGNUM;
+         else if (word == 0x47fe040f)                  /* bis zero,sp,fp */
+           frame_reg = ALPHA_GCC_FP_REGNUM;
+       }
 
-      if ((inst & 0xfc1f0000) == 0xb41e0000
-         && (inst & 0xffff0000) != 0xb7fe0000)
-       continue;               /* stq reg,n($sp) */
-      /* reg != $zero */
-      if ((inst & 0xfc1f0000) == 0x9c1e0000
-         && (inst & 0xffff0000) != 0x9ffe0000)
-       continue;               /* stt reg,n($sp) */
-      /* reg != $zero */
-      if (inst == 0x47de040f)  /* bis sp,sp,fp */
-       continue;
+      /* If we haven't found a valid return address register yet, keep
+        searching in the procedure prologue.  */
+      if (return_reg == -1)
+       {
+         while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80))
+           {
+             unsigned int word = alpha_read_insn (cur_pc);
 
-      break;
+             if ((word & 0xfc1f0000) == 0xb41e0000)    /* stq reg,n($sp) */
+               {
+                 reg = (word & 0x03e00000) >> 21;
+                 if (reg == ALPHA_T7_REGNUM
+                     || reg == ALPHA_T9_REGNUM
+                     || reg == ALPHA_RA_REGNUM)
+                   {
+                     return_reg = reg;
+                     break;
+                   }
+               }
+             else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */
+               {
+                 return_reg = (word >> 16) & 0x1f;
+                 break;
+               }
+           }
+       }
     }
-  return pc + offset;
-}
 
-static CORE_ADDR
-alpha_skip_prologue (CORE_ADDR addr)
-{
-  return (alpha_skip_prologue_internal (addr, 0));
-}
+  /* Failing that, do default to the customary RA.  */
+  if (return_reg == -1)
+    return_reg = ALPHA_RA_REGNUM;
+  info->return_reg = return_reg;
 
-#if 0
-/* Is address PC in the prologue (loosely defined) for function at
-   STARTADDR?  */
+  frame_unwind_unsigned_register (next_frame, frame_reg, &val);
+  info->vfp = val + frame_size;
 
-static int
-alpha_in_lenient_prologue (CORE_ADDR startaddr, CORE_ADDR pc)
-{
-  CORE_ADDR end_prologue = alpha_skip_prologue_internal (startaddr, 1);
-  return pc >= startaddr && pc < end_prologue;
+  /* Convert offsets to absolute addresses.  See above about adding
+     one to the offsets to make all detected offsets non-zero.  */
+  for (reg = 0; reg < ALPHA_NUM_REGS; ++reg)
+    if (info->saved_regs[reg])
+      info->saved_regs[reg] += val - 1;
+
+  return info;
 }
-#endif
 
-/* The alpha needs a conversion between register and memory format if
-   the register is a floating point register and
-   memory format is float, as the register format must be double
-   or
-   memory format is an integer with 4 bytes or less, as the representation
-   of integers in floating point registers is different. */
-static void
-alpha_register_convert_to_virtual (int regnum, struct type *valtype,
-                                  char *raw_buffer, char *virtual_buffer)
+/* Given a GDB frame, determine the address of the calling function's
+   frame.  This will be used to create a new GDB frame struct.  */
+
+void
+alpha_heuristic_frame_this_id (struct frame_info *next_frame,
+                                void **this_prologue_cache,
+                                struct frame_id *this_id)
 {
-  if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
-    {
-      memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
-      return;
-    }
+  struct alpha_heuristic_unwind_cache *info
+    = alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
 
-  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
-    {
-      double d = deprecated_extract_floating (raw_buffer, REGISTER_RAW_SIZE (regnum));
-      deprecated_store_floating (virtual_buffer, TYPE_LENGTH (valtype), d);
-    }
-  else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
-    {
-      ULONGEST l;
-      l = extract_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum));
-      l = ((l >> 32) & 0xc0000000) | ((l >> 29) & 0x3fffffff);
-      store_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype), l);
-    }
-  else
-    error ("Cannot retrieve value from floating point register");
+  *this_id = frame_id_build (info->vfp, info->start_pc);
 }
 
-static void
-alpha_register_convert_to_raw (struct type *valtype, int regnum,
-                              char *virtual_buffer, char *raw_buffer)
+/* Retrieve the value of REGNUM in FRAME.  Don't give up!  */
+
+void
+alpha_heuristic_frame_prev_register (struct frame_info *next_frame,
+                                    void **this_prologue_cache,
+                                    int regnum, int *optimizedp,
+                                    enum lval_type *lvalp, CORE_ADDR *addrp,
+                                    int *realnump, void *bufferp)
 {
-  if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
+  struct alpha_heuristic_unwind_cache *info
+    = alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
+
+  /* The PC of the previous frame is stored in the link register of
+     the current frame.  Frob regnum so that we pull the value from
+     the correct place.  */
+  if (regnum == ALPHA_PC_REGNUM)
+    regnum = info->return_reg;
+  
+  /* For all registers known to be saved in the current frame, 
+     do the obvious and pull the value out.  */
+  if (info->saved_regs[regnum])
     {
-      memcpy (raw_buffer, virtual_buffer, REGISTER_RAW_SIZE (regnum));
+      *optimizedp = 0;
+      *lvalp = lval_memory;
+      *addrp = info->saved_regs[regnum];
+      *realnump = -1;
+      if (bufferp != NULL)
+       read_memory (*addrp, bufferp, ALPHA_REGISTER_SIZE);
       return;
     }
 
-  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
-    {
-      double d = deprecated_extract_floating (virtual_buffer, TYPE_LENGTH (valtype));
-      deprecated_store_floating (raw_buffer, REGISTER_RAW_SIZE (regnum), d);
-    }
-  else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
+  /* The stack pointer of the previous frame is computed by popping
+     the current stack frame.  */
+  if (regnum == ALPHA_SP_REGNUM)
     {
-      ULONGEST l;
-      if (TYPE_UNSIGNED (valtype))
-       l = extract_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype));
-      else
-       l = extract_signed_integer (virtual_buffer, TYPE_LENGTH (valtype));
-      l = ((l & 0xc0000000) << 32) | ((l & 0x3fffffff) << 29);
-      store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), l);
+      *optimizedp = 0;
+      *lvalp = not_lval;
+      *addrp = 0;
+      *realnump = -1;
+      if (bufferp != NULL)
+       store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp);
+      return;
     }
-  else
-    error ("Cannot store value in floating point register");
-}
-
-static const unsigned char *
-alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
-{
-  static const unsigned char alpha_breakpoint[] =
-    { 0x80, 0, 0, 0 }; /* call_pal bpt */
 
-  *lenptr = sizeof(alpha_breakpoint);
-  return (alpha_breakpoint);
+  /* Otherwise assume the next frame has the same register value.  */
+  frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
+                 realnump, bufferp);
 }
 
-/* Given a return value in `regbuf' with a type `valtype', 
-   extract and copy its value into `valbuf'.  */
+static const struct frame_unwind alpha_heuristic_frame_unwind = {
+  NORMAL_FRAME,
+  alpha_heuristic_frame_this_id,
+  alpha_heuristic_frame_prev_register
+};
 
-static void
-alpha_extract_return_value (struct type *valtype,
-                           char regbuf[ALPHA_REGISTER_BYTES], char *valbuf)
+static const struct frame_unwind *
+alpha_heuristic_frame_p (CORE_ADDR pc)
 {
-  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
-    alpha_register_convert_to_virtual (FP0_REGNUM, valtype,
-                                      regbuf + REGISTER_BYTE (FP0_REGNUM),
-                                      valbuf);
-  else
-    memcpy (valbuf, regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
-            TYPE_LENGTH (valtype));
+  return &alpha_heuristic_frame_unwind;
 }
 
-/* Given a return value in `regbuf' with a type `valtype', 
-   write its value into the appropriate register.  */
-
-static void
-alpha_store_return_value (struct type *valtype, char *valbuf)
+CORE_ADDR
+alpha_heuristic_frame_base_address (struct frame_info *next_frame,
+                                   void **this_prologue_cache)
 {
-  char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
-  int regnum = ALPHA_V0_REGNUM;
-  int length = TYPE_LENGTH (valtype);
-
-  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
-    {
-      regnum = FP0_REGNUM;
-      length = REGISTER_RAW_SIZE (regnum);
-      alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer);
-    }
-  else
-    memcpy (raw_buffer, valbuf, length);
+  struct alpha_heuristic_unwind_cache *info
+    = alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
 
-  deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length);
+  return info->vfp;
 }
 
+static const struct frame_base alpha_heuristic_frame_base = {
+  &alpha_heuristic_frame_unwind,
+  alpha_heuristic_frame_base_address,
+  alpha_heuristic_frame_base_address,
+  alpha_heuristic_frame_base_address
+};
+
 /* Just like reinit_frame_cache, but with the right arguments to be
-   callable as an sfunc.  */
+   callable as an sfunc.  Used by the "set heuristic-fence-post" command.  */
 
 static void
 reinit_frame_cache_sfunc (char *args, int from_tty, struct cmd_list_element *c)
@@ -1559,90 +978,53 @@ reinit_frame_cache_sfunc (char *args, int from_tty, struct cmd_list_element *c)
   reinit_frame_cache ();
 }
 
-/* This is the definition of CALL_DUMMY_ADDRESS.  It's a heuristic that is used
-   to find a convenient place in the text segment to stick a breakpoint to
-   detect the completion of a target function call (ala call_function_by_hand).
- */
-
-CORE_ADDR
-alpha_call_dummy_address (void)
-{
-  CORE_ADDR entry;
-  struct minimal_symbol *sym;
-
-  entry = entry_point_address ();
-
-  if (entry != 0)
-    return entry;
+\f
+/* ALPHA stack frames are almost impenetrable.  When execution stops,
+   we basically have to look at symbol information for the function
+   that we stopped in, which tells us *which* register (if any) is
+   the base of the frame pointer, and what offset from that register
+   the frame itself is at.  
 
-  sym = lookup_minimal_symbol ("_Prelude", NULL, symfile_objfile);
+   This presents a problem when trying to examine a stack in memory
+   (that isn't executing at the moment), using the "frame" command.  We
+   don't have a PC, nor do we have any registers except SP.
 
-  if (!sym || MSYMBOL_TYPE (sym) != mst_text)
-    return 0;
-  else
-    return SYMBOL_VALUE_ADDRESS (sym) + 4;
-}
+   This routine takes two arguments, SP and PC, and tries to make the
+   cached frames look as if these two arguments defined a frame on the
+   cache.  This allows the rest of info frame to extract the important
+   arguments without difficulty.  */
 
-static void
-alpha_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
-                      struct value **args, struct type *type, int gcc_p)
+struct frame_info *
+alpha_setup_arbitrary_frame (int argc, CORE_ADDR *argv)
 {
-  CORE_ADDR bp_address = CALL_DUMMY_ADDRESS ();
+  if (argc != 2)
+    error ("ALPHA frame specifications require two arguments: sp and pc");
 
-  if (bp_address == 0)
-    error ("no place to put call");
-  write_register (ALPHA_RA_REGNUM, bp_address);
-  write_register (ALPHA_T12_REGNUM, fun);
+  return create_new_frame (argv[0], argv[1]);
 }
 
-/* On the Alpha, the call dummy code is nevery copied to user space
-   (see alpha_fix_call_dummy() above).  The contents of this do not
-   matter.  */
-LONGEST alpha_call_dummy_words[] = { 0 };
-
-static int
-alpha_use_struct_convention (int gcc_p, struct type *type)
-{
-  /* Structures are returned by ref in extra arg0.  */
-  return 1;
-}
+/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
+   dummy frame.  The frame ID's base needs to match the TOS value
+   saved by save_dummy_frame_tos(), and the PC match the dummy frame's
+   breakpoint.  */
 
-static void
-alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+static struct frame_id
+alpha_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  /* Store the address of the place in which to copy the structure the
-     subroutine will return.  Handled by alpha_push_arguments.  */
+  ULONGEST base;
+  frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &base);
+  return frame_id_build (base, frame_pc_unwind (next_frame));
 }
 
 static CORE_ADDR
-alpha_extract_struct_value_address (char *regbuf)
-{
-  return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
-                          REGISTER_RAW_SIZE (ALPHA_V0_REGNUM)));
-}
-
-/* Figure out where the longjmp will land.
-   We expect the first arg to be a pointer to the jmp_buf structure from
-   which we extract the PC (JB_PC) that we will land at.  The PC is copied
-   into the "pc".  This routine returns true on success.  */
-
-static int
-alpha_get_longjmp_target (CORE_ADDR *pc)
+alpha_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-  CORE_ADDR jb_addr;
-  char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
-
-  jb_addr = read_register (ALPHA_A0_REGNUM);
-
-  if (target_read_memory (jb_addr + (tdep->jb_pc * tdep->jb_elt_size),
-                         raw_buffer, tdep->jb_elt_size))
-    return 0;
-
-  *pc = extract_address (raw_buffer, tdep->jb_elt_size);
-  return 1;
+  ULONGEST pc;
+  frame_unwind_unsigned_register (next_frame, ALPHA_PC_REGNUM, &pc);
+  return pc;
 }
 
+\f
 /* alpha_software_single_step() is called just before we want to resume
    the inferior, if we want to single-step it but there is no hardware
    or kernel single-step support (NetBSD on Alpha, for example).  We find
@@ -1722,6 +1104,8 @@ alpha_next_pc (CORE_ADDR pc)
          if (rav >= 0)
            goto branch_taken;
          break;
+
+       /* ??? Missing floating-point branches.  */
        }
     }
 
@@ -1753,7 +1137,6 @@ alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p)
 }
 
 \f
-
 /* Initialize the current architecture based on INFO.  If possible, re-use an
    architecture from ARCHES, which is a list of architectures already created
    during this debugging session.
@@ -1783,12 +1166,11 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep = xmalloc (sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
 
-  /* Lowest text address.  This is used by heuristic_proc_start() to
-     decide when to stop looking.  */
+  /* Lowest text address.  This is used by heuristic_proc_start()
+     to decide when to stop looking.  */
   tdep->vm_min_address = (CORE_ADDR) 0x120000000;
 
   tdep->dynamic_sigtramp_offset = NULL;
-  tdep->skip_sigtramp_frame = NULL;
   tdep->sigcontext_addr = NULL;
 
   tdep->jb_pc = -1;    /* longjmp support not enabled by default  */
@@ -1829,53 +1211,34 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                                            alpha_register_convert_to_virtual);
   set_gdbarch_register_convert_to_raw (gdbarch, alpha_register_convert_to_raw);
 
+  /* Prologue heuristics.  */
   set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue);
 
+  /* Call info.  */
   set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
   set_gdbarch_frameless_function_invocation (gdbarch,
                                     generic_frameless_function_invocation_not);
 
-  set_gdbarch_deprecated_saved_pc_after_call (gdbarch, alpha_saved_pc_after_call);
-
-  set_gdbarch_deprecated_frame_chain (gdbarch, alpha_frame_chain);
-  set_gdbarch_deprecated_frame_saved_pc (gdbarch, alpha_frame_saved_pc);
-
-  set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, alpha_frame_init_saved_regs);
-
   set_gdbarch_use_struct_convention (gdbarch, alpha_use_struct_convention);
   set_gdbarch_deprecated_extract_return_value (gdbarch, alpha_extract_return_value);
-
   set_gdbarch_deprecated_store_struct_return (gdbarch, alpha_store_struct_return);
   set_gdbarch_deprecated_store_return_value (gdbarch, alpha_store_return_value);
   set_gdbarch_deprecated_extract_struct_value_address (gdbarch,
                                            alpha_extract_struct_value_address);
 
   /* Settings for calling functions in the inferior.  */
-  set_gdbarch_deprecated_use_generic_dummy_frames (gdbarch, 0);
   set_gdbarch_deprecated_push_arguments (gdbarch, alpha_push_arguments);
-  set_gdbarch_deprecated_pop_frame (gdbarch, alpha_pop_frame);
-
-  /* On the Alpha, the call dummy code is never copied to user space,
-     stopping the user call is achieved via a bp_call_dummy breakpoint.
-     But we need a fake CALL_DUMMY definition to enable the proper
-     call_function_by_hand and to avoid zero length array warnings.  */
   set_gdbarch_deprecated_call_dummy_words (gdbarch, alpha_call_dummy_words);
   set_gdbarch_deprecated_sizeof_call_dummy_words (gdbarch, 0);
-  set_gdbarch_frame_args_address (gdbarch, alpha_frame_args_address);
-  set_gdbarch_frame_locals_address (gdbarch, alpha_frame_locals_address);
-  set_gdbarch_deprecated_init_extra_frame_info (gdbarch, alpha_init_extra_frame_info);
-
-  /* Alpha OSF/1 inhibits execution of code on the stack.  But there is
-     no need for a dummy on the Alpha.  PUSH_ARGUMENTS takes care of all
-     argument handling and bp_call_dummy takes care of stopping the dummy.  */
-  set_gdbarch_call_dummy_address (gdbarch, alpha_call_dummy_address);
   set_gdbarch_deprecated_pc_in_call_dummy (gdbarch, deprecated_pc_in_call_dummy_at_entry_point);
-  set_gdbarch_deprecated_push_dummy_frame (gdbarch, alpha_push_dummy_frame);
-  /* Should be using push_dummy_call.  */
-  set_gdbarch_deprecated_dummy_write_sp (gdbarch, generic_target_write_sp);
   set_gdbarch_deprecated_fix_call_dummy (gdbarch, alpha_fix_call_dummy);
-  set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_noop);
-  set_gdbarch_deprecated_init_frame_pc_first (gdbarch, alpha_init_frame_pc_first);
+
+  /* Methods for saving / extracting a dummy frame's ID.  */
+  set_gdbarch_unwind_dummy_id (gdbarch, alpha_unwind_dummy_id);
+  set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+
+  /* Return the unwound PC value.  */
+  set_gdbarch_unwind_pc (gdbarch, alpha_unwind_pc);
 
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
@@ -1895,27 +1258,12 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (tdep->jb_pc >= 0)
     set_gdbarch_get_longjmp_target (gdbarch, alpha_get_longjmp_target);
 
-  return gdbarch;
-}
-
-static void
-alpha_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
-  if (tdep == NULL)
-    return;
+  frame_unwind_append_predicate (gdbarch, alpha_sigtramp_frame_p);
+  frame_unwind_append_predicate (gdbarch, alpha_heuristic_frame_p);
 
-  fprintf_unfiltered (file,
-                      "alpha_dump_tdep: vm_min_address = 0x%lx\n",
-                     (long) tdep->vm_min_address);
+  frame_base_set_default (gdbarch, &alpha_heuristic_frame_base);
 
-  fprintf_unfiltered (file,
-                     "alpha_dump_tdep: jb_pc = %d\n",
-                     tdep->jb_pc);
-  fprintf_unfiltered (file,
-                     "alpha_dump_tdep: jb_elt_size = %ld\n",
-                     (long) tdep->jb_elt_size);
+  return gdbarch;
 }
 
 void
@@ -1923,8 +1271,7 @@ _initialize_alpha_tdep (void)
 {
   struct cmd_list_element *c;
 
-  gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, alpha_dump_tdep);
-
+  gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, NULL);
   deprecated_tm_print_insn = print_insn_alpha;
 
   /* Let the user set the fence post for heuristic_proc_start.  */
index 0e8aefbfe16c93ccaf103ae0a9822fe8542892ae..412ec37c5a901e9565a6a4cd9b7ff6f3ee0398ba 100644 (file)
 /* Target-dependent structure in gdbarch.  */
 struct gdbarch_tdep
 {
-  CORE_ADDR vm_min_address;    /* used by heuristic_proc_start */
+  CORE_ADDR vm_min_address;    /* Used by alpha_heuristic_proc_start.  */
 
   /* If PC is inside a dynamically-generated signal trampoline function
      (i.e. one copied onto the user stack at run-time), return how many
      bytes PC is beyond the start of that function.  Otherwise, return -1.  */
   LONGEST (*dynamic_sigtramp_offset) (CORE_ADDR);
 
-  /* If FRAME refers to a sigtramp frame, return the address of the next
-     frame.  */
-  CORE_ADDR (*skip_sigtramp_frame) (struct frame_info *, CORE_ADDR);
-
-  /* Translate a signal handler frame into the address of the sigcontext
-     structure for that signal handler.  */
+  /* Translate a signal handler stack base address into the address of
+     the sigcontext structure for that signal handler.  */
   CORE_ADDR (*sigcontext_addr) (struct frame_info *);
 
   int jb_pc;                   /* Offset to PC value in jump buffer.
@@ -101,6 +97,22 @@ struct gdbarch_tdep
   size_t jb_elt_size;          /* And the size of each entry in the buf. */
 };
 
-void alpha_software_single_step (enum target_signal, int);
+extern unsigned int alpha_read_insn (CORE_ADDR pc);
+extern void alpha_software_single_step (enum target_signal, int);
+
+/* Let other files poke at the heuristic unwinder.  */
+extern CORE_ADDR alpha_after_prologue (CORE_ADDR pc);
+extern struct alpha_heuristic_unwind_cache *
+  alpha_heuristic_frame_unwind_cache (struct frame_info *, void **, CORE_ADDR);
+extern void alpha_heuristic_frame_this_id (struct frame_info *, void **,
+                                          struct frame_id *);
+extern void alpha_heuristic_frame_prev_register (struct frame_info *,
+                                                void **, int, int *,
+                                                enum lval_type *,
+                                                CORE_ADDR *, int *, void *);
+extern CORE_ADDR alpha_heuristic_frame_base_address (struct frame_info *,
+                                                    void **);
+
+extern void alpha_mdebug_init_abi (struct gdbarch_info, struct gdbarch *);
 
 #endif /* ALPHA_TDEP_H */
index 25538b345896602563a9c14dd1f82c1dedf6c462..8fe98f264b709ae21770c3c3fa62df4f2d28cb6d 100644 (file)
@@ -1,3 +1,4 @@
 # Target: Little-endian Alpha
-TDEPFILES= alpha-tdep.o alpha-linux-tdep.o solib.o solib-svr4.o solib-legacy.o
+TDEPFILES= alpha-tdep.o alpha-mdebug-tdep.o alpha-linux-tdep.o \
+          solib.o solib-svr4.o solib-legacy.o
 TM_FILE= tm-alphalinux.h
index feb752a14959684b83ef30882dcb566ce4481233..9ced4f238ed599410abae8e495eed8fe1ac0873a 100644 (file)
@@ -64,11 +64,6 @@ typedef struct alpha_extra_func_info
 #define mips_extra_func_info alpha_extra_func_info
 #define mips_extra_func_info_t alpha_extra_func_info_t
 
-
-#define PRINT_EXTRA_FRAME_INFO(fi) alpha_print_extra_frame_info ((fi))
-extern void alpha_print_extra_frame_info (struct frame_info *);
-
-
 /* It takes two values to specify a frame on the ALPHA.  Sigh.
 
    In fact, at the moment, the *PC* is the primary value that sets up
index 4858b90eba210fe6160d1d60fa7b63ec49dabe7a..30ae4f756f36a98e71867e23fe010eca8b3b82ef 100644 (file)
@@ -2,8 +2,8 @@
    definitions here are used when the _target_ system is running
    GNU/Linux.
 
-   Copyright 1996, 1998, 1999, 2000, 2002 Free Software Foundation,
-   Inc.
+   Copyright 1996, 1998, 1999, 2000, 2002, 2003
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 
 #include "alpha/tm-alpha.h"
 
-/* Get start and end address of sigtramp handler.  */
-
-extern LONGEST alpha_linux_sigtramp_offset (CORE_ADDR);
-#define SIGTRAMP_START(pc)     (pc - alpha_linux_sigtramp_offset (pc))
-#define SIGTRAMP_END(pc)       (SIGTRAMP_START(pc) + 3*4)
-
-
 /* Number of traps that happen between exec'ing the shell to run an
    inferior, and when we finally get to the inferior code.  This is 2
    on GNU/Linux and most implementations.  */