2002-04-24 David S. Miller <davem@redhat.com>
[deliverable/binutils-gdb.git] / gdb / i960-tdep.c
index 35c145d819c000bdc25d4b513852f8df81664557..98718a387a06b438a2186b82404318753d55633e 100644 (file)
 /* Target-machine dependent code for the Intel 960
-   Copyright (C) 1991 Free Software Foundation, Inc.
+
+   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+   2001, 2002 Free Software Foundation, Inc.
+
    Contributed by Intel Corporation.
    examine_prologue and other parts contributed by Wind River Systems.
 
-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 file is part of GDB.
 
-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 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.
 
-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.  */
+   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.
 
-/* Miscellaneous i80960-dependent routines.
-   Most are called from macros defined in "tm-i960.h".  */
+   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 <signal.h>
 #include "symtab.h"
 #include "value.h"
 #include "frame.h"
-#include "signame.h"
-#include "ieee-float.h"
+#include "floatformat.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
 
-/* Structure of i960 extended floating point format.  */
+static CORE_ADDR next_insn (CORE_ADDR memaddr,
+                           unsigned int *pword1, unsigned int *pword2);
 
-const struct ext_format ext_format_i960 = {
-/* tot sbyte smask expbyte manbyte */
-   12, 9,    0x80, 9,8,           4,0,         /* i960 */
-};
+struct type *
+i960_register_type (int regnum)
+{
+  if (regnum < FP0_REGNUM)
+    return builtin_type_int32;
+  else
+    return builtin_type_i960_ext;
+}
+
+
+/* Does the specified function use the "struct returning" convention
+   or the "value returning" convention?  The "value returning" convention
+   almost invariably returns the entire value in registers.  The
+   "struct returning" convention often returns the entire value in
+   memory, and passes a pointer (out of or into the function) saying
+   where the value (is or should go).
+
+   Since this sometimes depends on whether it was compiled with GCC,
+   this is also an argument.  This is used in call_function to build a
+   stack, and in value_being_returned to print return values.
+
+   On i960, a structure is returned in registers g0-g3, if it will fit.
+   If it's more than 16 bytes long, g13 pointed to it on entry.  */
+
+int
+i960_use_struct_convention (int gcc_p, struct type *type)
+{
+  return (TYPE_LENGTH (type) > 16);
+}
 
 /* gdb960 is always running on a non-960 host.  Check its characteristics.
    This routine must be called as part of gdb initialization.  */
 
 static void
-check_host()
+check_host (void)
 {
-       int i;
-
-       static struct typestruct {
-               int hostsize;           /* Size of type on host         */
-               int i960size;           /* Size of type on i960         */
-               char *typename;         /* Name of type, for error msg  */
-       } types[] = {
-               { sizeof(short),  2, "short" },
-               { sizeof(int),    4, "int" },
-               { sizeof(long),   4, "long" },
-               { sizeof(float),  4, "float" },
-               { sizeof(double), 8, "double" },
-               { sizeof(char *), 4, "pointer" },
-       };
+  int i;
+
+  static struct typestruct
+    {
+      int hostsize;            /* Size of type on host         */
+      int i960size;            /* Size of type on i960         */
+      char *typename;          /* Name of type, for error msg  */
+    }
+  types[] =
+  {
+    {
+      sizeof (short), 2, "short"
+    }
+     ,
+    {
+      sizeof (int), 4, "int"
+    }
+     ,
+    {
+      sizeof (long), 4, "long"
+    }
+     ,
+    {
+      sizeof (float), 4, "float"
+    }
+     ,
+    {
+      sizeof (double), 8, "double"
+    }
+     ,
+    {
+      sizeof (char *), 4, "pointer"
+    }
+     ,
+  };
 #define TYPELEN        (sizeof(types) / sizeof(struct typestruct))
 
-       /* Make sure that host type sizes are same as i960
-        */
-       for ( i = 0; i < TYPELEN; i++ ){
-               if ( types[i].hostsize != types[i].i960size ){
-                       printf("sizeof(%s) != %d:  PROCEED AT YOUR OWN RISK!\n",
-                                       types[i].typename, types[i].i960size );
-               }
+  /* Make sure that host type sizes are same as i960
+   */
+  for (i = 0; i < TYPELEN; i++)
+    {
+      if (types[i].hostsize != types[i].i960size)
+       {
+         printf_unfiltered ("sizeof(%s) != %d:  PROCEED AT YOUR OWN RISK!\n",
+                            types[i].typename, types[i].i960size);
+       }
 
+    }
+}
+\f
+/* Is this register part of the register window system?  A yes answer
+   implies that 1) The name of this register will not be the same in
+   other frames, and 2) This register is automatically "saved" upon
+   subroutine calls and thus there is no need to search more than one
+   stack frame for it.
+
+   On the i960, in fact, the name of this register in another frame is
+   "mud" -- there is no overlap between the windows.  Each window is
+   simply saved into the stack (true for our purposes, after having been
+   flushed; normally they reside on-chip and are restored from on-chip
+   without ever going to memory).  */
+
+static int
+register_in_window_p (int regnum)
+{
+  return regnum <= R15_REGNUM;
+}
+
+/* i960_find_saved_register ()
+
+   Return the address in which frame FRAME's value of register REGNUM
+   has been saved in memory.  Or return zero if it has not been saved.
+   If REGNUM specifies the SP, the value we return is actually the SP
+   value, not an address where it was saved.  */
+
+static CORE_ADDR
+i960_find_saved_register (struct frame_info *frame, int regnum)
+{
+  register struct frame_info *frame1 = NULL;
+  register CORE_ADDR addr = 0;
+
+  if (frame == NULL)           /* No regs saved if want current frame */
+    return 0;
+
+  /* We assume that a register in a register window will only be saved
+     in one place (since the name changes and/or disappears as you go
+     towards inner frames), so we only call get_frame_saved_regs on
+     the current frame.  This is directly in contradiction to the
+     usage below, which assumes that registers used in a frame must be
+     saved in a lower (more interior) frame.  This change is a result
+     of working on a register window machine; get_frame_saved_regs
+     always returns the registers saved within a frame, within the
+     context (register namespace) of that frame. */
+
+  /* However, note that we don't want this to return anything if
+     nothing is saved (if there's a frame inside of this one).  Also,
+     callers to this routine asking for the stack pointer want the
+     stack pointer saved for *this* frame; this is returned from the
+     next frame.  */
+
+  if (register_in_window_p (regnum))
+    {
+      frame1 = get_next_frame (frame);
+      if (!frame1)
+       return 0;               /* Registers of this frame are active.  */
+
+      /* Get the SP from the next frame in; it will be this
+         current frame.  */
+      if (regnum != SP_REGNUM)
+       frame1 = frame;
+
+      FRAME_INIT_SAVED_REGS (frame1);
+      return frame1->saved_regs[regnum];       /* ... which might be zero */
+    }
+
+  /* Note that this next routine assumes that registers used in
+     frame x will be saved only in the frame that x calls and
+     frames interior to it.  This is not true on the sparc, but the
+     above macro takes care of it, so we should be all right. */
+  while (1)
+    {
+      QUIT;
+      frame1 = get_next_frame (frame);
+      if (frame1 == 0)
+       break;
+      frame = frame1;
+      FRAME_INIT_SAVED_REGS (frame1);
+      if (frame1->saved_regs[regnum])
+       addr = frame1->saved_regs[regnum];
+    }
+
+  return addr;
+}
+
+/* i960_get_saved_register ()
+
+   Find register number REGNUM relative to FRAME and put its (raw,
+   target format) contents in *RAW_BUFFER.  Set *OPTIMIZED if the
+   variable was optimized out (and thus can't be fetched).  Set *LVAL
+   to lval_memory, lval_register, or not_lval, depending on whether
+   the value was fetched from memory, from a register, or in a strange
+   and non-modifiable way (e.g. a frame pointer which was calculated
+   rather than fetched).  Set *ADDRP to the address, either in memory
+   on as a REGISTER_BYTE offset into the registers array.
+
+   Note that this implementation never sets *LVAL to not_lval.  But it
+   can be replaced by defining GET_SAVED_REGISTER and supplying your
+   own.
+
+   The argument RAW_BUFFER must point to aligned memory.  */
+
+void
+i960_get_saved_register (char *raw_buffer,
+                        int *optimized,
+                        CORE_ADDR *addrp,
+                        struct frame_info *frame,
+                        int regnum,
+                        enum lval_type *lval)
+{
+  CORE_ADDR addr;
+
+  if (!target_has_registers)
+    error ("No registers.");
+
+  /* Normal systems don't optimize out things with register numbers.  */
+  if (optimized != NULL)
+    *optimized = 0;
+  addr = i960_find_saved_register (frame, regnum);
+  if (addr != 0)
+    {
+      if (lval != NULL)
+       *lval = lval_memory;
+      if (regnum == SP_REGNUM)
+       {
+         if (raw_buffer != NULL)
+           {
+             /* Put it back in target format.  */
+             store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
+                            (LONGEST) addr);
+           }
+         if (addrp != NULL)
+           *addrp = 0;
+         return;
        }
+      if (raw_buffer != NULL)
+       target_read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+    }
+  else
+    {
+      if (lval != NULL)
+       *lval = lval_register;
+      addr = REGISTER_BYTE (regnum);
+      if (raw_buffer != NULL)
+       read_register_gen (regnum, raw_buffer);
+    }
+  if (addrp != NULL)
+    *addrp = addr;
 }
 \f
 /* Examine an i960 function prologue, recording the addresses at which
@@ -91,23 +292,23 @@ check_host()
    the function prologue is given below:
 
    (lda LRn, g14
-    mov g14, g[0-7]
-    (mov 0, g14) | (lda 0, g14))?
+   mov g14, g[0-7]
+   (mov 0, g14) | (lda 0, g14))?
 
    (mov[qtl]? g[0-15], r[4-15])*
    ((addo [1-31], sp, sp) | (lda n(sp), sp))?
    (st[qtl]? g[0-15], n(fp))*
 
    (cmpobne 0, g14, LFn
-    mov sp, g14
-    lda 0x30(sp), sp
-    LFn: stq g0, (g14)
-    stq g4, 0x10(g14)
-    stq g8, 0x20(g14))?
+   mov sp, g14
+   lda 0x30(sp), sp
+   LFn: stq g0, (g14)
+   stq g4, 0x10(g14)
+   stq g8, 0x20(g14))?
 
    (st g14, n(fp))?
    (mov g13,r[4-15])?
-*/
+ */
 
 /* Macros for extracting fields from i960 instructions.  */
 
@@ -130,11 +331,8 @@ check_host()
   (((addr) < (lim)) ? next_insn (addr, pword1, pword2) : 0)
 
 static CORE_ADDR
-examine_prologue (ip, limit, frame_addr, fsr)
-     register CORE_ADDR ip;
-     register CORE_ADDR limit;
-     FRAME_ADDR frame_addr;
-     struct frame_saved_regs *fsr;
+examine_prologue (register CORE_ADDR ip, register CORE_ADDR limit,
+                 CORE_ADDR frame_addr, struct frame_saved_regs *fsr)
 {
   register CORE_ADDR next_ip;
   register int src, dst;
@@ -143,15 +341,15 @@ examine_prologue (ip, limit, frame_addr, fsr)
   int size;
   int within_leaf_prologue;
   CORE_ADDR save_addr;
-  static unsigned int varargs_prologue_code [] =
-    {
-       0x3507a00c,     /* cmpobne 0x0, g14, LFn */
-       0x5cf01601,     /* mov sp, g14           */
-       0x8c086030,     /* lda 0x30(sp), sp      */
-       0xb2879000,     /* LFn: stq  g0, (g14)   */
-       0xb2a7a010,     /* stq g4, 0x10(g14)     */
-       0xb2c7a020      /* stq g8, 0x20(g14)     */
-    };
+  static unsigned int varargs_prologue_code[] =
+  {
+    0x3507a00c,                        /* cmpobne 0x0, g14, LFn */
+    0x5cf01601,                        /* mov sp, g14           */
+    0x8c086030,                        /* lda 0x30(sp), sp      */
+    0xb2879000,                        /* LFn: stq  g0, (g14)   */
+    0xb2a7a010,                        /* stq g4, 0x10(g14)     */
+    0xb2c7a020                 /* stq g8, 0x20(g14)     */
+  };
 
   /* Accept a leaf procedure prologue code fragment if present.
      Note that ip might point to either the leaf or non-leaf
@@ -159,8 +357,8 @@ examine_prologue (ip, limit, frame_addr, fsr)
 
   within_leaf_prologue = 0;
   if ((next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2))
-      && ((insn1 & 0xfffff000) == 0x8cf00000         /* lda LRx, g14 (MEMA) */
-         || (insn1 & 0xfffffc60) == 0x8cf03000))    /* lda LRx, g14 (MEMB) */
+      && ((insn1 & 0xfffff000) == 0x8cf00000   /* lda LRx, g14 (MEMA) */
+         || (insn1 & 0xfffffc60) == 0x8cf03000))       /* lda LRx, g14 (MEMB) */
     {
       within_leaf_prologue = 1;
       next_ip = NEXT_PROLOGUE_INSN (next_ip, limit, &insn1, &insn2);
@@ -169,13 +367,13 @@ examine_prologue (ip, limit, frame_addr, fsr)
   /* Now look for the prologue code at a leaf entry point:  */
 
   if (next_ip
-      && (insn1 & 0xff87ffff) == 0x5c80161e         /* mov g14, gx */
+      && (insn1 & 0xff87ffff) == 0x5c80161e    /* mov g14, gx */
       && REG_SRCDST (insn1) <= G0_REGNUM + 7)
     {
       within_leaf_prologue = 1;
       if ((next_ip = NEXT_PROLOGUE_INSN (next_ip, limit, &insn1, &insn2))
-         && (insn1 == 0x8cf00000                   /* lda 0, g14 */
-             || insn1 == 0x5cf01e00))              /* mov 0, g14 */
+         && (insn1 == 0x8cf00000       /* lda 0, g14 */
+             || insn1 == 0x5cf01e00))  /* mov 0, g14 */
        {
          ip = next_ip;
          next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2);
@@ -189,7 +387,7 @@ examine_prologue (ip, limit, frame_addr, fsr)
 
   if (within_leaf_prologue)
     return (ip);
-         
+
   /* Accept zero or more instances of "mov[qtl]? gx, ry", where y >= 4.
      This may cause us to mistake the moving of a register
      parameter to a local register for the saving of a callee-saved
@@ -232,16 +430,16 @@ examine_prologue (ip, limit, frame_addr, fsr)
      since that is matched explicitly below.  */
 
   while (next_ip &&
-        ((insn1 & 0xf787f000) == 0x9287e000      /* stl? gx, n(fp) (MEMA) */
-         || (insn1 & 0xf787fc60) == 0x9287f400   /* stl? gx, n(fp) (MEMB) */
-         || (insn1 & 0xef87f000) == 0xa287e000   /* st[tq] gx, n(fp) (MEMA) */
-         || (insn1 & 0xef87fc60) == 0xa287f400)  /* st[tq] gx, n(fp) (MEMB) */
+        ((insn1 & 0xf787f000) == 0x9287e000    /* stl? gx, n(fp) (MEMA) */
+         || (insn1 & 0xf787fc60) == 0x9287f400         /* stl? gx, n(fp) (MEMB) */
+         || (insn1 & 0xef87f000) == 0xa287e000         /* st[tq] gx, n(fp) (MEMA) */
+         || (insn1 & 0xef87fc60) == 0xa287f400)        /* st[tq] gx, n(fp) (MEMB) */
         && ((src = MEM_SRCDST (insn1)) != G14_REGNUM))
     {
       save_addr = frame_addr + ((insn1 & BITMASK (12, 1))
                                ? insn2 : MEMA_OFFSET (insn1));
       size = (insn1 & BITMASK (29, 1)) ? ((insn1 & BITMASK (28, 1)) ? 4 : 3)
-                                      : ((insn1 & BITMASK (27, 1)) ? 2 : 1);
+       : ((insn1 & BITMASK (27, 1)) ? 2 : 1);
       while (size--)
        {
          fsr->regs[src++] = save_addr;
@@ -264,11 +462,11 @@ examine_prologue (ip, limit, frame_addr, fsr)
   /* Accept an optional "st g14, n(fp)".  */
 
   if (next_ip &&
-      ((insn1 & 0xfffff000) == 0x92f7e000       /* st g14, n(fp) (MEMA) */
-       || (insn1 & 0xfffffc60) == 0x92f7f400))   /* st g14, n(fp) (MEMB) */
+      ((insn1 & 0xfffff000) == 0x92f7e000      /* st g14, n(fp) (MEMA) */
+       || (insn1 & 0xfffffc60) == 0x92f7f400)) /* st g14, n(fp) (MEMB) */
     {
       fsr->regs[G14_REGNUM] = frame_addr + ((insn1 & BITMASK (12, 1))
-                                           ? insn2 : MEMA_OFFSET (insn1));
+                                           ? insn2 : MEMA_OFFSET (insn1));
       ip = next_ip;
       next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2);
     }
@@ -281,9 +479,9 @@ examine_prologue (ip, limit, frame_addr, fsr)
       && (dst = REG_SRCDST (insn1)) >= (R0_REGNUM + 4))
     {
       save_addr = frame_addr + ((dst - R0_REGNUM) * 4);
-      fsr->regs[G0_REGNUM+13] = save_addr;
+      fsr->regs[G0_REGNUM + 13] = save_addr;
       ip = next_ip;
-#if 0  /* We'll need this once there is a subsequent instruction examined. */
+#if 0                          /* We'll need this once there is a subsequent instruction examined. */
       next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2);
 #endif
     }
@@ -296,8 +494,7 @@ examine_prologue (ip, limit, frame_addr, fsr)
    prologue.  */
 
 CORE_ADDR
-skip_prologue (ip)
-     CORE_ADDR (ip);
+i960_skip_prologue (CORE_ADDR ip)
 {
   struct frame_saved_regs saved_regs_dummy;
   struct symtab_and_line sal;
@@ -306,7 +503,7 @@ skip_prologue (ip)
   sal = find_pc_line (ip, 0);
   limit = (sal.end) ? sal.end : 0xffffffff;
 
-  return (examine_prologue (ip, limit, (FRAME_ADDR) 0, &saved_regs_dummy));
+  return (examine_prologue (ip, limit, (CORE_ADDR) 0, &saved_regs_dummy));
 }
 
 /* Put here the code to store, into a struct frame_saved_regs,
@@ -315,19 +512,16 @@ skip_prologue (ip)
    ways in the stack frame.  sp is even more special:
    the address we return for it IS the sp for the next frame.
 
-   We cache the result of doing this in the frame_cache_obstack, since
-   it is fairly expensive.  */
+   We cache the result of doing this in the frame_obstack, since it is
+   fairly expensive.  */
 
 void
-frame_find_saved_regs (fi, fsr)
-     struct frame_info *fi;
-     struct frame_saved_regs *fsr;
+frame_find_saved_regs (struct frame_info *fi, struct frame_saved_regs *fsr)
 {
   register CORE_ADDR next_addr;
   register CORE_ADDR *saved_regs;
   register int regnum;
   register struct frame_saved_regs *cache_fsr;
-  extern struct obstack frame_cache_obstack;
   CORE_ADDR ip;
   struct symtab_and_line sal;
   CORE_ADDR limit;
@@ -335,25 +529,24 @@ frame_find_saved_regs (fi, fsr)
   if (!fi->fsr)
     {
       cache_fsr = (struct frame_saved_regs *)
-                 obstack_alloc (&frame_cache_obstack,
-                                sizeof (struct frame_saved_regs));
-      bzero (cache_fsr, sizeof (struct frame_saved_regs));
+       frame_obstack_alloc (sizeof (struct frame_saved_regs));
+      memset (cache_fsr, '\0', sizeof (struct frame_saved_regs));
       fi->fsr = cache_fsr;
 
       /* Find the start and end of the function prologue.  If the PC
-        is in the function prologue, we only consider the part that
-        has executed already.  */
-         
+         is in the function prologue, we only consider the part that
+         has executed already.  */
+
       ip = get_pc_function_start (fi->pc);
       sal = find_pc_line (ip, 0);
-      limit = (sal.end && sal.end < fi->pc) ? sal.end: fi->pc;
+      limit = (sal.end && sal.end < fi->pc) ? sal.end : fi->pc;
 
       examine_prologue (ip, limit, fi->frame, cache_fsr);
 
       /* Record the addresses at which the local registers are saved.
-        Strictly speaking, we should only do this for non-leaf procedures,
-        but no one will ever look at these values if it is a leaf procedure,
-        since local registers are always caller-saved.  */
+         Strictly speaking, we should only do this for non-leaf procedures,
+         but no one will ever look at these values if it is a leaf procedure,
+         since local registers are always caller-saved.  */
 
       next_addr = (CORE_ADDR) fi->frame;
       saved_regs = cache_fsr->regs;
@@ -377,7 +570,7 @@ frame_find_saved_regs (fi, fsr)
      through to FRAME_FIND_SAVED_REGS (), permitting more efficient
      computation of saved register addresses (e.g., on the i960,
      we don't have to examine the prologue to find local registers). 
-       -- markf@wrs.com 
+     -- markf@wrs.com 
      FIXME, we don't need to refetch this, since the cache is cleared
      every time the child process is restarted.  If GDB itself
      modifies SP, it has to clear the cache by hand (does it?).  -gnu */
@@ -389,10 +582,8 @@ frame_find_saved_regs (fi, fsr)
    described by FI.  Returns 0 if the address is unknown.  */
 
 CORE_ADDR
-frame_args_address (fi, must_be_correct)
-     struct frame_info *fi;
+frame_args_address (struct frame_info *fi, int must_be_correct)
 {
-  register FRAME frame;
   struct frame_saved_regs fsr;
   CORE_ADDR ap;
 
@@ -400,18 +591,20 @@ frame_args_address (fi, must_be_correct)
      the saved value.  If the frame is current and we are being sloppy,
      return the value of g14.  Otherwise, return zero.  */
 
-  frame = FRAME_INFO_ID (fi);
   get_frame_saved_regs (fi, &fsr);
   if (fsr.regs[G14_REGNUM])
-    ap = read_memory_integer (fsr.regs[G14_REGNUM],4);
-  else {
-    if (must_be_correct)
-      return 0;                        /* Don't cache this result */
-    if (get_next_frame (frame))
-      ap = 0;
-    else
-      ap = read_register (G14_REGNUM);
-  }
+    ap = read_memory_integer (fsr.regs[G14_REGNUM], 4);
+  else
+    {
+      if (must_be_correct)
+       return 0;               /* Don't cache this result */
+      if (get_next_frame (fi))
+       ap = 0;
+      else
+       ap = read_register (G14_REGNUM);
+      if (ap == 0)
+       ap = fi->frame;
+    }
   fi->arg_pointer = ap;                /* Cache it for next time */
   return ap;
 }
@@ -420,10 +613,8 @@ frame_args_address (fi, must_be_correct)
    described by FI.  Returns 0 if the address is unknown.  */
 
 CORE_ADDR
-frame_struct_result_address (fi)
-     struct frame_info *fi;
+frame_struct_result_address (struct frame_info *fi)
 {
-  register FRAME frame;
   struct frame_saved_regs fsr;
   CORE_ADDR ap;
 
@@ -435,23 +626,26 @@ frame_struct_result_address (fi)
      the function prologue, and only use the current value if we have
      no saved value and are at TOS?   -- gnu@cygnus.com */
 
-  frame = FRAME_INFO_ID (fi);
-  if (get_next_frame (frame)) {
-    get_frame_saved_regs (fi, &fsr);
-    if (fsr.regs[G13_REGNUM])
-      ap = read_memory_integer (fsr.regs[G13_REGNUM],4);
-    else
-      ap = 0;
-  } else {
+  if (get_next_frame (fi))
+    {
+      get_frame_saved_regs (fi, &fsr);
+      if (fsr.regs[G13_REGNUM])
+       ap = read_memory_integer (fsr.regs[G13_REGNUM], 4);
+      else
+       ap = 0;
+    }
+  else
     ap = read_register (G13_REGNUM);
-  }
+
   return ap;
 }
 
 /* Return address to which the currently executing leafproc will return,
-   or 0 if ip is not in a leafproc (or if we can't tell if it is).
-  
-   Do this by finding the starting address of the routine in which ip lies.
+   or 0 if IP, the value of the instruction pointer from the currently
+   executing function, is not in a leafproc (or if we can't tell if it
+   is).
+
+   Do this by finding the starting address of the routine in which IP lies.
    If the instruction there is "mov g14, gx" (where x is in [0,7]), this
    is a leafproc and the return address is in register gx.  Well, this is
    true unless the return address points at a RET instruction in the current
@@ -459,48 +653,47 @@ frame_struct_result_address (fi)
    has been entered through the CALL entry point.  */
 
 CORE_ADDR
-leafproc_return (ip)
-     CORE_ADDR ip;     /* ip from currently executing function */
+leafproc_return (CORE_ADDR ip)
 {
   register struct minimal_symbol *msymbol;
   char *p;
   int dst;
   unsigned int insn1, insn2;
   CORE_ADDR return_addr;
-  char *index ();
 
   if ((msymbol = lookup_minimal_symbol_by_pc (ip)) != NULL)
     {
-      if ((p = index (msymbol -> name, '.')) && !strcmp (p, ".lf"))
+      if ((p = strchr (SYMBOL_NAME (msymbol), '.')) && STREQ (p, ".lf"))
        {
-         if (next_insn (msymbol -> address, &insn1, &insn2)
-             && (insn1 & 0xff87ffff) == 0x5c80161e       /* mov g14, gx */
+         if (next_insn (SYMBOL_VALUE_ADDRESS (msymbol), &insn1, &insn2)
+             && (insn1 & 0xff87ffff) == 0x5c80161e     /* mov g14, gx */
              && (dst = REG_SRCDST (insn1)) <= G0_REGNUM + 7)
            {
              /* Get the return address.  If the "mov g14, gx" 
-                instruction hasn't been executed yet, read
-                the return address from g14; otherwise, read it
-                from the register into which g14 was moved.  */
+                instruction hasn't been executed yet, read
+                the return address from g14; otherwise, read it
+                from the register into which g14 was moved.  */
 
-             return_addr = read_register ((ip == msymbol->address)
-                                          ? G14_REGNUM : dst);
+             return_addr =
+               read_register ((ip == SYMBOL_VALUE_ADDRESS (msymbol))
+                              ? G14_REGNUM : dst);
 
              /* We know we are in a leaf procedure, but we don't know
-                whether the caller actually did a "bal" to the ".lf"
-                entry point, or a normal "call" to the non-leaf entry
-                point one instruction before.  In the latter case, the
-                return address will be the address of a "ret"
-                instruction within the procedure itself.  We test for
-                this below.  */
+                whether the caller actually did a "bal" to the ".lf"
+                entry point, or a normal "call" to the non-leaf entry
+                point one instruction before.  In the latter case, the
+                return address will be the address of a "ret"
+                instruction within the procedure itself.  We test for
+                this below.  */
 
              if (!next_insn (return_addr, &insn1, &insn2)
-                 || (insn1 & 0xff000000) != 0xa000000   /* ret */
-                 || lookup_minimal_symbol_by_pc (return_addr) != msymbol)
+                 || (insn1 & 0xff000000) != 0xa000000  /* ret */
+                 || lookup_minimal_symbol_by_pc (return_addr) != msymbol)
                return (return_addr);
            }
        }
     }
-  
+
   return (0);
 }
 
@@ -512,23 +705,22 @@ leafproc_return (ip)
    unless the function is a leaf procedure.  */
 
 CORE_ADDR
-saved_pc_after_call (frame)
-     FRAME frame;
+saved_pc_after_call (struct frame_info *frame)
 {
   CORE_ADDR saved_pc;
-  CORE_ADDR get_frame_pc ();
 
   saved_pc = leafproc_return (get_frame_pc (frame));
   if (!saved_pc)
     saved_pc = FRAME_SAVED_PC (frame);
 
-  return (saved_pc);
+  return saved_pc;
 }
 
 /* Discard from the stack the innermost frame,
    restoring all saved registers.  */
 
-pop_frame ()
+void
+i960_pop_frame (void)
 {
   register struct frame_info *current_fi, *prev_fi;
   register int i;
@@ -537,7 +729,7 @@ pop_frame ()
   struct frame_saved_regs fsr;
   char local_regs_buf[16 * 4];
 
-  current_fi = get_frame_info (get_current_frame ());
+  current_fi = get_current_frame ();
 
   /* First, undo what the hardware does when we return.
      If this is a non-leaf procedure, restore local registers from
@@ -548,10 +740,10 @@ pop_frame ()
   if (!leaf_return_addr)
     {
       /* Non-leaf procedure.  Restore local registers, incl IP.  */
-      prev_fi = get_frame_info (get_prev_frame (FRAME_INFO_ID (current_fi)));
+      prev_fi = get_prev_frame (current_fi);
       read_memory (prev_fi->frame, local_regs_buf, sizeof (local_regs_buf));
-      write_register_bytes (REGISTER_BYTE (R0_REGNUM), local_regs_buf, 
-                           sizeof (local_regs_buf));
+      write_register_bytes (REGISTER_BYTE (R0_REGNUM), local_regs_buf,
+                           sizeof (local_regs_buf));
 
       /* Restore frame pointer.  */
       write_register (FP_REGNUM, prev_fi->frame);
@@ -566,7 +758,8 @@ pop_frame ()
   get_frame_saved_regs (current_fi, &fsr);
   for (i = G0_REGNUM; i < G14_REGNUM; i++)
     {
-      if (save_addr = fsr.regs[i])
+      save_addr = fsr.regs[i];
+      if (save_addr != 0)
        write_register (i, read_memory_integer (save_addr, 4));
     }
 
@@ -574,69 +767,289 @@ pop_frame ()
      and make it the current frame.  */
 
   flush_cached_frames ();
-  set_current_frame (create_new_frame (read_register (FP_REGNUM), read_pc ()));
 }
 
-/* Print out text describing a "signal number" with which the i80960 halted.
-  
-   See the file "fault.c" in the nindy monitor source code for a list
-   of stop codes.  */
+/* Given a 960 stop code (fault or trace), return the signal which
+   corresponds.  */
 
-void
-print_fault( siggnal )
-    int siggnal;       /* Signal number, as returned by target_wait() */
+enum target_signal
+i960_fault_to_signal (int fault)
+{
+  switch (fault)
+    {
+    case 0:
+      return TARGET_SIGNAL_BUS;        /* parallel fault */
+    case 1:
+      return TARGET_SIGNAL_UNKNOWN;
+    case 2:
+      return TARGET_SIGNAL_ILL;        /* operation fault */
+    case 3:
+      return TARGET_SIGNAL_FPE;        /* arithmetic fault */
+    case 4:
+      return TARGET_SIGNAL_FPE;        /* floating point fault */
+
+      /* constraint fault.  This appears not to distinguish between
+         a range constraint fault (which should be SIGFPE) and a privileged
+         fault (which should be SIGILL).  */
+    case 5:
+      return TARGET_SIGNAL_ILL;
+
+    case 6:
+      return TARGET_SIGNAL_SEGV;       /* virtual memory fault */
+
+      /* protection fault.  This is for an out-of-range argument to
+         "calls".  I guess it also could be SIGILL. */
+    case 7:
+      return TARGET_SIGNAL_SEGV;
+
+    case 8:
+      return TARGET_SIGNAL_BUS;        /* machine fault */
+    case 9:
+      return TARGET_SIGNAL_BUS;        /* structural fault */
+    case 0xa:
+      return TARGET_SIGNAL_ILL;        /* type fault */
+    case 0xb:
+      return TARGET_SIGNAL_UNKNOWN;    /* reserved fault */
+    case 0xc:
+      return TARGET_SIGNAL_BUS;        /* process fault */
+    case 0xd:
+      return TARGET_SIGNAL_SEGV;       /* descriptor fault */
+    case 0xe:
+      return TARGET_SIGNAL_BUS;        /* event fault */
+    case 0xf:
+      return TARGET_SIGNAL_UNKNOWN;    /* reserved fault */
+    case 0x10:
+      return TARGET_SIGNAL_TRAP;       /* single-step trace */
+    case 0x11:
+      return TARGET_SIGNAL_TRAP;       /* branch trace */
+    case 0x12:
+      return TARGET_SIGNAL_TRAP;       /* call trace */
+    case 0x13:
+      return TARGET_SIGNAL_TRAP;       /* return trace */
+    case 0x14:
+      return TARGET_SIGNAL_TRAP;       /* pre-return trace */
+    case 0x15:
+      return TARGET_SIGNAL_TRAP;       /* supervisor call trace */
+    case 0x16:
+      return TARGET_SIGNAL_TRAP;       /* breakpoint trace */
+    default:
+      return TARGET_SIGNAL_UNKNOWN;
+    }
+}
+
+/****************************************/
+/* MEM format                           */
+/****************************************/
+
+struct tabent
 {
-       static char unknown[] = "Unknown fault or trace";
-       static char *sigmsgs[] = {
-               /* FAULTS */
-               "parallel fault",       /* 0x00 */
-               unknown,                /* 0x01 */
-               "operation fault",      /* 0x02 */
-               "arithmetic fault",     /* 0x03 */
-               "floating point fault", /* 0x04 */
-               "constraint fault",     /* 0x05 */
-               "virtual memory fault", /* 0x06 */
-               "protection fault",     /* 0x07 */
-               "machine fault",        /* 0x08 */
-               "structural fault",     /* 0x09 */
-               "type fault",           /* 0x0a */
-               "reserved (0xb) fault", /* 0x0b */
-               "process fault",        /* 0x0c */
-               "descriptor fault",     /* 0x0d */
-               "event fault",          /* 0x0e */
-               "reserved (0xf) fault", /* 0x0f */
-
-               /* TRACES */
-               "single-step trace",    /* 0x10 */
-               "branch trace",         /* 0x11 */
-               "call trace",           /* 0x12 */
-               "return trace",         /* 0x13 */
-               "pre-return trace",     /* 0x14 */
-               "supervisor call trace",/* 0x15 */
-               "breakpoint trace",     /* 0x16 */
-       };
-#      define NUMMSGS ((int)( sizeof(sigmsgs) / sizeof(sigmsgs[0]) ))
-
-       if (siggnal < NSIG) {
-             printf ("\nProgram received signal %d, %s\n",
-                     siggnal,
-                     sys_siglist[siggnal]);
-       } else {
-               /* The various target_wait()s bias the 80960 "signal number"
-                  by adding NSIG to it, so it won't get confused with any
-                  of the Unix signals elsewhere in GDB.  We need to
-                  "unbias" it before using it.  */
-               siggnal -= NSIG;
-
-               printf("Program stopped for reason #%d: %s.\n", siggnal,
-                               (siggnal < NUMMSGS && siggnal >= 0)?
-                               sigmsgs[siggnal] : unknown );
+  char *name;
+  char numops;
+};
+
+/* Return instruction length, either 4 or 8.  When NOPRINT is non-zero
+   (TRUE), don't output any text.  (Actually, as implemented, if NOPRINT
+   is 0, abort() is called.) */
+
+static int
+mem (unsigned long memaddr, unsigned long word1, unsigned long word2,
+     int noprint)
+{
+  int i, j;
+  int len;
+  int mode;
+  int offset;
+  const char *reg1, *reg2, *reg3;
+
+  /* This lookup table is too sparse to make it worth typing in, but not
+   * so large as to make a sparse array necessary.  We allocate the
+   * table at runtime, initialize all entries to empty, and copy the
+   * real ones in from an initialization table.
+   *
+   * NOTE: In this table, the meaning of 'numops' is:
+   *       1: single operand
+   *       2: 2 operands, load instruction
+   *      -2: 2 operands, store instruction
+   */
+  static struct tabent *mem_tab = NULL;
+/* Opcodes of 0x8X, 9X, aX, bX, and cX must be in the table.  */
+#define MEM_MIN        0x80
+#define MEM_MAX        0xcf
+#define MEM_SIZ        ((MEM_MAX-MEM_MIN+1) * sizeof(struct tabent))
+
+  static struct
+    {
+      int opcode;
+      char *name;
+      char numops;
+    }
+  mem_init[] =
+  {
+    0x80, "ldob", 2,
+      0x82, "stob", -2,
+      0x84, "bx", 1,
+      0x85, "balx", 2,
+      0x86, "callx", 1,
+      0x88, "ldos", 2,
+      0x8a, "stos", -2,
+      0x8c, "lda", 2,
+      0x90, "ld", 2,
+      0x92, "st", -2,
+      0x98, "ldl", 2,
+      0x9a, "stl", -2,
+      0xa0, "ldt", 2,
+      0xa2, "stt", -2,
+      0xb0, "ldq", 2,
+      0xb2, "stq", -2,
+      0xc0, "ldib", 2,
+      0xc2, "stib", -2,
+      0xc8, "ldis", 2,
+      0xca, "stis", -2,
+      0, NULL, 0
+  };
+
+  if (mem_tab == NULL)
+    {
+      mem_tab = (struct tabent *) xmalloc (MEM_SIZ);
+      memset (mem_tab, '\0', MEM_SIZ);
+      for (i = 0; mem_init[i].opcode != 0; i++)
+       {
+         j = mem_init[i].opcode - MEM_MIN;
+         mem_tab[j].name = mem_init[i].name;
+         mem_tab[j].numops = mem_init[i].numops;
        }
+    }
+
+  i = ((word1 >> 24) & 0xff) - MEM_MIN;
+  mode = (word1 >> 10) & 0xf;
+
+  if ((mem_tab[i].name != NULL)        /* Valid instruction */
+      && ((mode == 5) || (mode >= 12)))
+    {                          /* With 32-bit displacement */
+      len = 8;
+    }
+  else
+    {
+      len = 4;
+    }
+
+  if (noprint)
+    {
+      return len;
+    }
+  internal_error (__FILE__, __LINE__, "failed internal consistency check");
 }
 
-/* Initialization stub */
+/* Read the i960 instruction at 'memaddr' and return the address of 
+   the next instruction after that, or 0 if 'memaddr' is not the
+   address of a valid instruction.  The first word of the instruction
+   is stored at 'pword1', and the second word, if any, is stored at
+   'pword2'.  */
 
-_initialize_i960_tdep ()
+static CORE_ADDR
+next_insn (CORE_ADDR memaddr, unsigned int *pword1, unsigned int *pword2)
+{
+  int len;
+  char buf[8];
+
+  /* Read the two (potential) words of the instruction at once,
+     to eliminate the overhead of two calls to read_memory ().
+     FIXME: Loses if the first one is readable but the second is not
+     (e.g. last word of the segment).  */
+
+  read_memory (memaddr, buf, 8);
+  *pword1 = extract_unsigned_integer (buf, 4);
+  *pword2 = extract_unsigned_integer (buf + 4, 4);
+
+  /* Divide instruction set into classes based on high 4 bits of opcode */
+
+  switch ((*pword1 >> 28) & 0xf)
+    {
+    case 0x0:
+    case 0x1:                  /* ctrl */
+
+    case 0x2:
+    case 0x3:                  /* cobr */
+
+    case 0x5:
+    case 0x6:
+    case 0x7:                  /* reg */
+      len = 4;
+      break;
+
+    case 0x8:
+    case 0x9:
+    case 0xa:
+    case 0xb:
+    case 0xc:
+      len = mem (memaddr, *pword1, *pword2, 1);
+      break;
+
+    default:                   /* invalid instruction */
+      len = 0;
+      break;
+    }
+
+  if (len)
+    return memaddr + len;
+  else
+    return 0;
+}
+
+/* 'start_frame' is a variable in the MON960 runtime startup routine
+   that contains the frame pointer of the 'start' routine (the routine
+   that calls 'main').  By reading its contents out of remote memory,
+   we can tell where the frame chain ends:  backtraces should halt before
+   they display this frame.  */
+
+int
+mon960_frame_chain_valid (CORE_ADDR chain, struct frame_info *curframe)
+{
+  struct symbol *sym;
+  struct minimal_symbol *msymbol;
+
+  /* crtmon960.o is an assembler module that is assumed to be linked
+   * first in an i80960 executable.  It contains the true entry point;
+   * it performs startup up initialization and then calls 'main'.
+   *
+   * 'sf' is the name of a variable in crtmon960.o that is set
+   *      during startup to the address of the first frame.
+   *
+   * 'a' is the address of that variable in 80960 memory.
+   */
+  static char sf[] = "start_frame";
+  CORE_ADDR a;
+
+
+  chain &= ~0x3f;              /* Zero low 6 bits because previous frame pointers
+                                  contain return status info in them.  */
+  if (chain == 0)
+    {
+      return 0;
+    }
+
+  sym = lookup_symbol (sf, 0, VAR_NAMESPACE, (int *) NULL,
+                      (struct symtab **) NULL);
+  if (sym != 0)
+    {
+      a = SYMBOL_VALUE (sym);
+    }
+  else
+    {
+      msymbol = lookup_minimal_symbol (sf, NULL, NULL);
+      if (msymbol == NULL)
+       return 0;
+      a = SYMBOL_VALUE_ADDRESS (msymbol);
+    }
+
+  return (chain != read_memory_integer (a, 4));
+}
+
+
+void
+_initialize_i960_tdep (void)
 {
   check_host ();
+
+  tm_print_insn = print_insn_i960;
 }
This page took 0.037719 seconds and 4 git commands to generate.