Example #1
0
/* The 64 bit ABI retun value convention.

   Return non-zero if the return-value is stored in a register, return
   0 if the return-value is instead stored on the stack (a.k.a.,
   struct return convention).

   For a return-value stored in a register: when WRITEBUF is non-NULL,
   copy the buffer to the corresponding register return-value location
   location; when READBUF is non-NULL, fill the buffer from the
   corresponding register return-value location.  */
enum return_value_convention
ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
			     struct regcache *regcache, gdb_byte *readbuf,
			     const gdb_byte *writebuf)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  /* This function exists to support a calling convention that
     requires floating-point registers.  It shouldn't be used on
     processors that lack them.  */
  gdb_assert (ppc_floating_point_unit_p (gdbarch));

  /* Floats and doubles in F1.  */
  if (TYPE_CODE (valtype) == TYPE_CODE_FLT && TYPE_LENGTH (valtype) <= 8)
    {
      gdb_byte regval[MAX_REGISTER_SIZE];
      struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum);
      if (writebuf != NULL)
	{
	  convert_typed_floating (writebuf, valtype, regval, regtype);
	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, regval);
	}
      if (readbuf != NULL)
	{
	  regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval);
	  convert_typed_floating (regval, regtype, readbuf, valtype);
	}
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
  if ((TYPE_CODE (valtype) == TYPE_CODE_INT
       || TYPE_CODE (valtype) == TYPE_CODE_ENUM)
      && TYPE_LENGTH (valtype) <= 8)
    {
      /* Integers in r3.  */
      if (writebuf != NULL)
	{
	  /* Be careful to sign extend the value.  */
	  regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
					  unpack_long (valtype, writebuf));
	}
      if (readbuf != NULL)
	{
	  /* Extract the integer from r3.  Since this is truncating the
	     value, there isn't a sign extension problem.  */
	  ULONGEST regval;
	  regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
					 &regval);
	  store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), regval);
	}
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
  /* All pointers live in r3.  */
  if (TYPE_CODE (valtype) == TYPE_CODE_PTR)
    {
      /* All pointers live in r3.  */
      if (writebuf != NULL)
	regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
      if (readbuf != NULL)
	regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
      && TYPE_LENGTH (valtype) <= 8
      && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
      && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
    {
      /* Small character arrays are returned, right justified, in r3.  */
      int offset = (register_size (gdbarch, tdep->ppc_gp0_regnum + 3)
		    - TYPE_LENGTH (valtype));
      if (writebuf != NULL)
	regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3,
				    offset, TYPE_LENGTH (valtype), writebuf);
      if (readbuf != NULL)
	regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3,
				   offset, TYPE_LENGTH (valtype), readbuf);
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
  /* Big floating point values get stored in adjacent floating
     point registers.  */
  if (TYPE_CODE (valtype) == TYPE_CODE_FLT
      && (TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 32))
    {
      if (writebuf || readbuf != NULL)
	{
	  int i;
	  for (i = 0; i < TYPE_LENGTH (valtype) / 8; i++)
	    {
	      if (writebuf != NULL)
		regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
				       (const bfd_byte *) writebuf + i * 8);
	      if (readbuf != NULL)
		regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
				      (bfd_byte *) readbuf + i * 8);
	    }
	}
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
  /* Complex values get returned in f1:f2, need to convert.  */
  if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
      && (TYPE_LENGTH (valtype) == 8 || TYPE_LENGTH (valtype) == 16))
    {
      if (regcache != NULL)
	{
	  int i;
	  for (i = 0; i < 2; i++)
	    {
	      gdb_byte regval[MAX_REGISTER_SIZE];
	      struct type *regtype =
		register_type (current_gdbarch, tdep->ppc_fp0_regnum);
	      if (writebuf != NULL)
		{
		  convert_typed_floating ((const bfd_byte *) writebuf +
					  i * (TYPE_LENGTH (valtype) / 2),
					  valtype, regval, regtype);
		  regcache_cooked_write (regcache,
                                         tdep->ppc_fp0_regnum + 1 + i,
					 regval);
		}
	      if (readbuf != NULL)
		{
		  regcache_cooked_read (regcache,
                                        tdep->ppc_fp0_regnum + 1 + i,
                                        regval);
		  convert_typed_floating (regval, regtype,
					  (bfd_byte *) readbuf +
					  i * (TYPE_LENGTH (valtype) / 2),
					  valtype);
		}
	    }
	}
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
  /* Big complex values get stored in f1:f4.  */
  if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX && TYPE_LENGTH (valtype) == 32)
    {
      if (regcache != NULL)
	{
	  int i;
	  for (i = 0; i < 4; i++)
	    {
	      if (writebuf != NULL)
		regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
				       (const bfd_byte *) writebuf + i * 8);
	      if (readbuf != NULL)
		regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
				      (bfd_byte *) readbuf + i * 8);
	    }
	}
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
  return RETURN_VALUE_STRUCT_CONVENTION;
}
Example #2
0
static enum return_value_convention
d10v_return_value (struct gdbarch *gdbarch, struct type *valtype,
		   struct regcache *regcache, void *readbuf,
		   const void *writebuf)
{
  if (TYPE_LENGTH (valtype) > 8)
    /* Anything larger than 8 bytes (4 registers) goes on the stack.  */
    return RETURN_VALUE_STRUCT_CONVENTION;
  if (TYPE_LENGTH (valtype) == 5
      || TYPE_LENGTH (valtype) == 6)
    /* Anything 5 or 6 bytes in size goes in memory.  Contents don't
       appear to matter.  Note that 7 and 8 byte objects do end up in
       registers!  */
    return RETURN_VALUE_STRUCT_CONVENTION;
  if (TYPE_LENGTH (valtype) == 1)
    {
      /* All single byte values go in a register stored right-aligned.
         Note: 2 byte integer values are handled further down.  */
      if (readbuf)
	{
	  /* Since TYPE is smaller than the register, there isn't a
             sign extension problem.  Let the extraction truncate the
             register value.  */
	  ULONGEST regval;
	  regcache_cooked_read_unsigned (regcache, R0_REGNUM,
					 &regval);
	  store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), regval);

	}
      if (writebuf)
	{
	  ULONGEST regval;
	  if (TYPE_CODE (valtype) == TYPE_CODE_INT)
	    /* Some sort of integer value stored in R0.  Use
	       unpack_long since that should handle any required sign
	       extension.  */
	    regval = unpack_long (valtype, writebuf);
	  else
	    /* Some other type.  Don't sign-extend the value when
               storing it in the register.  */
	    regval = extract_unsigned_integer (writebuf, 1);
	  regcache_cooked_write_unsigned (regcache, R0_REGNUM, regval);
	}
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
  if ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
       || TYPE_CODE (valtype) == TYPE_CODE_UNION)
      && TYPE_NFIELDS (valtype) > 1
      && TYPE_FIELD_BITPOS (valtype, 1) == 8)
    /* If a composite is 8 bit aligned (determined by looking at the
       start address of the second field), put it in memory.  */
    return RETURN_VALUE_STRUCT_CONVENTION;
  /* Assume it is in registers.  */
  if (writebuf || readbuf)
    {
      int reg;
      /* Per above, the value is never more than 8 bytes long.  */
      gdb_assert (TYPE_LENGTH (valtype) <= 8);
      /* Xfer 2 bytes at a time.  */
      for (reg = 0; (reg * 2) + 1 < TYPE_LENGTH (valtype); reg++)
	{
	  if (readbuf)
	    regcache_cooked_read (regcache, R0_REGNUM + reg,
				  (bfd_byte *) readbuf + reg * 2);
	  if (writebuf)
	    regcache_cooked_write (regcache, R0_REGNUM + reg,
				   (bfd_byte *) writebuf + reg * 2);
	}
      /* Any trailing byte ends up _left_ aligned.  */
      if ((reg * 2) < TYPE_LENGTH (valtype))
	{
	  if (readbuf)
	    regcache_cooked_read_part (regcache, R0_REGNUM + reg,
				       0, 1, (bfd_byte *) readbuf + reg * 2);
	  if (writebuf)
	    regcache_cooked_write_part (regcache, R0_REGNUM + reg,
					0, 1, (bfd_byte *) writebuf + reg * 2);
	}
    }
  return RETURN_VALUE_REGISTER_CONVENTION;
}