Blame SOURCES/gdb-rhbz1182151-ibm-z13-14of22.patch

01917d
commit 80f75320167acb66486124c6b03e715596e9c789
01917d
Author: Andreas Arnez <arnez@linux.vnet.ibm.com>
01917d
Date:   Mon Apr 27 11:38:46 2015 +0200
01917d
01917d
    S390: Restructure s390_push_dummy_call
01917d
    
01917d
    Simplify the structure of s390_push_dummy_call and its various helper
01917d
    functions.  This reduces the code and makes it easier to extend.  The
01917d
    new code should be functionally equivalent to the old one, except that
01917d
    copies created by the caller are now always aligned on an 8-byte
01917d
    boundary.
01917d
    
01917d
    gdb/ChangeLog:
01917d
    
01917d
    	* s390-linux-tdep.c
01917d
    	(is_float_singleton): Remove function.  Move the "singleton" part
01917d
    	of the logic...
01917d
    	(s390_effective_inner_type): ...here.  New function.
01917d
    	(is_float_like): Remove function.  Inline its logic...
01917d
    	(s390_function_arg_float): ...here.
01917d
    	(is_pointer_like, is_integer_like, is_struct_like): Remove
01917d
    	functions.  Inline their logic...
01917d
    	(s390_function_arg_integer): ...here.
01917d
    	(s390_function_arg_pass_by_reference): Remove function.
01917d
    	(extend_simple_arg): Remove function.
01917d
    	(alignment_of): Remove function.
01917d
    	(struct s390_arg_state): New structure.
01917d
    	(s390_handle_arg): New function.
01917d
    	(s390_push_dummy_call): Move parameter placement logic to the new
01917d
    	function s390_handle_arg.  Call it for calculating the stack area
01917d
    	sizes first, and again for actually writing the parameters.
01917d
01917d
### a/gdb/ChangeLog
01917d
### b/gdb/ChangeLog
01917d
## -1,5 +1,25 @@
01917d
 2015-04-27  Andreas Arnez  <arnez@linux.vnet.ibm.com>
01917d
 
01917d
+	* s390-linux-tdep.c
01917d
+	(is_float_singleton): Remove function.  Move the "singleton" part
01917d
+	of the logic...
01917d
+	(s390_effective_inner_type): ...here.  New function.
01917d
+	(is_float_like): Remove function.  Inline its logic...
01917d
+	(s390_function_arg_float): ...here.
01917d
+	(is_pointer_like, is_integer_like, is_struct_like): Remove
01917d
+	functions.  Inline their logic...
01917d
+	(s390_function_arg_integer): ...here.
01917d
+	(s390_function_arg_pass_by_reference): Remove function.
01917d
+	(extend_simple_arg): Remove function.
01917d
+	(alignment_of): Remove function.
01917d
+	(struct s390_arg_state): New structure.
01917d
+	(s390_handle_arg): New function.
01917d
+	(s390_push_dummy_call): Move parameter placement logic to the new
01917d
+	function s390_handle_arg.  Call it for calculating the stack area
01917d
+	sizes first, and again for actually writing the parameters.
01917d
+
01917d
+2015-04-27  Andreas Arnez  <arnez@linux.vnet.ibm.com>
01917d
+
01917d
 	* s390-linux-tdep.c (is_power_of_two): Add comment.  Return
01917d
 	  false if the argument is zero.
01917d
 
01917d
Index: gdb-7.6.1/gdb/s390-tdep.c
01917d
===================================================================
01917d
--- gdb-7.6.1.orig/gdb/s390-tdep.c	2016-02-21 22:27:47.198043364 +0100
01917d
+++ gdb-7.6.1/gdb/s390-tdep.c	2016-02-21 22:30:02.980113202 +0100
01917d
@@ -2546,99 +2546,40 @@
01917d
 
01917d
 /* Dummy function calls.  */
01917d
 
01917d
-/* Return non-zero if TYPE is an integer-like type, zero otherwise.
01917d
-   "Integer-like" types are those that should be passed the way
01917d
-   integers are: integers, enums, ranges, characters, and booleans.  */
01917d
-static int
01917d
-is_integer_like (struct type *type)
01917d
-{
01917d
-  enum type_code code = TYPE_CODE (type);
01917d
+/* Unwrap any single-field structs in TYPE and return the effective
01917d
+   "inner" type.  E.g., yield "float" for all these cases:
01917d
 
01917d
-  return (code == TYPE_CODE_INT
01917d
-          || code == TYPE_CODE_ENUM
01917d
-          || code == TYPE_CODE_RANGE
01917d
-          || code == TYPE_CODE_CHAR
01917d
-          || code == TYPE_CODE_BOOL);
01917d
-}
01917d
+     float x;
01917d
+     struct { float x };
01917d
+     struct { struct { float x; } x; };
01917d
+     struct { struct { struct { float x; } x; } x; };  */
01917d
 
01917d
-/* Return non-zero if TYPE is a pointer-like type, zero otherwise.
01917d
-   "Pointer-like" types are those that should be passed the way
01917d
-   pointers are: pointers and references.  */
01917d
-static int
01917d
-is_pointer_like (struct type *type)
01917d
+static struct type *
01917d
+s390_effective_inner_type (struct type *type)
01917d
 {
01917d
-  enum type_code code = TYPE_CODE (type);
01917d
-
01917d
-  return (code == TYPE_CODE_PTR
01917d
-          || code == TYPE_CODE_REF);
01917d
+  while (TYPE_CODE (type) == TYPE_CODE_STRUCT
01917d
+	 && TYPE_NFIELDS (type) == 1)
01917d
+    type = check_typedef (TYPE_FIELD_TYPE (type, 0));
01917d
+  return type;
01917d
 }
01917d
 
01917d
+/* Return non-zero if TYPE should be passed like "float" or
01917d
+   "double".  */
01917d
 
01917d
-/* Return non-zero if TYPE is a `float singleton' or `double
01917d
-   singleton', zero otherwise.
01917d
-
01917d
-   A `T singleton' is a struct type with one member, whose type is
01917d
-   either T or a `T singleton'.  So, the following are all float
01917d
-   singletons:
01917d
-
01917d
-   struct { float x };
01917d
-   struct { struct { float x; } x; };
01917d
-   struct { struct { struct { float x; } x; } x; };
01917d
-
01917d
-   ... and so on.
01917d
-
01917d
-   All such structures are passed as if they were floats or doubles,
01917d
-   as the (revised) ABI says.  */
01917d
 static int
01917d
-is_float_singleton (struct type *type)
01917d
-{
01917d
-  if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
01917d
-    {
01917d
-      struct type *singleton_type = TYPE_FIELD_TYPE (type, 0);
01917d
-      CHECK_TYPEDEF (singleton_type);
01917d
-
01917d
-      return (TYPE_CODE (singleton_type) == TYPE_CODE_FLT
01917d
-	      || TYPE_CODE (singleton_type) == TYPE_CODE_DECFLOAT
01917d
-	      || is_float_singleton (singleton_type));
01917d
-    }
01917d
-
01917d
-  return 0;
01917d
-}
01917d
-
01917d
-
01917d
-/* Return non-zero if TYPE is a struct-like type, zero otherwise.
01917d
-   "Struct-like" types are those that should be passed as structs are:
01917d
-   structs and unions.
01917d
-
01917d
-   As an odd quirk, not mentioned in the ABI, GCC passes float and
01917d
-   double singletons as if they were a plain float, double, etc.  (The
01917d
-   corresponding union types are handled normally.)  So we exclude
01917d
-   those types here.  *shrug* */
01917d
-static int
01917d
-is_struct_like (struct type *type)
01917d
+s390_function_arg_float (struct type *type)
01917d
 {
01917d
-  enum type_code code = TYPE_CODE (type);
01917d
-
01917d
-  return (code == TYPE_CODE_UNION
01917d
-          || (code == TYPE_CODE_STRUCT && ! is_float_singleton (type)));
01917d
-}
01917d
+  /* Note that long double as well as complex types are intentionally
01917d
+     excluded. */
01917d
+  if (TYPE_LENGTH (type) > 8)
01917d
+    return 0;
01917d
 
01917d
+  /* A struct containing just a float or double is passed like a float
01917d
+     or double.  */
01917d
+  type = s390_effective_inner_type (type);
01917d
 
01917d
-/* Return non-zero if TYPE is a float-like type, zero otherwise.
01917d
-   "Float-like" types are those that should be passed as
01917d
-   floating-point values are.
01917d
-
01917d
-   You'd think this would just be floats, doubles, long doubles, etc.
01917d
-   But as an odd quirk, not mentioned in the ABI, GCC passes float and
01917d
-   double singletons as if they were a plain float, double, etc.  (The
01917d
-   corresponding union types are handled normally.)  So we include
01917d
-   those types here.  *shrug* */
01917d
-static int
01917d
-is_float_like (struct type *type)
01917d
-{
01917d
   return (TYPE_CODE (type) == TYPE_CODE_FLT
01917d
-	  || TYPE_CODE (type) == TYPE_CODE_DECFLOAT
01917d
-          || is_float_singleton (type));
01917d
+	  || TYPE_CODE (type) == TYPE_CODE_DECFLOAT);
01917d
 }
01917d
 
01917d
 /* Determine whether N is a power of two.  */
01917d
@@ -2649,101 +2590,172 @@
01917d
   return n && ((n & (n - 1)) == 0);
01917d
 }
01917d
 
01917d
-/* Return non-zero if TYPE should be passed as a pointer to a copy,
01917d
-   zero otherwise.  */
01917d
-static int
01917d
-s390_function_arg_pass_by_reference (struct type *type)
01917d
-{
01917d
-  if (TYPE_LENGTH (type) > 8)
01917d
-    return 1;
01917d
-
01917d
-  return (is_struct_like (type) && !is_power_of_two (TYPE_LENGTH (type)))
01917d
-	  || TYPE_CODE (type) == TYPE_CODE_COMPLEX
01917d
-	  || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type));
01917d
-}
01917d
-
01917d
-/* Return non-zero if TYPE should be passed in a float register
01917d
-   if possible.  */
01917d
-static int
01917d
-s390_function_arg_float (struct type *type)
01917d
-{
01917d
-  if (TYPE_LENGTH (type) > 8)
01917d
-    return 0;
01917d
-
01917d
-  return is_float_like (type);
01917d
-}
01917d
+/* For an argument whose type is TYPE and which is not passed like a
01917d
+   float, return non-zero if it should be passed like "int" or "long
01917d
+   long".  */
01917d
 
01917d
-/* Return non-zero if TYPE should be passed in an integer register
01917d
-   (or a pair of integer registers) if possible.  */
01917d
 static int
01917d
 s390_function_arg_integer (struct type *type)
01917d
 {
01917d
+  enum type_code code = TYPE_CODE (type);
01917d
+
01917d
   if (TYPE_LENGTH (type) > 8)
01917d
     return 0;
01917d
 
01917d
-   return is_integer_like (type)
01917d
-	  || is_pointer_like (type)
01917d
-	  || (is_struct_like (type) && is_power_of_two (TYPE_LENGTH (type)));
01917d
-}
01917d
-
01917d
-/* Return ARG, a `SIMPLE_ARG', sign-extended or zero-extended to a full
01917d
-   word as required for the ABI.  */
01917d
-static LONGEST
01917d
-extend_simple_arg (struct gdbarch *gdbarch, struct value *arg)
01917d
-{
01917d
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
01917d
-  struct type *type = check_typedef (value_type (arg));
01917d
+  if (code == TYPE_CODE_INT
01917d
+      || code == TYPE_CODE_ENUM
01917d
+      || code == TYPE_CODE_RANGE
01917d
+      || code == TYPE_CODE_CHAR
01917d
+      || code == TYPE_CODE_BOOL
01917d
+      || code == TYPE_CODE_PTR
01917d
+      || code == TYPE_CODE_REF)
01917d
+    return 1;
01917d
 
01917d
-  /* Even structs get passed in the least significant bits of the
01917d
-     register / memory word.  It's not really right to extract them as
01917d
-     an integer, but it does take care of the extension.  */
01917d
-  if (TYPE_UNSIGNED (type))
01917d
-    return extract_unsigned_integer (value_contents (arg),
01917d
-                                     TYPE_LENGTH (type), byte_order);
01917d
-  else
01917d
-    return extract_signed_integer (value_contents (arg),
01917d
-                                   TYPE_LENGTH (type), byte_order);
01917d
+  return ((code == TYPE_CODE_UNION || code == TYPE_CODE_STRUCT)
01917d
+	  && is_power_of_two (TYPE_LENGTH (type)));
01917d
 }
01917d
 
01917d
+/* Argument passing state: Internal data structure passed to helper
01917d
+   routines of s390_push_dummy_call.  */
01917d
 
01917d
-/* Return the alignment required by TYPE.  */
01917d
-static int
01917d
-alignment_of (struct type *type)
01917d
+struct s390_arg_state
01917d
+  {
01917d
+    /* Register cache, or NULL, if we are in "preparation mode".  */
01917d
+    struct regcache *regcache;
01917d
+    /* Next available general/floating-point register for argument
01917d
+       passing.  */
01917d
+    int gr, fr;
01917d
+    /* Current pointer to copy area (grows downwards).  */
01917d
+    CORE_ADDR copy;
01917d
+    /* Current pointer to parameter area (grows upwards).  */
01917d
+    CORE_ADDR argp;
01917d
+  };
01917d
+
01917d
+/* Prepare one argument ARG for a dummy call and update the argument
01917d
+   passing state AS accordingly.  If the regcache field in AS is set,
01917d
+   operate in "write mode" and write ARG into the inferior.  Otherwise
01917d
+   run "preparation mode" and skip all updates to the inferior.  */
01917d
+
01917d
+static void
01917d
+s390_handle_arg (struct s390_arg_state *as, struct value *arg,
01917d
+		 struct gdbarch_tdep *tdep, int word_size,
01917d
+		 enum bfd_endian byte_order)
01917d
 {
01917d
-  int alignment;
01917d
+  struct type *type = check_typedef (value_type (arg));
01917d
+  ULONGEST length = TYPE_LENGTH (type);
01917d
+  int write_mode = as->regcache != NULL;
01917d
 
01917d
-  if (is_integer_like (type)
01917d
-      || is_pointer_like (type)
01917d
-      || TYPE_CODE (type) == TYPE_CODE_FLT
01917d
-      || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
01917d
-    alignment = TYPE_LENGTH (type);
01917d
-  else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
01917d
-           || TYPE_CODE (type) == TYPE_CODE_UNION)
01917d
+  if (s390_function_arg_float (type))
01917d
+    {
01917d
+      /* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass
01917d
+	 arguments.  The GNU/Linux for zSeries ABI uses 0, 2, 4, and
01917d
+	 6.  */
01917d
+      if (as->fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6))
01917d
+	{
01917d
+	  /* When we store a single-precision value in an FP register,
01917d
+	     it occupies the leftmost bits.  */
01917d
+	  if (write_mode)
01917d
+	    regcache_cooked_write_part (as->regcache,
01917d
+					S390_F0_REGNUM + as->fr,
01917d
+					0, length,
01917d
+					value_contents (arg));
01917d
+	  as->fr += 2;
01917d
+	}
01917d
+      else
01917d
+	{
01917d
+	  /* When we store a single-precision value in a stack slot,
01917d
+	     it occupies the rightmost bits.  */
01917d
+	  as->argp = align_up (as->argp + length, word_size);
01917d
+	  if (write_mode)
01917d
+	    write_memory (as->argp - length, value_contents (arg),
01917d
+			  length);
01917d
+	}
01917d
+    }
01917d
+  else if (s390_function_arg_integer (type) && length <= word_size)
01917d
     {
01917d
-      int i;
01917d
+      ULONGEST val;
01917d
 
01917d
-      alignment = 1;
01917d
-      for (i = 0; i < TYPE_NFIELDS (type); i++)
01917d
+      if (write_mode)
01917d
         {
01917d
-          int field_alignment
01917d
-	    = alignment_of (check_typedef (TYPE_FIELD_TYPE (type, i)));
01917d
-
01917d
-          if (field_alignment > alignment)
01917d
-            alignment = field_alignment;
01917d
+	  /* Place value in least significant bits of the register or
01917d
+	     memory word and sign- or zero-extend to full word size.
01917d
+	     This also applies to a struct or union.  */
01917d
+	  val = TYPE_UNSIGNED (type)
01917d
+	    ? extract_unsigned_integer (value_contents (arg),
01917d
+					length, byte_order)
01917d
+	    : extract_signed_integer (value_contents (arg),
01917d
+				      length, byte_order);
01917d
+	}
01917d
+
01917d
+      if (as->gr <= 6)
01917d
+	{
01917d
+	  if (write_mode)
01917d
+	    regcache_cooked_write_unsigned (as->regcache,
01917d
+					    S390_R0_REGNUM + as->gr,
01917d
+					    val);
01917d
+	  as->gr++;
01917d
+	}
01917d
+      else
01917d
+	{
01917d
+	  if (write_mode)
01917d
+	    write_memory_unsigned_integer (as->argp, word_size,
01917d
+					   byte_order, val);
01917d
+	  as->argp += word_size;
01917d
         }
01917d
     }
01917d
+  else if (s390_function_arg_integer (type) && length == 8)
01917d
+    {
01917d
+      if (as->gr <= 5)
01917d
+	{
01917d
+	  if (write_mode)
01917d
+	    {
01917d
+	      regcache_cooked_write (as->regcache,
01917d
+				     S390_R0_REGNUM + as->gr,
01917d
+				     value_contents (arg));
01917d
+	      regcache_cooked_write (as->regcache,
01917d
+				     S390_R0_REGNUM + as->gr + 1,
01917d
+				     value_contents (arg) + word_size);
01917d
+	    }
01917d
+	  as->gr += 2;
01917d
+	}
01917d
+      else
01917d
+	{
01917d
+	  /* If we skipped r6 because we couldn't fit a DOUBLE_ARG
01917d
+	     in it, then don't go back and use it again later.  */
01917d
+	  as->gr = 7;
01917d
+
01917d
+	  if (write_mode)
01917d
+	    write_memory (as->argp, value_contents (arg), length);
01917d
+	  as->argp += length;
01917d
+	}
01917d
+    }
01917d
   else
01917d
-    alignment = 1;
01917d
-
01917d
-  /* Check that everything we ever return is a power of two.  Lots of
01917d
-     code doesn't want to deal with aligning things to arbitrary
01917d
-     boundaries.  */
01917d
-  gdb_assert ((alignment & (alignment - 1)) == 0);
01917d
-
01917d
-  return alignment;
01917d
+    {
01917d
+      /* This argument type is never passed in registers.  Place the
01917d
+	 value in the copy area and pass a pointer to it.  Use 8-byte
01917d
+	 alignment as a conservative assumption.  */
01917d
+      as->copy = align_down (as->copy - length, 8);
01917d
+      if (write_mode)
01917d
+	write_memory (as->copy, value_contents (arg), length);
01917d
+
01917d
+      if (as->gr <= 6)
01917d
+	{
01917d
+	  if (write_mode)
01917d
+	    regcache_cooked_write_unsigned (as->regcache,
01917d
+					    S390_R0_REGNUM + as->gr,
01917d
+					    as->copy);
01917d
+	  as->gr++;
01917d
+	}
01917d
+      else
01917d
+	{
01917d
+	  if (write_mode)
01917d
+	    write_memory_unsigned_integer (as->argp, word_size,
01917d
+					   byte_order, as->copy);
01917d
+	  as->argp += word_size;
01917d
+	}
01917d
+    }
01917d
 }
01917d
 
01917d
-
01917d
 /* Put the actual parameter values pointed to by ARGS[0..NARGS-1] in
01917d
    place to be passed to a function, as specified by the "GNU/Linux
01917d
    for S/390 ELF Application Binary Interface Supplement".
01917d
@@ -2758,6 +2770,7 @@
01917d
 
01917d
    Our caller has taken care of any type promotions needed to satisfy
01917d
    prototypes or the old K&R argument-passing rules.  */
01917d
+
01917d
 static CORE_ADDR
01917d
 s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
01917d
 		      struct regcache *regcache, CORE_ADDR bp_addr,
01917d
@@ -2768,151 +2781,48 @@
01917d
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
01917d
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
01917d
   int i;
01917d
+  struct s390_arg_state arg_state, arg_prep;
01917d
+  CORE_ADDR param_area_start, new_sp;
01917d
 
01917d
-  /* If the i'th argument is passed as a reference to a copy, then
01917d
-     copy_addr[i] is the address of the copy we made.  */
01917d
-  CORE_ADDR *copy_addr = alloca (nargs * sizeof (CORE_ADDR));
01917d
+  arg_prep.copy = sp;
01917d
+  arg_prep.gr = struct_return ? 3 : 2;
01917d
+  arg_prep.fr = 0;
01917d
+  arg_prep.argp = 0;
01917d
+  arg_prep.regcache = NULL;
01917d
 
01917d
-  /* Reserve space for the reference-to-copy area.  */
01917d
-  for (i = 0; i < nargs; i++)
01917d
-    {
01917d
-      struct value *arg = args[i];
01917d
-      struct type *type = check_typedef (value_type (arg));
01917d
+  /* Initialize arg_state for "preparation mode".  */
01917d
+  arg_state = arg_prep;
01917d
 
01917d
-      if (s390_function_arg_pass_by_reference (type))
01917d
-        {
01917d
-          sp -= TYPE_LENGTH (type);
01917d
-          sp = align_down (sp, alignment_of (type));
01917d
-          copy_addr[i] = sp;
01917d
-        }
01917d
-    }
01917d
+  /* Update arg_state.copy with the start of the reference-to-copy area
01917d
+     and arg_state.argp with the size of the parameter area.  */
01917d
+  for (i = 0; i < nargs; i++)
01917d
+    s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order);
01917d
 
01917d
-  /* Reserve space for the parameter area.  As a conservative
01917d
-     simplification, we assume that everything will be passed on the
01917d
-     stack.  Since every argument larger than 8 bytes will be 
01917d
-     passed by reference, we use this simple upper bound.  */
01917d
-  sp -= nargs * 8;
01917d
-
01917d
-  /* After all that, make sure it's still aligned on an eight-byte
01917d
-     boundary.  */
01917d
-  sp = align_down (sp, 8);
01917d
+  param_area_start = align_down (arg_state.copy - arg_state.argp, 8);
01917d
 
01917d
   /* Allocate the standard frame areas: the register save area, the
01917d
-     word reserved for the compiler (which seems kind of meaningless),
01917d
-     and the back chain pointer.  */
01917d
-  sp -= 16*word_size + 32;
01917d
-
01917d
-  /* Now we have the final SP value.  Make sure we didn't underflow;
01917d
-     on 31-bit, this would result in addresses with the high bit set,
01917d
-     which causes confusion elsewhere.  Note that if we error out
01917d
-     here, stack and registers remain untouched.  */
01917d
-  if (gdbarch_addr_bits_remove (gdbarch, sp) != sp)
01917d
+     word reserved for the compiler, and the back chain pointer.  */
01917d
+  new_sp = param_area_start - (16 * word_size + 32);
01917d
+
01917d
+  /* Now we have the final stack pointer.  Make sure we didn't
01917d
+     underflow; on 31-bit, this would result in addresses with the
01917d
+     high bit set, which causes confusion elsewhere.  Note that if we
01917d
+     error out here, stack and registers remain untouched.  */
01917d
+  if (gdbarch_addr_bits_remove (gdbarch, new_sp) != new_sp)
01917d
     error (_("Stack overflow"));
01917d
 
01917d
+  /* Pass the structure return address in general register 2.  */
01917d
+  if (struct_return)
01917d
+    regcache_cooked_write_unsigned (regcache, S390_R2_REGNUM, struct_addr);
01917d
+
01917d
+  /* Initialize arg_state for "write mode".  */
01917d
+  arg_state = arg_prep;
01917d
+  arg_state.argp = param_area_start;
01917d
+  arg_state.regcache = regcache;
01917d
 
01917d
-  /* Finally, place the actual parameters, working from SP towards
01917d
-     higher addresses.  The code above is supposed to reserve enough
01917d
-     space for this.  */
01917d
-  {
01917d
-    int fr = 0;
01917d
-    int gr = 2;
01917d
-    CORE_ADDR starg = sp + 16*word_size + 32;
01917d
-
01917d
-    /* A struct is returned using general register 2.  */
01917d
-    if (struct_return)
01917d
-      {
01917d
-	regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr,
01917d
-				        struct_addr);
01917d
-	gr++;
01917d
-      }
01917d
-
01917d
-    for (i = 0; i < nargs; i++)
01917d
-      {
01917d
-        struct value *arg = args[i];
01917d
-        struct type *type = check_typedef (value_type (arg));
01917d
-        ULONGEST length = TYPE_LENGTH (type);
01917d
-
01917d
-	if (s390_function_arg_pass_by_reference (type))
01917d
-	  {
01917d
-	    /* Actually copy the argument contents to the stack slot
01917d
-	       that was reserved above.  */
01917d
-	    write_memory (copy_addr[i], value_contents (arg), length);
01917d
-
01917d
-	    if (gr <= 6)
01917d
-	      {
01917d
-		regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr,
01917d
-					        copy_addr[i]);
01917d
-		gr++;
01917d
-	      }
01917d
-	    else
01917d
-	      {
01917d
-		write_memory_unsigned_integer (starg, word_size, byte_order,
01917d
-					       copy_addr[i]);
01917d
-		starg += word_size;
01917d
-	      }
01917d
-	  }
01917d
-	else if (s390_function_arg_float (type))
01917d
-	  {
01917d
-	    /* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass arguments,
01917d
-	       the GNU/Linux for zSeries ABI uses 0, 2, 4, and 6.  */
01917d
-	    if (fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6))
01917d
-	      {
01917d
-		/* When we store a single-precision value in an FP register,
01917d
-		   it occupies the leftmost bits.  */
01917d
-		regcache_cooked_write_part (regcache, S390_F0_REGNUM + fr,
01917d
-					    0, length, value_contents (arg));
01917d
-		fr += 2;
01917d
-	      }
01917d
-	    else
01917d
-	      {
01917d
-		/* When we store a single-precision value in a stack slot,
01917d
-		   it occupies the rightmost bits.  */
01917d
-		starg = align_up (starg + length, word_size);
01917d
-                write_memory (starg - length, value_contents (arg), length);
01917d
-	      }
01917d
-	  }
01917d
-	else if (s390_function_arg_integer (type) && length <= word_size)
01917d
-	  {
01917d
-	    if (gr <= 6)
01917d
-	      {
01917d
-		/* Integer arguments are always extended to word size.  */
01917d
-		regcache_cooked_write_signed (regcache, S390_R0_REGNUM + gr,
01917d
-					      extend_simple_arg (gdbarch,
01917d
-								 arg));
01917d
-		gr++;
01917d
-	      }
01917d
-	    else
01917d
-	      {
01917d
-		/* Integer arguments are always extended to word size.  */
01917d
-		write_memory_signed_integer (starg, word_size, byte_order,
01917d
-                                             extend_simple_arg (gdbarch, arg));
01917d
-                starg += word_size;
01917d
-	      }
01917d
-	  }
01917d
-	else if (s390_function_arg_integer (type) && length == 2*word_size)
01917d
-	  {
01917d
-	    if (gr <= 5)
01917d
-	      {
01917d
-		regcache_cooked_write (regcache, S390_R0_REGNUM + gr,
01917d
-				       value_contents (arg));
01917d
-		regcache_cooked_write (regcache, S390_R0_REGNUM + gr + 1,
01917d
-				       value_contents (arg) + word_size);
01917d
-		gr += 2;
01917d
-	      }
01917d
-	    else
01917d
-	      {
01917d
-		/* If we skipped r6 because we couldn't fit a DOUBLE_ARG
01917d
-		   in it, then don't go back and use it again later.  */
01917d
-		gr = 7;
01917d
-
01917d
-		write_memory (starg, value_contents (arg), length);
01917d
-		starg += length;
01917d
-	      }
01917d
-	  }
01917d
-	else
01917d
-	  internal_error (__FILE__, __LINE__, _("unknown argument type"));
01917d
-      }
01917d
-  }
01917d
+  /* Write all parameters.  */
01917d
+  for (i = 0; i < nargs; i++)
01917d
+    s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order);
01917d
 
01917d
   /* Store return PSWA.  In 31-bit mode, keep addressing mode bit.  */
01917d
   if (word_size == 4)
01917d
@@ -2924,11 +2834,11 @@
01917d
   regcache_cooked_write_unsigned (regcache, S390_RETADDR_REGNUM, bp_addr);
01917d
 
01917d
   /* Store updated stack pointer.  */
01917d
-  regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, sp);
01917d
+  regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, new_sp);
01917d
 
01917d
   /* We need to return the 'stack part' of the frame ID,
01917d
      which is actually the top of the register save area.  */
01917d
-  return sp + 16*word_size + 32;
01917d
+  return param_area_start;
01917d
 }
01917d
 
01917d
 /* Assuming THIS_FRAME is a dummy, return the frame ID of that