[PATCH 2/8] small integral parameters and return values

Joel Brobecker
2010-12-28T04:43:31Z

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.

Tested on both ia64-hpux and ia64-linux.

---
gdb/ia64-tdep.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 48 insertions(+), 1 deletions(-)

diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index 6e24c9e..1cd6a38 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -3143,6 +3143,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)
@@ -3167,6 +3176,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;
@@ -3671,7 +3695,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);
--
1.7.1