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); }