aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog4
-rw-r--r--gdb/hppa-tdep.c214
2 files changed, 119 insertions, 99 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 439cd23..92ebb50 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,7 @@
+2004-02-25 Andrew Cagney <cagney@redhat.com>
+
+ * hppa-tdep.c (hppa32_push_dummy_call): Rewrite.
+
2004-02-25 Mark Kettenis <kettenis@gnu.org>
* config/i386/tm-x86-64linux.h: Tweak comments.
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index 9a5395d..0fc1131 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -2174,6 +2174,121 @@ hppa_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
/* 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)
+{
+ /* NOTE: cagney/2004-02-27: This is a guess - its implemented by
+ reverse engineering testsuite failures. */
+
+ /* Stack base address at which any pass-by-reference parameters are
+ stored. */
+ CORE_ADDR struct_end = 0;
+ /* Stack base address at which the first parameter is stored. */
+ CORE_ADDR param_end = 0;
+
+ /* The inner most end of the stack after all the parameters have
+ been pushed. */
+ CORE_ADDR new_sp = 0;
+
+ /* Two passes. First pass computes the location of everything,
+ second pass writes the bytes out. */
+ int write_pass;
+ for (write_pass = 0; write_pass < 2; write_pass++)
+ {
+ CORE_ADDR struct_ptr = struct_end;
+ CORE_ADDR param_ptr = param_end;
+ int reg = 27; /* NOTE: Registers go down. */
+ int i;
+ for (i = 0; i < nargs; i++)
+ {
+ struct value *arg = args[i];
+ struct type *type = check_typedef (VALUE_TYPE (arg));
+ /* The corresponding parameter that is pushed onto the
+ stack, and [possibly] passed in a register. */
+ char param_val[8];
+ int param_len;
+ memset (param_val, 0, sizeof param_val);
+ if (TYPE_LENGTH (type) > 8)
+ {
+ /* Large parameter, pass by reference. Store the value
+ in "struct" area and then pass its address. */
+ param_len = 4;
+ struct_ptr -= align_up (TYPE_LENGTH (type), 8);
+ if (write_pass)
+ write_memory (struct_ptr, VALUE_CONTENTS (arg),
+ TYPE_LENGTH (type));
+ store_unsigned_integer (param_val, 4, struct_ptr);
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ /* Integer value store, right aligned. "unpack_long"
+ takes care of any sign-extension problems. */
+ param_len = align_up (TYPE_LENGTH (type), 4);
+ store_unsigned_integer (param_val, param_len,
+ unpack_long (type,
+ VALUE_CONTENTS (arg)));
+ }
+ else
+ {
+ /* Small struct value, store right aligned? */
+ param_len = align_up (TYPE_LENGTH (type), 4);
+ memcpy (param_val + param_len - TYPE_LENGTH (type),
+ VALUE_CONTENTS (arg), TYPE_LENGTH (type));
+ }
+ param_ptr -= param_len;
+ reg -= param_len / 4;
+ if (write_pass)
+ {
+ write_memory (param_ptr, param_val, param_len);
+ if (reg >= 23)
+ {
+ regcache_cooked_write (regcache, reg, param_val);
+ if (param_len > 4)
+ regcache_cooked_write (regcache, reg + 1, param_val + 4);
+ }
+ }
+ }
+
+ /* Update the various stack pointers. */
+ if (!write_pass)
+ {
+ struct_end = sp + struct_ptr;
+ /* PARAM_PTR 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. */
+ param_end = struct_end + max (align_up (param_ptr, 8),
+ REG_PARM_STACK_SPACE);
+ }
+ }
+
+ /* 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 param_end + 32;
+}
+
+/* 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.)
@@ -2297,105 +2412,6 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
}
-/* 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