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/pa] Fix 64-bit abi


Hello,

This fixes the HP/PA 64-bit return_value and push_dummy_call code sufficient to consider it "useable". The ABI is simple, the stack being up-side down, is not.

committed to mainline,
Andrew
2004-03-07  Andrew Cagney  <cagney@redhat.com>

	* hppa-tdep.c: Replace PC_REGNUM with PCOQ_HEAD_REGNUM.
	(hppa64_return_value, hppa64_push_dummy_call): Rewrite.
	(hppa_gdbarch_init): Do not set PC_REGNUM.

Index: hppa-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-tdep.c,v
retrieving revision 1.130
diff -u -r1.130 hppa-tdep.c
--- hppa-tdep.c	5 Mar 2004 04:49:52 -0000	1.130
+++ hppa-tdep.c	7 Mar 2004 17:01:27 -0000
@@ -303,7 +303,8 @@
      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)
+  if (TYPE_CODE (type) == TYPE_CODE_FLT
+      && TYPE_LENGTH (type) <= 8)
     {
       /* Floats are right aligned?  */
       int offset = register_size (gdbarch, FP4_REGNUM) - TYPE_LENGTH (type);
@@ -333,15 +334,15 @@
       int b;
       for (b = 0; b < TYPE_LENGTH (type); b += 8)
 	{
-	  int part = (TYPE_LENGTH (type) - b - 1) % 8 + 1;
+	  int part = min (8, TYPE_LENGTH (type) - b);
 	  if (readbuf != NULL)
-	    regcache_cooked_read_part (regcache, 28, 0, part,
+	    regcache_cooked_read_part (regcache, 28 + b / 8, 0, part,
 				       (char *) readbuf + b);
 	  if (writebuf != NULL)
-	    regcache_cooked_write_part (regcache, 28, 0, part,
+	    regcache_cooked_write_part (regcache, 28 + b / 8, 0, part,
 					(const char *) writebuf + b);
 	}
-  return RETURN_VALUE_REGISTER_CONVENTION;
+      return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else
     return RETURN_VALUE_STRUCT_CONVENTION;
@@ -1137,7 +1138,7 @@
      are saved in the exact same order as GDB numbers registers.  How
      convienent.  */
   if (pc_in_interrupt_handler (pc))
-    return read_memory_integer (get_frame_base (frame) + PC_REGNUM * 4,
+    return read_memory_integer (get_frame_base (frame) + PCOQ_HEAD_REGNUM * 4,
 				TARGET_PTR_BIT / 8) & ~0x3;
 
   if ((get_frame_pc (frame) >= get_frame_base (frame)
@@ -2292,111 +2293,106 @@
 			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;
+  /* NOTE: cagney/2004-02-27: This is a guess - its implemented by
+     reverse engineering testsuite failures.  */
 
-  /* The total number of bytes reserved for the arguments.  */
-  int cum_bytes_reserved = 0;
+  /* 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;
 
-  /* Similarly, but aligned.  */
-  int cum_bytes_aligned = 0;
-  int i;
+  /* The inner most end of the stack after all the parameters have
+     been pushed.  */
+  CORE_ADDR new_sp = 0;
 
-  /* Iterate over each argument provided by the user.  */
-  for (i = 0; i < nargs; i++)
+  /* 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++)
     {
-      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)
+      CORE_ADDR struct_ptr = 0;
+      CORE_ADDR param_ptr = 0;
+      int i;
+      for (i = 0; i < nargs; i++)
 	{
-	  args[i] = value_cast ((TYPE_UNSIGNED (arg_type)
-				 ? builtin_type_unsigned_long
-				 : builtin_type_long),
-				args[i]);
-	  arg_type = VALUE_TYPE (args[i]);
+	  struct value *arg = args[i];
+	  struct type *type = check_typedef (VALUE_TYPE (arg));
+	  if ((TYPE_CODE (type) == TYPE_CODE_INT
+	       || TYPE_CODE (type) == TYPE_CODE_ENUM)
+	      && TYPE_LENGTH (type) <= 8)
+	    {
+	      /* Integer value store, right aligned.  "unpack_long"
+		 takes care of any sign-extension problems.  */
+	      param_ptr += 8;
+	      if (write_pass)
+		{
+		  ULONGEST val = unpack_long (type, VALUE_CONTENTS (arg));
+		  int reg = 27 - param_ptr / 8;
+		  write_memory_unsigned_integer (param_end - param_ptr,
+						 val, 8);
+		  if (reg >= 19)
+		    regcache_cooked_write_unsigned (regcache, reg, val);
+		}
+	    }
+	  else
+	    {
+	      /* Small struct value, store left aligned?  */
+	      int reg;
+	      if (TYPE_LENGTH (type) > 8)
+		{
+		  param_ptr = align_up (param_ptr, 16);
+		  reg = 26 - param_ptr / 8;
+		  param_ptr += align_up (TYPE_LENGTH (type), 16);
+		}
+	      else
+		{
+		  param_ptr = align_up (param_ptr, 8);
+		  reg = 26 - param_ptr / 8;
+		  param_ptr += align_up (TYPE_LENGTH (type), 8);
+		}
+	      if (write_pass)
+		{
+		  int byte;
+		  write_memory (param_end - param_ptr, VALUE_CONTENTS (arg),
+				TYPE_LENGTH (type));
+		  for (byte = 0; byte < TYPE_LENGTH (type); byte += 8)
+		    {
+		      if (reg >= 19)
+			{
+			  int len = min (8, TYPE_LENGTH (type) - byte);
+			  regcache_cooked_write_part (regcache, reg, 0, len,
+						      VALUE_CONTENTS (arg) + byte);
+			}
+		      reg--;
+		    }
+		}
+	    }
 	}
-
-      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)
+      /* Update the various stack pointers.  */
+      if (!write_pass)
 	{
-	  /* 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;
+	  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, 16),
+					REG_PARM_STACK_SPACE);
 	}
-
-      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;
-
+  /* The stack will have 32 bytes of additional space for a frame marker.  */
+  return param_end + 64;
 }
 
 static CORE_ADDR
@@ -2946,7 +2942,7 @@
   if (flags & 2)
     return read_register_pid (31, ptid) & ~0x3;
 
-  return read_register_pid (PC_REGNUM, ptid) & ~0x3;
+  return read_register_pid (PCOQ_HEAD_REGNUM, ptid) & ~0x3;
 }
 
 /* Write out the PC.  If currently in a syscall, then also write the new
@@ -2965,7 +2961,7 @@
   if (flags & 2)
     write_register_pid (31, v | 0x3, ptid);
 
-  write_register_pid (PC_REGNUM, v, ptid);
+  write_register_pid (PCOQ_HEAD_REGNUM, v, ptid);
   write_register_pid (PCOQ_TAIL_REGNUM, v + 4, ptid);
 }
 
@@ -4908,7 +4904,7 @@
 static CORE_ADDR
 hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  return frame_unwind_register_signed (next_frame, PC_REGNUM) & ~3;
+  return frame_unwind_register_signed (next_frame, PCOQ_HEAD_REGNUM) & ~3;
 }
 
 /* Exception handling support for the HP-UX ANSI C++ compiler.
@@ -5779,7 +5775,6 @@
   set_gdbarch_deprecated_fp_regnum (gdbarch, 3);
   set_gdbarch_sp_regnum (gdbarch, 30);
   set_gdbarch_fp0_regnum (gdbarch, 64);
-  set_gdbarch_pc_regnum (gdbarch, PCOQ_HEAD_REGNUM);
   set_gdbarch_deprecated_register_raw_size (gdbarch, hppa_register_raw_size);
   set_gdbarch_deprecated_register_byte (gdbarch, hppa_register_byte);
   set_gdbarch_deprecated_register_virtual_size (gdbarch, hppa_register_raw_size);

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