* alpha-tdep.c (alpha_register_convert_to_virtual): Tidy use of
[binutils-gdb.git] / gdb / alpha-tdep.c
index cd29c95e4f7642af6e50772091aae41eae64a11f..99e8b62dfc807e3edd3cbebdbab1e59826553b39 100644 (file)
@@ -20,6 +20,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
+#include "doublest.h"
 #include "frame.h"
 #include "frame-unwind.h"
 #include "frame-base.h"
@@ -34,7 +35,7 @@
 #include "gdb_string.h"
 #include "linespec.h"
 #include "regcache.h"
-#include "doublest.h"
+#include "reggroups.h"
 #include "arch-utils.h"
 #include "osabi.h"
 #include "block.h"
@@ -47,7 +48,7 @@
 static const char *
 alpha_register_name (int regno)
 {
-  static char *register_names[] =
+  static const char * const register_names[] =
   {
     "v0",   "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",
     "t7",   "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "fp",
@@ -57,26 +58,26 @@ alpha_register_name (int regno)
     "f8",   "f9",   "f10",  "f11",  "f12",  "f13",  "f14",  "f15",
     "f16",  "f17",  "f18",  "f19",  "f20",  "f21",  "f22",  "f23",
     "f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "fpcr",
-    "pc",   "vfp",  "unique",
+    "pc",   "",     "unique"
   };
 
   if (regno < 0)
-    return (NULL);
+    return NULL;
   if (regno >= (sizeof(register_names) / sizeof(*register_names)))
-    return (NULL);
-  return (register_names[regno]);
+    return NULL;
+  return register_names[regno];
 }
 
 static int
 alpha_cannot_fetch_register (int regno)
 {
-  return (regno == ALPHA_FP_REGNUM || regno == ALPHA_ZERO_REGNUM);
+  return regno == ALPHA_ZERO_REGNUM;
 }
 
 static int
 alpha_cannot_store_register (int regno)
 {
-  return (regno == ALPHA_FP_REGNUM || regno == ALPHA_ZERO_REGNUM);
+  return regno == ALPHA_ZERO_REGNUM;
 }
 
 static int
@@ -88,8 +89,50 @@ alpha_register_convertible (int regno)
 static struct type *
 alpha_register_virtual_type (int regno)
 {
-  return ((regno >= FP0_REGNUM && regno < (FP0_REGNUM+31))
-         ? builtin_type_double : builtin_type_long);
+  if (regno == ALPHA_SP_REGNUM || regno == ALPHA_GP_REGNUM)
+    return builtin_type_void_data_ptr;
+  if (regno == ALPHA_PC_REGNUM)
+    return builtin_type_void_func_ptr;
+
+  /* Don't need to worry about little vs big endian until 
+     some jerk tries to port to alpha-unicosmk.  */
+  if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 31)
+    return builtin_type_ieee_double_little;
+
+  return builtin_type_int64;
+}
+
+/* Is REGNUM a member of REGGROUP?  */
+
+static int
+alpha_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+                          struct reggroup *group)
+{
+  /* Filter out any registers eliminated, but whose regnum is 
+     reserved for backward compatibility, e.g. the vfp.  */
+  if (REGISTER_NAME (regnum) == NULL || *REGISTER_NAME (regnum) == '\0')
+    return 0;
+
+  /* Since we implement no pseudo registers, save/restore is equal to all. */
+  if (group == all_reggroup
+      || group == save_reggroup
+      || group == restore_reggroup)
+    return 1;
+
+  /* All other groups are non-overlapping.  */
+
+  /* Since this is really a PALcode memory slot...  */
+  if (regnum == ALPHA_UNIQUE_REGNUM)
+    return group == system_reggroup;
+
+  /* Force the FPCR to be considered part of the floating point state.  */
+  if (regnum == ALPHA_FPCR_REGNUM)
+    return group == float_reggroup;
+
+  if (regnum >= ALPHA_FP0_REGNUM && regnum < ALPHA_FP0_REGNUM + 31)
+    return group == float_reggroup;
+  else
+    return group == general_reggroup;
 }
 
 static int
@@ -116,25 +159,38 @@ alpha_register_virtual_size (int regno)
    bytes or less, as the representation of integers in floating point
    registers is different. */
 
+static void
+alpha_convert_flt_dbl (void *out, const void *in)
+{
+  DOUBLEST d = extract_typed_floating (in, builtin_type_ieee_single_little);
+  store_typed_floating (out, builtin_type_ieee_double_little, d);
+}
+
+static void
+alpha_convert_dbl_flt (void *out, const void *in)
+{
+  DOUBLEST d = extract_typed_floating (in, builtin_type_ieee_double_little);
+  store_typed_floating (out, builtin_type_ieee_single_little, d);
+}
+
 static void
 alpha_register_convert_to_virtual (int regnum, struct type *valtype,
                                   char *raw_buffer, char *virtual_buffer)
 {
-  if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
+  if (TYPE_LENGTH (valtype) >= ALPHA_REGISTER_SIZE)
     {
-      memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
+      memcpy (virtual_buffer, raw_buffer, ALPHA_REGISTER_SIZE);
       return;
     }
 
+  /* Note that everything below is less than 8 bytes long.  */
+
   if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
-    {
-      double d = deprecated_extract_floating (raw_buffer, REGISTER_RAW_SIZE (regnum));
-      deprecated_store_floating (virtual_buffer, TYPE_LENGTH (valtype), d);
-    }
-  else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
+    alpha_convert_dbl_flt (virtual_buffer, raw_buffer);
+  else if (TYPE_CODE (valtype) == TYPE_CODE_INT)
     {
       ULONGEST l;
-      l = extract_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum));
+      l = extract_unsigned_integer (raw_buffer, ALPHA_REGISTER_SIZE);
       l = ((l >> 32) & 0xc0000000) | ((l >> 29) & 0x3fffffff);
       store_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype), l);
     }
@@ -146,26 +202,21 @@ static void
 alpha_register_convert_to_raw (struct type *valtype, int regnum,
                               char *virtual_buffer, char *raw_buffer)
 {
-  if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
+  if (TYPE_LENGTH (valtype) >= ALPHA_REGISTER_SIZE)
     {
-      memcpy (raw_buffer, virtual_buffer, REGISTER_RAW_SIZE (regnum));
+      memcpy (raw_buffer, virtual_buffer, ALPHA_REGISTER_SIZE);
       return;
     }
 
+  /* Note that everything below is less than 8 bytes long.  */
+
   if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+    alpha_convert_flt_dbl (raw_buffer, virtual_buffer);
+  else if (TYPE_CODE (valtype) == TYPE_CODE_INT)
     {
-      double d = deprecated_extract_floating (virtual_buffer, TYPE_LENGTH (valtype));
-      deprecated_store_floating (raw_buffer, REGISTER_RAW_SIZE (regnum), d);
-    }
-  else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
-    {
-      ULONGEST l;
-      if (TYPE_UNSIGNED (valtype))
-       l = extract_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype));
-      else
-       l = extract_signed_integer (virtual_buffer, TYPE_LENGTH (valtype));
+      ULONGEST l = unpack_long (valtype, virtual_buffer);
       l = ((l & 0xc0000000) << 32) | ((l & 0x3fffffff) << 29);
-      store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), l);
+      store_unsigned_integer (raw_buffer, ALPHA_REGISTER_SIZE, l);
     }
   else
     error ("Cannot store value in floating point register");
@@ -173,38 +224,50 @@ alpha_register_convert_to_raw (struct type *valtype, int regnum,
 
 \f
 /* The alpha passes the first six arguments in the registers, the rest on
-   the stack. The register arguments are eventually transferred to the
-   argument transfer area immediately below the stack by the called function
-   anyway. So we `push' at least six arguments on the stack, `reload' the
-   argument registers and then adjust the stack pointer to point past the
-   sixth argument. This algorithm simplifies the passing of a large struct
-   which extends from the registers to the stack.
+   the stack.  The register arguments are stored in ARG_REG_BUFFER, and
+   then moved into the register file; this simplifies the passing of a
+   large struct which extends from the registers to the stack, plus avoids
+   three ptrace invocations per word.
+
+   We don't bother tracking which register values should go in integer
+   regs or fp regs; we load the same values into both.
+
    If the called function is returning a structure, the address of the
    structure to be returned is passed as a hidden first argument.  */
 
 static CORE_ADDR
-alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
-                     int struct_return, CORE_ADDR struct_addr)
+alpha_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+                      struct regcache *regcache, CORE_ADDR bp_addr,
+                      int nargs, struct value **args, CORE_ADDR sp,
+                      int struct_return, CORE_ADDR struct_addr)
 {
   int i;
   int accumulate_size = struct_return ? 8 : 0;
-  int arg_regs_size = ALPHA_NUM_ARG_REGS * 8;
   struct alpha_arg
     {
       char *contents;
       int len;
       int offset;
     };
-  struct alpha_arg *alpha_args =
-  (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
+  struct alpha_arg *alpha_args
+    = (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
   register struct alpha_arg *m_arg;
-  char raw_buffer[ALPHA_REGISTER_BYTES];
+  char arg_reg_buffer[ALPHA_REGISTER_SIZE * ALPHA_NUM_ARG_REGS];
   int required_arg_regs;
 
+  /* The ABI places the address of the called function in T12.  */
+  regcache_cooked_write_signed (regcache, ALPHA_T12_REGNUM, func_addr);
+
+  /* Set the return address register to point to the entry point
+     of the program, where a breakpoint lies in wait.  */
+  regcache_cooked_write_signed (regcache, ALPHA_RA_REGNUM, bp_addr);
+
+  /* Lay out the arguments in memory.  */
   for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++)
     {
       struct value *arg = args[i];
       struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+
       /* Cast argument to long if necessary as the compiler does it too.  */
       switch (TYPE_CODE (arg_type))
        {
@@ -219,6 +282,30 @@ alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
              arg = value_cast (arg_type, arg);
            }
          break;
+       case TYPE_CODE_FLT:
+         /* "float" arguments loaded in registers must be passed in
+            register format, aka "double".  */
+         if (accumulate_size < sizeof (arg_reg_buffer)
+             && TYPE_LENGTH (arg_type) == 4)
+           {
+             arg_type = builtin_type_double;
+             arg = value_cast (arg_type, arg);
+           }
+         /* Tru64 5.1 has a 128-bit long double, and passes this by
+            invisible reference.  No one else uses this data type.  */
+         else if (TYPE_LENGTH (arg_type) == 16)
+           {
+             /* Allocate aligned storage.  */
+             sp = (sp & -16) - 16;
+
+             /* Write the real data into the stack.  */
+             write_memory (sp, VALUE_CONTENTS (arg), 16);
+
+             /* Construct the indirection.  */
+             arg_type = lookup_pointer_type (arg_type);
+             arg = value_from_pointer (arg_type, sp);
+           }
+         break;
        default:
          break;
        }
@@ -235,33 +322,59 @@ alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
     required_arg_regs = ALPHA_NUM_ARG_REGS;
 
   /* Make room for the arguments on the stack.  */
-  if (accumulate_size < arg_regs_size)
-    accumulate_size = arg_regs_size;
+  if (accumulate_size < sizeof(arg_reg_buffer))
+    accumulate_size = 0;
+  else
+    accumulate_size -= sizeof(arg_reg_buffer);
   sp -= accumulate_size;
 
-  /* Keep sp aligned to a multiple of 16 as the compiler does it too.  */
+  /* Keep sp aligned to a multiple of 16 as the ABI requires.  */
   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);
-  if (struct_return)
     {
-      store_unsigned_integer (raw_buffer, ALPHA_REGISTER_BYTES, struct_addr);
-      write_memory (sp, raw_buffer, ALPHA_REGISTER_BYTES);
+      char *contents = m_arg->contents;
+      int offset = m_arg->offset;
+      int len = m_arg->len;
+
+      /* Copy the bytes destined for registers into arg_reg_buffer.  */
+      if (offset < sizeof(arg_reg_buffer))
+       {
+         if (offset + len <= sizeof(arg_reg_buffer))
+           {
+             memcpy (arg_reg_buffer + offset, contents, len);
+             continue;
+           }
+         else
+           {
+             int tlen = sizeof(arg_reg_buffer) - offset;
+             memcpy (arg_reg_buffer + offset, contents, tlen);
+             offset += tlen;
+             contents += tlen;
+             len -= tlen;
+           }
+       }
+
+      /* Everything else goes to the stack.  */
+      write_memory (sp + offset - sizeof(arg_reg_buffer), contents, len);
     }
+  if (struct_return)
+    store_unsigned_integer (arg_reg_buffer, ALPHA_REGISTER_SIZE, struct_addr);
 
   /* Load the argument registers.  */
   for (i = 0; i < required_arg_regs; i++)
     {
-      LONGEST val;
-
-      val = read_memory_integer (sp + i * 8, ALPHA_REGISTER_BYTES);
-      write_register (ALPHA_A0_REGNUM + i, val);
-      write_register (ALPHA_FPA0_REGNUM + i, val);
+      regcache_cooked_write (regcache, ALPHA_A0_REGNUM + i,
+                            arg_reg_buffer + i*ALPHA_REGISTER_SIZE);
+      regcache_cooked_write (regcache, ALPHA_FPA0_REGNUM + i,
+                            arg_reg_buffer + i*ALPHA_REGISTER_SIZE);
     }
 
-  return sp + arg_regs_size;
+  /* Finally, update the stack pointer.  */
+  regcache_cooked_write_signed (regcache, ALPHA_SP_REGNUM, sp);
+
+  return sp;
 }
 
 /* Given a return value in `regbuf' with a type `valtype', 
@@ -286,14 +399,14 @@ alpha_extract_return_value (struct type *valtype,
 static void
 alpha_store_return_value (struct type *valtype, char *valbuf)
 {
-  char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
+  char raw_buffer[ALPHA_REGISTER_SIZE];
   int regnum = ALPHA_V0_REGNUM;
   int length = TYPE_LENGTH (valtype);
 
   if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
     {
       regnum = FP0_REGNUM;
-      length = REGISTER_RAW_SIZE (regnum);
+      length = ALPHA_REGISTER_SIZE;
       alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer);
     }
   else
@@ -319,8 +432,8 @@ alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
 static CORE_ADDR
 alpha_extract_struct_value_address (char *regbuf)
 {
-  return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
-                          REGISTER_RAW_SIZE (ALPHA_V0_REGNUM)));
+  return (extract_unsigned_integer (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
+                                   REGISTER_RAW_SIZE (ALPHA_V0_REGNUM)));
 }
 
 \f
@@ -437,28 +550,6 @@ alpha_skip_prologue (CORE_ADDR pc)
   return pc + offset;
 }
 
-\f
-/* Construct an inferior call to FUN.  For Alpha this is as simple as
-   initializing the RA and T12 registers; everything else is set up by
-   generic code.  */
-
-static void
-alpha_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
-                      struct value **args, struct type *type, int gcc_p)
-{
-  CORE_ADDR bp_address = CALL_DUMMY_ADDRESS ();
-
-  if (bp_address == 0)
-    error ("no place to put call");
-  write_register (ALPHA_RA_REGNUM, bp_address);
-  write_register (ALPHA_T12_REGNUM, fun);
-}
-
-/* On the Alpha, the call dummy code is never copied to user space
-   (see alpha_fix_call_dummy() above).  The contents of this do not
-   matter.  */
-LONGEST alpha_call_dummy_words[] = { 0 };
-
 \f
 /* Figure out where the longjmp will land.
    We expect the first arg to be a pointer to the jmp_buf structure from
@@ -470,7 +561,7 @@ alpha_get_longjmp_target (CORE_ADDR *pc)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   CORE_ADDR jb_addr;
-  char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
+  char raw_buffer[ALPHA_REGISTER_SIZE];
 
   jb_addr = read_register (ALPHA_A0_REGNUM);
 
@@ -478,7 +569,7 @@ alpha_get_longjmp_target (CORE_ADDR *pc)
                          raw_buffer, tdep->jb_elt_size))
     return 0;
 
-  *pc = extract_address (raw_buffer, tdep->jb_elt_size);
+  *pc = extract_unsigned_integer (raw_buffer, tdep->jb_elt_size);
   return 1;
 }
 
@@ -1203,19 +1294,13 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Register info */
   set_gdbarch_num_regs (gdbarch, ALPHA_NUM_REGS);
   set_gdbarch_sp_regnum (gdbarch, ALPHA_SP_REGNUM);
-  set_gdbarch_deprecated_fp_regnum (gdbarch, ALPHA_FP_REGNUM);
   set_gdbarch_pc_regnum (gdbarch, ALPHA_PC_REGNUM);
   set_gdbarch_fp0_regnum (gdbarch, ALPHA_FP0_REGNUM);
 
   set_gdbarch_register_name (gdbarch, alpha_register_name);
-  set_gdbarch_deprecated_register_size (gdbarch, ALPHA_REGISTER_SIZE);
-  set_gdbarch_deprecated_register_bytes (gdbarch, ALPHA_REGISTER_BYTES);
   set_gdbarch_register_byte (gdbarch, alpha_register_byte);
   set_gdbarch_register_raw_size (gdbarch, alpha_register_raw_size);
-  set_gdbarch_deprecated_max_register_raw_size (gdbarch, ALPHA_MAX_REGISTER_RAW_SIZE);
   set_gdbarch_register_virtual_size (gdbarch, alpha_register_virtual_size);
-  set_gdbarch_deprecated_max_register_virtual_size (gdbarch,
-                                         ALPHA_MAX_REGISTER_VIRTUAL_SIZE);
   set_gdbarch_register_virtual_type (gdbarch, alpha_register_virtual_type);
 
   set_gdbarch_cannot_fetch_register (gdbarch, alpha_cannot_fetch_register);
@@ -1226,9 +1311,14 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                                            alpha_register_convert_to_virtual);
   set_gdbarch_register_convert_to_raw (gdbarch, alpha_register_convert_to_raw);
 
+  set_gdbarch_register_reggroup_p (gdbarch, alpha_register_reggroup_p);
+
   /* Prologue heuristics.  */
   set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue);
 
+  /* Disassembler.  */
+  set_gdbarch_print_insn (gdbarch, print_insn_alpha);
+
   /* Call info.  */
   set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
   set_gdbarch_frameless_function_invocation (gdbarch,
@@ -1242,11 +1332,7 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                                            alpha_extract_struct_value_address);
 
   /* Settings for calling functions in the inferior.  */
-  set_gdbarch_deprecated_push_arguments (gdbarch, alpha_push_arguments);
-  set_gdbarch_deprecated_call_dummy_words (gdbarch, alpha_call_dummy_words);
-  set_gdbarch_deprecated_sizeof_call_dummy_words (gdbarch, 0);
-  set_gdbarch_deprecated_pc_in_call_dummy (gdbarch, deprecated_pc_in_call_dummy_at_entry_point);
-  set_gdbarch_deprecated_fix_call_dummy (gdbarch, alpha_fix_call_dummy);
+  set_gdbarch_push_dummy_call (gdbarch, alpha_push_dummy_call);
 
   /* Methods for saving / extracting a dummy frame's ID.  */
   set_gdbarch_unwind_dummy_id (gdbarch, alpha_unwind_dummy_id);
@@ -1287,7 +1373,6 @@ _initialize_alpha_tdep (void)
   struct cmd_list_element *c;
 
   gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, NULL);
-  deprecated_tm_print_insn = print_insn_alpha;
 
   /* Let the user set the fence post for heuristic_proc_start.  */