You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
8.9 KiB
296 lines
8.9 KiB
6 years ago
|
commit cc0e89c519912e0e4e75a2fc0d836f715cdc6806
|
||
|
Author: Ulrich Weigand <ulrich.weigand@de.ibm.com>
|
||
|
Date: Tue Feb 4 18:42:35 2014 +0100
|
||
|
|
||
|
PowerPC64 ELFv2 ABI: structure passing / return
|
||
|
|
||
|
Another significant difference in the ELFv2 ABI is that "homogeneous"
|
||
|
floating-point and vector aggregates, i.e. aggregates the consist
|
||
|
(recursively) only of members of the same floating-point or vector type,
|
||
|
are passed in a series of floating-point / vector registers, as if they
|
||
|
were seperate parameters. (This is similar to the ARM ABI.) This
|
||
|
applies to both calls and returns.
|
||
|
|
||
|
In addition when returning any aggregate of up to 16 bytes, ELFv2 now
|
||
|
used general-purpose registers.
|
||
|
|
||
|
This patch adds support for these aspects of the ABI, which is relatively
|
||
|
straightforward after the refactoring patch to ppc-sysv-tdep.c.
|
||
|
|
||
|
gdb/ChangeLog:
|
||
|
|
||
|
* ppc-sysv-tdep.c (ppc64_aggregate_candidate): New routine.
|
||
|
(ppc64_elfv2_abi_homogeneous_aggregate): Likewise.
|
||
|
(ppc64_sysv_abi_push_param): Handle ELFv2 homogeneous structs.
|
||
|
(ppc64_sysv_abi_return_value): Likewise. Also, handle small
|
||
|
structures returned in GPRs.
|
||
|
|
||
|
Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c
|
||
|
===================================================================
|
||
|
--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c
|
||
|
+++ gdb-7.6.1/gdb/ppc-sysv-tdep.c
|
||
|
@@ -1100,6 +1100,160 @@ convert_code_addr_to_desc_addr (CORE_ADD
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
+/* Walk down the type tree of TYPE counting consecutive base elements.
|
||
|
+ If *FIELD_TYPE is NULL, then set it to the first valid floating point
|
||
|
+ or vector type. If a non-floating point or vector type is found, or
|
||
|
+ if a floating point or vector type that doesn't match a non-NULL
|
||
|
+ *FIELD_TYPE is found, then return -1, otherwise return the count in the
|
||
|
+ sub-tree. */
|
||
|
+
|
||
|
+static LONGEST
|
||
|
+ppc64_aggregate_candidate (struct type *type,
|
||
|
+ struct type **field_type)
|
||
|
+{
|
||
|
+ type = check_typedef (type);
|
||
|
+
|
||
|
+ switch (TYPE_CODE (type))
|
||
|
+ {
|
||
|
+ case TYPE_CODE_FLT:
|
||
|
+ case TYPE_CODE_DECFLOAT:
|
||
|
+ if (!*field_type)
|
||
|
+ *field_type = type;
|
||
|
+ if (TYPE_CODE (*field_type) == TYPE_CODE (type)
|
||
|
+ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type))
|
||
|
+ return 1;
|
||
|
+ break;
|
||
|
+
|
||
|
+ case TYPE_CODE_COMPLEX:
|
||
|
+ type = TYPE_TARGET_TYPE (type);
|
||
|
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
|
||
|
+ || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
|
||
|
+ {
|
||
|
+ if (!*field_type)
|
||
|
+ *field_type = type;
|
||
|
+ if (TYPE_CODE (*field_type) == TYPE_CODE (type)
|
||
|
+ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type))
|
||
|
+ return 2;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+
|
||
|
+ case TYPE_CODE_ARRAY:
|
||
|
+ if (TYPE_VECTOR (type))
|
||
|
+ {
|
||
|
+ if (!*field_type)
|
||
|
+ *field_type = type;
|
||
|
+ if (TYPE_CODE (*field_type) == TYPE_CODE (type)
|
||
|
+ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type))
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ LONGEST count, low_bound, high_bound;
|
||
|
+
|
||
|
+ count = ppc64_aggregate_candidate
|
||
|
+ (TYPE_TARGET_TYPE (type), field_type);
|
||
|
+ if (count == -1)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ if (!get_array_bounds (type, &low_bound, &high_bound))
|
||
|
+ return -1;
|
||
|
+ count *= high_bound - low_bound;
|
||
|
+
|
||
|
+ /* There must be no padding. */
|
||
|
+ if (count == 0)
|
||
|
+ return TYPE_LENGTH (type) == 0 ? 0 : -1;
|
||
|
+ else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type))
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ return count;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+
|
||
|
+ case TYPE_CODE_STRUCT:
|
||
|
+ case TYPE_CODE_UNION:
|
||
|
+ {
|
||
|
+ LONGEST count = 0;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
|
||
|
+ {
|
||
|
+ LONGEST sub_count;
|
||
|
+
|
||
|
+ if (field_is_static (&TYPE_FIELD (type, i)))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ sub_count = ppc64_aggregate_candidate
|
||
|
+ (TYPE_FIELD_TYPE (type, i), field_type);
|
||
|
+ if (sub_count == -1)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
|
||
|
+ count += sub_count;
|
||
|
+ else
|
||
|
+ count = max (count, sub_count);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* There must be no padding. */
|
||
|
+ if (count == 0)
|
||
|
+ return TYPE_LENGTH (type) == 0 ? 0 : -1;
|
||
|
+ else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type))
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ return count;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return -1;
|
||
|
+}
|
||
|
+
|
||
|
+/* If an argument of type TYPE is a homogeneous float or vector aggregate
|
||
|
+ that shall be passed in FP/vector registers according to the ELFv2 ABI,
|
||
|
+ return the homogeneous element type in *ELT_TYPE and the number of
|
||
|
+ elements in *N_ELTS, and return non-zero. Otherwise, return zero. */
|
||
|
+
|
||
|
+static int
|
||
|
+ppc64_elfv2_abi_homogeneous_aggregate (struct type *type,
|
||
|
+ struct type **elt_type, int *n_elts)
|
||
|
+{
|
||
|
+ /* Complex types at the top level are treated separately. However,
|
||
|
+ complex types can be elements of homogeneous aggregates. */
|
||
|
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
|
||
|
+ || TYPE_CODE (type) == TYPE_CODE_UNION
|
||
|
+ || (TYPE_CODE (type) == TYPE_CODE_ARRAY && !TYPE_VECTOR (type)))
|
||
|
+ {
|
||
|
+ struct type *field_type = NULL;
|
||
|
+ LONGEST field_count = ppc64_aggregate_candidate (type, &field_type);
|
||
|
+
|
||
|
+ if (field_count > 0)
|
||
|
+ {
|
||
|
+ int n_regs = ((TYPE_CODE (field_type) == TYPE_CODE_FLT
|
||
|
+ || TYPE_CODE (field_type) == TYPE_CODE_DECFLOAT)?
|
||
|
+ (TYPE_LENGTH (field_type) + 7) >> 3 : 1);
|
||
|
+
|
||
|
+ /* The ELFv2 ABI allows homogeneous aggregates to occupy
|
||
|
+ up to 8 registers. */
|
||
|
+ if (field_count * n_regs <= 8)
|
||
|
+ {
|
||
|
+ if (elt_type)
|
||
|
+ *elt_type = field_type;
|
||
|
+ if (n_elts)
|
||
|
+ *n_elts = (int) field_count;
|
||
|
+ /* Note that field_count is LONGEST since it may hold the size
|
||
|
+ of an array, while *n_elts is int since its value is bounded
|
||
|
+ by the number of registers used for argument passing. The
|
||
|
+ cast cannot overflow due to the bounds checking above. */
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
/* Structure holding the next argument position. */
|
||
|
struct ppc64_sysv_argpos
|
||
|
{
|
||
|
@@ -1388,6 +1542,29 @@ ppc64_sysv_abi_push_param (struct gdbarc
|
||
|
if (TYPE_CODE (type) == TYPE_CODE_FLT)
|
||
|
ppc64_sysv_abi_push_freg (gdbarch, type, val, argpos);
|
||
|
}
|
||
|
+
|
||
|
+ /* In the ELFv2 ABI, homogeneous floating-point or vector
|
||
|
+ aggregates are passed in a series of registers. */
|
||
|
+ if (tdep->elf_abi == POWERPC_ELF_V2)
|
||
|
+ {
|
||
|
+ struct type *eltype;
|
||
|
+ int i, nelt;
|
||
|
+
|
||
|
+ if (ppc64_elfv2_abi_homogeneous_aggregate (type, &eltype, &nelt))
|
||
|
+ for (i = 0; i < nelt; i++)
|
||
|
+ {
|
||
|
+ const gdb_byte *elval = val + i * TYPE_LENGTH (eltype);
|
||
|
+
|
||
|
+ if (TYPE_CODE (eltype) == TYPE_CODE_FLT
|
||
|
+ || TYPE_CODE (eltype) == TYPE_CODE_DECFLOAT)
|
||
|
+ ppc64_sysv_abi_push_freg (gdbarch, eltype, elval, argpos);
|
||
|
+ else if (TYPE_CODE (eltype) == TYPE_CODE_ARRAY
|
||
|
+ && TYPE_VECTOR (eltype)
|
||
|
+ && tdep->vector_abi == POWERPC_VEC_ALTIVEC
|
||
|
+ && TYPE_LENGTH (eltype) == 16)
|
||
|
+ ppc64_sysv_abi_push_vreg (gdbarch, elval, argpos);
|
||
|
+ }
|
||
|
+ }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -1833,6 +2010,72 @@ ppc64_sysv_abi_return_value (struct gdba
|
||
|
return RETURN_VALUE_REGISTER_CONVENTION;
|
||
|
}
|
||
|
|
||
|
+ /* In the ELFv2 ABI, homogeneous floating-point or vector
|
||
|
+ aggregates are returned in registers. */
|
||
|
+ if (tdep->elf_abi == POWERPC_ELF_V2
|
||
|
+ && ppc64_elfv2_abi_homogeneous_aggregate (valtype, &eltype, &nelt))
|
||
|
+ {
|
||
|
+ for (i = 0; i < nelt; i++)
|
||
|
+ {
|
||
|
+ ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
|
||
|
+ readbuf, writebuf, i);
|
||
|
+ gdb_assert (ok);
|
||
|
+
|
||
|
+ if (readbuf)
|
||
|
+ readbuf += TYPE_LENGTH (eltype);
|
||
|
+ if (writebuf)
|
||
|
+ writebuf += TYPE_LENGTH (eltype);
|
||
|
+ }
|
||
|
+
|
||
|
+ return RETURN_VALUE_REGISTER_CONVENTION;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* In the ELFv2 ABI, aggregate types of up to 16 bytes are
|
||
|
+ returned in registers r3:r4. */
|
||
|
+ if (tdep->elf_abi == POWERPC_ELF_V2
|
||
|
+ && TYPE_LENGTH (valtype) <= 16
|
||
|
+ && (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
|
||
|
+ || TYPE_CODE (valtype) == TYPE_CODE_UNION
|
||
|
+ || (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
|
||
|
+ && !TYPE_VECTOR (valtype))))
|
||
|
+ {
|
||
|
+ int n_regs = ((TYPE_LENGTH (valtype) + tdep->wordsize - 1)
|
||
|
+ / tdep->wordsize);
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 0; i < n_regs; i++)
|
||
|
+ {
|
||
|
+ gdb_byte regval[MAX_REGISTER_SIZE];
|
||
|
+ int regnum = tdep->ppc_gp0_regnum + 3 + i;
|
||
|
+ int offset = i * tdep->wordsize;
|
||
|
+ int len = TYPE_LENGTH (valtype) - offset;
|
||
|
+
|
||
|
+ if (len > tdep->wordsize)
|
||
|
+ len = tdep->wordsize;
|
||
|
+
|
||
|
+ if (writebuf != NULL)
|
||
|
+ {
|
||
|
+ memset (regval, 0, sizeof regval);
|
||
|
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
|
||
|
+ && offset == 0)
|
||
|
+ memcpy (regval + tdep->wordsize - len, writebuf, len);
|
||
|
+ else
|
||
|
+ memcpy (regval, writebuf + offset, len);
|
||
|
+ regcache_cooked_write (regcache, regnum, regval);
|
||
|
+ }
|
||
|
+ if (readbuf != NULL)
|
||
|
+ {
|
||
|
+ regcache_cooked_read (regcache, regnum, regval);
|
||
|
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
|
||
|
+ && offset == 0)
|
||
|
+ memcpy (readbuf, regval + tdep->wordsize - len, len);
|
||
|
+ else
|
||
|
+ memcpy (readbuf + offset, regval, len);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return RETURN_VALUE_REGISTER_CONVENTION;
|
||
|
+ }
|
||
|
+
|
||
|
/* Handle plain base types. */
|
||
|
if (ppc64_sysv_abi_return_value_base (gdbarch, valtype, regcache,
|
||
|
readbuf, writebuf, 0))
|