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