X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gdb%2Fppc-sysv-tdep.c;h=c2952f5c8b8b4a57865c32ca7c3dc747b2bd09eb;hb=9b254dd1ce46c19dde1dde5b8d1e22e862dfacce;hp=4285077e4362dd2835ac28ffdf5e8337c8112615;hpb=61bf9ae086ed8e0107ab376dd19659e6f1c923a0;p=thirdparty%2Fbinutils-gdb.git
diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c
index 4285077e436..c2952f5c8b8 100644
--- a/gdb/ppc-sysv-tdep.c
+++ b/gdb/ppc-sysv-tdep.c
@@ -1,14 +1,14 @@
/* Target-dependent code for PowerPC systems using the SVR4 ABI
for GDB, the GNU debugger.
- Copyright 2000, 2001, 2002, 2003, 2005
+ 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,
@@ -17,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"
@@ -50,11 +48,16 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
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
@@ -102,8 +105,8 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
int len = TYPE_LENGTH (type);
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,
@@ -132,28 +135,47 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
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
@@ -167,13 +189,6 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
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. */
@@ -191,16 +206,52 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
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++;
}
@@ -214,7 +265,8 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
}
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
@@ -226,7 +278,7 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
if (greg <= 10)
{
if (write_pass)
- regcache_cooked_write (current_regcache,
+ regcache_cooked_write (regcache,
tdep->ppc_ev0_regnum + greg, val);
greg++;
}
@@ -248,9 +300,15 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|| 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
@@ -316,7 +374,7 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
}
/* 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);
@@ -345,14 +403,14 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
static enum return_value_convention
do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, void *readbuf,
- const void *writebuf, int broken_gcc)
+ struct regcache *regcache, gdb_byte *readbuf,
+ const gdb_byte *writebuf, int broken_gcc)
{
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 (gdbarch))
+ && !tdep->soft_float)
{
if (readbuf)
{
@@ -375,6 +433,53 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
}
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))
{
@@ -382,22 +487,27 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
{
/* A long long, or a double stored in the 32 bit r3/r4. */
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
- (bfd_byte *) readbuf + 0);
+ readbuf + 0);
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
- (bfd_byte *) readbuf + 4);
+ readbuf + 4);
}
if (writebuf)
{
/* A long long, or a double stored in the 32 bit r3/r4. */
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
- (const bfd_byte *) writebuf + 0);
+ writebuf + 0);
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
- (const bfd_byte *) writebuf + 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 (readbuf)
{
@@ -420,7 +530,8 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
}
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 (readbuf)
{
@@ -434,9 +545,42 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
}
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
@@ -588,11 +732,8 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
int struct_return, CORE_ADDR struct_addr)
{
CORE_ADDR func_addr = find_function_addr (function, NULL);
- 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 ();
+ 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
@@ -610,6 +751,17 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
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
@@ -684,8 +836,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
memory. */
if (write_pass)
{
- if (ppc_floating_point_unit_p (current_gdbarch)
- && freg <= 13)
+ if (freg <= 13)
{
gdb_byte regval[MAX_REGISTER_SIZE];
struct type *regtype
@@ -720,6 +871,41 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
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)
@@ -786,22 +972,17 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
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++;
@@ -815,11 +996,57 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
value to memory. Fortunately, doing this
simplifies the code. */
write_memory (gparam, val, TYPE_LENGTH (type));
- if (write_pass)
- /* WARNING: cagney/2004-06-20: It appears that GCC
- likes to put structures containing a single
- floating-point member in an FP register instead of
- general general purpose. */
+ 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);
}
@@ -839,7 +1066,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
}
/* 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);
@@ -867,7 +1094,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
}
-/* 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.,
@@ -906,11 +1133,11 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
+ /* Integers in r3. */
if ((TYPE_CODE (valtype) == TYPE_CODE_INT
|| TYPE_CODE (valtype) == TYPE_CODE_ENUM)
&& TYPE_LENGTH (valtype) <= 8)
{
- /* Integers in r3. */
if (writebuf != NULL)
{
/* Be careful to sign extend the value. */
@@ -938,24 +1165,37 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
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 (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;
+ 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))
{
@@ -985,7 +1225,7 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
{
gdb_byte regval[MAX_REGISTER_SIZE];
struct type *regtype =
- register_type (current_gdbarch, tdep->ppc_fp0_regnum);
+ register_type (gdbarch, tdep->ppc_fp0_regnum);
if (writebuf != NULL)
{
convert_typed_floating ((const bfd_byte *) writebuf +