This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Fix ppc64 structs ABI issue
- From: "Joseph S. Myers" <joseph at codesourcery dot com>
- To: gdb-patches at sourceware dot org
- Date: Fri, 26 Oct 2007 00:37:36 +0000 (UTC)
- Subject: Fix ppc64 structs ABI issue
A number of the gdb.base/structs.exp tests fail for 64-bit Power
because GDB does not implement the currently specified and implemented
ABI
<http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html>.
There are two specific ABI problems:
* GDB is expecting GCC bugs fixed in 3.4 and had comments that appear
to relate to an ABI version 1.5 or older (the revision history for
1.6 says "structure passing" as what's fixed).
* GDB fails to allow for the rule about single-element structs
containing floating point values (version 1.8 says "single element
FP structs", presumably the ABI was fixed to agree with the
implementation), with a comment describing this as a GCC bug
instead. (Said comment also appeared as the sole contents of an if,
if (write_pass)
/* comment */
next statement;
so it seems that statement was unintentionally conditional.)
I think the right thing to do here is to implement the ABI as it now
is documented and implemented, and not try to allow for the bugs of
very old compilers. This is what this patch does.
The ABI rule on single-element structs applies to those where the
floating-point value is at any level of nesting of single-element
structs, but does not apply to unions.
This patch is relative to a tree with both Daniel's ABI detection
patch and my IBM long double patch
<http://sourceware.org/ml/gdb-patches/2007-10/msg00687.html>. Tested
with cross to powerpc-linux-gnu, -m64. OK to commit once those
previous patches are in?
2007-10-25 Joseph Myers <joseph@codesourcery.com>
Daniel Jacobowitz <dan@codesourcery.com>
* ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): Right-align
struct values smaller than one doubleword; left-align those
larger. Pass structs containing a single floating-point value in
registers.
diff -rupN gdb-mainline/gdb/ppc-sysv-tdep.c gdb-mainline.ppc64/gdb/ppc-sysv-tdep.c
--- gdb-mainline/gdb/ppc-sysv-tdep.c 2007-10-25 15:08:22.000000000 -0700
+++ gdb-mainline.ppc64/gdb/ppc-sysv-tdep.c 2007-10-25 16:24:51.000000000 -0700
@@ -939,22 +939,17 @@ ppc64_sysv_abi_push_dummy_call (struct g
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
+ <http://gcc.gnu.org/gcc-3.4/powerpc-abi.html>. */
+ if (byte == 0)
memcpy (regval + tdep->wordsize - len,
val + byte, len);
+ else
+ memcpy (regval, val + byte, len);
regcache_cooked_write (regcache, greg, regval);
}
greg++;
@@ -968,11 +963,57 @@ ppc64_sysv_abi_push_dummy_call (struct g
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 (current_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);
}
--
Joseph S. Myers
joseph@codesourcery.com