[ia64] small integral parameters and return values
authorJoel Brobecker <brobecker@gnat.com>
Thu, 13 Jan 2011 16:23:00 +0000 (16:23 +0000)
committerJoel Brobecker <brobecker@gnat.com>
Thu, 13 Jan 2011 16:23:00 +0000 (16:23 +0000)
This patch fixes a small problem on ia64-hpux when calling functions
whose parameter are small integral values (less than 8 bytes).  In
that case, the parameter value was stored on the wrong side of the
register.  Same problem for return values.

With this patch, the results for gdb.base/callfuncs.exp improve from

        # of expected passes            41
        # of unexpected failures        78

To:

        # of expected passes            95
        # of unexpected failures        24

gdb/ChangeLog:

        * ia64-tdep.c (ia64_struct_type_p): New function.
        (ia64_extract_return_value): Handle integral values that are
        less than 8 bytes long.
        (ia64_push_dummy_call): Likewise.

gdb/ChangeLog
gdb/ia64-tdep.c

index c548a19..e52214d 100644 (file)
@@ -1,5 +1,12 @@
 2011-01-13  Joel Brobecker  <brobecker@adacore.com>
 
+       * ia64-tdep.c (ia64_struct_type_p): New function.
+       (ia64_extract_return_value): Handle integral values that are
+       less than 8 bytes long.
+       (ia64_push_dummy_call): Likewise.
+
+2011-01-13  Joel Brobecker  <brobecker@adacore.com>
+
        * ia64-tdep.c (floatformat_ia64_ext_little): Renames
        floatformat_ia64_ext.
        (floatformat_ia64_ext_big): New static const.
index 81d42b6..05ca3a1 100644 (file)
@@ -3177,6 +3177,15 @@ ia64_use_struct_convention (struct type *type)
   return TYPE_LENGTH (type) > 32;
 }
 
+/* Return non-zero if TYPE is a structure or union type.  */
+
+static int
+ia64_struct_type_p (const struct type *type)
+{
+  return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+          || TYPE_CODE (type) == TYPE_CODE_UNION);
+}
+
 static void
 ia64_extract_return_value (struct type *type, struct regcache *regcache,
                           gdb_byte *valbuf)
@@ -3201,6 +3210,21 @@ ia64_extract_return_value (struct type *type, struct regcache *regcache,
          regnum++;
        }
     }
+  else if (!ia64_struct_type_p (type) && TYPE_LENGTH (type) < 8)
+    {
+      /* This is an integral value, and its size is less than 8 bytes.
+         These values are LSB-aligned, so extract the relevant bytes,
+         and copy them into VALBUF.  */
+      /* brobecker/2005-12-30: Actually, all integral values are LSB aligned,
+        so I suppose we should also add handling here for integral values
+        whose size is greater than 8.  But I wasn't able to create such
+        a type, neither in C nor in Ada, so not worrying about these yet.  */
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      ULONGEST val;
+
+      regcache_cooked_read_unsigned (regcache, IA64_GR8_REGNUM, &val);
+      store_unsigned_integer (valbuf, TYPE_LENGTH (type), byte_order, val);
+    }
   else
     {
       ULONGEST val;
@@ -3705,8 +3729,30 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
          char val_buf[8];
 
          memset (val_buf, 0, 8);
-         memcpy (val_buf, value_contents (arg) + argoffset,
-                 (len > 8) ? 8 : len);
+          if (!ia64_struct_type_p (type) && len < 8)
+            {
+              /* Integral types are LSB-aligned, so we have to be careful
+                 to insert the argument on the correct side of the buffer.
+                 This is why we use store_unsigned_integer.  */
+              store_unsigned_integer
+                (val_buf, 8, byte_order,
+                 extract_unsigned_integer (value_contents (arg), len,
+                                          byte_order));
+            }
+          else
+            {
+              /* This is either an 8bit integral type, or an aggregate.
+                 For 8bit integral type, there is no problem, we just
+                 copy the value over.
+
+                 For aggregates, the only potentially tricky portion
+                 is to write the last one if it is less than 8 bytes.
+                 In this case, the data is Byte0-aligned.  Happy news,
+                 this means that we don't need to differentiate the
+                 handling of 8byte blocks and less-than-8bytes blocks.  */
+              memcpy (val_buf, value_contents (arg) + argoffset,
+                      (len > 8) ? 8 : len);
+            }
 
          if (slotnum < rseslots)
            write_memory (rse_address_add (bsp, slotnum), val_buf, 8);