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.
295 lines
8.9 KiB
295 lines
8.9 KiB
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))
|
|
|