Add support for FreeBSD/i386 ELF.
[deliverable/binutils-gdb.git] / gdb / alpha-tdep.c
index a1b53e6e378a68690f506f2b2ad4b7a680b93899..e4962d050b2420c93d62e88035933db12fc4d6fb 100644 (file)
@@ -1,21 +1,22 @@
 /* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger.
-   Copyright 1993 Free Software Foundation, Inc.
+   Copyright 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
 
-This file is part of GDB.
+   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 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.
+   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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   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"
@@ -25,37 +26,49 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "gdbcmd.h"
 #include "gdbcore.h"
 #include "dis-asm.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb_string.h"
 
 /* FIXME: Some of this code should perhaps be merged with mips-tdep.c.  */
 
-#define VM_MIN_ADDRESS (CORE_ADDR)0x120000000
-\f
+/* Prototypes for local functions. */
 
-/* Forward declarations.  */
+static alpha_extra_func_info_t push_sigtramp_desc PARAMS ((CORE_ADDR low_addr));
 
-static CORE_ADDR
-read_next_frame_reg PARAMS ((FRAME, int));
+static CORE_ADDR read_next_frame_reg PARAMS ((struct frame_info *, int));
 
-static CORE_ADDR
-heuristic_proc_start PARAMS ((CORE_ADDR));
+static CORE_ADDR heuristic_proc_start PARAMS ((CORE_ADDR));
 
-static alpha_extra_func_info_t
-heuristic_proc_desc PARAMS ((CORE_ADDR, CORE_ADDR, FRAME));
+static alpha_extra_func_info_t heuristic_proc_desc PARAMS ((CORE_ADDR,
+                                                           CORE_ADDR,
+                                                     struct frame_info *));
 
-static alpha_extra_func_info_t
-find_proc_desc PARAMS ((CORE_ADDR, FRAME));
+static alpha_extra_func_info_t find_proc_desc PARAMS ((CORE_ADDR,
+                                                      struct frame_info *));
 
-static int
-alpha_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+#if 0
+static int alpha_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+#endif
 
-static void
-reinit_frame_cache_sfunc PARAMS ((char *, int, struct cmd_list_element *));
+static void reinit_frame_cache_sfunc PARAMS ((char *, int,
+                                             struct cmd_list_element *));
+
+static CORE_ADDR after_prologue PARAMS ((CORE_ADDR pc,
+                                        alpha_extra_func_info_t proc_desc));
+
+static int alpha_in_prologue PARAMS ((CORE_ADDR pc,
+                                     alpha_extra_func_info_t proc_desc));
+
+static int alpha_about_to_return PARAMS ((CORE_ADDR pc));
+
+void _initialize_alpha_tdep PARAMS ((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:
 
                 |                              |
@@ -98,10 +111,16 @@ static unsigned int heuristic_fence_post = 0;
    -------------|-------------------------------|<-- sp
                 |                              |
 */
+/* *INDENT-ON* */
+
+
 
-#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */
-#define PROC_HIGH_ADDR(proc) ((proc)->pdr.iline) /* upper address bound */
-#define PROC_DUMMY_FRAME(proc) ((proc)->pdr.iopt) /* frame for CALL_DUMMY */
+#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)
@@ -116,191 +135,543 @@ static unsigned int heuristic_fence_post = 0;
 #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
+
+/* 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.
+ */
+
+#ifndef TM_LINUXALPHA_H
+/* HACK: Provide a prototype when compiling this file for non
+   linuxalpha targets. */
+long alpha_linux_sigtramp_offset PARAMS ((CORE_ADDR pc));
+#endif
+long
+alpha_linux_sigtramp_offset (pc)
+     CORE_ADDR pc;
 {
-  struct alpha_extra_func_info info;
-  struct linked_proc_info *next;
-} *linked_proc_desc_table = NULL;
+  unsigned int i[3], w;
+  long off;
+
+  if (read_memory_nobpt (pc, (char *) &w, 4) != 0)
+    return -1;
+
+  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;
+    }
+  pc -= off;
+  if (pc & 0x7)
+    {
+      /* designated sequence is not quadword aligned */
+      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;
+}
 \f
-#define READ_FRAME_REG(fi, regno) read_next_frame_reg((fi)->next, regno)
 
-static CORE_ADDR
-read_next_frame_reg(fi, regno)
-     FRAME fi;
-     int regno;
+/* Under OSF/1, the __sigtramp routine is frameless and has a frame
+   size of zero, but we are able to backtrace through it.  */
+CORE_ADDR
+alpha_osf_skip_sigtramp_frame (frame, pc)
+     struct frame_info *frame;
+     CORE_ADDR pc;
+{
+  char *name;
+  find_pc_partial_function (pc, &name, (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
+  if (IN_SIGTRAMP (pc, name))
+    return frame->frame;
+  else
+    return 0;
+}
+\f
+
+/* 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 (low_addr)
+     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;
+  SET_PROC_DESC_IS_DYN_SIGTRAMP (proc_desc);
+  return (proc_desc);
+}
+\f
+
+/* Guaranteed to set frame->saved_regs to some values (it never leaves it
+   NULL).  */
+
+void
+alpha_find_saved_regs (frame)
+     struct frame_info *frame;
 {
-  /* If it is the frame for sigtramp we have a pointer to the sigcontext
-     on the stack.
-     If the stack layout for __sigtramp changes or if sigcontext offsets
-     change we might have to update this code.  */
+  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
-  for (; fi; fi = fi->next)
+  if (frame->signal_handler_caller)
     {
-      if (fi->signal_handler_caller)
+      CORE_ADDR sigcontext_addr;
+
+      sigcontext_addr = SIGCONTEXT_ADDR (frame);
+      for (ireg = 0; ireg < 32; ireg++)
        {
-         int offset;
-         CORE_ADDR sigcontext_addr = read_memory_integer(fi->frame, 8);
+         reg_position = sigcontext_addr + SIGFRAME_REGSAVE_OFF + ireg * 8;
+         frame->saved_regs[ireg] = reg_position;
+       }
+      for (ireg = 0; ireg < 32; ireg++)
+       {
+         reg_position = sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + ireg * 8;
+         frame->saved_regs[FP0_REGNUM + ireg] = reg_position;
+       }
+      frame->saved_regs[PC_REGNUM] = sigcontext_addr + SIGFRAME_PC_OFF;
+      return;
+    }
 
-         if (regno == PC_REGNUM)
-           offset = SIGFRAME_PC_OFF;
-         else if (regno < 32)
-           offset = SIGFRAME_REGSAVE_OFF + regno * 8;
-         else
-           return 0;
-         return read_memory_integer(sigcontext_addr + offset, 8);
-        }
-      else if (regno == SP_REGNUM)
+  proc_desc = 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.  */
+
+  reg_position = frame->frame + 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))
+    {
+      frame->saved_regs[returnreg] = reg_position;
+      reg_position += 8;
+      mask &= ~(1 << returnreg);       /* Clear bit for RA so we
+                                          don't save again later. */
+    }
+
+  for (ireg = 0; ireg <= 31; ++ireg)
+    if (mask & (1 << ireg))
+      {
+       frame->saved_regs[ireg] = reg_position;
+       reg_position += 8;
+      }
+
+  /* Fill in the offsets for the registers which float_mask says
+     were saved.  */
+
+  reg_position = frame->frame + PROC_FREG_OFFSET (proc_desc);
+  mask = PROC_FREG_MASK (proc_desc);
+
+  for (ireg = 0; ireg <= 31; ++ireg)
+    if (mask & (1 << ireg))
+      {
+       frame->saved_regs[FP0_REGNUM + ireg] = reg_position;
+       reg_position += 8;
+      }
+
+  frame->saved_regs[PC_REGNUM] = frame->saved_regs[returnreg];
+}
+
+static CORE_ADDR
+read_next_frame_reg (fi, regno)
+     struct frame_info *fi;
+     int regno;
+{
+  for (; fi; fi = fi->next)
+    {
+      /* We have to get the saved sp from the sigcontext
+         if it is a signal handler frame.  */
+      if (regno == SP_REGNUM && !fi->signal_handler_caller)
        return fi->frame;
-      else if (fi->saved_regs->regs[regno])
-       return read_memory_integer(fi->saved_regs->regs[regno], 8);
+      else
+       {
+         if (fi->saved_regs == NULL)
+           alpha_find_saved_regs (fi);
+         if (fi->saved_regs[regno])
+           return read_memory_integer (fi->saved_regs[regno], 8);
+       }
     }
-  return read_register(regno);
+  return read_register (regno);
 }
 
 CORE_ADDR
-alpha_frame_saved_pc(frame)
-     FRAME frame;
+alpha_frame_saved_pc (frame)
+     struct frame_info *frame;
 {
   alpha_extra_func_info_t proc_desc = frame->proc_desc;
-  int pcreg = proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM;
+  /* We have to get the saved pc from the sigcontext
+     if it is a signal handler frame.  */
+  int pcreg = frame->signal_handler_caller ? PC_REGNUM : frame->pc_reg;
 
-  if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
-      return read_memory_integer(frame->frame - 8, 8);
+  if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc))
+    return read_memory_integer (frame->frame - 8, 8);
 
-  return read_next_frame_reg(frame, pcreg);
+  return read_next_frame_reg (frame, pcreg);
 }
 
 CORE_ADDR
 alpha_saved_pc_after_call (frame)
-     FRAME frame;
+     struct frame_info *frame;
 {
-  alpha_extra_func_info_t proc_desc = find_proc_desc (frame->pc, frame->next);
-  int pcreg = proc_desc ? PROC_PC_REG (proc_desc) : RA_REGNUM;
+  CORE_ADDR pc = frame->pc;
+  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;
 
-  return read_register (pcreg);
+  proc_desc = find_proc_desc (pc, frame->next);
+  pcreg = proc_desc ? PROC_PC_REG (proc_desc) : RA_REGNUM;
+
+  if (frame->signal_handler_caller)
+    return alpha_frame_saved_pc (frame);
+  else
+    return read_register (pcreg);
 }
 
 
 static struct alpha_extra_func_info temp_proc_desc;
 static struct frame_saved_regs temp_saved_regs;
 
+/* Nonzero if instruction at PC is a return instruction.  "ret
+   $zero,($ra),1" on alpha. */
+
+static int
+alpha_about_to_return (pc)
+     CORE_ADDR pc;
+{
+  return read_memory_integer (pc, 4) == 0x6bfa8001;
+}
+
+
+
 /* This fencepost looks highly suspicious to me.  Removing it also
    seems suspicious as it could affect remote debugging across serial
    lines.  */
 
 static CORE_ADDR
-heuristic_proc_start(pc)
-    CORE_ADDR pc;
+heuristic_proc_start (pc)
+     CORE_ADDR pc;
 {
-    CORE_ADDR start_pc = pc;
-    CORE_ADDR fence = start_pc - heuristic_fence_post;
+  CORE_ADDR start_pc = pc;
+  CORE_ADDR fence = start_pc - heuristic_fence_post;
 
-    if (start_pc == 0) return 0;
+  if (start_pc == 0)
+    return 0;
 
-    if (heuristic_fence_post == UINT_MAX
-       || fence < VM_MIN_ADDRESS)
-      fence = VM_MIN_ADDRESS;
+  if (heuristic_fence_post == UINT_MAX
+      || fence < VM_MIN_ADDRESS)
+    fence = VM_MIN_ADDRESS;
 
-    /* search back for previous return */
-    for (start_pc -= 4; ; start_pc -= 4)
-       if (start_pc < fence)
+  /* 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_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_quietly)
          {
-           /* It's not clear to me why we reach this point when
-              stop_soon_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_quietly)
+           static int blurb_printed = 0;
+
+           if (fence == 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)
              {
-               static int blurb_printed = 0;
-
-               if (fence == 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%lx", pc);
-               if (!blurb_printed)
-                 {
-                   printf_filtered ("\
+               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;
-                 }
+               blurb_printed = 1;
              }
-
-           return 0; 
          }
-       else if (ABOUT_TO_RETURN(start_pc))
-           break;
 
-    start_pc += 4; /* skip return */
-    return start_pc;
+       return 0;
+      }
+    else if (alpha_about_to_return (start_pc))
+      break;
+
+  start_pc += 4;               /* skip return */
+  return start_pc;
 }
 
 static alpha_extra_func_info_t
-heuristic_proc_desc(start_pc, limit_pc, next_frame)
-    CORE_ADDR start_pc, limit_pc;
-    FRAME next_frame;
+heuristic_proc_desc (start_pc, limit_pc, next_frame)
+     CORE_ADDR start_pc, limit_pc;
+     struct frame_info *next_frame;
 {
-    CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM);
-    CORE_ADDR cur_pc;
-    int frame_size;
-    int has_frame_reg = 0;
-    unsigned long reg_mask = 0;
-
-    if (start_pc == 0)
-      return NULL;
-    memset(&temp_proc_desc, '\0', sizeof(temp_proc_desc));
-    memset(&temp_saved_regs, '\0', sizeof(struct frame_saved_regs));
-    PROC_LOW_ADDR(&temp_proc_desc) = start_pc;
-
-    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;
-
-       status = read_memory_nobpt (cur_pc, buf, 4); 
-       if (status)
-         memory_error (status, cur_pc);
-       word = extract_unsigned_integer (buf, 4);
-
-       if ((word & 0xffff0000) == 0x23de0000)          /* lda $sp,n($sp) */
-         frame_size += (-word) & 0xffff;
-       else if ((word & 0xfc1f0000) == 0xb41e0000      /* stq reg,n($sp) */
-                && (word & 0xffff0000) != 0xb7fe0000)  /* reg != $zero */
-         {
-           int reg = (word & 0x03e00000) >> 21;
-           reg_mask |= 1 << reg;
-           temp_saved_regs.regs[reg] = sp + (short)word;
-         }
-       else if (word == 0x47de040f)                    /* bis sp,sp fp */
-         has_frame_reg = 1;
-      }
-    if (has_frame_reg)
-      PROC_FRAME_REG(&temp_proc_desc) = GCC_FP_REGNUM;
-    else
-      PROC_FRAME_REG(&temp_proc_desc) = SP_REGNUM;
-    PROC_FRAME_OFFSET(&temp_proc_desc) = frame_size;
-    PROC_REG_MASK(&temp_proc_desc) = reg_mask;
-    PROC_PC_REG(&temp_proc_desc) = RA_REGNUM;
-    return &temp_proc_desc;
+  CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM);
+  CORE_ADDR cur_pc;
+  int frame_size;
+  int has_frame_reg = 0;
+  unsigned long reg_mask = 0;
+  int pcreg = -1;
+
+  if (start_pc == 0)
+    return NULL;
+  memset (&temp_proc_desc, '\0', sizeof (temp_proc_desc));
+  memset (&temp_saved_regs, '\0', sizeof (struct frame_saved_regs));
+  PROC_LOW_ADDR (&temp_proc_desc) = start_pc;
+
+  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;
+
+      status = read_memory_nobpt (cur_pc, buf, 4);
+      if (status)
+       memory_error (status, cur_pc);
+      word = extract_unsigned_integer (buf, 4);
+
+      if ((word & 0xffff0000) == 0x23de0000)   /* lda $sp,n($sp) */
+       {
+         if (word & 0x8000)
+           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;
+         temp_saved_regs.regs[reg] = sp + (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 == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM))
+           pcreg = reg;
+       }
+      else if ((word & 0xffe0ffff) == 0x6be08001)      /* ret zero,reg,1 */
+       pcreg = (word >> 16) & 0x1f;
+      else if (word == 0x47de040f)     /* bis sp,sp fp */
+       has_frame_reg = 1;
+    }
+  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;
+
+         if (read_memory_nobpt (cur_pc, buf, 4))
+           break;
+         cur_pc += 4;
+         word = extract_unsigned_integer (buf, 4);
+
+         if ((word & 0xfc1f0000) == 0xb41e0000         /* stq reg,n($sp) */
+             && (word & 0xffff0000) != 0xb7fe0000)     /* reg != $zero */
+           {
+             int reg = (word & 0x03e00000) >> 21;
+             if (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM)
+               {
+                 pcreg = reg;
+                 break;
+               }
+           }
+         else if ((word & 0xffe0ffff) == 0x6be08001)   /* ret zero,reg,1 */
+           {
+             pcreg = (word >> 16) & 0x1f;
+             break;
+           }
+       }
+    }
+
+  if (has_frame_reg)
+    PROC_FRAME_REG (&temp_proc_desc) = GCC_FP_REGNUM;
+  else
+    PROC_FRAME_REG (&temp_proc_desc) = SP_REGNUM;
+  PROC_FRAME_OFFSET (&temp_proc_desc) = frame_size;
+  PROC_REG_MASK (&temp_proc_desc) = reg_mask;
+  PROC_PC_REG (&temp_proc_desc) = (pcreg == -1) ? RA_REGNUM : pcreg;
+  PROC_LOCALOFF (&temp_proc_desc) = 0; /* XXX - bogus */
+  return &temp_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
+after_prologue (pc, proc_desc)
+     CORE_ADDR pc;
+     alpha_extra_func_info_t proc_desc;
+{
+  struct symtab_and_line sal;
+  CORE_ADDR func_addr, func_end;
+
+  if (!proc_desc)
+    proc_desc = find_proc_desc (pc, NULL);
+
+  if (proc_desc)
+    {
+      if (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;
+    }
+
+  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;
+
+  /* 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;
+}
+
+/* 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_in_prologue (pc, proc_desc)
+     CORE_ADDR pc;
+     alpha_extra_func_info_t proc_desc;
+{
+  CORE_ADDR after_prologue_pc;
+
+  after_prologue_pc = after_prologue (pc, proc_desc);
+
+  if (after_prologue_pc == 0
+      || pc < after_prologue_pc)
+    return 1;
+  else
+    return 0;
 }
 
 static alpha_extra_func_info_t
-find_proc_desc(pc, next_frame)
-    CORE_ADDR pc;
-    FRAME next_frame;
+find_proc_desc (pc, next_frame)
+     CORE_ADDR pc;
+     struct frame_info *next_frame;
 {
   alpha_extra_func_info_t proc_desc;
   struct block *b;
@@ -314,10 +685,11 @@ find_proc_desc(pc, next_frame)
      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 (PC_IN_CALL_DUMMY (pc, 0, 0))
     {
       struct linked_proc_info *link;
-      CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM);
+      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;
 
@@ -334,7 +706,8 @@ find_proc_desc(pc, next_frame)
        return found_proc_desc;
     }
 
-  b = block_for_pc(pc);
+  b = block_for_pc (pc);
+
   find_pc_partial_function (pc, NULL, &startaddr, NULL);
   if (b == NULL)
     sym = NULL;
@@ -350,48 +723,65 @@ find_proc_desc(pc, next_frame)
                             0, NULL);
     }
 
+  /* 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;
+
   if (sym)
     {
-       /* IF (this is the topmost frame OR a frame interrupted by a signal)
-        * 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 || next_frame->signal_handler_caller) {
-           struct symtab_and_line val;
-           struct symbol *proc_symbol =
-               PROC_DESC_IS_DUMMY(proc_desc) ? 0 : PROC_SYMBOL(proc_desc);
-
-           if (proc_symbol) {
-               val = find_pc_line (BLOCK_START
-                                   (SYMBOL_BLOCK_VALUE(proc_symbol)),
-                                   0);
-               val.pc = val.end ? val.end : pc;
-           }
-           if (!proc_symbol || pc < val.pc) {
-               alpha_extra_func_info_t found_heuristic =
-                   heuristic_proc_desc(PROC_LOW_ADDR(proc_desc),
-                                       pc, next_frame);
-               if (found_heuristic)
-                 {
-                   /* The call to heuristic_proc_desc determines
-                      which registers have been saved so far and if the
-                      frame is already set up.
-                      The heuristic algorithm doesn't work well for other
-                      information in the procedure descriptor, so copy
-                      it from the found procedure descriptor.  */
-                   PROC_LOCALOFF(found_heuristic) = PROC_LOCALOFF(proc_desc);
-                   PROC_PC_REG(found_heuristic) = PROC_PC_REG(proc_desc);
-                   proc_desc = found_heuristic;
-                 }
+      /* 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
     {
-      if (startaddr == 0)
+      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 = 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 =
@@ -402,147 +792,96 @@ find_proc_desc(pc, next_frame)
 
 alpha_extra_func_info_t cached_proc_desc;
 
-FRAME_ADDR
-alpha_frame_chain(frame)
-    FRAME frame;
+CORE_ADDR
+alpha_frame_chain (frame)
+     struct frame_info *frame;
 {
-    alpha_extra_func_info_t proc_desc;
-    CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
-
-    if (saved_pc == 0 || inside_entry_file (saved_pc))
-      return 0;
-
-    proc_desc = find_proc_desc(saved_pc, frame);
-    if (!proc_desc)
-      return 0;
-
-    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 (FRAME_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 alpha __sigtramp routine is frameless and has a frame size
-          of zero. Luckily it is the only procedure which has PC_REGNUM
-          as PROC_PC_REG.  */
-       && PROC_PC_REG (proc_desc) != PC_REGNUM
-       /* The previous frame from a sigtramp frame might be frameless
-          and have frame size zero.  */
-       && !frame->signal_handler_caller)
-      return 0;
-    else
-      return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
-       + PROC_FRAME_OFFSET(proc_desc);
+  alpha_extra_func_info_t proc_desc;
+  CORE_ADDR saved_pc = FRAME_SAVED_PC (frame);
+
+  if (saved_pc == 0 || inside_entry_file (saved_pc))
+    return 0;
+
+  proc_desc = find_proc_desc (saved_pc, frame);
+  if (!proc_desc)
+    return 0;
+
+  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.  */
+      && !frame->signal_handler_caller)
+    return FRAME_PAST_SIGTRAMP_FRAME (frame, saved_pc);
+  else
+    return read_next_frame_reg (frame, PROC_FRAME_REG (proc_desc))
+      + PROC_FRAME_OFFSET (proc_desc);
 }
 
 void
-init_extra_frame_info(fci)
-     struct frame_info *fci;
+init_extra_frame_info (frame)
+     struct frame_info *frame;
 {
-  extern struct obstack frame_cache_obstack;
   /* Use proc_desc calculated in frame_chain */
   alpha_extra_func_info_t proc_desc =
-    fci->next ? cached_proc_desc : find_proc_desc(fci->pc, fci->next);
+  frame->next ? cached_proc_desc : find_proc_desc (frame->pc, frame->next);
 
-  fci->saved_regs = (struct frame_saved_regs*)
-    obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs));
-  memset (fci->saved_regs, 0, sizeof (struct frame_saved_regs));
-  fci->proc_desc =
-    proc_desc == &temp_proc_desc ? 0 : proc_desc;
+  frame->saved_regs = NULL;
+  frame->localoff = 0;
+  frame->pc_reg = RA_REGNUM;
+  frame->proc_desc = proc_desc == &temp_proc_desc ? 0 : proc_desc;
   if (proc_desc)
     {
-      int ireg;
-      CORE_ADDR reg_position;
-      unsigned long mask;
-      int returnreg;
-
-      /* Get the locals offset from the procedure descriptor, it is valid
-        even if we are in the middle of the prologue.  */
-      fci->localoff = PROC_LOCALOFF(proc_desc);
+      /* 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.  */
+      frame->localoff = PROC_LOCALOFF (proc_desc);
+      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))
-       fci->frame = (FRAME_ADDR) PROC_DUMMY_FRAME(proc_desc);
+         descriptor.  */
+      if (PROC_DESC_IS_DUMMY (proc_desc))
+       frame->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 (fci->pc == PROC_LOW_ADDR(proc_desc))
-       fci->frame = READ_FRAME_REG(fci, SP_REGNUM);
+         Get the value of the frame relative sp, procedure might have been
+         interrupted by a signal at it's very start.  */
+      else if (frame->pc == PROC_LOW_ADDR (proc_desc)
+              && !PROC_DESC_IS_DYN_SIGTRAMP (proc_desc))
+       frame->frame = read_next_frame_reg (frame->next, SP_REGNUM);
       else
-       fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc))
-                     + PROC_FRAME_OFFSET(proc_desc);
-
-      /* If this is the innermost frame, and we are still in the
-        prologue (loosely defined), then the registers may not have
-        been saved yet.  */
-      if (fci->next == NULL
-          && !PROC_DESC_IS_DUMMY(proc_desc)
-         && alpha_in_lenient_prologue (PROC_LOW_ADDR (proc_desc), fci->pc))
-       {
-         /* Can't just say that the registers are not saved, because they
-            might get clobbered halfway through the prologue.
-            heuristic_proc_desc already has the right code to figure out
-            exactly what has been saved, so use it.  As far as I know we
-            could be doing this (as we do on the 68k, for example)
-            regardless of whether we are in the prologue; I'm leaving in
-            the check for being in the prologue only out of conservatism
-            (I'm not sure whether heuristic_proc_desc handles all cases,
-            for example).
-
-            This stuff is ugly (and getting uglier by the minute).  Probably
-            the best way to clean it up is to ignore the proc_desc's from
-            the symbols altogher, and get all the information we need by
-            examining the prologue (provided we can make the prologue
-            examining code good enough to get all the cases...).  */
-         proc_desc =
-           heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
-                                fci->pc,
-                                fci->next);
-       }
+       frame->frame = read_next_frame_reg (frame->next, PROC_FRAME_REG (proc_desc))
+         + PROC_FRAME_OFFSET (proc_desc);
 
       if (proc_desc == &temp_proc_desc)
-       *fci->saved_regs = temp_saved_regs;
-      else
        {
-         /* Find which general-purpose registers were saved.
-            The return address register is the first saved register,
-            the other registers follow in ascending order.  */
-         reg_position = fci->frame + PROC_REG_OFFSET(proc_desc);
-         mask = PROC_REG_MASK(proc_desc) & 0xffffffffL;
-         returnreg = PROC_PC_REG(proc_desc);
-         if (mask & (1 << returnreg))
+         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 frame->signal_handler_caller, it is not yet set.  */
+         find_pc_partial_function (frame->pc, &name,
+                                   (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
+         if (!IN_SIGTRAMP (frame->pc, name))
            {
-             fci->saved_regs->regs[returnreg] = reg_position;
-             reg_position += 8;
+             frame->saved_regs = (CORE_ADDR *)
+               frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS);
+             memcpy (frame->saved_regs, temp_saved_regs.regs, SIZEOF_FRAME_SAVED_REGS);
+             frame->saved_regs[PC_REGNUM]
+               = frame->saved_regs[RA_REGNUM];
            }
-         for (ireg = 0; mask; ireg++, mask >>= 1)
-           if (mask & 1)
-             {
-               if (ireg == returnreg)
-                 continue;
-               fci->saved_regs->regs[ireg] = reg_position;
-               reg_position += 8;
-             }
-         /* find which floating-point registers were saved */
-         reg_position = fci->frame + PROC_FREG_OFFSET(proc_desc);
-         mask = PROC_FREG_MASK(proc_desc) & 0xffffffffL;
-         for (ireg = 0; mask; ireg++, mask >>= 1)
-           if (mask & 1)
-             {
-               fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
-               reg_position += 8;
-             }
        }
-
-      fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[PROC_PC_REG(proc_desc)];
     }
 }
 
@@ -561,10 +900,10 @@ init_extra_frame_info(fci)
    cache.  This allows the rest of info frame to extract the important
    arguments without difficulty.  */
 
-FRAME
+struct frame_info *
 setup_arbitrary_frame (argc, argv)
      int argc;
-     FRAME_ADDR *argv;
+     CORE_ADDR *argv;
 {
   if (argc != 2)
     error ("ALPHA frame specifications require two arguments: sp and pc");
@@ -584,32 +923,52 @@ setup_arbitrary_frame (argc, argv)
 
 CORE_ADDR
 alpha_push_arguments (nargs, args, sp, struct_return, struct_addr)
-  int nargs;
-  value *args;
-  CORE_ADDR sp;
-  int struct_return;
-  CORE_ADDR struct_addr;
+     int nargs;
+     value_ptr *args;
+     CORE_ADDR sp;
+     int struct_return;
+     CORE_ADDR struct_addr;
 {
-  register i;
+  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
+    {
+      char *contents;
+      int len;
+      int offset;
+    };
   struct alpha_arg *alpha_args =
-      (struct alpha_arg*)alloca (nargs * sizeof (struct alpha_arg));
+  (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;
 
   for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++)
     {
-      value arg = value_arg_coerce (args[i]);
+      value_ptr arg = args[i];
+      struct type *arg_type = check_typedef (VALUE_TYPE (arg));
       /* Cast argument to long if necessary as the compiler does it too.  */
-      if (TYPE_LENGTH (VALUE_TYPE (arg)) < TYPE_LENGTH (builtin_type_long))
-        arg = value_cast (builtin_type_long, arg);
-      m_arg->len = TYPE_LENGTH (VALUE_TYPE (arg));
+      switch (TYPE_CODE (arg_type))
+       {
+       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;
+       }
+      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);
+      m_arg->contents = VALUE_CONTENTS (arg);
     }
 
   /* Determine required argument register loads, loading an argument register
@@ -620,15 +979,15 @@ alpha_push_arguments (nargs, args, sp, struct_return, struct_addr)
 
   /* Make room for the arguments on the stack.  */
   if (accumulate_size < arg_regs_size)
-    accumulate_size = arg_regs_size; 
+    accumulate_size = arg_regs_size;
   sp -= accumulate_size;
 
   /* Keep sp aligned to a multiple of 16 as the compiler does it too.  */
   sp &= ~15;
 
   /* `Push' arguments on the stack.  */
-  for (i = nargs; m_arg--, --i >= 0; )
-    write_memory(sp + m_arg->offset, m_arg->contents, m_arg->len);
+  for (i = nargs; m_arg--, --i >= 0;)
+    write_memory (sp + m_arg->offset, m_arg->contents, m_arg->len);
   if (struct_return)
     {
       store_address (raw_buffer, sizeof (CORE_ADDR), struct_addr);
@@ -649,20 +1008,22 @@ alpha_push_arguments (nargs, args, sp, struct_return, struct_addr)
 }
 
 void
-alpha_push_dummy_frame()
+alpha_push_dummy_frame ()
 {
   int ireg;
-  struct linked_proc_info *link = (struct linked_proc_info*)
-      xmalloc(sizeof (struct linked_proc_info));
-  alpha_extra_func_info_t proc_desc = &link->info;
+  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[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.
@@ -670,20 +1031,20 @@ alpha_push_dummy_frame()
    *
    * Dummy frame layout:
    *  (high memory)
-   *   Saved PC
+   *    Saved PC
    *    Saved F30
    *    ...
    *    Saved F0
-   *   Saved R29
-   *   ...
-   *   Saved R0
-   *   Saved R26 (RA)
-   *   Parameter build area
+   *    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) (((1L << ((j)+1)) - 1) ^ ((1L << (i)) - 1))
+#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))
@@ -692,27 +1053,27 @@ alpha_push_dummy_frame()
      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_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
+  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;
+       + 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);
+  save_address = sp + PROC_REG_OFFSET (proc_desc);
   store_address (raw_buffer, 8, read_register (RA_REGNUM));
   write_memory (save_address, raw_buffer, 8);
   save_address += 8;
-  mask = PROC_REG_MASK(proc_desc) & 0xffffffffL;
+  mask = PROC_REG_MASK (proc_desc) & 0xffffffffL;
   for (ireg = 0; mask; ireg++, mask >>= 1)
     if (mask & 1)
       {
@@ -727,8 +1088,8 @@ alpha_push_dummy_frame()
   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;
+  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)
       {
@@ -749,47 +1110,57 @@ alpha_push_dummy_frame()
      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) = FP_REGNUM;
-  PROC_FRAME_OFFSET(proc_desc) = 0;
-  sp += PROC_REG_OFFSET(proc_desc);
+  PROC_DUMMY_FRAME (proc_desc) = sp;
+  PROC_FRAME_REG (proc_desc) = FP_REGNUM;
+  PROC_FRAME_OFFSET (proc_desc) = 0;
+  sp += PROC_REG_OFFSET (proc_desc);
   write_register (SP_REGNUM, sp);
 
-  PROC_LOW_ADDR(proc_desc) = entry_point_address ();
-  PROC_HIGH_ADDR(proc_desc) = PROC_LOW_ADDR(proc_desc) + 4;
+  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) = RA_REGNUM;
+  SET_PROC_DESC_IS_DUMMY (proc_desc);
+  PROC_PC_REG (proc_desc) = RA_REGNUM;
 }
 
 void
-alpha_pop_frame()
+alpha_pop_frame ()
 {
   register int regnum;
-  FRAME frame = get_current_frame ();
+  struct frame_info *frame = get_current_frame ();
   CORE_ADDR new_sp = frame->frame;
 
   alpha_extra_func_info_t proc_desc = frame->proc_desc;
 
-  write_register (PC_REGNUM, FRAME_SAVED_PC(frame));
+  /* 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 (frame->pc, frame->next);
+
+  /* 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... */
+
+  write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
+  if (frame->saved_regs == NULL)
+    alpha_find_saved_regs (frame);
   if (proc_desc)
     {
-      for (regnum = 32; --regnum >= 0; )
-       if (PROC_REG_MASK(proc_desc) & (1 << regnum))
+      for (regnum = 32; --regnum >= 0;)
+       if (PROC_REG_MASK (proc_desc) & (1 << regnum))
          write_register (regnum,
-                         read_memory_integer (frame->saved_regs->regs[regnum],
+                         read_memory_integer (frame->saved_regs[regnum],
                                               8));
-      for (regnum = 32; --regnum >= 0; )
-       if (PROC_FREG_MASK(proc_desc) & (1 << regnum))
+      for (regnum = 32; --regnum >= 0;)
+       if (PROC_FREG_MASK (proc_desc) & (1 << regnum))
          write_register (regnum + FP0_REGNUM,
-                         read_memory_integer (frame->saved_regs->regs[regnum + FP0_REGNUM], 8));
+          read_memory_integer (frame->saved_regs[regnum + FP0_REGNUM], 8));
     }
   write_register (SP_REGNUM, new_sp);
   flush_cached_frames ();
-  /* We let init_extra_frame_info figure out the frame pointer */
-  set_current_frame (create_new_frame (0, read_pc ()));
 
-  if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
+  if (proc_desc && (PROC_DESC_IS_DUMMY (proc_desc)
+                   || PROC_DESC_IS_DYN_SIGTRAMP (proc_desc)))
     {
       struct linked_proc_info *pi_ptr, *prev_ptr;
 
@@ -827,49 +1198,77 @@ alpha_skip_prologue (pc, lenient)
      CORE_ADDR pc;
      int lenient;
 {
-    unsigned long inst;
-    int offset;
+  unsigned long inst;
+  int offset;
+  CORE_ADDR post_prologue_pc;
+  char buf[4];
+
+#ifdef GDB_TARGET_HAS_SHARED_LIBS
+  /* 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.  */
+  if (target_read_memory (pc, buf, 4))
+    return pc;
+#endif
 
-    /* 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)
-      {
-       char buf[4];
-       int status;
+  /* 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.  */
 
-       status = read_memory_nobpt (pc + offset, buf, 4);
-       if (status)
-         memory_error (status, pc + offset);
-       inst = extract_unsigned_integer (buf, 4);
+  post_prologue_pc = after_prologue (pc, NULL);
 
-       /* 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;
+  if (post_prologue_pc != 0)
+    return max (pc, post_prologue_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;
-       else if ((inst & 0xfc1f0000) == 0xb41e0000
-                && (inst & 0xffff0000) != 0xb7fe0000)
-           continue;                           /* stq reg,n($sp) */
-                                               /* reg != $zero */
-       else if ((inst & 0xfc1f0000) == 0x9c1e0000
-                && (inst & 0xffff0000) != 0x9ffe0000)
-           continue;                           /* stt reg,n($sp) */
-                                               /* reg != $zero */
-       else if (inst == 0x47de040f)            /* bis sp,sp,fp */
-           continue;
-       else
-           break;
+  /* Can't determine prologue from the symbol table, need to examine
+     instructions.  */
+
+  /* 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)
+    {
+      int status;
+
+      status = read_memory_nobpt (pc + offset, buf, 4);
+      if (status)
+       memory_error (status, pc + offset);
+      inst = extract_unsigned_integer (buf, 4);
+
+      /* 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;
+
+      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 ((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;
+
+      break;
     }
-    return pc + offset;
+  return pc + offset;
 }
 
+#if 0
 /* Is address PC in the prologue (loosely defined) for function at
    STARTADDR?  */
 
@@ -881,19 +1280,20 @@ alpha_in_lenient_prologue (startaddr, pc)
   CORE_ADDR end_prologue = alpha_skip_prologue (startaddr, 1);
   return pc >= startaddr && pc < end_prologue;
 }
+#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
+   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. */
+   memory format is an integer with 4 bytes or less, as the representation
+   of integers in floating point registers is different. */
 void
 alpha_register_convert_to_virtual (regnum, valtype, raw_buffer, virtual_buffer)
-    int regnum;
-    struct type *valtype;
-    char *raw_buffer;
-    char *virtual_buffer;
+     int regnum;
+     struct type *valtype;
+     char *raw_buffer;
+     char *virtual_buffer;
 {
   if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
     {
@@ -908,7 +1308,7 @@ alpha_register_convert_to_virtual (regnum, valtype, raw_buffer, virtual_buffer)
     }
   else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
     {
-      unsigned LONGEST l;
+      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);
@@ -919,10 +1319,10 @@ alpha_register_convert_to_virtual (regnum, valtype, raw_buffer, virtual_buffer)
 
 void
 alpha_register_convert_to_raw (valtype, regnum, virtual_buffer, raw_buffer)
-    struct type *valtype;
-    int regnum;
-    char *virtual_buffer;
-    char *raw_buffer;
+     struct type *valtype;
+     int regnum;
+     char *virtual_buffer;
+     char *raw_buffer;
 {
   if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
     {
@@ -937,7 +1337,7 @@ alpha_register_convert_to_raw (valtype, regnum, virtual_buffer, raw_buffer)
     }
   else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
     {
-      unsigned LONGEST l;
+      ULONGEST l;
       if (TYPE_UNSIGNED (valtype))
        l = extract_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype));
       else
@@ -951,52 +1351,48 @@ alpha_register_convert_to_raw (valtype, regnum, virtual_buffer, raw_buffer)
 
 /* Given a return value in `regbuf' with a type `valtype', 
    extract and copy its value into `valbuf'.  */
+
 void
 alpha_extract_return_value (valtype, regbuf, valbuf)
-    struct type *valtype;
-    char regbuf[REGISTER_BYTES];
-    char *valbuf;
+     struct type *valtype;
+     char regbuf[REGISTER_BYTES];
+     char *valbuf;
 {
-  int regnum;
-  
-  regnum = TYPE_CODE (valtype) == TYPE_CODE_FLT ? FP0_REGNUM : V0_REGNUM;
-
-  memcpy (valbuf, regbuf + REGISTER_BYTE (regnum), TYPE_LENGTH (valtype));
+  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 (V0_REGNUM), TYPE_LENGTH (valtype));
 }
 
 /* Given a return value in `regbuf' with a type `valtype', 
-   write it's value into the appropriate register.  */
+   write its value into the appropriate register.  */
+
 void
 alpha_store_return_value (valtype, valbuf)
-    struct type *valtype;
-    char *valbuf;
+     struct type *valtype;
+     char *valbuf;
 {
-  int regnum;
   char raw_buffer[MAX_REGISTER_RAW_SIZE];
-  
-  regnum = TYPE_CODE (valtype) == TYPE_CODE_FLT ? FP0_REGNUM : V0_REGNUM;
-  memcpy(raw_buffer, valbuf, TYPE_LENGTH (valtype));
+  int regnum = V0_REGNUM;
+  int length = TYPE_LENGTH (valtype);
 
-  write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
-}
-
-/* Print the instruction at address MEMADDR in debugged memory,
-   on STREAM.  Returns length of the instruction, in bytes.  */
-
-int
-print_insn (memaddr, stream)
-     CORE_ADDR memaddr;
-     GDB_FILE *stream;
-{
-  disassemble_info info;
-
-  GDB_INIT_DISASSEMBLE_INFO(info, stream);
+  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);
 
-  return print_insn_alpha (memaddr, &info);
+  write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length);
 }
 
 /* Just like reinit_frame_cache, but with the right arguments to be
    callable as an sfunc.  */
+
 static void
 reinit_frame_cache_sfunc (args, from_tty, c)
      char *args;
@@ -1006,11 +1402,37 @@ reinit_frame_cache_sfunc (args, from_tty, 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 ()
+{
+  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;
+}
+
 void
 _initialize_alpha_tdep ()
 {
   struct cmd_list_element *c;
 
+  tm_print_insn = print_insn_alpha;
+
   /* Let the user set the fence post for heuristic_proc_start.  */
 
   /* We really would like to have both "0" and "unlimited" work, but
This page took 0.04184 seconds and 4 git commands to generate.