/* 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-2020 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"
#include "infcall.h"
#include "dwarf2.h"
+#include "target-float.h"
+#include <algorithm>
/* Check whether FTPYE is a (pointer to) function type that should use
are passed in user stack.
If the function is returning a structure, then the return address is passed
- in r3, then the first 7 words of the parametes can be passed in registers,
+ in r3, then the first 7 words of the parameters can be passed in registers,
starting from r4. */
CORE_ADDR
ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
(which will be passed in r3) is used for struct return
address. In that case we should advance one word and start
from r4 register to copy parameters. */
- if (struct_return)
+ if (return_method == return_method_struct)
{
if (write_pass)
regcache_cooked_write_signed (regcache,
{
/* Always store the floating point value using
the register's floating-point format. */
- gdb_byte regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[PPC_MAX_REGISTER_SIZE];
struct type *regtype
= register_type (gdbarch, tdep->ppc_fp0_regnum + freg);
- convert_typed_floating (val, type, regval, regtype);
- regcache_cooked_write (regcache,
- tdep->ppc_fp0_regnum + freg,
- regval);
+ target_float_convert (val, type, regval, regtype);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + freg,
+ regval);
}
freg++;
}
{
if (write_pass)
{
- regcache_cooked_write (regcache,
- tdep->ppc_fp0_regnum + freg,
- val);
- regcache_cooked_write (regcache,
- tdep->ppc_fp0_regnum + freg + 1,
- val + 8);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + freg, val);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + freg + 1,
+ val + 8);
}
freg += 2;
}
greg++;
if (write_pass)
{
- regcache_cooked_write (regcache,
- tdep->ppc_gp0_regnum + greg + 0,
- val + 0);
- regcache_cooked_write (regcache,
- tdep->ppc_gp0_regnum + greg + 1,
- val + 4);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + greg + 0,
+ val + 0);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + greg + 1,
+ val + 4);
}
greg += 2;
}
{
if (write_pass)
{
- regcache_cooked_write (regcache,
- tdep->ppc_gp0_regnum + greg + 0,
- val + 0);
- regcache_cooked_write (regcache,
- tdep->ppc_gp0_regnum + greg + 1,
- val + 4);
- regcache_cooked_write (regcache,
- tdep->ppc_gp0_regnum + greg + 2,
- val + 8);
- regcache_cooked_write (regcache,
- tdep->ppc_gp0_regnum + greg + 3,
- val + 12);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + greg + 0,
+ val + 0);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + greg + 1,
+ val + 4);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + greg + 2,
+ val + 8);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + greg + 3,
+ val + 12);
}
greg += 4;
}
{
if (write_pass)
{
- gdb_byte regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[PPC_MAX_REGISTER_SIZE];
const gdb_byte *p;
/* 32-bit decimal floats are right aligned in the
else
p = val;
- regcache_cooked_write (regcache,
- tdep->ppc_fp0_regnum + freg, p);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + freg, p);
}
freg++;
if (write_pass)
{
- regcache_cooked_write (regcache,
- tdep->ppc_fp0_regnum + freg, val);
- regcache_cooked_write (regcache,
- tdep->ppc_fp0_regnum + freg + 1, val + 8);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + freg, val);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + freg + 1,
+ val + 8);
}
}
else
if (write_pass)
{
int regnum = tdep->ppc_fp0_regnum + freg;
- gdb_byte regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[PPC_MAX_REGISTER_SIZE];
struct type *regtype
= register_type (gdbarch, regnum);
- convert_typed_floating (elval, eltype,
- regval, regtype);
- regcache_cooked_write (regcache, regnum, regval);
+ target_float_convert (elval, eltype,
+ regval, regtype);
+ regcache->cooked_write (regnum, regval);
}
freg++;
}
if (write_pass)
{
int regnum = tdep->ppc_gp0_regnum + greg;
- regcache_cooked_write (regcache,
- regnum + 0, elval + 0);
- regcache_cooked_write (regcache,
- regnum + 1, elval + 4);
+ regcache->cooked_write (regnum + 0, elval + 0);
+ regcache->cooked_write (regnum + 1, elval + 4);
}
greg += 2;
}
}
else
{
- gdb_byte word[MAX_REGISTER_SIZE];
+ gdb_byte word[PPC_MAX_REGISTER_SIZE];
store_unsigned_integer (word, tdep->wordsize, byte_order,
unpack_long (eltype, elval));
if (greg <= 10)
{
if (write_pass)
- regcache_cooked_write (regcache,
- tdep->ppc_gp0_regnum + greg,
- word);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + greg,
+ word);
greg++;
}
else
if (vreg <= 13)
{
if (write_pass)
- regcache_cooked_write (regcache,
- tdep->ppc_vr0_regnum + vreg,
- elval);
+ regcache->cooked_write (tdep->ppc_vr0_regnum + vreg,
+ elval);
vreg++;
}
else
if (vreg <= 13)
{
if (write_pass)
- regcache_cooked_write (regcache,
- tdep->ppc_vr0_regnum + vreg, val);
+ regcache->cooked_write (tdep->ppc_vr0_regnum + vreg, val);
vreg++;
}
else
if (greg <= 10)
{
if (write_pass)
- regcache_cooked_write (regcache,
- tdep->ppc_ev0_regnum + greg, val);
+ regcache->cooked_write (tdep->ppc_ev0_regnum + greg, val);
greg++;
}
else
{
/* Reduce the parameter down to something that fits in a
"word". */
- gdb_byte word[MAX_REGISTER_SIZE];
- memset (word, 0, MAX_REGISTER_SIZE);
+ gdb_byte word[PPC_MAX_REGISTER_SIZE];
+ memset (word, 0, PPC_MAX_REGISTER_SIZE);
if (len > tdep->wordsize
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION)
if (greg <= 10)
{
if (write_pass)
- regcache_cooked_write (regcache,
- tdep->ppc_gp0_regnum + greg, word);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + greg, word);
greg++;
}
else
}
/* 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)
{
if (writebuf != NULL)
{
- gdb_byte regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[PPC_MAX_REGISTER_SIZE];
const gdb_byte *p;
/* 32-bit decimal float is right aligned in the doubleword. */
else
p = writebuf;
- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, p);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + 1, p);
}
if (readbuf != NULL)
{
- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, readbuf);
+ regcache->cooked_read (tdep->ppc_fp0_regnum + 1, readbuf);
/* Left align 32-bit decimal float. */
if (TYPE_LENGTH (valtype) == 4)
for (i = 0; i < 2; i++)
{
if (writebuf != NULL)
- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 2 + i,
- writebuf + i * 8);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + 2 + i,
+ writebuf + i * 8);
if (readbuf != NULL)
- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 2 + i,
- readbuf + i * 8);
+ regcache->cooked_read (tdep->ppc_fp0_regnum + 2 + i,
+ readbuf + i * 8);
}
}
}
{
/* Floats and doubles stored in "f1". Convert the value to
the required type. */
- gdb_byte regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[PPC_MAX_REGISTER_SIZE];
struct type *regtype = register_type (gdbarch,
tdep->ppc_fp0_regnum + 1);
- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval);
- convert_typed_floating (regval, regtype, readbuf, type);
+ regcache->cooked_read (tdep->ppc_fp0_regnum + 1, regval);
+ target_float_convert (regval, regtype, readbuf, type);
}
if (writebuf)
{
/* Floats and doubles stored in "f1". Convert the value to
the register's "double" type. */
- gdb_byte regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[PPC_MAX_REGISTER_SIZE];
struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum);
- convert_typed_floating (writebuf, type, regval, regtype);
- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, regval);
+ target_float_convert (writebuf, type, regval, regtype);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + 1, regval);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
/* IBM long double stored in f1 and f2. */
if (readbuf)
{
- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, readbuf);
- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 2,
- readbuf + 8);
+ regcache->cooked_read (tdep->ppc_fp0_regnum + 1, readbuf);
+ regcache->cooked_read (tdep->ppc_fp0_regnum + 2, readbuf + 8);
}
if (writebuf)
{
- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, writebuf);
- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 2,
- writebuf + 8);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + 1, writebuf);
+ regcache->cooked_write (tdep->ppc_fp0_regnum + 2, writebuf + 8);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
r5, r6. */
if (readbuf)
{
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
- readbuf + 4);
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 5,
- readbuf + 8);
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 6,
- readbuf + 12);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 3, readbuf);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 4, readbuf + 4);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 5, readbuf + 8);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 6, readbuf + 12);
}
if (writebuf)
{
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
- writebuf + 4);
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 5,
- writebuf + 8);
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 6,
- writebuf + 12);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 3, writebuf);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 4, writebuf + 4);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 5, writebuf + 8);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 6, writebuf + 12);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
{
/* A long long, double or _Decimal64 stored in the 32 bit
r3/r4. */
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
- readbuf + 0);
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
- readbuf + 4);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 3, readbuf + 0);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 4, readbuf + 4);
}
if (writebuf)
{
/* A long long, double or _Decimal64 stored in the 32 bit
r3/r4. */
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
- writebuf + 0);
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
- writebuf + 4);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 3, writebuf + 0);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 4, writebuf + 4);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
|| TYPE_CODE (type) == TYPE_CODE_CHAR
|| TYPE_CODE (type) == TYPE_CODE_BOOL
|| TYPE_CODE (type) == TYPE_CODE_PTR
- || TYPE_CODE (type) == TYPE_CODE_REF
+ || TYPE_IS_REFERENCE (type)
|| TYPE_CODE (type) == TYPE_CODE_ENUM)
&& TYPE_LENGTH (type) <= tdep->wordsize)
{
if (TYPE_CODE (eltype) == TYPE_CODE_FLT)
{
int regnum = tdep->ppc_fp0_regnum + 1 + i;
- gdb_byte regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[PPC_MAX_REGISTER_SIZE];
struct type *regtype = register_type (gdbarch, regnum);
if (writebuf != NULL)
{
- convert_typed_floating (writebuf + offset, eltype,
- regval, regtype);
- regcache_cooked_write (regcache, regnum, regval);
+ target_float_convert (writebuf + offset, eltype,
+ regval, regtype);
+ regcache->cooked_write (regnum, regval);
}
if (readbuf != NULL)
{
- regcache_cooked_read (regcache, regnum, regval);
- convert_typed_floating (regval, regtype,
- readbuf + offset, eltype);
+ regcache->cooked_read (regnum, regval);
+ target_float_convert (regval, regtype,
+ readbuf + offset, eltype);
}
}
else
int regnum = tdep->ppc_vr0_regnum + 2 + i;
if (writebuf != NULL)
- regcache_cooked_write (regcache, regnum, writebuf + offset);
+ regcache->cooked_write (regnum, writebuf + offset);
if (readbuf != NULL)
- regcache_cooked_read (regcache, regnum, readbuf + offset);
+ regcache->cooked_read (regnum, readbuf + offset);
}
return RETURN_VALUE_REGISTER_CONVENTION;
if (readbuf)
{
/* Altivec places the return value in "v2". */
- regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf);
+ regcache->cooked_read (tdep->ppc_vr0_regnum + 2, readbuf);
}
if (writebuf)
{
/* Altivec places the return value in "v2". */
- regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, writebuf);
+ regcache->cooked_write (tdep->ppc_vr0_regnum + 2, writebuf);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
ABI risks in that case; we don't try to support it. */
if (readbuf)
{
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
- readbuf + 0);
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
- readbuf + 4);
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 5,
- readbuf + 8);
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 6,
- readbuf + 12);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 3, readbuf + 0);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 4, readbuf + 4);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 5, readbuf + 8);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 6, readbuf + 12);
}
if (writebuf)
{
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
- writebuf + 0);
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
- writebuf + 4);
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 5,
- writebuf + 8);
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 6,
- writebuf + 12);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 3, writebuf + 0);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 4, writebuf + 4);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 5, writebuf + 8);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 6, writebuf + 12);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
only corresponds to the least significant 32-bits. So place
the 64-bit DSP type's value in ev3. */
if (readbuf)
- regcache_cooked_read (regcache, tdep->ppc_ev0_regnum + 3, readbuf);
+ regcache->cooked_read (tdep->ppc_ev0_regnum + 3, readbuf);
if (writebuf)
- regcache_cooked_write (regcache, tdep->ppc_ev0_regnum + 3, writebuf);
+ regcache->cooked_write (tdep->ppc_ev0_regnum + 3, writebuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (broken_gcc && TYPE_LENGTH (type) <= 8)
/* GCC screwed up for structures or unions whose size is less
than or equal to 8 bytes.. Instead of left-aligning, it
right-aligns the data into the buffer formed by r3, r4. */
- gdb_byte regvals[MAX_REGISTER_SIZE * 2];
+ gdb_byte regvals[PPC_MAX_REGISTER_SIZE * 2];
int len = TYPE_LENGTH (type);
int offset = (2 * tdep->wordsize - len) % tdep->wordsize;
if (readbuf)
{
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
- regvals + 0 * tdep->wordsize);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 3,
+ regvals + 0 * tdep->wordsize);
if (len > tdep->wordsize)
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
- regvals + 1 * tdep->wordsize);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 4,
+ regvals + 1 * tdep->wordsize);
memcpy (readbuf, regvals + offset, len);
}
if (writebuf)
{
memset (regvals, 0, sizeof regvals);
memcpy (regvals + offset, writebuf, len);
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
- regvals + 0 * tdep->wordsize);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 3,
+ regvals + 0 * tdep->wordsize);
if (len > tdep->wordsize)
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
- regvals + 1 * tdep->wordsize);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 4,
+ regvals + 1 * tdep->wordsize);
}
return RETURN_VALUE_REGISTER_CONVENTION;
/* This matches SVr4 PPC, it does not match GCC. */
/* The value is right-padded to 8 bytes and then loaded, as
two "words", into r3/r4. */
- gdb_byte regvals[MAX_REGISTER_SIZE * 2];
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
- regvals + 0 * tdep->wordsize);
+ gdb_byte regvals[PPC_MAX_REGISTER_SIZE * 2];
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 3,
+ regvals + 0 * tdep->wordsize);
if (TYPE_LENGTH (type) > tdep->wordsize)
- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
- regvals + 1 * tdep->wordsize);
+ regcache->cooked_read (tdep->ppc_gp0_regnum + 4,
+ regvals + 1 * tdep->wordsize);
memcpy (readbuf, regvals, TYPE_LENGTH (type));
}
if (writebuf)
/* This matches SVr4 PPC, it does not match GCC. */
/* The value is padded out to 8 bytes and then loaded, as
two "words" into r3/r4. */
- gdb_byte regvals[MAX_REGISTER_SIZE * 2];
+ gdb_byte regvals[PPC_MAX_REGISTER_SIZE * 2];
memset (regvals, 0, sizeof regvals);
memcpy (regvals, writebuf, TYPE_LENGTH (type));
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
- regvals + 0 * tdep->wordsize);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 3,
+ regvals + 0 * tdep->wordsize);
if (TYPE_LENGTH (type) > tdep->wordsize)
- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
- regvals + 1 * tdep->wordsize);
+ regcache->cooked_write (tdep->ppc_gp0_regnum + 4,
+ regvals + 1 * tdep->wordsize);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
{
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 || dot_fn.minsym->linkage_name ()[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 (dot_fn.minsym->linkage_name () + 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 = std::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
{
while (len >= tdep->wordsize)
{
if (argpos->regcache && argpos->greg <= 10)
- regcache_cooked_write (argpos->regcache,
- tdep->ppc_gp0_regnum + argpos->greg, val);
+ argpos->regcache->cooked_write (tdep->ppc_gp0_regnum + argpos->greg,
+ val);
argpos->greg++;
len -= tdep->wordsize;
val += tdep->wordsize;
if (len > 0)
{
if (argpos->regcache && argpos->greg <= 10)
- regcache_cooked_write_part (argpos->regcache,
- tdep->ppc_gp0_regnum + argpos->greg,
- offset, len, val);
+ argpos->regcache->cooked_write_part
+ (tdep->ppc_gp0_regnum + argpos->greg, offset, len, val);
argpos->greg++;
}
}
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- gdb_byte buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[PPC_MAX_REGISTER_SIZE];
if (argpos->regcache)
store_unsigned_integer (buf, tdep->wordsize, byte_order, val);
{
int regnum = tdep->ppc_fp0_regnum + argpos->freg;
struct type *regtype = register_type (gdbarch, regnum);
- gdb_byte regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[PPC_MAX_REGISTER_SIZE];
- convert_typed_floating (val, type, regval, regtype);
- regcache_cooked_write (argpos->regcache, regnum, regval);
+ target_float_convert (val, type, regval, regtype);
+ argpos->regcache->cooked_write (regnum, regval);
}
argpos->freg++;
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);
+ argpos->regcache->cooked_write_part (regnum, offset,
+ TYPE_LENGTH (type), val);
}
argpos->freg++;
{
int regnum = tdep->ppc_fp0_regnum + argpos->freg;
- regcache_cooked_write (argpos->regcache, regnum, val);
+ argpos->regcache->cooked_write (regnum, val);
if (argpos->freg <= 12)
- regcache_cooked_write (argpos->regcache, regnum + 1, val + 8);
+ argpos->regcache->cooked_write (regnum + 1, val + 8);
}
argpos->freg += 2;
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 + hipart);
- regcache_cooked_write (argpos->regcache, regnum + 1, val + lopart);
+ argpos->regcache->cooked_write (regnum, val + hipart);
+ argpos->regcache->cooked_write (regnum + 1, val + lopart);
}
argpos->freg += 2;
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (argpos->regcache && argpos->vreg <= 13)
- regcache_cooked_write (argpos->regcache,
- tdep->ppc_vr0_regnum + argpos->vreg, val);
+ argpos->regcache->cooked_write (tdep->ppc_vr0_regnum + argpos->vreg, val);
argpos->vreg++;
}
|| TYPE_CODE (type) == TYPE_CODE_BOOL
|| TYPE_CODE (type) == TYPE_CODE_CHAR
|| TYPE_CODE (type) == TYPE_CODE_PTR
- || TYPE_CODE (type) == TYPE_CODE_REF)
+ || TYPE_IS_REFERENCE (type))
&& TYPE_LENGTH (type) <= tdep->wordsize)
{
ULONGEST word = 0;
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);
+ }
+ }
}
}
struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
{
CORE_ADDR func_addr = find_function_addr (function, NULL);
struct gdbarch_tdep *tdep = gdbarch_tdep (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
containing the address of that struct.. In that case we
should advance one word and start from r4 register to copy
parameters. This also consumes one on-stack parameter slot. */
- if (struct_return)
+ if (return_method == return_method_struct)
ppc64_sysv_abi_push_integer (gdbarch, struct_addr, &argpos);
for (argno = 0; argno < nargs; argno++)
{
int regnum = tdep->ppc_fp0_regnum + 1 + index;
struct type *regtype = register_type (gdbarch, regnum);
- gdb_byte regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[PPC_MAX_REGISTER_SIZE];
if (writebuf != NULL)
{
- convert_typed_floating (writebuf, valtype, regval, regtype);
- regcache_cooked_write (regcache, regnum, regval);
+ target_float_convert (writebuf, valtype, regval, regtype);
+ regcache->cooked_write (regnum, regval);
}
if (readbuf != NULL)
{
- regcache_cooked_read (regcache, regnum, regval);
- convert_typed_floating (regval, regtype, readbuf, valtype);
+ regcache->cooked_read (regnum, regval);
+ target_float_convert (regval, regtype, readbuf, valtype);
}
return 1;
}
offset = 8 - TYPE_LENGTH (valtype);
if (writebuf != NULL)
- regcache_cooked_write_part (regcache, regnum,
- offset, TYPE_LENGTH (valtype), writebuf);
+ regcache->cooked_write_part (regnum, offset, TYPE_LENGTH (valtype),
+ writebuf);
if (readbuf != NULL)
- regcache_cooked_read_part (regcache, regnum,
- offset, TYPE_LENGTH (valtype), readbuf);
+ regcache->cooked_read_part (regnum, offset, TYPE_LENGTH (valtype),
+ readbuf);
return 1;
}
if (writebuf != NULL)
{
- regcache_cooked_write (regcache, regnum, writebuf);
- regcache_cooked_write (regcache, regnum + 1, writebuf + 8);
+ regcache->cooked_write (regnum, writebuf);
+ regcache->cooked_write (regnum + 1, writebuf + 8);
}
if (readbuf != NULL)
{
- regcache_cooked_read (regcache, regnum, readbuf);
- regcache_cooked_read (regcache, regnum + 1, readbuf + 8);
+ regcache->cooked_read (regnum, readbuf);
+ regcache->cooked_read (regnum + 1, readbuf + 8);
}
return 1;
}
if (writebuf != NULL)
{
- regcache_cooked_write (regcache, regnum, writebuf + hipart);
- regcache_cooked_write (regcache, regnum + 1, writebuf + lopart);
+ regcache->cooked_write (regnum, writebuf + hipart);
+ regcache->cooked_write (regnum + 1, writebuf + lopart);
}
if (readbuf != NULL)
{
- regcache_cooked_read (regcache, regnum, readbuf + hipart);
- regcache_cooked_read (regcache, regnum + 1, readbuf + lopart);
+ regcache->cooked_read (regnum, readbuf + hipart);
+ regcache->cooked_read (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;
if (writebuf != NULL)
- regcache_cooked_write (regcache, regnum, writebuf);
+ regcache->cooked_write (regnum, writebuf);
+ if (readbuf != NULL)
+ regcache->cooked_read (regnum, readbuf);
+ 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 (regnum, offset, TYPE_LENGTH (valtype),
+ writebuf);
if (readbuf != NULL)
- regcache_cooked_read (regcache, regnum, readbuf);
+ regcache->cooked_read_part (regnum, offset, TYPE_LENGTH (valtype),
+ readbuf);
return 1;
}
struct type *func_type = function ? value_type (function) : NULL;
int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0;
struct type *eltype;
- int nelt, i, ok;
+ int nelt, ok;
/* This function exists to support a calling convention that
requires floating-point registers. It shouldn't be used on
{
eltype = check_typedef (TYPE_TARGET_TYPE (valtype));
- for (i = 0; i < 2; i++)
+ for (int i = 0; i < 2; i++)
{
ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
readbuf, writebuf, i);
eltype = register_type (gdbarch, tdep->ppc_vr0_regnum);
nelt = TYPE_LENGTH (valtype) / TYPE_LENGTH (eltype);
- for (i = 0; i < nelt; i++)
+ for (int i = 0; i < nelt; i++)
{
ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
readbuf, writebuf, i);
}
/* All pointers live in r3. */
- if (TYPE_CODE (valtype) == TYPE_CODE_PTR
- || TYPE_CODE (valtype) == TYPE_CODE_REF)
+ if (TYPE_CODE (valtype) == TYPE_CODE_PTR || TYPE_IS_REFERENCE (valtype))
{
int regnum = tdep->ppc_gp0_regnum + 3;
if (writebuf != NULL)
- regcache_cooked_write (regcache, regnum, writebuf);
+ regcache->cooked_write (regnum, writebuf);
if (readbuf != NULL)
- regcache_cooked_read (regcache, regnum, readbuf);
+ regcache->cooked_read (regnum, readbuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
/* 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)
int offset = (register_size (gdbarch, regnum) - TYPE_LENGTH (valtype));
if (writebuf != NULL)
- regcache_cooked_write_part (regcache, regnum,
- offset, TYPE_LENGTH (valtype), writebuf);
+ regcache->cooked_write_part (regnum, offset, TYPE_LENGTH (valtype),
+ writebuf);
if (readbuf != NULL)
- regcache_cooked_read_part (regcache, regnum,
- offset, TYPE_LENGTH (valtype), readbuf);
+ regcache->cooked_read_part (regnum, offset, TYPE_LENGTH (valtype),
+ readbuf);
+ 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 (int 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);
+
+ for (int i = 0; i < n_regs; i++)
+ {
+ gdb_byte regval[PPC_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 (regnum, regval);
+ }
+ if (readbuf != NULL)
+ {
+ regcache->cooked_read (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;
}