2003-10-03 Andrew Cagney <cagney@redhat.com>

* rs6000-tdep.c (rs6000_gdbarch_init): When the 64 bit SysV ABI,
	set extract_return_value, store_return_value and
	use_struct_convention to ppc64_sysv_abi_extract_return_value,
	ppc64_sysv_abi_store_return_value and
	ppc64_sysv_abi_use_struct_convention.
	* ppc-tdep.h (ppc64_sysv_abi_extract_return_value): Declare.
	(ppc64_sysv_abi_store_return_value): Declare.
	(ppc64_sysv_abi_use_struct_convention): Declare.
	* ppc-sysv-tdep.c (enum return_value_convention): Define.
	(ppc64_sysv_abi_extract_return_value): New function.
	(ppc64_sysv_abi_store_return_value): New function.
	(ppc64_sysv_abi_use_struct_convention): New function.
	(ppc64_sysv_abi_return_value): New function.
This commit is contained in:
Andrew Cagney 2003-10-03 21:11:39 +00:00
parent 268e218846
commit afd48b755b
4 changed files with 231 additions and 4 deletions

View file

@ -1,3 +1,19 @@
2003-10-03 Andrew Cagney <cagney@redhat.com>
* rs6000-tdep.c (rs6000_gdbarch_init): When the 64 bit SysV ABI,
set extract_return_value, store_return_value and
use_struct_convention to ppc64_sysv_abi_extract_return_value,
ppc64_sysv_abi_store_return_value and
ppc64_sysv_abi_use_struct_convention.
* ppc-tdep.h (ppc64_sysv_abi_extract_return_value): Declare.
(ppc64_sysv_abi_store_return_value): Declare.
(ppc64_sysv_abi_use_struct_convention): Declare.
* ppc-sysv-tdep.c (enum return_value_convention): Define.
(ppc64_sysv_abi_extract_return_value): New function.
(ppc64_sysv_abi_store_return_value): New function.
(ppc64_sysv_abi_use_struct_convention): New function.
(ppc64_sysv_abi_return_value): New function.
2003-10-03 Andrew Cagney <cagney@redhat.com>
* ppc-linux-tdep.c (ppc64_linux_convert_from_func_ptr_addr): Only

View file

@ -325,3 +325,197 @@ ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
return (TYPE_LENGTH (value_type) > 8);
}
/* The 64 bit ABI retun value convention.
Return non-zero if the return-value is stored in a register, return
0 if the return-value is instead stored on the stack (a.k.a.,
struct return convention).
For a return-value stored in a register: when INVAL is non-NULL,
copy the buffer to the corresponding register return-value location
location; when OUTVAL is non-NULL, fill the buffer from the
corresponding register return-value location. */
/* Potential ways that a function can return a value of a given type. */
enum return_value_convention
{
/* Where the return value has been squeezed into one or more
registers. */
RETURN_VALUE_REGISTER_CONVENTION,
/* Commonly known as the "struct return convention". The caller
passes an additional hidden first parameter to the caller. That
parameter contains the address at which the value being returned
should be stored. While typically, and historically, used for
large structs, this is convention is applied to values of many
different types. */
RETURN_VALUE_STRUCT_CONVENTION
};
static enum return_value_convention
ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
const void *inval, void *outval)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
/* Floats and doubles in F1. */
if (TYPE_CODE (valtype) == TYPE_CODE_FLT
&& TYPE_LENGTH (valtype) <= 8)
{
char regval[MAX_REGISTER_SIZE];
struct type *regtype = register_type (current_gdbarch, FP0_REGNUM);
if (inval != NULL)
{
convert_typed_floating (inval, valtype, regval, regtype);
regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
}
if (outval != NULL)
{
regcache_cooked_read (regcache, FP0_REGNUM + 1, regval);
convert_typed_floating (regval, regtype, outval, valtype);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (valtype) == TYPE_CODE_INT
&& TYPE_LENGTH (valtype) <= 8)
{
/* Integers in r3. */
if (inval != NULL)
{
/* Be careful to sign extend the value. */
regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
unpack_long (valtype, inval));
}
if (outval != NULL)
{
/* Extract the integer from r3. Since this is truncating the
value, there isn't a sign extension problem. */
ULONGEST regval;
regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
&regval);
store_unsigned_integer (outval, TYPE_LENGTH (valtype), regval);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
/* All pointers live in r3. */
if (TYPE_CODE (valtype) == TYPE_CODE_PTR)
{
/* All pointers live in r3. */
if (inval != NULL)
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, inval);
if (outval != NULL)
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, outval);
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
&& TYPE_LENGTH (valtype) <= 8
&& TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
&& TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
{
/* Small character arrays are returned, right justified, in r3. */
int offset = (register_size (current_gdbarch, tdep->ppc_gp0_regnum + 3)
- TYPE_LENGTH (valtype));
if (inval != NULL)
regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3,
offset, TYPE_LENGTH (valtype), inval);
if (outval != NULL)
regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3,
offset, TYPE_LENGTH (valtype), outval);
return RETURN_VALUE_REGISTER_CONVENTION;
}
/* Big floating point values get stored in adjacent floating
point registers. */
if (TYPE_CODE (valtype) == TYPE_CODE_FLT
&& (TYPE_LENGTH (valtype) == 16
|| TYPE_LENGTH (valtype) == 32))
{
if (inval || outval != NULL)
{
int i;
for (i = 0; i < TYPE_LENGTH (valtype) / 8; i++)
{
if (inval != NULL)
regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
(const bfd_byte *) inval + i * 8);
if (outval != NULL)
regcache_cooked_read (regcache, FP0_REGNUM + 1 + i,
(bfd_byte *) outval + i * 8);
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
/* Complex values get returned in f1:f2, need to convert. */
if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
&& (TYPE_LENGTH (valtype) == 8 || TYPE_LENGTH (valtype) == 16))
{
if (regcache != NULL)
{
int i;
for (i = 0; i < 2; i++)
{
char regval[MAX_REGISTER_SIZE];
struct type *regtype = register_type (current_gdbarch, FP0_REGNUM);
if (inval != NULL)
{
convert_typed_floating ((const bfd_byte *) inval + i * (TYPE_LENGTH (valtype) / 2),
valtype, regval, regtype);
regcache_cooked_write (regcache, FP0_REGNUM + 1 + i, regval);
}
if (outval != NULL)
{
regcache_cooked_read (regcache, FP0_REGNUM + 1 + i, regval);
convert_typed_floating (regval, regtype,
(bfd_byte *) outval + i * (TYPE_LENGTH (valtype) / 2),
valtype);
}
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
/* Big complex values get stored in f1:f4. */
if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
&& TYPE_LENGTH (valtype) == 32)
{
if (regcache != NULL)
{
int i;
for (i = 0; i < 4; i++)
{
if (inval != NULL)
regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
(const bfd_byte *) inval + i * 8);
if (outval != NULL)
regcache_cooked_read (regcache, FP0_REGNUM + 1 + i,
(bfd_byte *) outval + i * 8);
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
return RETURN_VALUE_STRUCT_CONVENTION;
}
int
ppc64_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
{
return (ppc64_sysv_abi_return_value (value_type, NULL, NULL, NULL)
== RETURN_VALUE_STRUCT_CONVENTION);
}
void
ppc64_sysv_abi_extract_return_value (struct type *valtype,
struct regcache *regbuf,
void *valbuf)
{
if (ppc64_sysv_abi_return_value (valtype, regbuf, NULL, valbuf)
!= RETURN_VALUE_REGISTER_CONVENTION)
error ("Function return value unknown");
}
void
ppc64_sysv_abi_store_return_value (struct type *valtype,
struct regcache *regbuf,
const void *valbuf)
{
if (!ppc64_sysv_abi_return_value (valtype, regbuf, valbuf, NULL))
error ("Function return value location unknown");
}

View file

@ -47,6 +47,14 @@ struct link_map_offsets *ppc_linux_svr4_fetch_link_map_offsets (void);
void ppc_linux_supply_gregset (char *buf);
void ppc_linux_supply_fpregset (char *buf);
int ppc64_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type);
void ppc64_sysv_abi_extract_return_value (struct type *valtype,
struct regcache *regbuf,
void *valbuf);
void ppc64_sysv_abi_store_return_value (struct type *valtype,
struct regcache *regbuf,
const void *valbuf);
/* From rs6000-tdep.c... */
CORE_ADDR rs6000_frame_saved_pc (struct frame_info *fi);

View file

@ -2830,9 +2830,16 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_pc_regnum (gdbarch, 64);
set_gdbarch_sp_regnum (gdbarch, 1);
set_gdbarch_deprecated_fp_regnum (gdbarch, 1);
set_gdbarch_deprecated_extract_return_value (gdbarch,
rs6000_extract_return_value);
if (sysv_abi && wordsize == 8)
{
set_gdbarch_extract_return_value (gdbarch, ppc64_sysv_abi_extract_return_value);
set_gdbarch_store_return_value (gdbarch, ppc64_sysv_abi_store_return_value);
}
else
{
set_gdbarch_deprecated_extract_return_value (gdbarch, rs6000_extract_return_value);
set_gdbarch_deprecated_store_return_value (gdbarch, rs6000_store_return_value);
}
if (v->arch == bfd_arch_powerpc)
switch (v->mach)
@ -2967,9 +2974,11 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Not sure on this. FIXMEmgo */
set_gdbarch_frame_args_skip (gdbarch, 8);
if (sysv_abi)
if (sysv_abi && wordsize == 4)
set_gdbarch_use_struct_convention (gdbarch,
ppc_sysv_abi_use_struct_convention);
else if (sysv_abi && wordsize == 8)
set_gdbarch_use_struct_convention (gdbarch, ppc64_sysv_abi_use_struct_convention);
else
set_gdbarch_use_struct_convention (gdbarch,
rs6000_use_struct_convention);