This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] gdb passes and returns incorrect values when dealing with small array on Sparc


From: Vladimir Mezentsev <vladimir.mezentsev@oracle.com>

	gdb has a special type (TYPE_CODE_ARRAY) to support the gcc extension
	(https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html).
	TYPE_CODE_ARRAY is handled incorrectly for both (32- and 64-bit) modes on Sparc machines.

	Tested on sparc64-linux-gnu and sparc-solaris (32- and 64-bit mode).
	No regressions.

	2017-03-27 Vladimir Mezentsev <vladimir.mezentsev@oracle.com>

	* gdb/sparc-tdep.c (sparc_structure_return_p): New function.
	* gdb/sparc-tdep.c (sparc_arg_on_registers_p): Likewise.
	* gdb/sparc-tdep.c (sparc32_store_arguments): Use the new functions.
	* gdb/sparc64-tdep.c: (sparc64_16_byte_align_p): Handle TYPE_CODE_ARRAY
	* gdb/sparc64-tdep.c: (sparc64_store_floating_fields): Likewise
	* gdb/sparc64-tdep.c: (sparc64_extract_floating_fields): Likewise
---
 gdb/sparc-tdep.c   |   68 +++++++++++++++++++++++++++++++++++++++-------------
 gdb/sparc64-tdep.c |   42 ++++++++++++++++++++++++++++++-
 2 files changed, 91 insertions(+), 19 deletions(-)

diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c
index d346aec..07808f3 100644
--- a/gdb/sparc-tdep.c
+++ b/gdb/sparc-tdep.c
@@ -297,6 +297,39 @@ sparc_structure_or_union_p (const struct type *type)
   return 0;
 }
 
+static int
+sparc_structure_return_p (const struct type *type)
+{
+  if ((TYPE_CODE (type) == TYPE_CODE_ARRAY) && (TYPE_LENGTH (type) <= 8))
+    {
+      struct type *t = check_typedef (TYPE_TARGET_TYPE (type));
+
+      if (sparc_floating_p (t) && (TYPE_LENGTH (t) == 8))
+        return 1;
+      return 0;
+    }
+  if (sparc_floating_p (type) && (TYPE_LENGTH (type) == 16))
+    return 1;
+  return sparc_structure_or_union_p (type);
+}
+
+static int
+sparc_arg_on_registers_p (const struct type *type)
+{
+  if ((TYPE_CODE (type) == TYPE_CODE_ARRAY) && (TYPE_LENGTH (type) <= 8))
+    {
+      struct type *t = check_typedef (TYPE_TARGET_TYPE (type));
+
+      if (sparc_floating_p (t) && (TYPE_LENGTH (t) == 8))
+        return 0;
+      return 1;
+    }
+  if (sparc_structure_or_union_p (type) || sparc_complex_floating_p (type)
+      || (sparc_floating_p (type) && (TYPE_LENGTH (type) == 16)))
+    return 0;
+  return 1;
+}
+
 /* Register information.  */
 #define SPARC32_FPU_REGISTERS                             \
   "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",         \
@@ -569,9 +602,7 @@ sparc32_store_arguments (struct regcache *regcache, int nargs,
       struct type *type = value_type (args[i]);
       int len = TYPE_LENGTH (type);
 
-      if (sparc_structure_or_union_p (type)
-	  || (sparc_floating_p (type) && len == 16)
-	  || sparc_complex_floating_p (type))
+      if (!sparc_arg_on_registers_p (type))
 	{
 	  /* Structure, Union and Quad-Precision Arguments.  */
 	  sp -= len;
@@ -593,11 +624,8 @@ sparc32_store_arguments (struct regcache *regcache, int nargs,
       else
 	{
 	  /* Integral and pointer arguments.  */
-	  gdb_assert (sparc_integral_or_pointer_p (type));
-
-	  if (len < 4)
-	    args[i] = value_cast (builtin_type (gdbarch)->builtin_int32,
-				  args[i]);
+	  gdb_assert (sparc_integral_or_pointer_p (type) ||
+                      ((TYPE_CODE (type) == TYPE_CODE_ARRAY) && (len <= 8)));
 	  num_elements += ((len + 3) / 4);
 	}
     }
@@ -619,6 +647,15 @@ sparc32_store_arguments (struct regcache *regcache, int nargs,
       const bfd_byte *valbuf = value_contents (args[i]);
       struct type *type = value_type (args[i]);
       int len = TYPE_LENGTH (type);
+      gdb_byte buf[4];
+
+      if (len < 4)
+        {
+          memset (buf, 0, 4 - len);
+          memcpy (buf + 4 - len, valbuf, len);
+          valbuf = buf;
+          len = 4;
+        }
 
       gdb_assert (len == 4 || len == 8);
 
@@ -1344,10 +1381,10 @@ sparc32_extract_return_value (struct type *type, struct regcache *regcache,
   int len = TYPE_LENGTH (type);
   gdb_byte buf[32];
 
-  gdb_assert (!sparc_structure_or_union_p (type));
-  gdb_assert (!(sparc_floating_p (type) && len == 16));
+  gdb_assert (!sparc_structure_return_p (type));
 
-  if (sparc_floating_p (type) || sparc_complex_floating_p (type))
+  if (sparc_floating_p (type) || sparc_complex_floating_p (type) ||
+      (TYPE_CODE (type) == TYPE_CODE_ARRAY))
     {
       /* Floating return values.  */
       regcache_cooked_read (regcache, SPARC_F0_REGNUM, buf);
@@ -1396,11 +1433,9 @@ sparc32_store_return_value (struct type *type, struct regcache *regcache,
 			    const gdb_byte *valbuf)
 {
   int len = TYPE_LENGTH (type);
-  gdb_byte buf[8];
+  gdb_byte buf[32];
 
-  gdb_assert (!sparc_structure_or_union_p (type));
-  gdb_assert (!(sparc_floating_p (type) && len == 16));
-  gdb_assert (len <= 8);
+  gdb_assert (!sparc_structure_return_p (type));
 
   if (sparc_floating_p (type) || sparc_complex_floating_p (type))
     {
@@ -1456,8 +1491,7 @@ sparc32_return_value (struct gdbarch *gdbarch, struct value *function,
      guarantees that we can always find the return value, not just
      before the function returns.  */
 
-  if (sparc_structure_or_union_p (type)
-      || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16))
+  if (sparc_structure_return_p (type))
     {
       ULONGEST sp;
       CORE_ADDR addr;
diff --git a/gdb/sparc64-tdep.c b/gdb/sparc64-tdep.c
index bf0da18..0b1a0ee 100644
--- a/gdb/sparc64-tdep.c
+++ b/gdb/sparc64-tdep.c
@@ -669,6 +669,12 @@ static const struct frame_base sparc64_frame_base =
 static int
 sparc64_16_byte_align_p (struct type *type)
 {
+  if ((TYPE_CODE (type) == TYPE_CODE_ARRAY)) {
+    struct type *t = check_typedef (TYPE_TARGET_TYPE (type));
+
+    if (sparc64_floating_p (t))
+      return 1;
+  }
   if (sparc64_floating_p (type) && TYPE_LENGTH (type) == 16)
     return 1;
 
@@ -703,7 +709,23 @@ sparc64_store_floating_fields (struct regcache *regcache, struct type *type,
 
   gdb_assert (element < 16);
 
-  if (sparc64_floating_p (type)
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+    {
+      gdb_byte buf[8];
+      int regnum = SPARC_F0_REGNUM + element * 2 + bitpos / 32;
+
+      valbuf += (bitpos / 8);
+      if (len < 8)
+        {
+          memset (buf, 0, 8 - len);
+          memcpy (buf + 8 - len, valbuf, len);
+          valbuf = buf;
+          len = 8;
+        }
+      for (int n = 0; n < ((len + 3) / 4); n++)
+        regcache_cooked_write (regcache, regnum + n, valbuf + n * 4);
+    }
+  else if (sparc64_floating_p (type)
       || (sparc64_complex_floating_p (type) && len <= 16))
     {
       int regnum;
@@ -776,7 +798,23 @@ sparc64_extract_floating_fields (struct regcache *regcache, struct type *type,
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
 
-  if (sparc64_floating_p (type))
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+    {
+      int len = TYPE_LENGTH (type);
+      int regnum =  SPARC_F0_REGNUM + (bitpos / 32);
+
+      valbuf += (bitpos / 8);
+      if (len < 4)
+        {
+          gdb_byte buf[4];
+          regcache_cooked_read (regcache, regnum, buf);
+          memcpy (valbuf, buf + 4 - len, len);
+        }
+      else
+        for (int i = 0; i < ((len + 3) / 4); i++)
+          regcache_cooked_read (regcache, regnum + i, valbuf + i * 4);
+    }
+  else if (sparc64_floating_p (type))
     {
       int len = TYPE_LENGTH (type);
       int regnum;
-- 
1.7.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]