Pass aarch64_debug_reg_state to functions
[deliverable/binutils-gdb.git] / gdb / s390-linux-tdep.c
index e60951f0a4d64e517f97c3676f3fde8f6c71c9d3..ec28448e119b290bebbf96feec40e78acae545df 100644 (file)
@@ -54,6 +54,8 @@
 #include "cli/cli-utils.h"
 #include <ctype.h>
 #include "elf/common.h"
+#include "elf/s390.h"
+#include "elf-bfd.h"
 
 #include "features/s390-linux32.c"
 #include "features/s390-linux32v1.c"
@@ -80,6 +82,12 @@ enum s390_abi_kind
   ABI_LINUX_ZSERIES
 };
 
+enum s390_vector_abi_kind
+{
+  S390_VECTOR_ABI_NONE,
+  S390_VECTOR_ABI_128
+};
+
 /* The tdep structure.  */
 
 struct gdbarch_tdep
@@ -87,6 +95,9 @@ struct gdbarch_tdep
   /* ABI version.  */
   enum s390_abi_kind abi;
 
+  /* Vector ABI.  */
+  enum s390_vector_abi_kind vector_abi;
+
   /* Pseudo register numbers.  */
   int gpr_full_regnum;
   int pc_regnum;
@@ -1462,15 +1473,23 @@ static CORE_ADDR
 s390_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
   struct s390_prologue_data data;
-  CORE_ADDR skip_pc;
+  CORE_ADDR skip_pc, func_addr;
+
+  if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
+    {
+      CORE_ADDR post_prologue_pc
+       = skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+       return max (pc, post_prologue_pc);
+    }
+
   skip_pc = s390_analyze_prologue (gdbarch, pc, (CORE_ADDR)-1, &data);
   return skip_pc ? skip_pc : pc;
 }
 
-/* Return true if we are in the functin's epilogue, i.e. after the
-   instruction that destroyed the function's stack frame.  */
+/* Implmement the stack_frame_destroyed_p gdbarch method.  */
 static int
-s390_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+s390_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
 
@@ -1818,9 +1837,9 @@ s390_prologue_frame_unwind_cache (struct frame_info *this_frame,
       && (next_frame == NULL
          || get_frame_type (get_next_frame (this_frame)) != NORMAL_FRAME))
     {
-      /* See the comment in s390_in_function_epilogue_p on why this is
+      /* See the comment in s390_stack_frame_destroyed_p on why this is
         not completely reliable ...  */
-      if (s390_in_function_epilogue_p (gdbarch, get_frame_pc (this_frame)))
+      if (s390_stack_frame_destroyed_p (gdbarch, get_frame_pc (this_frame)))
        {
          memset (&data, 0, sizeof (data));
          size = 0;
@@ -1950,7 +1969,6 @@ static struct s390_unwind_cache *
 s390_frame_unwind_cache (struct frame_info *this_frame,
                         void **this_prologue_cache)
 {
-  volatile struct gdb_exception ex;
   struct s390_unwind_cache *info;
 
   if (*this_prologue_cache)
@@ -1963,15 +1981,19 @@ s390_frame_unwind_cache (struct frame_info *this_frame,
   info->frame_base = -1;
   info->local_base = -1;
 
-  TRY_CATCH (ex, RETURN_MASK_ERROR)
+  TRY
     {
       /* Try to use prologue analysis to fill the unwind cache.
         If this fails, fall back to reading the stack backchain.  */
       if (!s390_prologue_frame_unwind_cache (this_frame, info))
        s390_backchain_frame_unwind_cache (this_frame, info);
     }
-  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
-    throw_exception (ex);
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (ex.error != NOT_AVAILABLE_ERROR)
+       throw_exception (ex);
+    }
+  END_CATCH
 
   return info;
 }
@@ -2377,202 +2399,262 @@ s390_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
 
 /* Dummy function calls.  */
 
-/* Return non-zero if TYPE is an integer-like type, zero otherwise.
-   "Integer-like" types are those that should be passed the way
-   integers are: integers, enums, ranges, characters, and booleans.  */
-static int
-is_integer_like (struct type *type)
-{
-  enum type_code code = TYPE_CODE (type);
-
-  return (code == TYPE_CODE_INT
-         || code == TYPE_CODE_ENUM
-         || code == TYPE_CODE_RANGE
-         || code == TYPE_CODE_CHAR
-         || code == TYPE_CODE_BOOL);
-}
-
-/* Return non-zero if TYPE is a pointer-like type, zero otherwise.
-   "Pointer-like" types are those that should be passed the way
-   pointers are: pointers and references.  */
-static int
-is_pointer_like (struct type *type)
-{
-  enum type_code code = TYPE_CODE (type);
-
-  return (code == TYPE_CODE_PTR
-         || code == TYPE_CODE_REF);
-}
-
-
-/* Return non-zero if TYPE is a `float singleton' or `double
-   singleton', zero otherwise.
-
-   A `T singleton' is a struct type with one member, whose type is
-   either T or a `T singleton'.  So, the following are all float
-   singletons:
+/* Unwrap any single-field structs in TYPE and return the effective
+   "inner" type.  E.g., yield "float" for all these cases:
 
-   struct { float x };
-   struct { struct { float x; } x; };
-   struct { struct { struct { float x; } x; } x; };
+     float x;
+     struct { float x };
+     struct { struct { float x; } x; };
+     struct { struct { struct { float x; } x; } x; };
 
-   ... and so on.
+   However, if an inner type is smaller than MIN_SIZE, abort the
+   unwrapping.  */
 
-   All such structures are passed as if they were floats or doubles,
-   as the (revised) ABI says.  */
-static int
-is_float_singleton (struct type *type)
+static struct type *
+s390_effective_inner_type (struct type *type, unsigned int min_size)
 {
-  if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
+  while (TYPE_CODE (type) == TYPE_CODE_STRUCT
+        && TYPE_NFIELDS (type) == 1)
     {
-      struct type *singleton_type = TYPE_FIELD_TYPE (type, 0);
-      CHECK_TYPEDEF (singleton_type);
+      struct type *inner = check_typedef (TYPE_FIELD_TYPE (type, 0));
 
-      return (TYPE_CODE (singleton_type) == TYPE_CODE_FLT
-             || TYPE_CODE (singleton_type) == TYPE_CODE_DECFLOAT
-             || is_float_singleton (singleton_type));
+      if (TYPE_LENGTH (inner) < min_size)
+       break;
+      type = inner;
     }
 
-  return 0;
+  return type;
 }
 
+/* Return non-zero if TYPE should be passed like "float" or
+   "double".  */
 
-/* Return non-zero if TYPE is a struct-like type, zero otherwise.
-   "Struct-like" types are those that should be passed as structs are:
-   structs and unions.
-
-   As an odd quirk, not mentioned in the ABI, GCC passes float and
-   double singletons as if they were a plain float, double, etc.  (The
-   corresponding union types are handled normally.)  So we exclude
-   those types here.  *shrug* */
 static int
-is_struct_like (struct type *type)
+s390_function_arg_float (struct type *type)
 {
-  enum type_code code = TYPE_CODE (type);
-
-  return (code == TYPE_CODE_UNION
-         || (code == TYPE_CODE_STRUCT && ! is_float_singleton (type)));
-}
-
+  /* Note that long double as well as complex types are intentionally
+     excluded. */
+  if (TYPE_LENGTH (type) > 8)
+    return 0;
 
-/* Return non-zero if TYPE is a float-like type, zero otherwise.
-   "Float-like" types are those that should be passed as
-   floating-point values are.
+  /* A struct containing just a float or double is passed like a float
+     or double.  */
+  type = s390_effective_inner_type (type, 0);
 
-   You'd think this would just be floats, doubles, long doubles, etc.
-   But as an odd quirk, not mentioned in the ABI, GCC passes float and
-   double singletons as if they were a plain float, double, etc.  (The
-   corresponding union types are handled normally.)  So we include
-   those types here.  *shrug* */
-static int
-is_float_like (struct type *type)
-{
   return (TYPE_CODE (type) == TYPE_CODE_FLT
-         || TYPE_CODE (type) == TYPE_CODE_DECFLOAT
-         || is_float_singleton (type));
+         || TYPE_CODE (type) == TYPE_CODE_DECFLOAT);
 }
 
+/* Return non-zero if TYPE should be passed like a vector.  */
 
 static int
-is_power_of_two (unsigned int n)
+s390_function_arg_vector (struct type *type)
 {
-  return ((n & (n - 1)) == 0);
-}
+  if (TYPE_LENGTH (type) > 16)
+    return 0;
 
-/* Return non-zero if TYPE should be passed as a pointer to a copy,
-   zero otherwise.  */
-static int
-s390_function_arg_pass_by_reference (struct type *type)
-{
-  if (TYPE_LENGTH (type) > 8)
-    return 1;
+  /* Structs containing just a vector are passed like a vector.  */
+  type = s390_effective_inner_type (type, TYPE_LENGTH (type));
 
-  return (is_struct_like (type) && !is_power_of_two (TYPE_LENGTH (type)))
-         || TYPE_CODE (type) == TYPE_CODE_COMPLEX
-         || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type));
+  return TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type);
 }
 
-/* Return non-zero if TYPE should be passed in a float register
-   if possible.  */
+/* Determine whether N is a power of two.  */
+
 static int
-s390_function_arg_float (struct type *type)
+is_power_of_two (unsigned int n)
 {
-  if (TYPE_LENGTH (type) > 8)
-    return 0;
-
-  return is_float_like (type);
+  return n && ((n & (n - 1)) == 0);
 }
 
-/* Return non-zero if TYPE should be passed in an integer register
-   (or a pair of integer registers) if possible.  */
+/* For an argument whose type is TYPE and which is not passed like a
+   float or vector, return non-zero if it should be passed like "int"
+   or "long long".  */
+
 static int
 s390_function_arg_integer (struct type *type)
 {
+  enum type_code code = TYPE_CODE (type);
+
   if (TYPE_LENGTH (type) > 8)
     return 0;
 
-   return is_integer_like (type)
-         || is_pointer_like (type)
-         || (is_struct_like (type) && is_power_of_two (TYPE_LENGTH (type)));
+  if (code == TYPE_CODE_INT
+      || code == TYPE_CODE_ENUM
+      || code == TYPE_CODE_RANGE
+      || code == TYPE_CODE_CHAR
+      || code == TYPE_CODE_BOOL
+      || code == TYPE_CODE_PTR
+      || code == TYPE_CODE_REF)
+    return 1;
+
+  return ((code == TYPE_CODE_UNION || code == TYPE_CODE_STRUCT)
+         && is_power_of_two (TYPE_LENGTH (type)));
 }
 
-/* Return ARG, a `SIMPLE_ARG', sign-extended or zero-extended to a full
-   word as required for the ABI.  */
-static LONGEST
-extend_simple_arg (struct gdbarch *gdbarch, struct value *arg)
-{
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  struct type *type = check_typedef (value_type (arg));
+/* Argument passing state: Internal data structure passed to helper
+   routines of s390_push_dummy_call.  */
 
-  /* Even structs get passed in the least significant bits of the
-     register / memory word.  It's not really right to extract them as
-     an integer, but it does take care of the extension.  */
-  if (TYPE_UNSIGNED (type))
-    return extract_unsigned_integer (value_contents (arg),
-                                    TYPE_LENGTH (type), byte_order);
-  else
-    return extract_signed_integer (value_contents (arg),
-                                  TYPE_LENGTH (type), byte_order);
-}
+struct s390_arg_state
+  {
+    /* Register cache, or NULL, if we are in "preparation mode".  */
+    struct regcache *regcache;
+    /* Next available general/floating-point/vector register for
+       argument passing.  */
+    int gr, fr, vr;
+    /* Current pointer to copy area (grows downwards).  */
+    CORE_ADDR copy;
+    /* Current pointer to parameter area (grows upwards).  */
+    CORE_ADDR argp;
+  };
 
+/* Prepare one argument ARG for a dummy call and update the argument
+   passing state AS accordingly.  If the regcache field in AS is set,
+   operate in "write mode" and write ARG into the inferior.  Otherwise
+   run "preparation mode" and skip all updates to the inferior.  */
 
-/* Return the alignment required by TYPE.  */
-static int
-alignment_of (struct type *type)
+static void
+s390_handle_arg (struct s390_arg_state *as, struct value *arg,
+                struct gdbarch_tdep *tdep, int word_size,
+                enum bfd_endian byte_order, int is_unnamed)
 {
-  int alignment;
+  struct type *type = check_typedef (value_type (arg));
+  unsigned int length = TYPE_LENGTH (type);
+  int write_mode = as->regcache != NULL;
 
-  if (is_integer_like (type)
-      || is_pointer_like (type)
-      || TYPE_CODE (type) == TYPE_CODE_FLT
-      || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
-    alignment = TYPE_LENGTH (type);
-  else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
-          || TYPE_CODE (type) == TYPE_CODE_UNION)
+  if (s390_function_arg_float (type))
     {
-      int i;
+      /* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass
+        arguments.  The GNU/Linux for zSeries ABI uses 0, 2, 4, and
+        6.  */
+      if (as->fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6))
+       {
+         /* When we store a single-precision value in an FP register,
+            it occupies the leftmost bits.  */
+         if (write_mode)
+           regcache_cooked_write_part (as->regcache,
+                                       S390_F0_REGNUM + as->fr,
+                                       0, length,
+                                       value_contents (arg));
+         as->fr += 2;
+       }
+      else
+       {
+         /* When we store a single-precision value in a stack slot,
+            it occupies the rightmost bits.  */
+         as->argp = align_up (as->argp + length, word_size);
+         if (write_mode)
+           write_memory (as->argp - length, value_contents (arg),
+                         length);
+       }
+    }
+  else if (tdep->vector_abi == S390_VECTOR_ABI_128
+          && s390_function_arg_vector (type))
+    {
+      static const char use_vr[] = {24, 26, 28, 30, 25, 27, 29, 31};
 
-      alignment = 1;
-      for (i = 0; i < TYPE_NFIELDS (type); i++)
+      if (!is_unnamed && as->vr < ARRAY_SIZE (use_vr))
        {
-         int field_alignment
-           = alignment_of (check_typedef (TYPE_FIELD_TYPE (type, i)));
+         int regnum = S390_V24_REGNUM + use_vr[as->vr] - 24;
 
-         if (field_alignment > alignment)
-           alignment = field_alignment;
+         if (write_mode)
+           regcache_cooked_write_part (as->regcache, regnum,
+                                       0, length,
+                                       value_contents (arg));
+         as->vr++;
+       }
+      else
+       {
+         if (write_mode)
+           write_memory (as->argp, value_contents (arg), length);
+         as->argp = align_up (as->argp + length, word_size);
        }
     }
-  else
-    alignment = 1;
+  else if (s390_function_arg_integer (type) && length <= word_size)
+    {
+      /* Initialize it just to avoid a GCC false warning.  */
+      ULONGEST val = 0;
 
-  /* Check that everything we ever return is a power of two.  Lots of
-     code doesn't want to deal with aligning things to arbitrary
-     boundaries.  */
-  gdb_assert ((alignment & (alignment - 1)) == 0);
+      if (write_mode)
+       {
+         /* Place value in least significant bits of the register or
+            memory word and sign- or zero-extend to full word size.
+            This also applies to a struct or union.  */
+         val = TYPE_UNSIGNED (type)
+           ? extract_unsigned_integer (value_contents (arg),
+                                       length, byte_order)
+           : extract_signed_integer (value_contents (arg),
+                                     length, byte_order);
+       }
 
-  return alignment;
-}
+      if (as->gr <= 6)
+       {
+         if (write_mode)
+           regcache_cooked_write_unsigned (as->regcache,
+                                           S390_R0_REGNUM + as->gr,
+                                           val);
+         as->gr++;
+       }
+      else
+       {
+         if (write_mode)
+           write_memory_unsigned_integer (as->argp, word_size,
+                                          byte_order, val);
+         as->argp += word_size;
+       }
+    }
+  else if (s390_function_arg_integer (type) && length == 8)
+    {
+      if (as->gr <= 5)
+       {
+         if (write_mode)
+           {
+             regcache_cooked_write (as->regcache,
+                                    S390_R0_REGNUM + as->gr,
+                                    value_contents (arg));
+             regcache_cooked_write (as->regcache,
+                                    S390_R0_REGNUM + as->gr + 1,
+                                    value_contents (arg) + word_size);
+           }
+         as->gr += 2;
+       }
+      else
+       {
+         /* If we skipped r6 because we couldn't fit a DOUBLE_ARG
+            in it, then don't go back and use it again later.  */
+         as->gr = 7;
+
+         if (write_mode)
+           write_memory (as->argp, value_contents (arg), length);
+         as->argp += length;
+       }
+    }
+  else
+    {
+      /* This argument type is never passed in registers.  Place the
+        value in the copy area and pass a pointer to it.  Use 8-byte
+        alignment as a conservative assumption.  */
+      as->copy = align_down (as->copy - length, 8);
+      if (write_mode)
+       write_memory (as->copy, value_contents (arg), length);
 
+      if (as->gr <= 6)
+       {
+         if (write_mode)
+           regcache_cooked_write_unsigned (as->regcache,
+                                           S390_R0_REGNUM + as->gr,
+                                           as->copy);
+         as->gr++;
+       }
+      else
+       {
+         if (write_mode)
+           write_memory_unsigned_integer (as->argp, word_size,
+                                          byte_order, as->copy);
+         as->argp += word_size;
+       }
+    }
+}
 
 /* Put the actual parameter values pointed to by ARGS[0..NARGS-1] in
    place to be passed to a function, as specified by the "GNU/Linux
@@ -2588,6 +2670,7 @@ alignment_of (struct type *type)
 
    Our caller has taken care of any type promotions needed to satisfy
    prototypes or the old K&R argument-passing rules.  */
+
 static CORE_ADDR
 s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      struct regcache *regcache, CORE_ADDR bp_addr,
@@ -2598,151 +2681,55 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int i;
+  struct s390_arg_state arg_state, arg_prep;
+  CORE_ADDR param_area_start, new_sp;
+  struct type *ftype = check_typedef (value_type (function));
 
-  /* If the i'th argument is passed as a reference to a copy, then
-     copy_addr[i] is the address of the copy we made.  */
-  CORE_ADDR *copy_addr = alloca (nargs * sizeof (CORE_ADDR));
+  if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
+    ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
 
-  /* Reserve space for the reference-to-copy area.  */
-  for (i = 0; i < nargs; i++)
-    {
-      struct value *arg = args[i];
-      struct type *type = check_typedef (value_type (arg));
+  arg_prep.copy = sp;
+  arg_prep.gr = struct_return ? 3 : 2;
+  arg_prep.fr = 0;
+  arg_prep.vr = 0;
+  arg_prep.argp = 0;
+  arg_prep.regcache = NULL;
 
-      if (s390_function_arg_pass_by_reference (type))
-       {
-         sp -= TYPE_LENGTH (type);
-         sp = align_down (sp, alignment_of (type));
-         copy_addr[i] = sp;
-       }
-    }
+  /* Initialize arg_state for "preparation mode".  */
+  arg_state = arg_prep;
 
-  /* Reserve space for the parameter area.  As a conservative
-     simplification, we assume that everything will be passed on the
-     stack.  Since every argument larger than 8 bytes will be
-     passed by reference, we use this simple upper bound.  */
-  sp -= nargs * 8;
+  /* Update arg_state.copy with the start of the reference-to-copy area
+     and arg_state.argp with the size of the parameter area.  */
+  for (i = 0; i < nargs; i++)
+    s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order,
+                    TYPE_VARARGS (ftype) && i >= TYPE_NFIELDS (ftype));
 
-  /* After all that, make sure it's still aligned on an eight-byte
-     boundary.  */
-  sp = align_down (sp, 8);
+  param_area_start = align_down (arg_state.copy - arg_state.argp, 8);
 
   /* Allocate the standard frame areas: the register save area, the
-     word reserved for the compiler (which seems kind of meaningless),
-     and the back chain pointer.  */
-  sp -= 16*word_size + 32;
-
-  /* Now we have the final SP value.  Make sure we didn't underflow;
-     on 31-bit, this would result in addresses with the high bit set,
-     which causes confusion elsewhere.  Note that if we error out
-     here, stack and registers remain untouched.  */
-  if (gdbarch_addr_bits_remove (gdbarch, sp) != sp)
+     word reserved for the compiler, and the back chain pointer.  */
+  new_sp = param_area_start - (16 * word_size + 32);
+
+  /* Now we have the final stack pointer.  Make sure we didn't
+     underflow; on 31-bit, this would result in addresses with the
+     high bit set, which causes confusion elsewhere.  Note that if we
+     error out here, stack and registers remain untouched.  */
+  if (gdbarch_addr_bits_remove (gdbarch, new_sp) != new_sp)
     error (_("Stack overflow"));
 
+  /* Pass the structure return address in general register 2.  */
+  if (struct_return)
+    regcache_cooked_write_unsigned (regcache, S390_R2_REGNUM, struct_addr);
 
-  /* Finally, place the actual parameters, working from SP towards
-     higher addresses.  The code above is supposed to reserve enough
-     space for this.  */
-  {
-    int fr = 0;
-    int gr = 2;
-    CORE_ADDR starg = sp + 16*word_size + 32;
-
-    /* A struct is returned using general register 2.  */
-    if (struct_return)
-      {
-       regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr,
-                                       struct_addr);
-       gr++;
-      }
+  /* Initialize arg_state for "write mode".  */
+  arg_state = arg_prep;
+  arg_state.argp = param_area_start;
+  arg_state.regcache = regcache;
 
-    for (i = 0; i < nargs; i++)
-      {
-       struct value *arg = args[i];
-       struct type *type = check_typedef (value_type (arg));
-       unsigned length = TYPE_LENGTH (type);
-
-       if (s390_function_arg_pass_by_reference (type))
-         {
-           /* Actually copy the argument contents to the stack slot
-              that was reserved above.  */
-           write_memory (copy_addr[i], value_contents (arg), length);
-
-           if (gr <= 6)
-             {
-               regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr,
-                                               copy_addr[i]);
-               gr++;
-             }
-           else
-             {
-               write_memory_unsigned_integer (starg, word_size, byte_order,
-                                              copy_addr[i]);
-               starg += word_size;
-             }
-         }
-       else if (s390_function_arg_float (type))
-         {
-           /* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass arguments,
-              the GNU/Linux for zSeries ABI uses 0, 2, 4, and 6.  */
-           if (fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6))
-             {
-               /* When we store a single-precision value in an FP register,
-                  it occupies the leftmost bits.  */
-               regcache_cooked_write_part (regcache, S390_F0_REGNUM + fr,
-                                           0, length, value_contents (arg));
-               fr += 2;
-             }
-           else
-             {
-               /* When we store a single-precision value in a stack slot,
-                  it occupies the rightmost bits.  */
-               starg = align_up (starg + length, word_size);
-               write_memory (starg - length, value_contents (arg), length);
-             }
-         }
-       else if (s390_function_arg_integer (type) && length <= word_size)
-         {
-           if (gr <= 6)
-             {
-               /* Integer arguments are always extended to word size.  */
-               regcache_cooked_write_signed (regcache, S390_R0_REGNUM + gr,
-                                             extend_simple_arg (gdbarch,
-                                                                arg));
-               gr++;
-             }
-           else
-             {
-               /* Integer arguments are always extended to word size.  */
-               write_memory_signed_integer (starg, word_size, byte_order,
-                                            extend_simple_arg (gdbarch, arg));
-               starg += word_size;
-             }
-         }
-       else if (s390_function_arg_integer (type) && length == 2*word_size)
-         {
-           if (gr <= 5)
-             {
-               regcache_cooked_write (regcache, S390_R0_REGNUM + gr,
-                                      value_contents (arg));
-               regcache_cooked_write (regcache, S390_R0_REGNUM + gr + 1,
-                                      value_contents (arg) + word_size);
-               gr += 2;
-             }
-           else
-             {
-               /* If we skipped r6 because we couldn't fit a DOUBLE_ARG
-                  in it, then don't go back and use it again later.  */
-               gr = 7;
-
-               write_memory (starg, value_contents (arg), length);
-               starg += length;
-             }
-         }
-       else
-         internal_error (__FILE__, __LINE__, _("unknown argument type"));
-      }
-  }
+  /* Write all parameters.  */
+  for (i = 0; i < nargs; i++)
+    s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order,
+                    TYPE_VARARGS (ftype) && i >= TYPE_NFIELDS (ftype));
 
   /* Store return PSWA.  In 31-bit mode, keep addressing mode bit.  */
   if (word_size == 4)
@@ -2754,11 +2741,11 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   regcache_cooked_write_unsigned (regcache, S390_RETADDR_REGNUM, bp_addr);
 
   /* Store updated stack pointer.  */
-  regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, sp);
+  regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, new_sp);
 
   /* We need to return the 'stack part' of the frame ID,
      which is actually the top of the register save area.  */
-  return sp + 16*word_size + 32;
+  return param_area_start;
 }
 
 /* Assuming THIS_FRAME is a dummy, return the frame ID of that
@@ -2785,110 +2772,113 @@ s390_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
 }
 
 
-/* Function return value access.  */
+/* Helper for s390_return_value: Set or retrieve a function return
+   value if it resides in a register.  */
 
-static enum return_value_convention
-s390_return_value_convention (struct gdbarch *gdbarch, struct type *type)
+static void
+s390_register_return_value (struct gdbarch *gdbarch, struct type *type,
+                           struct regcache *regcache,
+                           gdb_byte *out, const gdb_byte *in)
 {
-  if (TYPE_LENGTH (type) > 8)
-    return RETURN_VALUE_STRUCT_CONVENTION;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+  int length = TYPE_LENGTH (type);
+  int code = TYPE_CODE (type);
 
-  switch (TYPE_CODE (type))
+  if (code == TYPE_CODE_FLT || code == TYPE_CODE_DECFLOAT)
     {
-    case TYPE_CODE_STRUCT:
-    case TYPE_CODE_UNION:
-    case TYPE_CODE_ARRAY:
-    case TYPE_CODE_COMPLEX:
-      return RETURN_VALUE_STRUCT_CONVENTION;
-
-    default:
-      return RETURN_VALUE_REGISTER_CONVENTION;
+      /* Float-like value: left-aligned in f0.  */
+      if (in != NULL)
+       regcache_cooked_write_part (regcache, S390_F0_REGNUM,
+                                   0, length, in);
+      else
+       regcache_cooked_read_part (regcache, S390_F0_REGNUM,
+                                  0, length, out);
+    }
+  else if (code == TYPE_CODE_ARRAY)
+    {
+      /* Vector: left-aligned in v24.  */
+      if (in != NULL)
+       regcache_cooked_write_part (regcache, S390_V24_REGNUM,
+                                   0, length, in);
+      else
+       regcache_cooked_read_part (regcache, S390_V24_REGNUM,
+                                  0, length, out);
+    }
+  else if (length <= word_size)
+    {
+      /* Integer: zero- or sign-extended in r2.  */
+      if (out != NULL)
+       regcache_cooked_read_part (regcache, S390_R2_REGNUM,
+                                  word_size - length, length, out);
+      else if (TYPE_UNSIGNED (type))
+       regcache_cooked_write_unsigned
+         (regcache, S390_R2_REGNUM,
+          extract_unsigned_integer (in, length, byte_order));
+      else
+       regcache_cooked_write_signed
+         (regcache, S390_R2_REGNUM,
+          extract_signed_integer (in, length, byte_order));
+    }
+  else if (length == 2 * word_size)
+    {
+      /* Double word: in r2 and r3.  */
+      if (in != NULL)
+       {
+         regcache_cooked_write (regcache, S390_R2_REGNUM, in);
+         regcache_cooked_write (regcache, S390_R3_REGNUM,
+                                in + word_size);
+       }
+      else
+       {
+         regcache_cooked_read (regcache, S390_R2_REGNUM, out);
+         regcache_cooked_read (regcache, S390_R3_REGNUM,
+                               out + word_size);
+       }
     }
+  else
+    internal_error (__FILE__, __LINE__, _("invalid return type"));
 }
 
+
+/* Implement the 'return_value' gdbarch method.  */
+
 static enum return_value_convention
 s390_return_value (struct gdbarch *gdbarch, struct value *function,
                   struct type *type, struct regcache *regcache,
                   gdb_byte *out, const gdb_byte *in)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  int word_size = gdbarch_ptr_bit (gdbarch) / 8;
   enum return_value_convention rvc;
-  int length;
 
   type = check_typedef (type);
-  rvc = s390_return_value_convention (gdbarch, type);
-  length = TYPE_LENGTH (type);
 
-  if (in)
+  switch (TYPE_CODE (type))
     {
-      switch (rvc)
-       {
-       case RETURN_VALUE_REGISTER_CONVENTION:
-         if (TYPE_CODE (type) == TYPE_CODE_FLT
-             || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
-           {
-             /* When we store a single-precision value in an FP register,
-                it occupies the leftmost bits.  */
-             regcache_cooked_write_part (regcache, S390_F0_REGNUM,
-                                         0, length, in);
-           }
-         else if (length <= word_size)
-           {
-             /* Integer arguments are always extended to word size.  */
-             if (TYPE_UNSIGNED (type))
-               regcache_cooked_write_unsigned (regcache, S390_R2_REGNUM,
-                       extract_unsigned_integer (in, length, byte_order));
-             else
-               regcache_cooked_write_signed (regcache, S390_R2_REGNUM,
-                       extract_signed_integer (in, length, byte_order));
-           }
-         else if (length == 2*word_size)
-           {
-             regcache_cooked_write (regcache, S390_R2_REGNUM, in);
-             regcache_cooked_write (regcache, S390_R3_REGNUM, in + word_size);
-           }
-         else
-           internal_error (__FILE__, __LINE__, _("invalid return type"));
-         break;
-
-       case RETURN_VALUE_STRUCT_CONVENTION:
-         error (_("Cannot set function return value."));
-         break;
-       }
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_COMPLEX:
+      rvc = RETURN_VALUE_STRUCT_CONVENTION;
+      break;
+    case TYPE_CODE_ARRAY:
+      rvc = (gdbarch_tdep (gdbarch)->vector_abi == S390_VECTOR_ABI_128
+            && TYPE_LENGTH (type) <= 16 && TYPE_VECTOR (type))
+       ? RETURN_VALUE_REGISTER_CONVENTION
+       : RETURN_VALUE_STRUCT_CONVENTION;
+      break;
+    default:
+      rvc = TYPE_LENGTH (type) <= 8
+       ? RETURN_VALUE_REGISTER_CONVENTION
+       : RETURN_VALUE_STRUCT_CONVENTION;
     }
-  else if (out)
-    {
-      switch (rvc)
-       {
-       case RETURN_VALUE_REGISTER_CONVENTION:
-         if (TYPE_CODE (type) == TYPE_CODE_FLT
-             || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
-           {
-             /* When we store a single-precision value in an FP register,
-                it occupies the leftmost bits.  */
-             regcache_cooked_read_part (regcache, S390_F0_REGNUM,
-                                        0, length, out);
-           }
-         else if (length <= word_size)
-           {
-             /* Integer arguments occupy the rightmost bits.  */
-             regcache_cooked_read_part (regcache, S390_R2_REGNUM,
-                                        word_size - length, length, out);
-           }
-         else if (length == 2*word_size)
-           {
-             regcache_cooked_read (regcache, S390_R2_REGNUM, out);
-             regcache_cooked_read (regcache, S390_R3_REGNUM, out + word_size);
-           }
-         else
-           internal_error (__FILE__, __LINE__, _("invalid return type"));
-         break;
 
-       case RETURN_VALUE_STRUCT_CONVENTION:
-         error (_("Function return value unknown."));
-         break;
-       }
+  if (in != NULL || out != NULL)
+    {
+      if (rvc == RETURN_VALUE_REGISTER_CONVENTION)
+       s390_register_return_value (gdbarch, type, regcache, out, in);
+      else if (in != NULL)
+       error (_("Cannot set function return value."));
+      else
+       error (_("Function return value unknown."));
     }
 
   return rvc;
@@ -2990,6 +2980,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   struct gdbarch *gdbarch;
   struct gdbarch_tdep *tdep;
   int tdep_abi;
+  enum s390_vector_abi_kind vector_abi;
   int have_upper = 0;
   int have_linux_v1 = 0;
   int have_linux_v2 = 0;
@@ -3172,6 +3163,18 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        }
     }
 
+  /* Determine vector ABI.  */
+  vector_abi = S390_VECTOR_ABI_NONE;
+#ifdef HAVE_ELF
+  if (have_vx
+      && info.abfd != NULL
+      && info.abfd->format == bfd_object
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour
+      && bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU,
+                                  Tag_GNU_S390_ABI_Vector) == 2)
+    vector_abi = S390_VECTOR_ABI_128;
+#endif
+
   /* Find a candidate among extant architectures.  */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
        arches != NULL;
@@ -3182,6 +3185,8 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        continue;
       if (tdep->abi != tdep_abi)
        continue;
+      if (tdep->vector_abi != vector_abi)
+       continue;
       if ((tdep->gpr_full_regnum != -1) != have_upper)
        continue;
       if (tdesc_data != NULL)
@@ -3192,6 +3197,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Otherwise create a new gdbarch for the specified machine type.  */
   tdep = XCNEW (struct gdbarch_tdep);
   tdep->abi = tdep_abi;
+  tdep->vector_abi = vector_abi;
   tdep->have_linux_v1 = have_linux_v1;
   tdep->have_linux_v2 = have_linux_v2;
   tdep->have_tdb = have_tdb;
@@ -3214,7 +3220,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_breakpoint_from_pc (gdbarch, s390_breakpoint_from_pc);
   set_gdbarch_skip_prologue (gdbarch, s390_skip_prologue);
-  set_gdbarch_in_function_epilogue_p (gdbarch, s390_in_function_epilogue_p);
+  set_gdbarch_stack_frame_destroyed_p (gdbarch, s390_stack_frame_destroyed_p);
 
   set_gdbarch_num_regs (gdbarch, S390_NUM_REGS);
   set_gdbarch_sp_regnum (gdbarch, S390_SP_REGNUM);
@@ -3283,8 +3289,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_displaced_step_fixup (gdbarch, s390_displaced_step_fixup);
   set_gdbarch_displaced_step_free_closure (gdbarch,
                                           simple_displaced_step_free_closure);
-  set_gdbarch_displaced_step_location (gdbarch,
-                                      displaced_step_at_entry_point);
+  set_gdbarch_displaced_step_location (gdbarch, linux_displaced_step_location);
   set_gdbarch_max_insn_length (gdbarch, S390_MAX_INSTR_SIZE);
 
   /* Note that GNU/Linux is the only OS supported on this
@@ -3325,8 +3330,6 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
                                             svr4_fetch_objfile_link_map);
 
-  set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
-
   /* SystemTap functions.  */
   set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes);
   set_gdbarch_stap_register_indirection_prefixes (gdbarch,
This page took 0.034471 seconds and 4 git commands to generate.