diff options
-rw-r--r-- | gdb/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/hppa-tdep.c | 245 |
2 files changed, 251 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7fbdc7c..942be44 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,11 @@ 2004-02-23 Andrew Cagney <cagney@redhat.com> + * hppa-tdep.c (hppa_frame_align): New function. + (hppa32_push_dummy_call): New function. + (hppa64_push_dummy_call): New function. + (hppa_gdbarch_init): Set frame_align and push_dummy_call; keep + disabled. + * infcall.c (legacy_push_dummy_code): Don't call deprecated FIX_CALL_DUMMY when push_dummy_call is available. (call_function_by_hand, push_dummy_code): Ditto. diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c index b561bbe..9a5395d 100644 --- a/gdb/hppa-tdep.c +++ b/gdb/hppa-tdep.c @@ -2171,6 +2171,241 @@ hppa_push_arguments (int nargs, struct value **args, CORE_ADDR sp, #endif +/* This function pushes a stack frame with arguments as part of the + inferior function calling mechanism. + + This is the version for the PA64, in which later arguments appear + at higher addresses. (The stack always grows towards higher + addresses.) + + We simply allocate the appropriate amount of stack space and put + arguments into their proper slots. + + This ABI also requires that the caller provide an argument pointer + to the callee, so we do that too. */ + +CORE_ADDR +hppa64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, + struct regcache *regcache, CORE_ADDR bp_addr, + int nargs, struct value **args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) +{ + /* Array of arguments' offsets. */ + int *offset = (int *) alloca (nargs * sizeof (int)); + + /* Array of arguments' lengths: real lengths in bytes, not aligned + to word size. */ + int *lengths = (int *) alloca (nargs * sizeof (int)); + + /* The value of SP as it was passed into this function. */ + CORE_ADDR orig_sp = sp; + + /* The number of stack bytes occupied by the current argument. */ + int bytes_reserved; + + /* The total number of bytes reserved for the arguments. */ + int cum_bytes_reserved = 0; + + /* Similarly, but aligned. */ + int cum_bytes_aligned = 0; + int i; + + /* Iterate over each argument provided by the user. */ + for (i = 0; i < nargs; i++) + { + struct type *arg_type = VALUE_TYPE (args[i]); + + /* Integral scalar values smaller than a register are padded on + the left. We do this by promoting them to full-width, + although the ABI says to pad them with garbage. */ + if (is_integral_type (arg_type) + && TYPE_LENGTH (arg_type) < DEPRECATED_REGISTER_SIZE) + { + args[i] = value_cast ((TYPE_UNSIGNED (arg_type) + ? builtin_type_unsigned_long + : builtin_type_long), + args[i]); + arg_type = VALUE_TYPE (args[i]); + } + + lengths[i] = TYPE_LENGTH (arg_type); + + /* Align the size of the argument to the word size for this + target. */ + bytes_reserved = (lengths[i] + DEPRECATED_REGISTER_SIZE - 1) & -DEPRECATED_REGISTER_SIZE; + + offset[i] = cum_bytes_reserved; + + /* Aggregates larger than eight bytes (the only types larger + than eight bytes we have) are aligned on a 16-byte boundary, + possibly padded on the right with garbage. This may leave an + empty word on the stack, and thus an unused register, as per + the ABI. */ + if (bytes_reserved > 8) + { + /* Round up the offset to a multiple of two slots. */ + int new_offset = ((offset[i] + 2*DEPRECATED_REGISTER_SIZE-1) + & -(2*DEPRECATED_REGISTER_SIZE)); + + /* Note the space we've wasted, if any. */ + bytes_reserved += new_offset - offset[i]; + offset[i] = new_offset; + } + + cum_bytes_reserved += bytes_reserved; + } + + /* CUM_BYTES_RESERVED already accounts for all the arguments passed + by the user. However, the ABIs mandate minimum stack space + allocations for outgoing arguments. + + The ABIs also mandate minimum stack alignments which we must + preserve. */ + cum_bytes_aligned = align_up (cum_bytes_reserved, 16); + sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE); + + /* Now write each of the args at the proper offset down the + stack. */ + for (i = 0; i < nargs; i++) + write_memory (orig_sp + offset[i], VALUE_CONTENTS (args[i]), lengths[i]); + + /* If a structure has to be returned, set up register 28 to hold its + address */ + if (struct_return) + write_register (28, struct_addr); + + /* For the PA64 we must pass a pointer to the outgoing argument + list. The ABI mandates that the pointer should point to the + first byte of storage beyond the register flushback area. + + However, the call dummy expects the outgoing argument pointer to + be passed in register %r4. */ + write_register (4, orig_sp + REG_PARM_STACK_SPACE); + + /* ?!? This needs further work. We need to set up the global data + pointer for this procedure. This assumes the same global pointer + for every procedure. The call dummy expects the dp value to be + passed in register %r6. */ + write_register (6, read_register (27)); + + /* Set the return address. */ + regcache_cooked_write_unsigned (regcache, RP_REGNUM, bp_addr); + + /* The stack will have 64 bytes of additional space for a frame + marker. */ + return sp + 64; + +} + +/* This function pushes a stack frame with arguments as part of the + inferior function calling mechanism. + + This is the version of the function for the 32-bit PA machines, in + which later arguments appear at lower addresses. (The stack always + grows towards higher addresses.) + + We simply allocate the appropriate amount of stack space and put + arguments into their proper slots. */ + +CORE_ADDR +hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, + struct regcache *regcache, CORE_ADDR bp_addr, + int nargs, struct value **args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) +{ + struct tdep *tdep = gdbarch_tdep (gdbarch); + + /* array of arguments' offsets */ + int *offset = (int *) alloca (nargs * sizeof (int)); + + /* array of arguments' lengths: real lengths in bytes, not aligned to + word size */ + int *lengths = (int *) alloca (nargs * sizeof (int)); + + /* The number of stack bytes occupied by the current argument. */ + int bytes_reserved; + + /* The total number of bytes reserved for the arguments. */ + int cum_bytes_reserved = 0; + + /* Similarly, but aligned. */ + int cum_bytes_aligned = 0; + int i; + + /* Iterate over each argument provided by the user. */ + for (i = 0; i < nargs; i++) + { + lengths[i] = TYPE_LENGTH (VALUE_TYPE (args[i])); + + /* Align the size of the argument to the word size for this + target. */ + bytes_reserved = (lengths[i] + 4 - 1) & -4; + + offset[i] = (cum_bytes_reserved + (lengths[i] > 4 + ? bytes_reserved : lengths[i])); + + /* If the argument is a double word argument, then it needs to be + double word aligned. */ + if ((bytes_reserved == 2 * 4) + && (offset[i] % 2 * 4)) + { + int new_offset = 0; + /* BYTES_RESERVED is already aligned to the word, so we put + the argument at one word more down the stack. + + This will leave one empty word on the stack, and one + unused register as mandated by the ABI. */ + new_offset = ((offset[i] + 2 * 4 - 1) + & -(2 * 4)); + + if ((new_offset - offset[i]) >= 2 * 4) + { + bytes_reserved += 4; + offset[i] += 4; + } + } + + cum_bytes_reserved += bytes_reserved; + + } + + /* CUM_BYTES_RESERVED already accounts for all the arguments passed + by the user. However, the ABI mandates minimum stack space + allocations for outgoing arguments. + + The ABI also mandates minimum stack alignments which we must + preserve. */ + cum_bytes_aligned = align_up (cum_bytes_reserved, 8); + sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE); + + /* Now write each of the args at the proper offset down the stack. + ?!? We need to promote values to a full register instead of skipping + words in the stack. */ + for (i = 0; i < nargs; i++) + write_memory (sp - offset[i], VALUE_CONTENTS (args[i]), lengths[i]); + + /* If a structure has to be returned, set up register 28 to hold its + address */ + if (struct_return) + write_register (28, struct_addr); + + /* Set the return address. */ + regcache_cooked_write_unsigned (regcache, RP_REGNUM, bp_addr); + + /* The stack will have 32 bytes of additional space for a frame marker. */ + return sp + 32; +} + +/* Force all frames to 16-byte alignment. Better safe than sorry. */ + +static CORE_ADDR +hppa_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) +{ + /* Just always 16-byte align. */ + return align_up (addr, 16); +} + + /* elz: Used to lookup a symbol in the shared libraries. This function calls shl_findsym, indirectly through a call to __d_shl_get. __d_shl_get is in end.c, which is always @@ -5587,6 +5822,16 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Inferior function call methods. */ if (0) { + set_gdbarch_frame_align (gdbarch, hppa_frame_align); + switch (tdep->bytes_per_address) + { + case 4: + set_gdbarch_push_dummy_call (gdbarch, hppa32_push_dummy_call); + break; + case 8: + set_gdbarch_push_dummy_call (gdbarch, hppa64_push_dummy_call); + break; + } } else { |