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]

ARM PATCH fix extract_return_value and store_return_value


This patch cleans up the way the ARM tdep code handles extracting and 
storing return values.  Not only does it convert the methods to the new 
regcache abstraction but it also fixes (at least I hope it fixes) the 
big-endian problems that Michael was reporting on a big-endian ARM.

Michael, I've only run this through a little-endian testsuite.  Could you 
let me know if it solves the problems you were reporting.

R.

2002-12-14  Richard Earnshaw  <rearnsha@arm.com>

	* arm-tdep.c (convert_from_extended): New argument to hold the
	type of floating point result we want to convert to.  Make input 
	argument const.  Fix all callers.
	(convert_to_extended): Similarly.
	(arm_extract_return_value): Now takes a regcache argument.  Change
	code to use regcache accessor functions.  Correctly extract 
	smaller-than-word results on big-endian machines.
	(arm_store_return_value): Now takes a regcache argument.  Change
	code to use regcache accessor functions.  Correctly zero/sign extend
	smaller than word results before storing into r0.
	(arm_gdbarch_init): Register new-style extract_return_value and
	store_return_value functions.


Index: arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.82
diff -p -p -r1.82 arm-tdep.c
*** arm-tdep.c	11 Dec 2002 02:26:34 -0000	1.82
--- arm-tdep.c	14 Dec 2002 10:30:14 -0000
*************** static void set_disassembly_flavor_sfunc
*** 131,137 ****
  					 struct cmd_list_element *);
  static void set_disassembly_flavor (void);
  
! static void convert_from_extended (void *ptr, void *dbl);
  
  /* Define other aspects of the stack frame.  We keep the offsets of
     all saved registers, 'cause we need 'em a lot!  We also keep the
--- 131,140 ----
  					 struct cmd_list_element *);
  static void set_disassembly_flavor (void);
  
! static void convert_from_extended (const struct floatformat *, const void *,
! 				   void *);
! static void convert_to_extended (const struct floatformat *, void *,
! 				 const void *);
  
  /* Define other aspects of the stack frame.  We keep the offsets of
     all saved registers, 'cause we need 'em a lot!  We also keep the
*************** arm_register_sim_regno (int regnum)
*** 1664,1670 ****
     little-endian systems.  */
  
  static void
! convert_from_extended (void *ptr, void *dbl)
  {
    DOUBLEST d;
    if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
--- 1667,1674 ----
     little-endian systems.  */
  
  static void
! convert_from_extended (const struct floatformat *fmt, const void *ptr,
! 		       void *dbl)
  {
    DOUBLEST d;
    if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
*************** convert_from_extended (void *ptr, void *
*** 1672,1685 ****
    else
      floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword,
  			     ptr, &d);
!   floatformat_from_doublest (TARGET_DOUBLE_FORMAT, &d, dbl);
  }
  
  static void
! convert_to_extended (void *dbl, void *ptr)
  {
    DOUBLEST d;
!   floatformat_to_doublest (TARGET_DOUBLE_FORMAT, ptr, &d);
    if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
      floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl);
    else
--- 1676,1689 ----
    else
      floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword,
  			     ptr, &d);
!   floatformat_from_doublest (fmt, &d, dbl);
  }
  
  static void
! convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr)
  {
    DOUBLEST d;
!   floatformat_to_doublest (fmt, ptr, &d);
    if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
      floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl);
    else
*************** arm_breakpoint_from_pc (CORE_ADDR *pcptr
*** 2217,2225 ****
  
  static void
  arm_extract_return_value (struct type *type,
! 			  char regbuf[REGISTER_BYTES],
! 			  char *valbuf)
  {
    if (TYPE_CODE_FLT == TYPE_CODE (type))
      {
        struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
--- 2221,2231 ----
  
  static void
  arm_extract_return_value (struct type *type,
! 			  struct regcache *regs,
! 			  void *dst)
  {
+   bfd_byte *valbuf = dst;
+ 
    if (TYPE_CODE_FLT == TYPE_CODE (type))
      {
        struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
*************** arm_extract_return_value (struct type *t
*** 2227,2240 ****
        switch (tdep->fp_model)
  	{
  	case ARM_FLOAT_FPA:
! 	  convert_from_extended (&regbuf[REGISTER_BYTE (ARM_F0_REGNUM)],
! 				 valbuf);
  	  break;
  
  	case ARM_FLOAT_SOFT:
  	case ARM_FLOAT_SOFT_VFP:
! 	  memcpy (valbuf, &regbuf[REGISTER_BYTE (ARM_A1_REGNUM)],
! 		  TYPE_LENGTH (type));
  	  break;
  
  	default:
--- 2233,2256 ----
        switch (tdep->fp_model)
  	{
  	case ARM_FLOAT_FPA:
! 	  {
! 	    /* The value is in register F0 in internal format.  We need to
! 	       extract the raw value and then convert it to the desired
! 	       internal type.  */
! 	    bfd_byte tmpbuf[FP_REGISTER_RAW_SIZE];
! 
! 	    regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
! 	    convert_from_extended (floatformat_from_type (type), tmpbuf,
! 				   valbuf);
! 	  }
  	  break;
  
  	case ARM_FLOAT_SOFT:
  	case ARM_FLOAT_SOFT_VFP:
! 	  regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf);
! 	  if (TYPE_LENGTH (type) > 4)
! 	    regcache_cooked_read (regs, ARM_A1_REGNUM + 1,
! 				  valbuf + INT_REGISTER_RAW_SIZE);
  	  break;
  
  	default:
*************** arm_extract_return_value (struct type *t
*** 2244,2252 ****
  	  break;
  	}
      }
    else
!     memcpy (valbuf, &regbuf[REGISTER_BYTE (ARM_A1_REGNUM)],
! 	    TYPE_LENGTH (type));
  }
  
  /* Extract from an array REGBUF containing the (raw) register state
--- 2260,2309 ----
  	  break;
  	}
      }
+   else if (TYPE_CODE (type) == TYPE_CODE_INT
+ 	   || TYPE_CODE (type) == TYPE_CODE_CHAR
+ 	   || TYPE_CODE (type) == TYPE_CODE_BOOL
+ 	   || TYPE_CODE (type) == TYPE_CODE_PTR
+ 	   || TYPE_CODE (type) == TYPE_CODE_REF
+ 	   || TYPE_CODE (type) == TYPE_CODE_ENUM)
+     {
+       /* If the the type is a plain integer, then the access is
+ 	 straight-forward.  Otherwise we have to play around a bit more.  */
+       int len = TYPE_LENGTH (type);
+       int regno = ARM_A1_REGNUM;
+       ULONGEST tmp;
+ 
+       while (len > 0)
+ 	{
+ 	  /* By using store_unsigned_integer we avoid having to do
+ 	     anything special for small big-endian values.  */
+ 	  regcache_cooked_read_unsigned (regs, regno++, &tmp);
+ 	  store_unsigned_integer (valbuf, 
+ 				  (len > INT_REGISTER_RAW_SIZE
+ 				   ? INT_REGISTER_RAW_SIZE : len),
+ 				  tmp);
+ 	  len -= INT_REGISTER_RAW_SIZE;
+ 	  valbuf += INT_REGISTER_RAW_SIZE;
+ 	}
+     }
    else
!     {
!       /* For a structure or union the behaviour is as if the value had
!          been stored to word-aligned memory and then loaded into 
!          registers with 32-bit load instruction(s).  */
!       int len = TYPE_LENGTH (type);
!       int regno = ARM_A1_REGNUM;
!       bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE];
! 
!       while (len > 0)
! 	{
! 	  regcache_cooked_read (regs, regno++, tmpbuf);
! 	  memcpy (valbuf, tmpbuf,
! 		  len > INT_REGISTER_RAW_SIZE ? INT_REGISTER_RAW_SIZE : len);
! 	  len -= INT_REGISTER_RAW_SIZE;
! 	  valbuf += INT_REGISTER_RAW_SIZE;
! 	}
!     }
  }
  
  /* Extract from an array REGBUF containing the (raw) register state
*************** arm_use_struct_convention (int gcc_p, st
*** 2359,2366 ****
     TYPE, given in virtual format.  */
  
  static void
! arm_store_return_value (struct type *type, char *valbuf)
  {
    if (TYPE_CODE (type) == TYPE_CODE_FLT)
      {
        struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
--- 2416,2426 ----
     TYPE, given in virtual format.  */
  
  static void
! arm_store_return_value (struct type *type, struct regcache *regs,
! 			const void *src)
  {
+   const bfd_byte *valbuf = src;
+ 
    if (TYPE_CODE (type) == TYPE_CODE_FLT)
      {
        struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
*************** arm_store_return_value (struct type *typ
*** 2370,2384 ****
  	{
  	case ARM_FLOAT_FPA:
  
! 	  convert_to_extended (valbuf, buf);
! 	  deprecated_write_register_bytes (REGISTER_BYTE (ARM_F0_REGNUM), buf,
! 					   FP_REGISTER_RAW_SIZE);
  	  break;
  
  	case ARM_FLOAT_SOFT:
  	case ARM_FLOAT_SOFT_VFP:
! 	  deprecated_write_register_bytes (ARM_A1_REGNUM, valbuf,
! 					   TYPE_LENGTH (type));
  	  break;
  
  	default:
--- 2430,2445 ----
  	{
  	case ARM_FLOAT_FPA:
  
! 	  convert_to_extended (floatformat_from_type (type), buf, valbuf);
! 	  regcache_cooked_write (regs, ARM_F0_REGNUM, buf);
  	  break;
  
  	case ARM_FLOAT_SOFT:
  	case ARM_FLOAT_SOFT_VFP:
! 	  regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf);
! 	  if (TYPE_LENGTH (type) > 4)
! 	    regcache_cooked_write (regs, ARM_A1_REGNUM + 1, 
! 				   valbuf + INT_REGISTER_RAW_SIZE);
  	  break;
  
  	default:
*************** arm_store_return_value (struct type *typ
*** 2388,2396 ****
  	  break;
  	}
      }
    else
!     deprecated_write_register_bytes (ARM_A1_REGNUM, valbuf,
! 				     TYPE_LENGTH (type));
  }
  
  /* Store the address of the place in which to copy the structure the
--- 2449,2505 ----
  	  break;
  	}
      }
+   else if (TYPE_CODE (type) == TYPE_CODE_INT
+ 	   || TYPE_CODE (type) == TYPE_CODE_CHAR
+ 	   || TYPE_CODE (type) == TYPE_CODE_BOOL
+ 	   || TYPE_CODE (type) == TYPE_CODE_PTR
+ 	   || TYPE_CODE (type) == TYPE_CODE_REF
+ 	   || TYPE_CODE (type) == TYPE_CODE_ENUM)
+     {
+       if (TYPE_LENGTH (type) <= 4)
+ 	{
+ 	  /* Values of one word or less are zero/sign-extended and
+ 	     returned in r0.  */
+ 	  bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE];
+ 	  LONGEST val = unpack_long (type, valbuf);
+ 
+ 	  store_signed_integer (tmpbuf, INT_REGISTER_RAW_SIZE, val);
+ 	  regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf);
+ 	}
+       else
+ 	{
+ 	  /* Integral values greater than one word are stored in consecutive
+ 	     registers starting with r0.  This will always be a multiple of
+ 	     the regiser size.  */
+ 	  int len = TYPE_LENGTH (type);
+ 	  int regno = ARM_A1_REGNUM;
+ 
+ 	  while (len > 0)
+ 	    {
+ 	      regcache_cooked_write (regs, regno++, valbuf);
+ 	      len -= INT_REGISTER_RAW_SIZE;
+ 	      valbuf += INT_REGISTER_RAW_SIZE;
+ 	    }
+ 	}
+     }
    else
!     {
!       /* For a structure or union the behaviour is as if the value had
!          been stored to word-aligned memory and then loaded into 
!          registers with 32-bit load instruction(s).  */
!       int len = TYPE_LENGTH (type);
!       int regno = ARM_A1_REGNUM;
!       bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE];
! 
!       while (len > 0)
! 	{
! 	  memcpy (tmpbuf, valbuf,
! 		  len > INT_REGISTER_RAW_SIZE ? INT_REGISTER_RAW_SIZE : len);
! 	  regcache_cooked_write (regs, regno++, tmpbuf);
! 	  len -= INT_REGISTER_RAW_SIZE;
! 	  valbuf += INT_REGISTER_RAW_SIZE;
! 	}
!     }
  }
  
  /* Store the address of the place in which to copy the structure the
*************** arm_gdbarch_init (struct gdbarch_info in
*** 2869,2876 ****
    set_gdbarch_register_name (gdbarch, arm_register_name);
  
    /* Returning results.  */
!   set_gdbarch_deprecated_extract_return_value (gdbarch, arm_extract_return_value);
!   set_gdbarch_deprecated_store_return_value (gdbarch, arm_store_return_value);
    set_gdbarch_store_struct_return (gdbarch, arm_store_struct_return);
    set_gdbarch_use_struct_convention (gdbarch, arm_use_struct_convention);
    set_gdbarch_extract_struct_value_address (gdbarch,
--- 2978,2985 ----
    set_gdbarch_register_name (gdbarch, arm_register_name);
  
    /* Returning results.  */
!   set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value);
!   set_gdbarch_store_return_value (gdbarch, arm_store_return_value);
    set_gdbarch_store_struct_return (gdbarch, arm_store_struct_return);
    set_gdbarch_use_struct_convention (gdbarch, arm_use_struct_convention);
    set_gdbarch_extract_struct_value_address (gdbarch,

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