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; } }
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); }
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; }