Example #1
0
static enum return_value_convention
amd64_windows_return_value (struct gdbarch *gdbarch, struct value *function,
			    struct type *type, struct regcache *regcache,
			    gdb_byte *readbuf, const gdb_byte *writebuf)
{
  int len = TYPE_LENGTH (type);
  int regnum = -1;

  /* See if our value is returned through a register.  If it is, then
     store the associated register number in REGNUM.  */
  switch (TYPE_CODE (type))
    {
      case TYPE_CODE_FLT:
      case TYPE_CODE_DECFLOAT:
        /* __m128, __m128i, __m128d, floats, and doubles are returned
           via XMM0.  */
        if (len == 4 || len == 8 || len == 16)
          regnum = AMD64_XMM0_REGNUM;
        break;
      default:
        /* All other values that are 1, 2, 4 or 8 bytes long are returned
           via RAX.  */
        if (len == 1 || len == 2 || len == 4 || len == 8)
          regnum = AMD64_RAX_REGNUM;
        break;
    }

  if (regnum < 0)
    {
      /* RAX contains the address where the return value has been stored.  */
      if (readbuf)
        {
	  ULONGEST addr;

	  regcache_raw_read_unsigned (regcache, AMD64_RAX_REGNUM, &addr);
	  read_memory (addr, readbuf, TYPE_LENGTH (type));
	}
      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
    }
  else
    {
      /* Extract the return value from the register where it was stored.  */
      if (readbuf)
	regcache_raw_read_part (regcache, regnum, 0, len, readbuf);
      if (writebuf)
	regcache_raw_write_part (regcache, regnum, 0, len, writebuf);
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
}
Example #2
0
static void
swapped_regcache_raw_read_part (struct regcache *regcache, int regnum,
                                int offset, int len, gdb_byte *buf)
{
  int j;
  gdb_byte swapper_buf[16];

  if (regnum < AMD64_XMM0_REGNUM || regnum > AMD64_XMM0_REGNUM + 15)
    {
       regcache_raw_read_part (regcache, regnum, offset, len, buf);
       return;
    }

  regcache_raw_read (regcache, regnum, swapper_buf);
  for (j = 0; j < 8; j++)
    {
      gdb_byte tmp = swapper_buf[j];
      swapper_buf[j] = swapper_buf[16 - j - 1];
      swapper_buf[16 - j - 1] = tmp;
    }

  memcpy (buf, &swapper_buf[offset], len);
}
Example #3
0
static enum return_value_convention
amd64_return_value(struct gdbarch *gdbarch, struct type *type,
		   struct regcache *regcache,
		   gdb_byte *readbuf, const gdb_byte *writebuf)
{
  enum amd64_reg_class reg_class[2];
  int len = TYPE_LENGTH(type);
  static int integer_regnum[] = { AMD64_RAX_REGNUM, AMD64_RDX_REGNUM };
  static int sse_regnum[] = { AMD64_XMM0_REGNUM, AMD64_XMM1_REGNUM };
  int integer_reg = 0;
  int sse_reg = 0;
  int i;

  gdb_assert(!(readbuf && writebuf));

  /* 1. Classify the return type with the classification algorithm: */
  amd64_classify(type, reg_class);

  /* 2. If the type has class MEMORY, then the caller provides space
     for the return value and passes the address of this storage in
     %rdi as if it were the first argument to the function. In effect,
     this address becomes a hidden first argument.

     On return %rax will contain the address that has been passed in
     by the caller in %rdi.  */
  if (reg_class[0] == AMD64_MEMORY)
    {
      /* As indicated by the comment above, the ABI guarantees that we
         can always find the return value just after the function has
         returned.  */

      if (readbuf)
	{
	  ULONGEST addr;

	  regcache_raw_read_unsigned(regcache, AMD64_RAX_REGNUM, &addr);
	  read_memory(addr, readbuf, TYPE_LENGTH(type));
	}

      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
    }

  gdb_assert(reg_class[1] != AMD64_MEMORY);
  gdb_assert(len <= 16);

  for (i = 0; len > 0; i++, len -= 8)
    {
      int regnum = -1;
      int offset = 0;

      switch (reg_class[i])
	{
	case AMD64_INTEGER:
	  /* 3. If the class is INTEGER, the next available register
	     of the sequence %rax, %rdx is used.  */
	  regnum = integer_regnum[integer_reg++];
	  break;

	case AMD64_SSE:
	  /* 4. If the class is SSE, the next available SSE register
             of the sequence %xmm0, %xmm1 is used.  */
	  regnum = sse_regnum[sse_reg++];
	  break;

	case AMD64_SSEUP:
	  /* 5. If the class is SSEUP, the eightbyte is passed in the
	     upper half of the last used SSE register.  */
	  gdb_assert (sse_reg > 0);
	  regnum = sse_regnum[sse_reg - 1];
	  offset = 8;
	  break;

	case AMD64_X87:
	  /* 6. If the class is X87, the value is returned on the X87
             stack in %st0 as 80-bit x87 number.  */
	  regnum = AMD64_ST0_REGNUM;
	  if (writebuf)
	    i387_return_value(gdbarch, regcache);
	  break;

	case AMD64_X87UP:
	  /* 7. If the class is X87UP, the value is returned together
             with the previous X87 value in %st0.  */
	  gdb_assert((i > 0) && (reg_class[0] == AMD64_X87));
	  regnum = AMD64_ST0_REGNUM;
	  offset = 8;
	  len = 2;
	  break;

	case AMD64_NO_CLASS:
	  continue;

	default:
	  gdb_assert(!"Unexpected register class.");
	}

      gdb_assert(regnum != -1);

      /* APPLE LOCAL: We keep the XMM registers in the "user's view"
         byte order inside gdb so we need to unswap them before the
         ABI read/writes which assume the actual machine byte order.  */

      if ((readbuf || writebuf)
          && ((regnum == sse_regnum[0]) || (regnum == sse_regnum[1])))
        {
          if (readbuf)
	    swapped_regcache_raw_read_part(regcache, regnum, offset,
                                           min(len, 8), readbuf + i * 8);
          if (writebuf)
	    swapped_regcache_raw_write_part(regcache, regnum, offset,
                                            min(len, 8), writebuf + i * 8);
          continue;
        }

      if (readbuf)
	regcache_raw_read_part(regcache, regnum, offset, min(len, 8),
                               readbuf + i * 8);
      if (writebuf)
	regcache_raw_write_part(regcache, regnum, offset, min(len, 8),
                                writebuf + i * 8);
    }

  return RETURN_VALUE_REGISTER_CONVENTION;
}