aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2004-02-22 19:22:37 +0000
committerAndrew Cagney <cagney@redhat.com>2004-02-22 19:22:37 +0000
commit537987fc729810448d405c6e47621cad06f5db4a (patch)
tree6ee313daf49135e24d6d5167e386c2b005ab4d81
parent10fc94a43ff647ddf1682bc242162e1ec40c44c3 (diff)
downloadfsf-binutils-gdb-537987fc729810448d405c6e47621cad06f5db4a.zip
fsf-binutils-gdb-537987fc729810448d405c6e47621cad06f5db4a.tar.gz
fsf-binutils-gdb-537987fc729810448d405c6e47621cad06f5db4a.tar.bz2
2004-02-22 Andrew Cagney <cagney@redhat.com>
* hppa-tdep.c (hppa32_return_value): New function. (hppa64_return_value): New function. (hppa_gdbarch_init): Set return_value; keep disabled.
-rw-r--r--gdb/ChangeLog4
-rw-r--r--gdb/hppa-tdep.c116
2 files changed, 120 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 501607b..7b5eb4c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -14,6 +14,10 @@
2004-02-22 Andrew Cagney <cagney@redhat.com>
+ * hppa-tdep.c (hppa32_return_value): New function.
+ (hppa64_return_value): New function.
+ (hppa_gdbarch_init): Set return_value; keep disabled.
+
* hppa-tdep.c (hppa_gdbarch_init): Re-order separating
struct-return and inferior function call methods.
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index 21f86d5..fbc0c53 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -255,6 +255,111 @@ hppa64_use_struct_convention (int gcc_p, struct type *type)
return TYPE_LENGTH (type) > 16;
}
+/* Handle 32/64-bit struct return conventions. */
+
+static enum return_value_convention
+hppa32_return_value (struct gdbarch *gdbarch,
+ struct type *type, struct regcache *regcache,
+ void *readbuf, const void *writebuf)
+{
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ if (readbuf != NULL)
+ regcache_cooked_read_part (regcache, FP4_REGNUM, 0,
+ TYPE_LENGTH (type), readbuf);
+ if (writebuf != NULL)
+ regcache_cooked_write_part (regcache, FP4_REGNUM, 0,
+ TYPE_LENGTH (type), writebuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ if (TYPE_LENGTH (type) <= 2 * 4)
+ {
+ /* The value always lives in the right hand end of the register
+ (or register pair)? */
+ int b;
+ int reg = 28;
+ int part = TYPE_LENGTH (type) % 4;
+ /* The left hand register contains only part of the value,
+ transfer that first so that the rest can be xfered as entire
+ 4-byte registers. */
+ if (part > 0)
+ {
+ if (readbuf != NULL)
+ regcache_cooked_read_part (regcache, reg, 4 - part,
+ part, readbuf);
+ if (writebuf != NULL)
+ regcache_cooked_write_part (regcache, reg, 4 - part,
+ part, writebuf);
+ reg++;
+ }
+ /* Now transfer the remaining register values. */
+ for (b = part; b < TYPE_LENGTH (type); b += 4)
+ {
+ if (readbuf != NULL)
+ regcache_cooked_read (regcache, reg, (char *) readbuf + b);
+ if (writebuf != NULL)
+ regcache_cooked_write (regcache, reg, (const char *) writebuf + b);
+ reg++;
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ else
+ return RETURN_VALUE_STRUCT_CONVENTION;
+}
+
+static enum return_value_convention
+hppa64_return_value (struct gdbarch *gdbarch,
+ struct type *type, struct regcache *regcache,
+ void *readbuf, const void *writebuf)
+{
+ /* RM: Floats are returned in FR4R, doubles in FR4. Integral values
+ are in r28, padded on the left. Aggregates less that 65 bits are
+ in r28, right padded. Aggregates upto 128 bits are in r28 and
+ r29, right padded. */
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ /* Floats are right aligned? */
+ int offset = register_size (gdbarch, FP4_REGNUM) - TYPE_LENGTH (type);
+ if (readbuf != NULL)
+ regcache_cooked_read_part (regcache, FP4_REGNUM, offset,
+ TYPE_LENGTH (type), readbuf);
+ if (writebuf != NULL)
+ regcache_cooked_write_part (regcache, FP4_REGNUM, offset,
+ TYPE_LENGTH (type), writebuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ else if (TYPE_LENGTH (type) <= 8 && is_integral_type (type))
+ {
+ /* Integrals are right aligned. */
+ int offset = register_size (gdbarch, FP4_REGNUM) - TYPE_LENGTH (type);
+ if (readbuf != NULL)
+ regcache_cooked_read_part (regcache, 28, offset,
+ TYPE_LENGTH (type), readbuf);
+ if (writebuf != NULL)
+ regcache_cooked_write_part (regcache, 28, offset,
+ TYPE_LENGTH (type), writebuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ else if (TYPE_LENGTH (type) <= 2 * 8)
+ {
+ /* Composite values are left aligned. */
+ int b;
+ for (b = 0; b < TYPE_LENGTH (type); b += 8)
+ {
+ int part = (TYPE_LENGTH (type) - b - 1) % 8 + 1;
+ if (readbuf != NULL)
+ regcache_cooked_read_part (regcache, 28, 0, part,
+ (char *) readbuf + b);
+ if (writebuf != NULL)
+ regcache_cooked_write_part (regcache, 28, 0, part,
+ (const char *) writebuf + b);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ else
+ return RETURN_VALUE_STRUCT_CONVENTION;
+}
+
/* Routines to extract various sized constants out of hppa
instructions. */
@@ -5506,6 +5611,17 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Struct return methods. */
if (0)
{
+ switch (tdep->bytes_per_address)
+ {
+ case 4:
+ set_gdbarch_return_value (gdbarch, hppa32_return_value);
+ break;
+ case 8:
+ set_gdbarch_return_value (gdbarch, hppa64_return_value);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
}
else
{