X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fppc-sysv-tdep.c;h=254c8c2d9da7a1f9fcbdabad72334f2f8d7c9417;hb=2117c711ae07700adb57ea5b5ca61e4c32d7e3d2;hp=8e460e5f675363d9fa9c67cd1d4cf28edb4b6af7;hpb=0ff3e01fdc67a3842ee54224cf197e9a55f0a750;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c index 8e460e5f67..254c8c2d9d 100644 --- a/gdb/ppc-sysv-tdep.c +++ b/gdb/ppc-sysv-tdep.c @@ -1101,6 +1101,160 @@ convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr) 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 { @@ -1352,8 +1506,9 @@ ppc64_sysv_abi_push_param (struct gdbarch *gdbarch, word = unpack_long (type, val); /* Convert any function code addresses into descriptors. */ - if (TYPE_CODE (type) == TYPE_CODE_PTR - || TYPE_CODE (type) == TYPE_CODE_REF) + if (tdep->elf_abi == POWERPC_ELF_V1 + && (TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF)) { struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type)); @@ -1388,6 +1543,29 @@ ppc64_sysv_abi_push_param (struct gdbarch *gdbarch, 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); + } + } } } @@ -1473,9 +1651,13 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, argpos.regcache = regcache; argpos.refparam = align_down (sp - refparam_size, 16); argpos.gparam = align_down (argpos.refparam - gparam_size, 16); - /* Add in space for the TOC, link editor double word, - compiler double word, LR save area, CR save area. */ - sp = align_down (argpos.gparam - 48, 16); + /* Add in space for the TOC, link editor double word (v1 only), + compiler double word (v1 only), LR save area, CR save area, + and backchain. */ + if (tdep->elf_abi == POWERPC_ELF_V1) + sp = align_down (argpos.gparam - 48, 16); + else + sp = align_down (argpos.gparam - 32, 16); } /* If the function is returning a `struct', then there is an @@ -1553,24 +1735,32 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, breakpoint. */ regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr); - /* Use the func_addr to find the descriptor, and use that to find - the TOC. If we're calling via a function pointer, the pointer - itself identifies the descriptor. */ - { - struct type *ftype = check_typedef (value_type (function)); - CORE_ADDR desc_addr = value_as_address (function); - - if (TYPE_CODE (ftype) == TYPE_CODE_PTR - || convert_code_addr_to_desc_addr (func_addr, &desc_addr)) - { - /* The TOC is the second double word in the descriptor. */ - CORE_ADDR toc = - read_memory_unsigned_integer (desc_addr + tdep->wordsize, - tdep->wordsize, byte_order); - regcache_cooked_write_unsigned (regcache, - tdep->ppc_gp0_regnum + 2, toc); - } - } + /* In the ELFv1 ABI, use the func_addr to find the descriptor, and use + that to find the TOC. If we're calling via a function pointer, + the pointer itself identifies the descriptor. */ + if (tdep->elf_abi == POWERPC_ELF_V1) + { + struct type *ftype = check_typedef (value_type (function)); + CORE_ADDR desc_addr = value_as_address (function); + + if (TYPE_CODE (ftype) == TYPE_CODE_PTR + || convert_code_addr_to_desc_addr (func_addr, &desc_addr)) + { + /* The TOC is the second double word in the descriptor. */ + CORE_ADDR toc = + read_memory_unsigned_integer (desc_addr + tdep->wordsize, + tdep->wordsize, byte_order); + + regcache_cooked_write_unsigned (regcache, + tdep->ppc_gp0_regnum + 2, toc); + } + } + + /* In the ELFv2 ABI, we need to pass the target address in r12 since + we may be calling a global entry point. */ + if (tdep->elf_abi == POWERPC_ELF_V2) + regcache_cooked_write_unsigned (regcache, + tdep->ppc_gp0_regnum + 12, func_addr); return sp; } @@ -1821,6 +2011,72 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function, 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))