summaryrefslogtreecommitdiff
path: root/gdb/s390-tdep.c
diff options
context:
space:
mode:
authorJim Blandy <jimb@codesourcery.com>2001-11-16 21:40:36 +0000
committerJim Blandy <jimb@codesourcery.com>2001-11-16 21:40:36 +0000
commitb840deb89cb15d10167f63a505520d29b8519268 (patch)
treee2886155772bd16e3eb9792c3219eede1f0ccfec /gdb/s390-tdep.c
parent439da7872cebd8850d4191a63d3caf2944c87e1c (diff)
downloadgdb-b840deb89cb15d10167f63a505520d29b8519268.tar.gz
* s390-tdep.c: Tweak argument-passing to match GCC bugs.
(is_float_singleton, is_struct_like, is_float_like): New functions, that isolate the weirdness. (is_double_or_float, is_simple_arg, pass_by_copy_ref, is_double_arg): Use is_struct_like and is_float_like, rather than testing the type codes ourselves. (s390_push_arguments): When passing args on the stack, align each on to a four-byte boundary, regardless of what the type itself needs.
Diffstat (limited to 'gdb/s390-tdep.c')
-rw-r--r--gdb/s390-tdep.c87
1 files changed, 73 insertions, 14 deletions
diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index d79654d878f..20c2f647d09 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -1221,6 +1221,68 @@ is_pointer_like (struct type *type)
}
+/* 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:
+
+ struct { float x };
+ struct { struct { float x; } x; };
+ struct { struct { struct { float x; } x; } x; };
+
+ ... and so on.
+
+ WHY THE HECK DO WE CARE ABOUT THIS??? Well, it turns out that GCC
+ passes all float singletons and double singletons as if they were
+ simply floats or doubles. This is *not* what the ABI says it
+ should do. */
+static int
+is_float_singleton (struct type *type)
+{
+ return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) == 1
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT
+ || is_float_singleton (TYPE_FIELD_TYPE (type, 0))));
+}
+
+
+/* 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)
+{
+ enum type_code code = TYPE_CODE (type);
+
+ return (code == TYPE_CODE_UNION
+ || (code == TYPE_CODE_STRUCT && ! is_float_singleton (type)));
+}
+
+
+/* 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.
+
+ 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 exclude
+ those types here. *shrug* */
+static int
+is_float_like (struct type *type)
+{
+ return (TYPE_CODE (type) == TYPE_CODE_FLT
+ || is_float_singleton (type));
+}
+
+
/* Return non-zero if TYPE is considered a `DOUBLE_OR_FLOAT', as
defined by the parameter passing conventions described in the
"Linux for S/390 ELF Application Binary Interface Supplement".
@@ -1228,7 +1290,7 @@ is_pointer_like (struct type *type)
static int
is_double_or_float (struct type *type)
{
- return (TYPE_CODE (type) == TYPE_CODE_FLT
+ return (is_float_like (type)
&& (TYPE_LENGTH (type) == 4
|| TYPE_LENGTH (type) == 8));
}
@@ -1240,17 +1302,14 @@ is_double_or_float (struct type *type)
static int
is_simple_arg (struct type *type)
{
- enum type_code code = TYPE_CODE (type);
unsigned length = TYPE_LENGTH (type);
/* This is almost a direct translation of the ABI's language, except
that we have to exclude 8-byte structs; those are DOUBLE_ARGs. */
return ((is_integer_like (type) && length <= 4)
|| is_pointer_like (type)
- || ((code == TYPE_CODE_STRUCT
- || code == TYPE_CODE_UNION)
- && length != 8)
- || (code == TYPE_CODE_FLT && length == 16));
+ || (is_struct_like (type) && length != 8)
+ || (is_float_like (type) && length == 16));
}
@@ -1260,12 +1319,10 @@ is_simple_arg (struct type *type)
static int
pass_by_copy_ref (struct type *type)
{
- enum type_code code = TYPE_CODE (type);
unsigned length = TYPE_LENGTH (type);
- return (((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
- && length != 1 && length != 2 && length != 4)
- || (code == TYPE_CODE_FLT && length == 16));
+ return ((is_struct_like (type) && length != 1 && length != 2 && length != 4)
+ || (is_float_like (type) && length == 16));
}
@@ -1294,12 +1351,10 @@ extend_simple_arg (struct value *arg)
static int
is_double_arg (struct type *type)
{
- enum type_code code = TYPE_CODE (type);
unsigned length = TYPE_LENGTH (type);
return ((is_integer_like (type)
- || code == TYPE_CODE_STRUCT
- || code == TYPE_CODE_UNION)
+ || is_struct_like (type))
&& length == 8);
}
@@ -1512,7 +1567,11 @@ s390_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
}
else
{
- starg = round_up (starg, alignment_of (type));
+ /* You'd think we should say:
+ starg = round_up (starg, alignment_of (type));
+ Unfortunately, GCC seems to simply align the stack on
+ a four-byte boundary, even when passing doubles. */
+ starg = round_up (starg, 4);
write_memory (starg, VALUE_CONTENTS (arg), length);
starg += length;
}