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

* rs6000-tdep.c (e500_store_return_value): Delete function.
	(e500_extract_return_value): Delete function.
	(rs6000_gdbarch_init): When SYSV, set "extract_return_value" and
	"restore_return_value" to "ppc_sysv_abi_extract_return_value" and
	"ppc_sysv_abi_restore_return_value" where applicable.
	* ppc-tdep.h: (ppc_sysv_abi_store_return_value): Declare.
	(ppc_sysv_abi_extract_return_value): Declare.
	(ppc_sysv_abi_broken_store_return_value): Declare.
	(ppc_sysv_abi_broken_extract_return_value): Declare.
	(ppc_sysv_abi_broken_use_struct_convention:) Delete declaration.
	* ppc-sysv-tdep.c (return_value_convention): Move definition to
	start of file.
	(do_ppc_sysv_return_value): New function.
	(ppc_sysv_abi_extract_return_value): New function.
	(ppc_sysv_abi_store_return_value): New function.
	(ppc_sysv_abi_broken_extract_return_value): New function.
	(ppc_sysv_abi_broken_store_return_value): New function.
	(ppc_sysv_abi_use_struct_convention): Call
	do_ppc_sysv_return_value.
This commit is contained in:
Andrew Cagney 2003-10-10 21:32:47 +00:00
parent 8d4ce20aa3
commit e754ae69e1
5 changed files with 294 additions and 108 deletions

View File

@ -1,3 +1,25 @@
2003-10-10 Andrew Cagney <cagney@redhat.com>
* rs6000-tdep.c (e500_store_return_value): Delete function.
(e500_extract_return_value): Delete function.
(rs6000_gdbarch_init): When SYSV, set "extract_return_value" and
"restore_return_value" to "ppc_sysv_abi_extract_return_value" and
"ppc_sysv_abi_restore_return_value" where applicable.
* ppc-tdep.h: (ppc_sysv_abi_store_return_value): Declare.
(ppc_sysv_abi_extract_return_value): Declare.
(ppc_sysv_abi_broken_store_return_value): Declare.
(ppc_sysv_abi_broken_extract_return_value): Declare.
(ppc_sysv_abi_broken_use_struct_convention:) Delete declaration.
* ppc-sysv-tdep.c (return_value_convention): Move definition to
start of file.
(do_ppc_sysv_return_value): New function.
(ppc_sysv_abi_extract_return_value): New function.
(ppc_sysv_abi_store_return_value): New function.
(ppc_sysv_abi_broken_extract_return_value): New function.
(ppc_sysv_abi_broken_store_return_value): New function.
(ppc_sysv_abi_use_struct_convention): Call
do_ppc_sysv_return_value.
2003-10-10 J. Brobecker <brobecker@gnat.com>
* blockframe.c (inside_main_func): No longer use symbol_lookup()

View File

@ -305,16 +305,262 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
return sp;
}
/* 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
};
/* Handle the return-value conventions specified by the SysV 32-bit
PowerPC ABI (including all the supplements):
no floating-point: floating-point values returned using 32-bit
general-purpose registers.
Altivec: 128-bit vectors returned using vector registers.
e500: 64-bit vectors returned using the full full 64 bit EV
register, floating-point values returned using 32-bit
general-purpose registers.
GCC (broken): Small struct values right (instead of left) aligned
when returned in general-purpose registers. */
static enum return_value_convention
do_ppc_sysv_return_value (struct type *type, struct regcache *regcache,
const void *inval, void *outval, int broken_gcc)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
gdb_assert (tdep->wordsize == 4);
if (TYPE_CODE (type) == TYPE_CODE_FLT
&& TYPE_LENGTH (type) <= 8
&& ppc_floating_point_unit_p (current_gdbarch))
{
if (outval)
{
/* Floats and doubles stored in "f1". Convert the value to
the required type. */
char regval[MAX_REGISTER_SIZE];
struct type *regtype = register_type (current_gdbarch,
FP0_REGNUM + 1);
regcache_cooked_read (regcache, FP0_REGNUM + 1, regval);
convert_typed_floating (regval, regtype, outval, type);
}
if (inval)
{
/* Floats and doubles stored in "f1". Convert the value to
the register's "double" type. */
char regval[MAX_REGISTER_SIZE];
struct type *regtype = register_type (current_gdbarch, FP0_REGNUM);
convert_typed_floating (inval, type, regval, regtype);
regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if ((TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) == 8)
|| (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8))
{
if (outval)
{
/* A long long, or a double stored in the 32 bit r3/r4. */
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
(bfd_byte *) outval + 0);
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
(bfd_byte *) outval + 4);
}
if (inval)
{
/* A long long, or a double stored in the 32 bit r3/r4. */
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
(bfd_byte *) inval + 0);
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
(bfd_byte *) inval + 4);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (type) == TYPE_CODE_INT
&& TYPE_LENGTH (type) <= tdep->wordsize)
{
if (outval)
{
/* Some sort of integer stored in r3. Since TYPE isn't
bigger than the register, sign extension isn't a problem
- just do everything unsigned. */
ULONGEST regval;
regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
&regval);
store_unsigned_integer (outval, TYPE_LENGTH (type), regval);
}
if (inval)
{
/* Some sort of integer stored in r3. Use unpack_long since
that should handle any required sign extension. */
regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
unpack_long (type, inval));
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_LENGTH (type) == 16
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& TYPE_VECTOR (type) && tdep->ppc_vr0_regnum >= 0)
{
if (outval)
{
/* Altivec places the return value in "v2". */
regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, outval);
}
if (inval)
{
/* Altivec places the return value in "v2". */
regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, inval);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_LENGTH (type) == 8
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& TYPE_VECTOR (type) && tdep->ppc_ev0_regnum >= 0)
{
/* The e500 ABI places return values for the 64-bit DSP types
(__ev64_opaque__) in r3. However, in GDB-speak, ev3
corresponds to the entire r3 value for e500, whereas GDB's r3
only corresponds to the least significant 32-bits. So place
the 64-bit DSP type's value in ev3. */
if (outval)
regcache_cooked_read (regcache, tdep->ppc_ev0_regnum + 3, outval);
if (inval)
regcache_cooked_write (regcache, tdep->ppc_ev0_regnum + 3, inval);
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (broken_gcc && TYPE_LENGTH (type) <= 8)
{
if (outval)
{
/* GCC screwed up. The last register isn't "left" aligned.
Need to extract the least significant part of each
register and then store that. */
/* Transfer any full words. */
int word = 0;
while (1)
{
ULONGEST reg;
int len = TYPE_LENGTH (type) - word * tdep->wordsize;
if (len <= 0)
break;
if (len > tdep->wordsize)
len = tdep->wordsize;
regcache_cooked_read_unsigned (regcache,
tdep->ppc_gp0_regnum + 3 + word,
&reg);
store_unsigned_integer (((bfd_byte *) outval
+ word * tdep->wordsize), len, reg);
word++;
}
}
if (inval)
{
/* GCC screwed up. The last register isn't "left" aligned.
Need to extract the least significant part of each
register and then store that. */
/* Transfer any full words. */
int word = 0;
while (1)
{
ULONGEST reg;
int len = TYPE_LENGTH (type) - word * tdep->wordsize;
if (len <= 0)
break;
if (len > tdep->wordsize)
len = tdep->wordsize;
reg = extract_unsigned_integer (((bfd_byte *) inval
+ word * tdep->wordsize), len);
regcache_cooked_write_unsigned (regcache,
tdep->ppc_gp0_regnum + 3 + word,
reg);
word++;
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_LENGTH (type) <= 8)
{
if (outval)
{
/* 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. */
char regvals[MAX_REGISTER_SIZE * 2];
regcache_cooked_read (regcache, 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);
memcpy (outval, regvals, TYPE_LENGTH (type));
}
if (inval)
{
/* 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. */
char regvals[MAX_REGISTER_SIZE * 2];
memset (regvals, 0, sizeof regvals);
memcpy (regvals, inval, TYPE_LENGTH (type));
regcache_cooked_write (regcache, 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);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
return RETURN_VALUE_STRUCT_CONVENTION;
}
void
ppc_sysv_abi_extract_return_value (struct type *type,
struct regcache *regcache, void *valbuf)
{
do_ppc_sysv_return_value (type, regcache, NULL, valbuf, 0);
}
void
ppc_sysv_abi_broken_extract_return_value (struct type *type,
struct regcache *regcache,
void *valbuf)
{
do_ppc_sysv_return_value (type, regcache, NULL, valbuf, 1);
}
void
ppc_sysv_abi_store_return_value (struct type *type, struct regcache *regcache,
const void *valbuf)
{
do_ppc_sysv_return_value (type, regcache, valbuf, NULL, 0);
}
void
ppc_sysv_abi_broken_store_return_value (struct type *type,
struct regcache *regcache,
const void *valbuf)
{
do_ppc_sysv_return_value (type, regcache, valbuf, NULL, 1);
}
/* Structures 8 bytes or less long are returned in the r3 & r4
registers, according to the SYSV ABI. */
int
ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
{
if ((TYPE_LENGTH (value_type) == 16 || TYPE_LENGTH (value_type) == 8)
&& TYPE_VECTOR (value_type))
return 0;
return (TYPE_LENGTH (value_type) > 8);
return (do_ppc_sysv_return_value (value_type, NULL, NULL, NULL, 0)
== RETURN_VALUE_STRUCT_CONVENTION);
}
/* Pass the arguments in either registers, or in the stack. Using the
@ -617,22 +863,6 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
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)

View File

@ -35,7 +35,18 @@ int ppc_linux_frameless_function_invocation (struct frame_info *);
void ppc_linux_frame_init_saved_regs (struct frame_info *);
CORE_ADDR ppc_linux_frame_chain (struct frame_info *);
int ppc_sysv_abi_use_struct_convention (int, struct type *);
int ppc_sysv_abi_broken_use_struct_convention (int, struct type *);
void ppc_sysv_abi_store_return_value (struct type *type,
struct regcache *regcache,
const void *valbuf);
void ppc_sysv_abi_extract_return_value (struct type *type,
struct regcache *regcache,
void *valbuf);
void ppc_sysv_abi_broken_store_return_value (struct type *type,
struct regcache *regcache,
const void *valbuf);
void ppc_sysv_abi_broken_extract_return_value (struct type *type,
struct regcache *regcache,
void *valbuf);
CORE_ADDR ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
CORE_ADDR func_addr,
struct regcache *regcache,

View File

@ -226,8 +226,11 @@ ppcnbsd_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
{
set_gdbarch_pc_in_sigtramp (gdbarch, ppcnbsd_pc_in_sigtramp);
/* For NetBSD, this is an on again, off again thing. Some systems
do use the broken struct convention, and some don't. */
set_gdbarch_use_struct_convention (gdbarch, ppcnbsd_use_struct_convention);
set_gdbarch_extract_return_value (gdbarch, ppc_sysv_abi_broken_extract_return_value);
set_gdbarch_store_return_value (gdbarch, ppc_sysv_abi_broken_store_return_value);
set_solib_svr4_fetch_link_map_offsets (gdbarch,
nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
}

View File

@ -1313,65 +1313,6 @@ ran_out_of_registers_for_arguments:
return sp;
}
/* Extract a function return value of type TYPE from raw register array
REGBUF, and copy that return value into VALBUF in virtual format. */
static void
e500_extract_return_value (struct type *valtype, struct regcache *regbuf, void *valbuf)
{
int offset = 0;
int vallen = TYPE_LENGTH (valtype);
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
&& vallen == 8
&& TYPE_VECTOR (valtype))
{
regcache_raw_read (regbuf, tdep->ppc_ev0_regnum + 3, valbuf);
}
else
{
/* Return value is copied starting from r3. Note that r3 for us
is a pseudo register. */
int offset = 0;
int return_regnum = tdep->ppc_gp0_regnum + 3;
int reg_size = DEPRECATED_REGISTER_RAW_SIZE (return_regnum);
int reg_part_size;
char *val_buffer;
int copied = 0;
int i = 0;
/* Compute where we will start storing the value from. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (vallen <= reg_size)
offset = reg_size - vallen;
else
offset = reg_size + (reg_size - vallen);
}
/* How big does the local buffer need to be? */
if (vallen <= reg_size)
val_buffer = alloca (reg_size);
else
val_buffer = alloca (vallen);
/* Read all we need into our private buffer. We copy it in
chunks that are as long as one register, never shorter, even
if the value is smaller than the register. */
while (copied < vallen)
{
reg_part_size = DEPRECATED_REGISTER_RAW_SIZE (return_regnum + i);
/* It is a pseudo/cooked register. */
regcache_cooked_read (regbuf, return_regnum + i,
val_buffer + copied);
copied += reg_part_size;
i++;
}
/* Put the stuff in the return buffer. */
memcpy (valbuf, val_buffer + offset, vallen);
}
}
/* PowerOpen always puts structures in memory. Vectors, which were
added later, do get returned in a register though. */
@ -2046,30 +1987,6 @@ rs6000_stab_reg_to_regnum (int num)
return regnum;
}
/* Write into appropriate registers a function return value
of type TYPE, given in virtual format. */
static void
e500_store_return_value (struct type *type, char *valbuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
/* Everything is returned in GPR3 and up. */
int copied = 0;
int i = 0;
int len = TYPE_LENGTH (type);
while (copied < len)
{
int regnum = gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum + 3 + i;
int reg_size = DEPRECATED_REGISTER_RAW_SIZE (regnum);
char *reg_val_buf = alloca (reg_size);
memcpy (reg_val_buf, valbuf + copied, reg_size);
copied += reg_size;
deprecated_write_register_gen (regnum, reg_val_buf);
i++;
}
}
static void
rs6000_store_return_value (struct type *type, char *valbuf)
{
@ -2835,6 +2752,11 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
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 if (sysv_abi && wordsize == 4)
{
set_gdbarch_extract_return_value (gdbarch, ppc_sysv_abi_extract_return_value);
set_gdbarch_store_return_value (gdbarch, ppc_sysv_abi_store_return_value);
}
else
{
set_gdbarch_deprecated_extract_return_value (gdbarch, rs6000_extract_return_value);
@ -2873,8 +2795,6 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, e500_dwarf2_reg_to_regnum);
set_gdbarch_pseudo_register_read (gdbarch, e500_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, e500_pseudo_register_write);
set_gdbarch_extract_return_value (gdbarch, e500_extract_return_value);
set_gdbarch_deprecated_store_return_value (gdbarch, e500_store_return_value);
break;
default:
tdep->ppc_vr0_regnum = -1;