* alpha-tdep.c (alpha_supply_int_regs, alpha_fill_int_regs): New.
[deliverable/binutils-gdb.git] / gdb / alpha-tdep.c
index 96ae1205d8e9c61852b2bd1fc3f5129c92487951..74e891baffaca8898bd62a972401b273582844f2 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"
@@ -57,7 +58,7 @@ 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)
@@ -70,13 +71,13 @@ alpha_register_name (int 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");
@@ -225,19 +276,27 @@ alpha_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
        case TYPE_CODE_CHAR:
        case TYPE_CODE_RANGE:
        case TYPE_CODE_ENUM:
-         if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long))
+         if (TYPE_LENGTH (arg_type) == 4)
+           {
+             /* 32-bit values must be sign-extended to 64 bits
+                even if the base data type is unsigned.  */
+             arg_type = builtin_type_int32;
+             arg = value_cast (arg_type, arg);
+           }
+         if (TYPE_LENGTH (arg_type) < ALPHA_REGISTER_SIZE)
            {
-             arg_type = builtin_type_long;
+             arg_type = builtin_type_int64;
              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_type = builtin_type_ieee_double_little;
              arg = value_cast (arg_type, arg);
            }
          /* Tru64 5.1 has a 128-bit long double, and passes this by
@@ -255,6 +314,28 @@ alpha_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
              arg = value_from_pointer (arg_type, sp);
            }
          break;
+
+       case TYPE_CODE_COMPLEX:
+         /* ??? The ABI says that complex values are passed as two
+            separate scalar values.  This distinction only matters
+            for complex float.  However, GCC does not implement this.  */
+
+         /* Tru64 5.1 has a 128-bit long double, and passes this by
+            invisible reference.  */
+         if (TYPE_LENGTH (arg_type) == 32)
+           {
+             /* Allocate aligned storage.  */
+             sp = (sp & -16) - 16;
+
+             /* Write the real data into the stack.  */
+             write_memory (sp, VALUE_CONTENTS (arg), 32);
+
+             /* Construct the indirection.  */
+             arg_type = lookup_pointer_type (arg_type);
+             arg = value_from_pointer (arg_type, sp);
+           }
+         break;
+
        default:
          break;
        }
@@ -326,42 +407,155 @@ alpha_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   return sp;
 }
 
-/* Given a return value in `regbuf' with a type `valtype', 
-   extract and copy its value into `valbuf'.  */
+/* Extract from REGCACHE the value about to be returned from a function
+   and copy it into VALBUF.  */
 
 static void
-alpha_extract_return_value (struct type *valtype,
-                           char regbuf[ALPHA_REGISTER_BYTES], char *valbuf)
+alpha_extract_return_value (struct type *valtype, struct regcache *regcache,
+                           void *valbuf)
 {
-  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
-    alpha_register_convert_to_virtual (FP0_REGNUM, valtype,
-                                      regbuf + REGISTER_BYTE (FP0_REGNUM),
-                                      valbuf);
-  else
-    memcpy (valbuf, regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
-            TYPE_LENGTH (valtype));
+  int length = TYPE_LENGTH (valtype);
+  char raw_buffer[ALPHA_REGISTER_SIZE];
+  ULONGEST l;
+
+  switch (TYPE_CODE (valtype))
+    {
+    case TYPE_CODE_FLT:
+      switch (length)
+       {
+       case 4:
+         regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, raw_buffer);
+         alpha_convert_dbl_flt (valbuf, raw_buffer);
+         break;
+
+       case 8:
+         regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
+         break;
+
+       case 16:
+         regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l);
+         read_memory (l, valbuf, 16);
+         break;
+
+       default:
+         internal_error (__FILE__, __LINE__, "unknown floating point width");
+       }
+      break;
+
+    case TYPE_CODE_COMPLEX:
+      switch (length)
+       {
+       case 8:
+         /* ??? This isn't correct wrt the ABI, but it's what GCC does.  */
+         regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
+         break;
+
+       case 16:
+         regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
+         regcache_cooked_read (regcache, ALPHA_FP0_REGNUM+1,
+                               (char *)valbuf + 8);
+         break;
+
+       case 32:
+         regcache_cooked_read_signed (regcache, ALPHA_V0_REGNUM, &l);
+         read_memory (l, valbuf, 32);
+         break;
+
+       default:
+         internal_error (__FILE__, __LINE__, "unknown floating point width");
+       }
+      break;
+
+    default:
+      /* Assume everything else degenerates to an integer.  */
+      regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l);
+      store_unsigned_integer (valbuf, length, l);
+      break;
+    }
+}
+
+/* Extract from REGCACHE the address of a structure about to be returned
+   from a function.  */
+
+static CORE_ADDR
+alpha_extract_struct_value_address (struct regcache *regcache)
+{
+  ULONGEST addr;
+  regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &addr);
+  return addr;
 }
 
-/* Given a return value in `regbuf' with a type `valtype', 
-   write its value into the appropriate register.  */
+/* Insert the given value into REGCACHE as if it was being 
+   returned by a function.  */
 
 static void
-alpha_store_return_value (struct type *valtype, char *valbuf)
+alpha_store_return_value (struct type *valtype, struct regcache *regcache,
+                         const void *valbuf)
 {
-  char raw_buffer[ALPHA_REGISTER_SIZE];
-  int regnum = ALPHA_V0_REGNUM;
   int length = TYPE_LENGTH (valtype);
+  char raw_buffer[ALPHA_REGISTER_SIZE];
+  ULONGEST l;
 
-  if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+  switch (TYPE_CODE (valtype))
     {
-      regnum = FP0_REGNUM;
-      length = ALPHA_REGISTER_SIZE;
-      alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer);
-    }
-  else
-    memcpy (raw_buffer, valbuf, length);
+    case TYPE_CODE_FLT:
+      switch (length)
+       {
+       case 4:
+         alpha_convert_flt_dbl (raw_buffer, valbuf);
+         regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, raw_buffer);
+         break;
 
-  deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length);
+       case 8:
+         regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
+         break;
+
+       case 16:
+         /* FIXME: 128-bit long doubles are returned like structures:
+            by writing into indirect storage provided by the caller
+            as the first argument.  */
+         error ("Cannot set a 128-bit long double return value.");
+
+       default:
+         internal_error (__FILE__, __LINE__, "unknown floating point width");
+       }
+      break;
+
+    case TYPE_CODE_COMPLEX:
+      switch (length)
+       {
+       case 8:
+         /* ??? This isn't correct wrt the ABI, but it's what GCC does.  */
+         regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
+         break;
+
+       case 16:
+         regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
+         regcache_cooked_write (regcache, ALPHA_FP0_REGNUM+1,
+                                (const char *)valbuf + 8);
+         break;
+
+       case 32:
+         /* FIXME: 128-bit long doubles are returned like structures:
+            by writing into indirect storage provided by the caller
+            as the first argument.  */
+         error ("Cannot set a 128-bit long double return value.");
+
+       default:
+         internal_error (__FILE__, __LINE__, "unknown floating point width");
+       }
+      break;
+
+    default:
+      /* Assume everything else degenerates to an integer.  */
+      /* 32-bit values must be sign-extended to 64 bits
+        even if the base data type is unsigned.  */
+      if (length == 4)
+       valtype = builtin_type_int32;
+      l = unpack_long (valtype, valbuf);
+      regcache_cooked_write_unsigned (regcache, ALPHA_V0_REGNUM, l);
+      break;
+    }
 }
 
 static int
@@ -371,20 +565,6 @@ alpha_use_struct_convention (int gcc_p, struct type *type)
   return 1;
 }
 
-static void
-alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
-{
-  /* Store the address of the place in which to copy the structure the
-     subroutine will return.  Handled by alpha_push_arguments.  */
-}
-
-static CORE_ADDR
-alpha_extract_struct_value_address (char *regbuf)
-{
-  return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
-                          REGISTER_RAW_SIZE (ALPHA_V0_REGNUM)));
-}
-
 \f
 static const unsigned char *
 alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
@@ -518,7 +698,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;
 }
 
@@ -1079,6 +1259,73 @@ alpha_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
   return pc;
 }
 
+\f
+/* Helper routines for alpha*-nat.c files to move register sets to and
+   from core files.  The UNIQUE pointer is allowed to be NULL, as most
+   targets don't supply this value in their core files.  */
+
+void
+alpha_supply_int_regs (int regno, const void *r0_r30,
+                      const void *pc, const void *unique)
+{
+  int i;
+
+  for (i = 0; i < 31; ++i)
+    if (regno == i || regno == -1)
+      supply_register (i, (const char *)r0_r30 + i*8);
+
+  if (regno == ALPHA_ZERO_REGNUM || regno == -1)
+    supply_register (ALPHA_ZERO_REGNUM, NULL);
+
+  if (regno == ALPHA_PC_REGNUM || regno == -1)
+    supply_register (ALPHA_PC_REGNUM, pc);
+
+  if (regno == ALPHA_UNIQUE_REGNUM || regno == -1)
+    supply_register (ALPHA_UNIQUE_REGNUM, unique);
+}
+
+void
+alpha_fill_int_regs (int regno, void *r0_r30, void *pc, void *unique)
+{
+  int i;
+
+  for (i = 0; i < 31; ++i)
+    if (regno == i || regno == -1)
+      regcache_collect (i, (char *)r0_r30 + i*8);
+
+  if (regno == ALPHA_PC_REGNUM || regno == -1)
+    regcache_collect (ALPHA_PC_REGNUM, pc);
+
+  if (unique && (regno == ALPHA_UNIQUE_REGNUM || regno == -1))
+    regcache_collect (ALPHA_UNIQUE_REGNUM, unique);
+}
+
+void
+alpha_supply_fp_regs (int regno, const void *f0_f30, const void *fpcr)
+{
+  int i;
+
+  for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i)
+    if (regno == i || regno == -1)
+      supply_register (i, (const char *)f0_f30 + (i - ALPHA_FP0_REGNUM) * 8);
+
+  if (regno == ALPHA_FPCR_REGNUM || regno == -1)
+    supply_register (ALPHA_FPCR_REGNUM, fpcr);
+}
+
+void
+alpha_fill_fp_regs (int regno, void *f0_f30, void *fpcr)
+{
+  int i;
+
+  for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i)
+    if (regno == i || regno == -1)
+      regcache_collect (i, (char *)f0_f30 + (i - ALPHA_FP0_REGNUM) * 8);
+
+  if (regno == ALPHA_FPCR_REGNUM || regno == -1)
+    regcache_collect (ALPHA_FPCR_REGNUM, fpcr);
+}
+
 \f
 /* alpha_software_single_step() is called just before we want to resume
    the inferior, if we want to single-step it but there is no hardware
@@ -1260,19 +1507,23 @@ 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,
                                     generic_frameless_function_invocation_not);
 
   set_gdbarch_use_struct_convention (gdbarch, alpha_use_struct_convention);
-  set_gdbarch_deprecated_extract_return_value (gdbarch, alpha_extract_return_value);
-  set_gdbarch_deprecated_store_struct_return (gdbarch, alpha_store_struct_return);
-  set_gdbarch_deprecated_store_return_value (gdbarch, alpha_store_return_value);
-  set_gdbarch_deprecated_extract_struct_value_address (gdbarch,
+  set_gdbarch_extract_return_value (gdbarch, alpha_extract_return_value);
+  set_gdbarch_store_return_value (gdbarch, alpha_store_return_value);
+  set_gdbarch_extract_struct_value_address (gdbarch,
                                            alpha_extract_struct_value_address);
 
   /* Settings for calling functions in the inferior.  */
@@ -1317,7 +1568,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.  */
 
This page took 0.030708 seconds and 4 git commands to generate.