/* Target-dependent code for PowerPC systems using the SVR4 ABI
for GDB, the GNU debugger.
- Copyright (C) 2000-2014 Free Software Foundation, Inc.
+ Copyright (C) 2000-2015 Free Software Foundation, Inc.
This file is part of GDB.
#include "inferior.h"
#include "regcache.h"
#include "value.h"
-#include <string.h>
-#include "gdb_assert.h"
#include "ppc-tdep.h"
#include "target.h"
#include "objfiles.h"
}
/* Handle the return-value conventions for Decimal Floating Point values. */
-static int
+static enum return_value_convention
get_decimal_float_return_value (struct gdbarch *gdbarch, struct type *valtype,
struct regcache *regcache, gdb_byte *readbuf,
const gdb_byte *writebuf)
{
struct obj_section *dot_fn_section;
struct bound_minimal_symbol dot_fn;
- struct minimal_symbol *fn;
+ struct bound_minimal_symbol fn;
/* Find the minimal symbol that corresponds to CODE_ADDR (should
have a name of the form ".FN"). */
dot_fn = lookup_minimal_symbol_by_pc (code_addr);
- if (dot_fn.minsym == NULL || SYMBOL_LINKAGE_NAME (dot_fn.minsym)[0] != '.')
+ if (dot_fn.minsym == NULL || MSYMBOL_LINKAGE_NAME (dot_fn.minsym)[0] != '.')
return 0;
/* Get the section that contains CODE_ADDR. Need this for the
"objfile" that it contains. */
address. Only look for the minimal symbol in ".FN"'s object file
- avoids problems when two object files (i.e., shared libraries)
contain a minimal symbol with the same name. */
- fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn.minsym) + 1, NULL,
+ fn = lookup_minimal_symbol (MSYMBOL_LINKAGE_NAME (dot_fn.minsym) + 1, NULL,
dot_fn_section->objfile);
- if (fn == NULL)
+ if (fn.minsym == NULL)
return 0;
/* Found a descriptor. */
- (*desc_addr) = SYMBOL_VALUE_ADDRESS (fn);
+ (*desc_addr) = BMSYMBOL_VALUE_ADDRESS (fn);
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
{
doubleword are right-aligned and those larger are left-aligned.
GCC versions before 3.4 implemented this incorrectly; see
<http://gcc.gnu.org/gcc-3.4/powerpc-abi.html>. */
- if (len < tdep->wordsize)
+ if (len < tdep->wordsize
+ && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
offset = tdep->wordsize - len;
if (argpos->regcache)
if (argpos->regcache && argpos->freg <= 13)
{
int regnum = tdep->ppc_fp0_regnum + argpos->freg;
- int offset = 8 - TYPE_LENGTH (type);
+ int offset = 0;
+
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ offset = 8 - TYPE_LENGTH (type);
regcache_cooked_write_part (argpos->regcache, regnum,
offset, TYPE_LENGTH (type), val);
if (argpos->regcache && argpos->freg <= 12)
{
int regnum = tdep->ppc_fp0_regnum + argpos->freg;
+ int lopart = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 : 0;
+ int hipart = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8;
- regcache_cooked_write (argpos->regcache, regnum, val);
- regcache_cooked_write (argpos->regcache, regnum + 1, val + 8);
+ regcache_cooked_write (argpos->regcache, regnum, val + hipart);
+ regcache_cooked_write (argpos->regcache, regnum + 1, val + lopart);
}
argpos->freg += 2;
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));
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);
+ }
+ }
}
}
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
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;
}
&& TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT)
{
int regnum = tdep->ppc_fp0_regnum + 1 + index;
- int offset = 8 - TYPE_LENGTH (valtype);
+ int offset = 0;
+
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ offset = 8 - TYPE_LENGTH (valtype);
if (writebuf != NULL)
regcache_cooked_write_part (regcache, regnum,
&& TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT)
{
int regnum = tdep->ppc_fp0_regnum + 2 + 2 * index;
+ int lopart = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 : 0;
+ int hipart = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8;
if (writebuf != NULL)
{
- regcache_cooked_write (regcache, regnum, writebuf);
- regcache_cooked_write (regcache, regnum + 1, writebuf + 8);
+ regcache_cooked_write (regcache, regnum, writebuf + hipart);
+ regcache_cooked_write (regcache, regnum + 1, writebuf + lopart);
}
if (readbuf != NULL)
{
- regcache_cooked_read (regcache, regnum, readbuf);
- regcache_cooked_read (regcache, regnum + 1, readbuf + 8);
+ regcache_cooked_read (regcache, regnum, readbuf + hipart);
+ regcache_cooked_read (regcache, regnum + 1, readbuf + lopart);
}
return 1;
}
/* AltiVec vectors are returned in VRs starting at v2. */
- if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY && TYPE_VECTOR (valtype)
+ if (TYPE_LENGTH (valtype) == 16
+ && TYPE_CODE (valtype) == TYPE_CODE_ARRAY && TYPE_VECTOR (valtype)
&& tdep->vector_abi == POWERPC_VEC_ALTIVEC)
{
int regnum = tdep->ppc_vr0_regnum + 2 + index;
return 1;
}
+ /* Short vectors are returned in GPRs starting at r3. */
+ if (TYPE_LENGTH (valtype) <= 8
+ && TYPE_CODE (valtype) == TYPE_CODE_ARRAY && TYPE_VECTOR (valtype))
+ {
+ int regnum = tdep->ppc_gp0_regnum + 3 + index;
+ int offset = 0;
+
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ offset = 8 - TYPE_LENGTH (valtype);
+
+ if (writebuf != NULL)
+ regcache_cooked_write_part (regcache, regnum,
+ offset, TYPE_LENGTH (valtype), writebuf);
+ if (readbuf != NULL)
+ regcache_cooked_read_part (regcache, regnum,
+ offset, TYPE_LENGTH (valtype), readbuf);
+ return 1;
+ }
+
return 0;
}
/* Small character arrays are returned, right justified, in r3. */
if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+ && !TYPE_VECTOR (valtype)
&& TYPE_LENGTH (valtype) <= 8
&& TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
&& TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
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)
+ && (TYPE_CODE (eltype) == TYPE_CODE_FLT
+ || TYPE_CODE (eltype) == TYPE_CODE_DECFLOAT
+ || (TYPE_CODE (eltype) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (eltype)
+ && tdep->vector_abi == POWERPC_VEC_ALTIVEC
+ && TYPE_LENGTH (eltype) == 16)))
+ {
+ 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))