2004-02-23 Andrew Cagney <cagney@redhat.com>
authorAndrew Cagney <cagney@redhat.com>
Mon, 23 Feb 2004 16:35:54 +0000 (16:35 +0000)
committerAndrew Cagney <cagney@redhat.com>
Mon, 23 Feb 2004 16:35:54 +0000 (16:35 +0000)
* 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.

gdb/ChangeLog
gdb/hppa-tdep.c

index 7fbdc7c..942be44 100644 (file)
@@ -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.
index b561bbe..9a5395d 100644 (file)
@@ -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
     {