diff options
-rw-r--r-- | gdb/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/hppa-tdep.c | 233 |
2 files changed, 142 insertions, 96 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c752aa3..4b789c3 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2004-12-21 Mark Kettenis <kettenis@gnu.org> + + * hppa-tdep.c (hppa32_return_value): Move further down. + (hppa64_return_value): Re-implement. + 2004-12-21 Jim Blandy <jimb@redhat.com> * remote.c (fetch_register_using_p): Fix formatting. diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c index 8deacc3..122fc9f 100644 --- a/gdb/hppa-tdep.c +++ b/gdb/hppa-tdep.c @@ -72,102 +72,6 @@ const struct objfile_data *hppa_objfile_priv_data = NULL; following functions static, once we hppa is partially multiarched. */ int hppa_pc_requires_run_before_use (CORE_ADDR pc); -/* 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_LENGTH (type) <= 2 * 4) - { - /* The value always lives in the right hand end of the register - (or register pair)? */ - int b; - int reg = TYPE_CODE (type) == TYPE_CODE_FLT ? HPPA_FP4_REGNUM : 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 - && TYPE_LENGTH (type) <= 8) - { - /* Floats are right aligned? */ - int offset = register_size (gdbarch, HPPA_FP4_REGNUM) - TYPE_LENGTH (type); - if (readbuf != NULL) - regcache_cooked_read_part (regcache, HPPA_FP4_REGNUM, offset, - TYPE_LENGTH (type), readbuf); - if (writebuf != NULL) - regcache_cooked_write_part (regcache, HPPA_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, HPPA_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 = min (8, TYPE_LENGTH (type) - b); - if (readbuf != NULL) - regcache_cooked_read_part (regcache, 28 + b / 8, 0, part, - (char *) readbuf + b); - if (writebuf != NULL) - regcache_cooked_write_part (regcache, 28 + b / 8, 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. */ @@ -1126,6 +1030,143 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } +/* 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_LENGTH (type) <= 2 * 4) + { + /* The value always lives in the right hand end of the register + (or register pair)? */ + int b; + int reg = TYPE_CODE (type) == TYPE_CODE_FLT ? HPPA_FP4_REGNUM : 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) +{ + int len = TYPE_LENGTH (type); + int regnum, offset; + + if (len > 16) + { + /* All return values larget than 128 bits must be aggregate + return values. */ + gdb_assert (!hppa64_integral_or_pointer_p()); + gdb_assert (!hppa64_floating_p()); + + /* "Aggregate return values larger than 128 bits are returned in + a buffer allocated by the caller. The address of the buffer + must be passed in GR 28." */ + return RETURN_VALUE_STRUCT_CONVENTION; + } + + if (hppa64_integral_or_pointer_p (type)) + { + /* "Integral return values are returned in GR 28. Values + smaller than 64 bits are padded on the left (with garbage)." */ + regnum = HPPA_RET0_REGNUM; + offset = 8 - len; + } + else if (hppa64_floating_p (type)) + { + if (len > 8) + { + /* "Double-extended- and quad-precision floating-point + values are returned in GRs 28 and 29. The sign, + exponent, and most-significant bits of the mantissa are + returned in GR 28; the least-significant bits of the + mantissa are passed in GR 29. For double-extended + precision values, GR 29 is padded on the right with 48 + bits of garbage." */ + regnum = HPPA_RET0_REGNUM; + offset = 0; + } + else + { + /* "Single-precision and double-precision floating-point + return values are returned in FR 4R (single precision) or + FR 4 (double-precision)." */ + regnum = HPPA64_FP4_REGNUM; + offset = 8 - len; + } + } + else + { + /* "Aggregate return values up to 64 bits in size are returned + in GR 28. Aggregates smaller than 64 bits are left aligned + in the register; the pad bits on the right are undefined." + + "Aggregate return values between 65 and 128 bits are returned + in GRs 28 and 29. The first 64 bits are placed in GR 28, and + the remaining bits are placed, left aligned, in GR 29. The + pad bits on the right of GR 29 (if any) are undefined." */ + regnum = HPPA_RET0_REGNUM; + offset = 0; + } + + if (readbuf) + { + char *buf = readbuf; + while (len > 0) + { + regcache_cooked_read_part (regcache, regnum, offset, + min (len, 8), buf); + buf += min (len, 8); + len -= min (len, 8); + regnum++; + } + } + + if (writebuf) + { + const char *buf = writebuf; + while (len > 0) + { + regcache_cooked_write_part (regcache, regnum, offset, + min (len, 8), buf); + buf += min (len, 8); + len -= min (len, 8); + regnum++; + } + } + + return RETURN_VALUE_REGISTER_CONVENTION; +} + + static CORE_ADDR hppa32_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr, |