This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[commit] Add HPPA push_dummy_call; keep disabled


While this works with a very simple inferior function call like:

(gdb) print func();

it doesn't pass parameters correct - the code has a rather subtle bug - it doesn't think to store the parameters in registers :-(

The old code was doing the register store in CALL_DUMMY_WORDS:
nop
copy %r4,%r29
copy %r5,%r22
copy %r6,%r27
fldd -64(0,%r29),%fr4
fldd -56(0,%r29),%fr5
fldd -48(0,%r29),%fr6
fldd -40(0,%r29),%fr7
fldd -32(0,%r29),%fr8
fldd -24(0,%r29),%fr9
fldd -16(0,%r29),%fr10
fldd -8(0,%r29),%fr11
copy %r22,%r1
ldd -64(%r29), %r26
ldd -56(%r29), %r25
ldd -48(%r29), %r24
ldd -40(%r29), %r23
ldd -32(%r29), %r22
ldd -24(%r29), %r21
ldd -16(%r29), %r20
bve,l (%r1),%r2
ldd -8(%r29), %r19
break 4, 8
mtsp %r21, %sr0
ble 0(%sr0, %r22)
nop
(outch!) so either someone gets to reverse engineer the above (anyone?) or, find a 32-bit and 64-bit PA-RISC ABI document and implement that.


Andrew

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.
	
Index: hppa-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-tdep.c,v
retrieving revision 1.124
diff -u -r1.124 hppa-tdep.c
--- hppa-tdep.c	23 Feb 2004 00:06:39 -0000	1.124
+++ hppa-tdep.c	23 Feb 2004 16:35:03 -0000
@@ -2171,6 +2171,241 @@
 
 #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 @@
   /* 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
     {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]