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 +