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:
parent
268e218846
commit
afd48b755b
4 changed files with 231 additions and 4 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
®val);
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue