X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fppc-sysv-tdep.c;h=3d5a7dbb8e498bd6229d224d0b9ec421a7bbce83;hb=d80b854b33baf5ebc3940cd5928dc06c8708750d;hp=048bb707f320f75675eeb7eeb6dc4654f8754618;hpb=197e01b6dcd118b70ed3621b62b2ff3fa929d50f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c index 048bb707f3..3d5a7dbb8e 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 (C) 2000, 2001, 2002, 2003, 2005 + Copyright (C) 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2009 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., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, 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, @@ -126,38 +129,64 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } else { - /* SysV ABI converts floats to doubles before - writing them to an 8 byte aligned stack location. */ - argoffset = align_up (argoffset, 8); + /* The SysV ABI tells us to convert floats to + doubles before writing them to an 8 byte aligned + stack location. Unfortunately GCC does not do + that, and stores floats into 4 byte aligned + locations without converting them to doubles. + Since there is no know compiler that actually + follows the ABI here, we implement the GCC + convention. */ + + /* Align to 4 bytes or 8 bytes depending on the type of + the argument (float or double). */ + argoffset = align_up (argoffset, len); 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); write_memory (sp + argoffset, val, len); + argoffset += len; + } + } + else if (TYPE_CODE (type) == TYPE_CODE_FLT + && len == 16 + && !tdep->soft_float + && (gdbarch_long_double_format (gdbarch) + == floatformats_ibm_long_double)) + { + /* 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); } - argoffset += 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 */ - || (!ppc_floating_point_unit_p (current_gdbarch) && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */ + else if (len == 8 + && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */ + || TYPE_CODE (type) == TYPE_CODE_FLT /* double */ + || (TYPE_CODE (type) == TYPE_CODE_DECFLOAT + && tdep->soft_float))) { - /* "long long" or "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 - aligned stack location. */ + /* "long long" or soft-float "double" or "_Decimal64" + 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 aligned stack + location. */ if (greg > 9) { /* Just in case GREG was 10. */ @@ -167,13 +196,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 +213,130 @@ 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)) + || (TYPE_CODE (type) == TYPE_CODE_DECFLOAT + && tdep->soft_float))) + { + /* Soft-float IBM long double or _Decimal128 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 (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && len <= 8 + && !tdep->soft_float) + { + /* 32-bit and 64-bit decimal floats go in f1 .. f8. They can + end up in memory. */ + + if (freg <= 8) + { + if (write_pass) + { + gdb_byte regval[MAX_REGISTER_SIZE]; + const gdb_byte *p; + + /* 32-bit decimal floats are right aligned in the + doubleword. */ + if (TYPE_LENGTH (type) == 4) + { + memcpy (regval + 4, val, 4); + p = regval; + } + else + p = val; + + regcache_cooked_write (regcache, + tdep->ppc_fp0_regnum + freg, p); + } + + freg++; + } + else + { + argoffset = align_up (argoffset, len); + + if (write_pass) + /* Write value in the stack's parameter save area. */ + write_memory (sp + argoffset, val, len); + + argoffset += len; + } + } + else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && len == 16 + && !tdep->soft_float) + { + /* 128-bit decimal floats go in f2 .. f7, always in even/odd + pairs. They can end up in memory, using two doublewords. */ + + if (freg <= 6) + { + /* Make sure freg is even. */ + freg += freg & 1; + + 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); + } + } + else + { + argoffset = align_up (argoffset, 8); + + if (write_pass) + write_memory (sp + argoffset, val, 16); + + argoffset += 16; + } + + /* If a 128-bit decimal float goes to the stack because only f7 + and f8 are free (thus there's no even/odd register pair + available), these registers should be marked as occupied. + Hence we increase freg even when writing to memory. */ + freg += 2; + } 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 +350,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 +363,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 +385,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 +459,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); @@ -328,6 +471,70 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, return sp; } +/* Handle the return-value conventions for Decimal Floating Point values + in both ppc32 and ppc64, which are the same. */ +static int +get_decimal_float_return_value (struct gdbarch *gdbarch, struct type *valtype, + struct regcache *regcache, gdb_byte *readbuf, + const gdb_byte *writebuf) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + gdb_assert (TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT); + + /* 32-bit and 64-bit decimal floats in f1. */ + if (TYPE_LENGTH (valtype) <= 8) + { + if (writebuf != NULL) + { + gdb_byte regval[MAX_REGISTER_SIZE]; + const gdb_byte *p; + + /* 32-bit decimal float is right aligned in the doubleword. */ + if (TYPE_LENGTH (valtype) == 4) + { + memcpy (regval + 4, writebuf, 4); + p = regval; + } + else + p = writebuf; + + regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, p); + } + if (readbuf != NULL) + { + regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, readbuf); + + /* Left align 32-bit decimal float. */ + if (TYPE_LENGTH (valtype) == 4) + memcpy (readbuf, readbuf + 4, 4); + } + } + /* 128-bit decimal floats in f2,f3. */ + else if (TYPE_LENGTH (valtype) == 16) + { + if (writebuf != NULL || readbuf != NULL) + { + int i; + + for (i = 0; i < 2; i++) + { + if (writebuf != NULL) + regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 2 + i, + writebuf + i * 8); + if (readbuf != NULL) + regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 2 + i, + readbuf + i * 8); + } + } + } + else + /* Can't happen. */ + internal_error (__FILE__, __LINE__, "Unknown decimal float size."); + + return RETURN_VALUE_REGISTER_CONVENTION; +} + /* Handle the return-value conventions specified by the SysV 32-bit PowerPC ABI (including all the supplements): @@ -345,14 +552,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,29 +582,90 @@ 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_LENGTH (type) == 16 + && ((TYPE_CODE (type) == TYPE_CODE_FLT + && (gdbarch_long_double_format (gdbarch) == floatformats_ibm_long_double)) + || (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && tdep->soft_float))) + { + /* Soft-float IBM long double or _Decimal128 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)) + || (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8) + || (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && TYPE_LENGTH (type) == 8 + && tdep->soft_float)) { if (readbuf) { - /* A long long, or a double stored in the 32 bit r3/r4. */ + /* A long long, double or _Decimal64 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. */ + /* A long long, double or _Decimal64 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) + if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && !tdep->soft_float) + return get_decimal_float_return_value (gdbarch, type, regcache, readbuf, + writebuf); + 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 +688,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 +703,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 @@ -515,9 +817,9 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type, } 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) +ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type, + struct type *valtype, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) { return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf, writebuf, 0); @@ -525,6 +827,7 @@ ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype, enum return_value_convention ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch, + struct type *func_type, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) @@ -588,11 +891,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 +910,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 @@ -640,7 +951,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, { /* During the first pass, GPARAM and VPARAM are more like offsets (start address zero) than addresses. That way - the accumulate the total stack space each region + they accumulate the total stack space each region requires. */ gparam = 0; vparam = 0; @@ -677,6 +988,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct value *arg = args[argno]; 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 @@ -684,40 +996,144 @@ 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) + gdb_byte regval[MAX_REGISTER_SIZE]; + const gdb_byte *p; + + /* Version 1.7 of the 64-bit PowerPC ELF ABI says: + + "Single precision floating point values are mapped to + the first word in a single doubleword." + + And version 1.9 says: + + "Single precision floating point values are mapped to + the second word in a single doubleword." + + GDB then writes single precision floating point values + at both words in a doubleword, to support both ABIs. */ + if (TYPE_LENGTH (type) == 4) + { + memcpy (regval, val, 4); + memcpy (regval + 4, val, 4); + p = regval; + } + else + p = val; + + /* Write value in the stack's parameter save area. */ + write_memory (gparam, p, 8); + + if (freg <= 13) { - 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); } + if (greg <= 10) + regcache_cooked_write (regcache, + tdep->ppc_gp0_regnum + greg, + regval); + } + + freg++; + greg++; + /* Always consume parameter stack space. */ + gparam = align_up (gparam + 8, 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) { - /* The ABI states "Single precision floating - point values are mapped to the first word in - a single doubleword" and "... floating point - values mapped to the first eight doublewords - of the parameter save area are also passed in - general registers"). - - This code interprets that to mean: store it, - left aligned, in the general register. */ - gdb_byte regval[MAX_REGISTER_SIZE]; - memset (regval, 0, sizeof regval); - memcpy (regval, val, TYPE_LENGTH (type)); regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, - regval); + val); + if (greg <= 9) + regcache_cooked_write (regcache, + tdep->ppc_gp0_regnum + greg + 1, + val + 8); } write_memory (gparam, val, TYPE_LENGTH (type)); } - /* Always consume parameter stack space. */ + freg += 2; + greg += 2; + gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); + } + else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT + && TYPE_LENGTH (type) <= 8) + { + /* 32-bit and 64-bit decimal floats go in f1 .. f13. They can + end up in memory. */ + if (write_pass) + { + gdb_byte regval[MAX_REGISTER_SIZE]; + const gdb_byte *p; + + /* 32-bit decimal floats are right aligned in the + doubleword. */ + if (TYPE_LENGTH (type) == 4) + { + memcpy (regval + 4, val, 4); + p = regval; + } + else + p = val; + + /* Write value in the stack's parameter save area. */ + write_memory (gparam, p, 8); + + if (freg <= 13) + regcache_cooked_write (regcache, + tdep->ppc_fp0_regnum + freg, p); + } + freg++; greg++; + /* Always consume parameter stack space. */ + gparam = align_up (gparam + 8, tdep->wordsize); + } + else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && + TYPE_LENGTH (type) == 16) + { + /* 128-bit decimal floats go in f2 .. f12, always in even/odd + pairs. They can end up in memory, using two doublewords. */ + if (write_pass) + { + if (freg <= 12) + { + /* Make sure freg is even. */ + freg += freg & 1; + regcache_cooked_write (regcache, + tdep->ppc_fp0_regnum + freg, val); + regcache_cooked_write (regcache, + tdep->ppc_fp0_regnum + freg + 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) @@ -745,7 +1161,10 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } else if ((TYPE_CODE (type) == TYPE_CODE_INT || TYPE_CODE (type) == TYPE_CODE_ENUM - || TYPE_CODE (type) == TYPE_CODE_PTR) + || TYPE_CODE (type) == TYPE_CODE_BOOL + || TYPE_CODE (type) == TYPE_CODE_CHAR + || TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF) && TYPE_LENGTH (type) <= 8) { /* Scalars and Pointers get sign[un]extended and go in @@ -757,11 +1176,18 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Convert any function code addresses into descriptors. */ if (TYPE_CODE (type) == TYPE_CODE_PTR - && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC) + || TYPE_CODE (type) == TYPE_CODE_REF) { - CORE_ADDR desc = word; - convert_code_addr_to_desc_addr (word, &desc); - word = desc; + struct type *target_type; + target_type = check_typedef (TYPE_TARGET_TYPE (type)); + + if (TYPE_CODE (target_type) == TYPE_CODE_FUNC + || TYPE_CODE (target_type) == TYPE_CODE_METHOD) + { + CORE_ADDR desc = word; + convert_code_addr_to_desc_addr (word, &desc); + word = desc; + } } if (greg <= 10) regcache_cooked_write_unsigned (regcache, @@ -786,40 +1212,87 @@ 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++; } if (write_pass) - /* WARNING: cagney/2003-09-21: Strictly speaking, this - isn't necessary, unfortunately, GCC appears to get - "struct convention" parameter passing wrong putting - odd sized structures in memory instead of in a - register. Work around this by always writing the - 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. */ + { + /* WARNING: cagney/2003-09-21: Strictly speaking, this + isn't necessary, unfortunately, GCC appears to get + "struct convention" parameter passing wrong putting + odd sized structures in memory instead of in a + register. Work around this by always writing the + value to memory. Fortunately, doing this + simplifies the code. */ + int len = TYPE_LENGTH (type); + if (len < tdep->wordsize) + write_memory (gparam + tdep->wordsize - len, val, len); + else + write_memory (gparam, val, len); + } + 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 +1312,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 +1340,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., @@ -878,9 +1351,9 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, location; when READBUF is non-NULL, fill the buffer from the corresponding register return-value location. */ 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) +ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type, + struct type *valtype, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); @@ -906,9 +1379,14 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype, } return RETURN_VALUE_REGISTER_CONVENTION; } + if (TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT) + return get_decimal_float_return_value (gdbarch, valtype, regcache, readbuf, + writebuf); /* Integers in r3. */ if ((TYPE_CODE (valtype) == TYPE_CODE_INT - || TYPE_CODE (valtype) == TYPE_CODE_ENUM) + || TYPE_CODE (valtype) == TYPE_CODE_ENUM + || TYPE_CODE (valtype) == TYPE_CODE_CHAR + || TYPE_CODE (valtype) == TYPE_CODE_BOOL) && TYPE_LENGTH (valtype) <= 8) { if (writebuf != NULL) @@ -929,7 +1407,8 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype, return RETURN_VALUE_REGISTER_CONVENTION; } /* All pointers live in r3. */ - if (TYPE_CODE (valtype) == TYPE_CODE_PTR) + if (TYPE_CODE (valtype) == TYPE_CODE_PTR + || TYPE_CODE (valtype) == TYPE_CODE_REF) { /* All pointers live in r3. */ if (writebuf != NULL) @@ -998,7 +1477,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 + @@ -1043,20 +1522,3 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype, return RETURN_VALUE_STRUCT_CONVENTION; } -CORE_ADDR -ppc64_sysv_abi_adjust_breakpoint_address (struct gdbarch *gdbarch, - CORE_ADDR bpaddr) -{ - /* 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); -}