[1/2] aarch64: handle big endian float registers correctly

Message ID 1414379668-5351-2-git-send-email-victor.kamensky@linaro.org
State New
Headers show

Commit Message

vkamensky Oct. 27, 2014, 3:14 a.m.
In big endian case vreg memory is in big endian format and all
pseudo registers will be in big endian format. But all smaller
pseudo registers are at higher memory addresses (least siginificant
part of vreg memory).

Introduce reg_addr_in_vreg function would return correct address
of pseudo register memory depending on current target endianity.
aarch64_pseudo_read_value and aarch64_pseudo_write and other
functions use that function to get address within vreg to copy
into/from target pseudo register memory.

That fixes numerous floating point gdb testsuite failures on
aarch64 big endian target. For example gdb.base/structs.exp,
gdb.base/float.exp, gdb.base/call-ar-st.exp and many others.

gdb/ChangeLog:

2014-10-24  Victor Kamensky  <victor.kamensky@linaro.org>

	* aarch64-tdep.c (reg_addr_in_vreg): New function.
	(pass_in_v): Added type parameter. Use reg_addr_in_vreg
	to place memory in vreg depending on endianity and type
	size.
	(pass_in_v_or_stack): Pass type to pass_in_v function.
	(aarch64_push_dummy_call): Handle big endian case
	correctly.
	(aarch64_extract_return_value): Ditto.
	(aarch64_store_return_value): Ditto.
	(aarch64_pseudo_read_value): Ditto.
	(aarch64_pseudo_write): Ditto.
---
 gdb/aarch64-tdep.c | 57 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 36 insertions(+), 21 deletions(-)

Patch

diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 1898f6b..959035e 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -1382,6 +1382,16 @@  pass_in_x (struct gdbarch *gdbarch, struct regcache *regcache,
     }
 }
 
+static gdb_byte * reg_addr_in_vreg (struct gdbarch *gdbarch,
+				    gdb_byte *vreg_addr,
+				    size_t size)
+{
+  gdb_byte *ret = vreg_addr;
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    ret = vreg_addr + (V_REGISTER_SIZE - size);
+  return ret;
+}
+
 /* Attempt to marshall a value in a V register.  Return 1 if
    successful, or 0 if insufficient registers are available.  This
    function, unlike the equivalent pass_in_x() function does not
@@ -1391,17 +1401,21 @@  static int
 pass_in_v (struct gdbarch *gdbarch,
 	   struct regcache *regcache,
 	   struct aarch64_call_info *info,
+	   struct type *type,
 	   const bfd_byte *buf)
 {
   if (info->nsrn < 8)
     {
-      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      bfd_byte xbuf[V_REGISTER_SIZE];
+      int len = TYPE_LENGTH (type);
+      int copy_len = len > V_REGISTER_SIZE ? V_REGISTER_SIZE : len;
       int regnum = AARCH64_V0_REGNUM + info->nsrn;
 
       info->argnum++;
       info->nsrn++;
 
-      regcache_cooked_write (regcache, regnum, buf);
+      memcpy (reg_addr_in_vreg (gdbarch, xbuf, copy_len), buf, copy_len);
+      regcache_cooked_write (regcache, regnum, xbuf);
       if (aarch64_debug)
 	fprintf_unfiltered (gdb_stdlog, "arg %d in %s\n",
 			    info->argnum,
@@ -1491,7 +1505,7 @@  pass_in_v_or_stack (struct gdbarch *gdbarch,
 		    struct type *type,
 		    const bfd_byte *buf)
 {
-  if (!pass_in_v (gdbarch, regcache, info, buf))
+  if (!pass_in_v (gdbarch, regcache, info, type, buf))
     pass_on_stack (info, type, buf);
 }
 
@@ -1616,8 +1630,8 @@  aarch64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 	      struct type *target_type =
 		check_typedef (TYPE_TARGET_TYPE (arg_type));
 
-	      pass_in_v (gdbarch, regcache, &info, buf);
-	      pass_in_v (gdbarch, regcache, &info,
+	      pass_in_v (gdbarch, regcache, &info, target_type, buf);
+	      pass_in_v (gdbarch, regcache, &info, target_type,
 			 buf + TYPE_LENGTH (target_type));
 	    }
 	  else
@@ -1925,7 +1939,7 @@  aarch64_extract_return_value (struct type *type, struct regcache *regs,
       int len = TYPE_LENGTH (type);
 
       regcache_cooked_read (regs, AARCH64_V0_REGNUM, buf);
-      memcpy (valbuf, buf, len);
+      memcpy (valbuf, reg_addr_in_vreg (gdbarch, buf, len), len);
     }
   else if (TYPE_CODE (type) == TYPE_CODE_INT
 	   || TYPE_CODE (type) == TYPE_CODE_CHAR
@@ -1961,10 +1975,10 @@  aarch64_extract_return_value (struct type *type, struct regcache *regs,
       int len = TYPE_LENGTH (target_type);
 
       regcache_cooked_read (regs, regno, buf);
-      memcpy (valbuf, buf, len);
+      memcpy (valbuf, reg_addr_in_vreg (gdbarch, buf, len), len);
       valbuf += len;
       regcache_cooked_read (regs, regno + 1, buf);
-      memcpy (valbuf, buf, len);
+      memcpy (valbuf, reg_addr_in_vreg (gdbarch, buf, len), len);
       valbuf += len;
     }
   else if (is_hfa (type))
@@ -1986,7 +2000,7 @@  aarch64_extract_return_value (struct type *type, struct regcache *regs,
 				gdbarch_register_name (gdbarch, regno));
 	  regcache_cooked_read (regs, regno, buf);
 
-	  memcpy (valbuf, buf, len);
+	  memcpy (valbuf, reg_addr_in_vreg (gdbarch, buf, len), len);
 	  valbuf += len;
 	}
     }
@@ -2058,8 +2072,9 @@  aarch64_store_return_value (struct type *type, struct regcache *regs,
     {
       bfd_byte buf[V_REGISTER_SIZE];
       int len = TYPE_LENGTH (type);
+      int copy_len = len > V_REGISTER_SIZE ? V_REGISTER_SIZE : len;
 
-      memcpy (buf, valbuf, len > V_REGISTER_SIZE ? V_REGISTER_SIZE : len);
+      memcpy (reg_addr_in_vreg (gdbarch, buf, copy_len), valbuf, copy_len);
       regcache_cooked_write (regs, AARCH64_V0_REGNUM, buf);
     }
   else if (TYPE_CODE (type) == TYPE_CODE_INT
@@ -2113,7 +2128,7 @@  aarch64_store_return_value (struct type *type, struct regcache *regs,
 				i + 1,
 				gdbarch_register_name (gdbarch, regno));
 
-	  memcpy (tmpbuf, valbuf, len);
+	  memcpy (reg_addr_in_vreg (gdbarch, tmpbuf, len), valbuf, len);
 	  regcache_cooked_write (regs, regno, tmpbuf);
 	  valbuf += len;
 	}
@@ -2360,7 +2375,7 @@  aarch64_pseudo_read_value (struct gdbarch *gdbarch,
 	mark_value_bytes_unavailable (result_value, 0,
 				      TYPE_LENGTH (value_type (result_value)));
       else
-	memcpy (buf, reg_buf, Q_REGISTER_SIZE);
+	memcpy (buf, reg_addr_in_vreg (gdbarch, reg_buf, Q_REGISTER_SIZE), Q_REGISTER_SIZE);
       return result_value;
     }
 
@@ -2375,7 +2390,7 @@  aarch64_pseudo_read_value (struct gdbarch *gdbarch,
 	mark_value_bytes_unavailable (result_value, 0,
 				      TYPE_LENGTH (value_type (result_value)));
       else
-	memcpy (buf, reg_buf, D_REGISTER_SIZE);
+	memcpy (buf, reg_addr_in_vreg (gdbarch, reg_buf, D_REGISTER_SIZE), D_REGISTER_SIZE);
       return result_value;
     }
 
@@ -2386,7 +2401,7 @@  aarch64_pseudo_read_value (struct gdbarch *gdbarch,
 
       v_regnum = AARCH64_V0_REGNUM + regnum - AARCH64_S0_REGNUM;
       status = regcache_raw_read (regcache, v_regnum, reg_buf);
-      memcpy (buf, reg_buf, S_REGISTER_SIZE);
+      memcpy (buf, reg_addr_in_vreg (gdbarch, reg_buf, S_REGISTER_SIZE), S_REGISTER_SIZE);
       return result_value;
     }
 
@@ -2401,7 +2416,7 @@  aarch64_pseudo_read_value (struct gdbarch *gdbarch,
 	mark_value_bytes_unavailable (result_value, 0,
 				      TYPE_LENGTH (value_type (result_value)));
       else
-	memcpy (buf, reg_buf, H_REGISTER_SIZE);
+	memcpy (buf, reg_addr_in_vreg (gdbarch, reg_buf, H_REGISTER_SIZE), H_REGISTER_SIZE);
       return result_value;
     }
 
@@ -2416,7 +2431,7 @@  aarch64_pseudo_read_value (struct gdbarch *gdbarch,
 	mark_value_bytes_unavailable (result_value, 0,
 				      TYPE_LENGTH (value_type (result_value)));
       else
-	memcpy (buf, reg_buf, B_REGISTER_SIZE);
+	memcpy (buf, reg_addr_in_vreg (gdbarch, reg_buf, B_REGISTER_SIZE), B_REGISTER_SIZE);
       return result_value;
     }
 
@@ -2445,7 +2460,7 @@  aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
       unsigned v_regnum;
 
       v_regnum = AARCH64_V0_REGNUM + regnum - AARCH64_Q0_REGNUM;
-      memcpy (reg_buf, buf, Q_REGISTER_SIZE);
+      memcpy (reg_addr_in_vreg (gdbarch, reg_buf, Q_REGISTER_SIZE), buf, Q_REGISTER_SIZE);
       regcache_raw_write (regcache, v_regnum, reg_buf);
       return;
     }
@@ -2456,7 +2471,7 @@  aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
       unsigned v_regnum;
 
       v_regnum = AARCH64_V0_REGNUM + regnum - AARCH64_D0_REGNUM;
-      memcpy (reg_buf, buf, D_REGISTER_SIZE);
+      memcpy (reg_addr_in_vreg (gdbarch, reg_buf, D_REGISTER_SIZE), buf, D_REGISTER_SIZE);
       regcache_raw_write (regcache, v_regnum, reg_buf);
       return;
     }
@@ -2466,7 +2481,7 @@  aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
       unsigned v_regnum;
 
       v_regnum = AARCH64_V0_REGNUM + regnum - AARCH64_S0_REGNUM;
-      memcpy (reg_buf, buf, S_REGISTER_SIZE);
+      memcpy (reg_addr_in_vreg (gdbarch, reg_buf, S_REGISTER_SIZE), buf, S_REGISTER_SIZE);
       regcache_raw_write (regcache, v_regnum, reg_buf);
       return;
     }
@@ -2477,7 +2492,7 @@  aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
       unsigned v_regnum;
 
       v_regnum = AARCH64_V0_REGNUM + regnum - AARCH64_H0_REGNUM;
-      memcpy (reg_buf, buf, H_REGISTER_SIZE);
+      memcpy (reg_addr_in_vreg (gdbarch, reg_buf, H_REGISTER_SIZE), buf, H_REGISTER_SIZE);
       regcache_raw_write (regcache, v_regnum, reg_buf);
       return;
     }
@@ -2488,7 +2503,7 @@  aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
       unsigned v_regnum;
 
       v_regnum = AARCH64_V0_REGNUM + regnum - AARCH64_B0_REGNUM;
-      memcpy (reg_buf, buf, B_REGISTER_SIZE);
+      memcpy (reg_addr_in_vreg (gdbarch, reg_buf, B_REGISTER_SIZE), buf, B_REGISTER_SIZE);
       regcache_raw_write (regcache, v_regnum, reg_buf);
       return;
     }