X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gdb%2Fppc-sysv-tdep.c;h=c2952f5c8b8b4a57865c32ca7c3dc747b2bd09eb;hb=9b254dd1ce46c19dde1dde5b8d1e22e862dfacce;hp=0fb0d6a6c9593e31741a4db7b2558e4d611e31fd;hpb=92ad9cd90faf2b59f2434c8f706902df65ee5c2d;p=thirdparty%2Fbinutils-gdb.git
diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c
index 0fb0d6a6c95..c2952f5c8b8 100644
--- a/gdb/ppc-sysv-tdep.c
+++ b/gdb/ppc-sysv-tdep.c
@@ -1,13 +1,14 @@
/* Target-dependent code for PowerPC systems using the SVR4 ABI
for GDB, the GNU debugger.
- Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2005, 2007, 2008
+ Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@@ -16,9 +17,7 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see . */
#include "defs.h"
#include "gdbcore.h"
@@ -28,6 +27,9 @@
#include "gdb_string.h"
#include "gdb_assert.h"
#include "ppc-tdep.h"
+#include "target.h"
+#include "objfiles.h"
+#include "infcall.h"
/* Pass the arguments in either registers, or in the stack. Using the
ppc sysv ABI, the first eight words of the argument list (that might
@@ -41,16 +43,21 @@
starting from r4. */
CORE_ADDR
-ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_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)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- const CORE_ADDR saved_sp = read_sp ();
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ULONGEST saved_sp;
int argspace = 0; /* 0 is an initial wrong guess. */
int write_pass;
+ gdb_assert (tdep->wordsize == 4);
+
+ regcache_cooked_read_unsigned (regcache, gdbarch_sp_regnum (gdbarch),
+ &saved_sp);
+
/* Go through the argument list twice.
Pass 1: Figure out how much new stack space is required for
@@ -94,12 +101,12 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
for (argno = 0; argno < nargs; argno++)
{
struct value *arg = args[argno];
- struct type *type = check_typedef (VALUE_TYPE (arg));
+ struct type *type = check_typedef (value_type (arg));
int len = TYPE_LENGTH (type);
- char *val = VALUE_CONTENTS (arg);
+ const bfd_byte *val = value_contents (arg);
- if (TYPE_CODE (type) == TYPE_CODE_FLT
- && ppc_floating_point_unit_p (current_gdbarch) && len <= 8)
+ if (TYPE_CODE (type) == TYPE_CODE_FLT && len <= 8
+ && !tdep->soft_float)
{
/* Floating point value converted to "double" then
passed in an FP register, when the registers run out,
@@ -110,11 +117,12 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
{
/* Always store the floating point value using
the register's floating-point format. */
- char regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[MAX_REGISTER_SIZE];
struct type *regtype
- = register_type (gdbarch, FP0_REGNUM + freg);
+ = register_type (gdbarch, tdep->ppc_fp0_regnum + freg);
convert_typed_floating (val, type, regval, regtype);
- regcache_cooked_write (regcache, FP0_REGNUM + freg,
+ regcache_cooked_write (regcache,
+ tdep->ppc_fp0_regnum + freg,
regval);
}
freg++;
@@ -127,28 +135,47 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
if (write_pass)
{
char memval[8];
- struct type *memtype;
- switch (TARGET_BYTE_ORDER)
- {
- case BFD_ENDIAN_BIG:
- memtype = builtin_type_ieee_double_big;
- break;
- case BFD_ENDIAN_LITTLE:
- memtype = builtin_type_ieee_double_little;
- break;
- default:
- internal_error (__FILE__, __LINE__, "bad switch");
- }
- convert_typed_floating (val, type, memval, memtype);
+ convert_typed_floating (val, type, memval,
+ builtin_type_ieee_double);
write_memory (sp + argoffset, val, len);
}
argoffset += 8;
}
}
- else if (len == 8 && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
- || (!ppc_floating_point_unit_p (current_gdbarch) && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && len == 16
+ && !tdep->soft_float
+ && (gdbarch_long_double_format (gdbarch)
+ == floatformats_ibm_long_double))
{
- /* "long long" or "double" passed in an odd/even
+ /* IBM long double passed in two FP registers if
+ available, otherwise 8-byte aligned stack. */
+ if (freg <= 7)
+ {
+ 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);
+ }
+ freg += 2;
+ }
+ else
+ {
+ argoffset = align_up (argoffset, 8);
+ if (write_pass)
+ write_memory (sp + argoffset, val, len);
+ argoffset += 16;
+ }
+ }
+ else if (len == 8
+ && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
+ || TYPE_CODE (type) == TYPE_CODE_FLT)) /* double */
+ {
+ /* "long long" or soft-float "double" passed in an odd/even
register pair with the low addressed word in the odd
register and the high addressed word in the even
register, or when the registers run out an 8 byte
@@ -162,13 +189,6 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
write_memory (sp + argoffset, val, len);
argoffset += 8;
}
- else if (tdep->wordsize == 8)
- {
- if (write_pass)
- regcache_cooked_write (regcache,
- tdep->ppc_gp0_regnum + greg, val);
- greg += 1;
- }
else
{
/* Must start on an odd register - r3/r4 etc. */
@@ -186,16 +206,52 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
greg += 2;
}
}
+ else if (len == 16 && TYPE_CODE (type) == TYPE_CODE_FLT
+ && (gdbarch_long_double_format (gdbarch)
+ == floatformats_ibm_long_double))
+ {
+ /* Soft-float IBM long double passed in four consecutive
+ registers, or on the stack. The registers are not
+ necessarily odd/even pairs. */
+ if (greg > 7)
+ {
+ greg = 11;
+ argoffset = align_up (argoffset, 8);
+ if (write_pass)
+ write_memory (sp + argoffset, val, len);
+ argoffset += 16;
+ }
+ else
+ {
+ 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);
+ }
+ greg += 4;
+ }
+ }
else if (len == 16
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
- && TYPE_VECTOR (type) && tdep->ppc_vr0_regnum >= 0)
+ && TYPE_VECTOR (type)
+ && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
{
/* Vector parameter passed in an Altivec register, or
when that runs out, 16 byte aligned stack location. */
if (vreg <= 13)
{
if (write_pass)
- regcache_cooked_write (current_regcache,
+ regcache_cooked_write (regcache,
tdep->ppc_vr0_regnum + vreg, val);
vreg++;
}
@@ -209,7 +265,8 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
}
else if (len == 8
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
- && TYPE_VECTOR (type) && tdep->ppc_ev0_regnum >= 0)
+ && TYPE_VECTOR (type)
+ && tdep->vector_abi == POWERPC_VEC_SPE)
{
/* Vector parameter passed in an e500 register, or when
that runs out, 8 byte aligned stack location. Note
@@ -221,7 +278,7 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
if (greg <= 10)
{
if (write_pass)
- regcache_cooked_write (current_regcache,
+ regcache_cooked_write (regcache,
tdep->ppc_ev0_regnum + greg, val);
greg++;
}
@@ -237,15 +294,21 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
{
/* Reduce the parameter down to something that fits in a
"word". */
- char word[MAX_REGISTER_SIZE];
+ gdb_byte word[MAX_REGISTER_SIZE];
memset (word, 0, MAX_REGISTER_SIZE);
if (len > tdep->wordsize
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION)
{
- /* Structs and large values are put on an 8 byte
- aligned stack ... */
- structoffset = align_up (structoffset, 8);
+ /* Structs and large values are put in an
+ aligned stack slot ... */
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type)
+ && len >= 16)
+ structoffset = align_up (structoffset, 16);
+ else
+ structoffset = align_up (structoffset, 8);
+
if (write_pass)
write_memory (sp + structoffset, val, len);
/* ... and then a "word" pointing to that address is
@@ -290,10 +353,28 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
/* Ensure that the stack is still 16 byte aligned. */
sp = align_down (sp, 16);
}
+
+ /* The psABI says that "A caller of a function that takes a
+ variable argument list shall set condition register bit 6 to
+ 1 if it passes one or more arguments in the floating-point
+ registers. It is strongly recommended that the caller set the
+ bit to 0 otherwise..." Doing this for normal functions too
+ shouldn't hurt. */
+ if (write_pass)
+ {
+ ULONGEST cr;
+
+ regcache_cooked_read_unsigned (regcache, tdep->ppc_cr_regnum, &cr);
+ if (freg > 1)
+ cr |= 0x02000000;
+ else
+ cr &= ~0x02000000;
+ regcache_cooked_write_unsigned (regcache, tdep->ppc_cr_regnum, cr);
+ }
}
/* Update %sp. */
- regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+ regcache_cooked_write_signed (regcache, gdbarch_sp_regnum (gdbarch), sp);
/* Write the backchain (it occupies WORDSIZED bytes). */
write_memory_signed_integer (sp, tdep->wordsize, saved_sp);
@@ -321,61 +402,114 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
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)
+do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, gdb_byte *readbuf,
+ const gdb_byte *writebuf, int broken_gcc)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_assert (tdep->wordsize == 4);
if (TYPE_CODE (type) == TYPE_CODE_FLT
&& TYPE_LENGTH (type) <= 8
- && ppc_floating_point_unit_p (current_gdbarch))
+ && !tdep->soft_float)
{
- if (outval)
+ if (readbuf)
{
/* 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);
+ gdb_byte regval[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);
}
- if (inval)
+ if (writebuf)
{
/* 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);
+ gdb_byte regval[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);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) == 16
+ && !tdep->soft_float
+ && (gdbarch_long_double_format (gdbarch) == floatformats_ibm_long_double))
+ {
+ /* 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);
+ }
+ if (writebuf)
+ {
+ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, writebuf);
+ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 2,
+ writebuf + 8);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) == 16
+ && (gdbarch_long_double_format (gdbarch) == floatformats_ibm_long_double))
+ {
+ /* Soft-float IBM long double stored in r3, r4, 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);
+ }
+ 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);
}
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)
+ if (readbuf)
{
/* 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);
+ readbuf + 0);
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
- (bfd_byte *) outval + 4);
+ readbuf + 4);
}
- if (inval)
+ if (writebuf)
{
/* 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);
+ writebuf + 0);
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
- (bfd_byte *) inval + 4);
+ writebuf + 4);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
- if (TYPE_CODE (type) == TYPE_CODE_INT
- && TYPE_LENGTH (type) <= tdep->wordsize)
+ else if ((TYPE_CODE (type) == TYPE_CODE_INT
+ || 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_CODE (type) == TYPE_CODE_ENUM)
+ && TYPE_LENGTH (type) <= tdep->wordsize)
{
- if (outval)
+ if (readbuf)
{
/* Some sort of integer stored in r3. Since TYPE isn't
bigger than the register, sign extension isn't a problem
@@ -383,121 +517,136 @@ do_ppc_sysv_return_value (struct type *type, struct regcache *regcache,
ULONGEST regval;
regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
®val);
- store_unsigned_integer (outval, TYPE_LENGTH (type), regval);
+ store_unsigned_integer (readbuf, TYPE_LENGTH (type), regval);
}
- if (inval)
+ if (writebuf)
{
/* 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));
+ unpack_long (type, writebuf));
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_LENGTH (type) == 16
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
- && TYPE_VECTOR (type) && tdep->ppc_vr0_regnum >= 0)
+ && TYPE_VECTOR (type)
+ && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
{
- if (outval)
+ if (readbuf)
{
/* Altivec places the return value in "v2". */
- regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, outval);
+ regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf);
}
- if (inval)
+ if (writebuf)
{
/* Altivec places the return value in "v2". */
- regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, inval);
+ regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, writebuf);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_LENGTH (type) == 16
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type)
+ && tdep->vector_abi == POWERPC_VEC_GENERIC)
+ {
+ /* GCC -maltivec -mabi=no-altivec returns vectors in r3/r4/r5/r6.
+ GCC without AltiVec returns them in memory, but it warns about
+ 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);
+ }
+ 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);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_LENGTH (type) == 8
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
- && TYPE_VECTOR (type) && tdep->ppc_ev0_regnum >= 0)
+ && TYPE_VECTOR (type)
+ && tdep->vector_abi == POWERPC_VEC_SPE)
{
/* 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);
+ if (readbuf)
+ regcache_cooked_read (regcache, tdep->ppc_ev0_regnum + 3, readbuf);
+ if (writebuf)
+ regcache_cooked_write (regcache, tdep->ppc_ev0_regnum + 3, writebuf);
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,
- ®);
- store_unsigned_integer (((bfd_byte *) outval
- + word * tdep->wordsize), len, reg);
- word++;
- }
+ /* 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];
+ 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);
+ if (len > tdep->wordsize)
+ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+ regvals + 1 * tdep->wordsize);
+ memcpy (readbuf, regvals + offset, len);
}
- if (inval)
+ if (writebuf)
{
- /* 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++;
- }
+ memset (regvals, 0, sizeof regvals);
+ memcpy (regvals + offset, writebuf, len);
+ regcache_cooked_write (regcache, 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);
}
+
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_LENGTH (type) <= 8)
{
- if (outval)
+ if (readbuf)
{
/* 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];
+ gdb_byte 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));
+ memcpy (readbuf, regvals, TYPE_LENGTH (type));
}
- if (inval)
+ 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. */
- char regvals[MAX_REGISTER_SIZE * 2];
+ gdb_byte regvals[MAX_REGISTER_SIZE * 2];
memset (regvals, 0, sizeof regvals);
- memcpy (regvals, inval, TYPE_LENGTH (type));
+ memcpy (regvals, writebuf, TYPE_LENGTH (type));
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
regvals + 0 * tdep->wordsize);
if (TYPE_LENGTH (type) > tdep->wordsize)
@@ -509,43 +658,64 @@ do_ppc_sysv_return_value (struct type *type, struct regcache *regcache,
return RETURN_VALUE_STRUCT_CONVENTION;
}
-void
-ppc_sysv_abi_extract_return_value (struct type *type,
- struct regcache *regcache, void *valbuf)
+enum return_value_convention
+ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, gdb_byte *readbuf,
+ const gdb_byte *writebuf)
{
- do_ppc_sysv_return_value (type, regcache, NULL, valbuf, 0);
+ return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
+ writebuf, 0);
}
-void
-ppc_sysv_abi_broken_extract_return_value (struct type *type,
- struct regcache *regcache,
- void *valbuf)
+enum return_value_convention
+ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
+ struct type *valtype,
+ struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
- do_ppc_sysv_return_value (type, regcache, NULL, valbuf, 1);
+ return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
+ writebuf, 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);
-}
+/* The helper function for 64-bit SYSV push_dummy_call. Converts the
+ function's code address back into the function's descriptor
+ address.
-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);
-}
+ Find a value for the TOC register. Every symbol should have both
+ ".FN" and "FN" in the minimal symbol table. "FN" points at the
+ FN's descriptor, while ".FN" points at the entry point (which
+ matches FUNC_ADDR). Need to reverse from FUNC_ADDR back to the
+ FN's descriptor address (while at the same time being careful to
+ find "FN" in the same object file as ".FN"). */
-/* 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)
+static int
+convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr)
{
- return (do_ppc_sysv_return_value (value_type, NULL, NULL, NULL, 0)
- == RETURN_VALUE_STRUCT_CONVENTION);
+ struct obj_section *dot_fn_section;
+ struct minimal_symbol *dot_fn;
+ struct minimal_symbol *fn;
+ CORE_ADDR toc;
+ /* 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 == NULL || SYMBOL_LINKAGE_NAME (dot_fn)[0] != '.')
+ return 0;
+ /* Get the section that contains CODE_ADDR. Need this for the
+ "objfile" that it contains. */
+ dot_fn_section = find_pc_section (code_addr);
+ if (dot_fn_section == NULL || dot_fn_section->objfile == NULL)
+ return 0;
+ /* Now find the corresponding "FN" (dropping ".") minimal symbol's
+ 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) + 1, NULL,
+ dot_fn_section->objfile);
+ if (fn == NULL)
+ return 0;
+ /* Found a descriptor. */
+ (*desc_addr) = SYMBOL_VALUE_ADDRESS (fn);
+ return 1;
}
/* Pass the arguments in either registers, or in the stack. Using the
@@ -556,16 +726,14 @@ ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
greatly simplifies the logic. */
CORE_ADDR
-ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ppc64_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)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- /* By this stage in the proceedings, SP has been decremented by "red
- zone size" + "struct return size". Fetch the stack-pointer from
- before this and use that as the BACK_CHAIN. */
- const CORE_ADDR back_chain = read_sp ();
+ CORE_ADDR func_addr = find_function_addr (function, NULL);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ULONGEST back_chain;
/* See for-loop comment below. */
int write_pass;
/* Size of the Altivec's vector parameter region, the final value is
@@ -583,6 +751,17 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
the possible values of tdep->wordsize. */
gdb_assert (tdep->wordsize == 8);
+ /* This function exists to support a calling convention that
+ requires floating-point registers. It shouldn't be used on
+ processors that lack them. */
+ gdb_assert (ppc_floating_point_unit_p (gdbarch));
+
+ /* By this stage in the proceedings, SP has been decremented by "red
+ zone size" + "struct return size". Fetch the stack-pointer from
+ before this and use that as the BACK_CHAIN. */
+ regcache_cooked_read_unsigned (regcache, gdbarch_sp_regnum (gdbarch),
+ &back_chain);
+
/* Go through the argument list twice.
Pass 1: Compute the function call's stack space and register
@@ -648,8 +827,8 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
for (argno = 0; argno < nargs; argno++)
{
struct value *arg = args[argno];
- struct type *type = check_typedef (VALUE_TYPE (arg));
- char *val = VALUE_CONTENTS (arg);
+ struct type *type = check_typedef (value_type (arg));
+ const bfd_byte *val = value_contents (arg);
if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8)
{
/* Floats and Doubles go in f1 .. f13. They also
@@ -657,14 +836,14 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
memory. */
if (write_pass)
{
- if (ppc_floating_point_unit_p (current_gdbarch)
- && freg <= 13)
+ if (freg <= 13)
{
- char regval[MAX_REGISTER_SIZE];
- struct type *regtype = register_type (gdbarch,
- FP0_REGNUM);
+ gdb_byte regval[MAX_REGISTER_SIZE];
+ struct type *regtype
+ = register_type (gdbarch, tdep->ppc_fp0_regnum);
convert_typed_floating (val, type, regval, regtype);
- regcache_cooked_write (regcache, FP0_REGNUM + freg,
+ regcache_cooked_write (regcache,
+ tdep->ppc_fp0_regnum + freg,
regval);
}
if (greg <= 10)
@@ -678,7 +857,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
This code interprets that to mean: store it,
left aligned, in the general register. */
- char regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[MAX_REGISTER_SIZE];
memset (regval, 0, sizeof regval);
memcpy (regval, val, TYPE_LENGTH (type));
regcache_cooked_write (regcache,
@@ -692,6 +871,41 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
greg++;
gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
}
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) == 16
+ && (gdbarch_long_double_format (gdbarch)
+ == floatformats_ibm_long_double))
+ {
+ /* IBM long double stored in two doublewords of the
+ parameter save area and corresponding registers. */
+ if (write_pass)
+ {
+ if (!tdep->soft_float && freg <= 13)
+ {
+ regcache_cooked_write (regcache,
+ tdep->ppc_fp0_regnum + freg,
+ val);
+ if (freg <= 12)
+ regcache_cooked_write (regcache,
+ tdep->ppc_fp0_regnum + freg + 1,
+ val + 8);
+ }
+ if (greg <= 10)
+ {
+ regcache_cooked_write (regcache,
+ tdep->ppc_gp0_regnum + greg,
+ val);
+ if (greg <= 9)
+ regcache_cooked_write (regcache,
+ tdep->ppc_gp0_regnum + greg + 1,
+ val + 8);
+ }
+ write_memory (gparam, val, TYPE_LENGTH (type));
+ }
+ freg += 2;
+ greg += 2;
+ gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+ }
else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& tdep->ppc_vr0_regnum >= 0)
@@ -716,15 +930,25 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
}
}
else if ((TYPE_CODE (type) == TYPE_CODE_INT
- || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ || TYPE_CODE (type) == TYPE_CODE_ENUM
+ || TYPE_CODE (type) == TYPE_CODE_PTR)
&& TYPE_LENGTH (type) <= 8)
{
- /* Scalars get sign[un]extended and go in gpr3 .. gpr10.
- They can also end up in memory. */
+ /* Scalars and Pointers get sign[un]extended and go in
+ gpr3 .. gpr10. They can also end up in memory. */
if (write_pass)
{
/* Sign extend the value, then store it unsigned. */
ULONGEST word = unpack_long (type, val);
+ /* Convert any function code addresses into
+ descriptors. */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR
+ && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)
+ {
+ CORE_ADDR desc = word;
+ convert_code_addr_to_desc_addr (word, &desc);
+ word = desc;
+ }
if (greg <= 10)
regcache_cooked_write_unsigned (regcache,
tdep->ppc_gp0_regnum +
@@ -743,27 +967,22 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
{
if (write_pass && greg <= 10)
{
- char regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[MAX_REGISTER_SIZE];
int len = TYPE_LENGTH (type) - byte;
if (len > tdep->wordsize)
len = tdep->wordsize;
memset (regval, 0, sizeof regval);
- /* WARNING: cagney/2003-09-21: As best I can
- tell, the ABI specifies that the value should
- be left aligned. Unfortunately, GCC doesn't
- do this - it instead right aligns even sized
- values and puts odd sized values on the
- stack. Work around that by putting both a
- left and right aligned value into the
- register (hopefully no one notices :-^).
- Arrrgh! */
- /* Left aligned (8 byte values such as pointers
- fill the buffer). */
- memcpy (regval, val + byte, len);
- /* Right aligned (but only if even). */
- if (len == 1 || len == 2 || len == 4)
+ /* The ABI (version 1.9) specifies that values
+ smaller than one doubleword are right-aligned
+ and those larger are left-aligned. GCC
+ versions before 3.4 implemented this
+ incorrectly; see
+ . */
+ if (byte == 0)
memcpy (regval + tdep->wordsize - len,
val + byte, len);
+ else
+ memcpy (regval, val + byte, len);
regcache_cooked_write (regcache, greg, regval);
}
greg++;
@@ -777,6 +996,57 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
value to memory. Fortunately, doing this
simplifies the code. */
write_memory (gparam, val, TYPE_LENGTH (type));
+ if (freg <= 13
+ && TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) == 1
+ && TYPE_LENGTH (type) <= 16)
+ {
+ /* The ABI (version 1.9) specifies that structs
+ containing a single floating-point value, at any
+ level of nesting of single-member structs, are
+ passed in floating-point registers. */
+ while (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) == 1)
+ type = check_typedef (TYPE_FIELD_TYPE (type, 0));
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ if (TYPE_LENGTH (type) <= 8)
+ {
+ if (write_pass)
+ {
+ gdb_byte regval[MAX_REGISTER_SIZE];
+ struct type *regtype
+ = register_type (gdbarch,
+ tdep->ppc_fp0_regnum);
+ convert_typed_floating (val, type, regval,
+ regtype);
+ regcache_cooked_write (regcache,
+ (tdep->ppc_fp0_regnum
+ + freg),
+ regval);
+ }
+ freg++;
+ }
+ else if (TYPE_LENGTH (type) == 16
+ && (gdbarch_long_double_format (gdbarch)
+ == floatformats_ibm_long_double))
+ {
+ if (write_pass)
+ {
+ regcache_cooked_write (regcache,
+ (tdep->ppc_fp0_regnum
+ + freg),
+ val);
+ if (freg <= 12)
+ regcache_cooked_write (regcache,
+ (tdep->ppc_fp0_regnum
+ + freg + 1),
+ val + 8);
+ }
+ freg += 2;
+ }
+ }
+ }
/* Always consume parameter stack space. */
gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
}
@@ -796,7 +1066,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
}
/* Update %sp. */
- regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+ regcache_cooked_write_signed (regcache, gdbarch_sp_regnum (gdbarch), sp);
/* Write the backchain (it occupies WORDSIZED bytes). */
write_memory_signed_integer (sp, tdep->wordsize, back_chain);
@@ -805,32 +1075,18 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
breakpoint. */
regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
- /* Find a value for the TOC register. Every symbol should have both
- ".FN" and "FN" in the minimal symbol table. "FN" points at the
- FN's descriptor, while ".FN" points at the entry point (which
- matches FUNC_ADDR). Need to reverse from FUNC_ADDR back to the
- FN's descriptor address. */
+ /* Use the func_addr to find the descriptor, and use that to find
+ the TOC. */
{
- /* Find the minimal symbol that corresponds to FUNC_ADDR (should
- have the name ".FN"). */
- struct minimal_symbol *dot_fn = lookup_minimal_symbol_by_pc (func_addr);
- if (dot_fn != NULL && SYMBOL_LINKAGE_NAME (dot_fn)[0] == '.')
+ CORE_ADDR desc_addr;
+ if (convert_code_addr_to_desc_addr (func_addr, &desc_addr))
{
- /* Now find the corresponding "FN" (dropping ".") minimal
- symbol's address. */
- struct minimal_symbol *fn =
- lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL,
- NULL);
- if (fn != NULL)
- {
- /* Got the address of that descriptor. The TOC is the
- second double word. */
- CORE_ADDR toc =
- read_memory_unsigned_integer (SYMBOL_VALUE_ADDRESS (fn) +
- tdep->wordsize, tdep->wordsize);
- regcache_cooked_write_unsigned (regcache,
- tdep->ppc_gp0_regnum + 2, toc);
- }
+ /* The TOC is the second double word in the descriptor. */
+ CORE_ADDR toc =
+ read_memory_unsigned_integer (desc_addr + tdep->wordsize,
+ tdep->wordsize);
+ regcache_cooked_write_unsigned (regcache,
+ tdep->ppc_gp0_regnum + 2, toc);
}
}
@@ -838,55 +1094,64 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
}
-/* The 64 bit ABI retun value convention.
+/* The 64 bit ABI return 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,
+ For a return-value stored in a register: when WRITEBUF is non-NULL,
copy the buffer to the corresponding register return-value location
- location; when OUTVAL is non-NULL, fill the buffer from the
+ location; when READBUF is non-NULL, fill the buffer from the
corresponding register return-value location. */
-static enum return_value_convention
-ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
- const void *inval, void *outval)
+enum return_value_convention
+ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, gdb_byte *readbuf,
+ const gdb_byte *writebuf)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* This function exists to support a calling convention that
+ requires floating-point registers. It shouldn't be used on
+ processors that lack them. */
+ gdb_assert (ppc_floating_point_unit_p (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)
+ gdb_byte regval[MAX_REGISTER_SIZE];
+ struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum);
+ if (writebuf != NULL)
{
- convert_typed_floating (inval, valtype, regval, regtype);
- regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
+ convert_typed_floating (writebuf, valtype, regval, regtype);
+ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, regval);
}
- if (outval != NULL)
+ if (readbuf != NULL)
{
- regcache_cooked_read (regcache, FP0_REGNUM + 1, regval);
- convert_typed_floating (regval, regtype, outval, valtype);
+ regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval);
+ convert_typed_floating (regval, regtype, readbuf, valtype);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
- if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 8)
+ /* Integers in r3. */
+ if ((TYPE_CODE (valtype) == TYPE_CODE_INT
+ || TYPE_CODE (valtype) == TYPE_CODE_ENUM)
+ && TYPE_LENGTH (valtype) <= 8)
{
- /* Integers in r3. */
- if (inval != NULL)
+ if (writebuf != NULL)
{
/* Be careful to sign extend the value. */
regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
- unpack_long (valtype, inval));
+ unpack_long (valtype, writebuf));
}
- if (outval != NULL)
+ if (readbuf != 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);
+ store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), regval);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
@@ -894,44 +1159,57 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
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);
+ if (writebuf != NULL)
+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
+ if (readbuf != NULL)
+ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
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)
+ /* Array type has more than one use. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
{
/* 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;
+ if (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, tdep->ppc_gp0_regnum + 3)
+ - TYPE_LENGTH (valtype));
+ if (writebuf != NULL)
+ regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3,
+ offset, TYPE_LENGTH (valtype), writebuf);
+ if (readbuf != NULL)
+ regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3,
+ offset, TYPE_LENGTH (valtype), readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ /* A VMX vector is returned in v2. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (valtype) && tdep->ppc_vr0_regnum >= 0)
+ {
+ if (readbuf)
+ regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf);
+ if (writebuf)
+ regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, writebuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
}
/* Big floating point values get stored in adjacent floating
- point registers. */
+ point registers, starting with F1. */
if (TYPE_CODE (valtype) == TYPE_CODE_FLT
&& (TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 32))
{
- if (inval || outval != NULL)
+ if (writebuf || readbuf != 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);
+ if (writebuf != NULL)
+ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
+ (const bfd_byte *) writebuf + i * 8);
+ if (readbuf != NULL)
+ regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
+ (bfd_byte *) readbuf + i * 8);
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
@@ -945,22 +1223,25 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
int i;
for (i = 0; i < 2; i++)
{
- char regval[MAX_REGISTER_SIZE];
+ gdb_byte regval[MAX_REGISTER_SIZE];
struct type *regtype =
- register_type (current_gdbarch, FP0_REGNUM);
- if (inval != NULL)
+ register_type (gdbarch, tdep->ppc_fp0_regnum);
+ if (writebuf != NULL)
{
- convert_typed_floating ((const bfd_byte *) inval +
+ convert_typed_floating ((const bfd_byte *) writebuf +
i * (TYPE_LENGTH (valtype) / 2),
valtype, regval, regtype);
- regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
+ regcache_cooked_write (regcache,
+ tdep->ppc_fp0_regnum + 1 + i,
regval);
}
- if (outval != NULL)
+ if (readbuf != NULL)
{
- regcache_cooked_read (regcache, FP0_REGNUM + 1 + i, regval);
+ regcache_cooked_read (regcache,
+ tdep->ppc_fp0_regnum + 1 + i,
+ regval);
convert_typed_floating (regval, regtype,
- (bfd_byte *) outval +
+ (bfd_byte *) readbuf +
i * (TYPE_LENGTH (valtype) / 2),
valtype);
}
@@ -976,12 +1257,12 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
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);
+ if (writebuf != NULL)
+ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
+ (const bfd_byte *) writebuf + i * 8);
+ if (readbuf != NULL)
+ regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
+ (bfd_byte *) readbuf + i * 8);
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
@@ -989,27 +1270,20 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
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)
+CORE_ADDR
+ppc64_sysv_abi_adjust_breakpoint_address (struct gdbarch *gdbarch,
+ CORE_ADDR bpaddr)
{
- if (!ppc64_sysv_abi_return_value (valtype, regbuf, valbuf, NULL))
- error ("Function return value location unknown");
+ /* PPC64 SYSV specifies that the minimal-symbol "FN" should point at
+ a function-descriptor while the corresponding minimal-symbol
+ ".FN" should point at the entry point. Consequently, a command
+ like "break FN" applied to an object file with only minimal
+ symbols, will insert the breakpoint into the descriptor at "FN"
+ and not the function at ".FN". Avoid this confusion by adjusting
+ any attempt to set a descriptor breakpoint into a corresponding
+ function breakpoint. Note that GDB warns the user when this
+ adjustment is applied - that's ok as otherwise the user will have
+ no way of knowing why their breakpoint at "FN" resulted in the
+ program stopping at ".FN". */
+ return gdbarch_convert_from_func_ptr_addr (gdbarch, bpaddr, ¤t_target);
}