/* MVS note this is deprecated. */ static void mn10300_store_return_value (struct type *type, struct regcache *regcache, const void *valbuf) { struct gdbarch *gdbarch = get_regcache_arch (regcache); int len = TYPE_LENGTH (type); int reg, regsz; if (TYPE_CODE (type) == TYPE_CODE_PTR) reg = 4; else reg = 0; regsz = register_size (gdbarch, reg); if (len <= regsz) regcache_raw_write_part (regcache, reg, 0, len, valbuf); else if (len <= 2 * regsz) { regcache_raw_write (regcache, reg, valbuf); gdb_assert (regsz == register_size (gdbarch, reg + 1)); regcache_raw_write_part (regcache, reg+1, 0, len - regsz, (char *) valbuf + regsz); } else internal_error (__FILE__, __LINE__, _("Cannot store return value %d bytes long."), len); }
static void swapped_regcache_raw_write_part (struct regcache *regcache, int regnum, int offset, int len, const gdb_byte *buf) { int j; gdb_byte swapper_buf[16]; if (regnum < AMD64_XMM0_REGNUM || regnum > AMD64_XMM0_REGNUM + 15) { regcache_raw_write_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 (&swapper_buf[offset], buf, len); 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; } regcache_raw_write (regcache, regnum, swapper_buf); }
static void m68k_store_return_value (struct type *type, struct regcache *regcache, const gdb_byte *valbuf) { int len = TYPE_LENGTH (type); if (len <= 4) regcache_raw_write_part (regcache, M68K_D0_REGNUM, 4 - len, len, valbuf); else if (len <= 8) { regcache_raw_write_part (regcache, M68K_D0_REGNUM, 8 - len, len - 4, valbuf); regcache_raw_write (regcache, M68K_D1_REGNUM, valbuf + (len - 4)); } else internal_error (__FILE__, __LINE__, _("Cannot store return value of %d bytes long."), len); }
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 CORE_ADDR amd64_push_arguments(struct regcache *regcache, int nargs, struct value **args, CORE_ADDR sp, int struct_return) { static int integer_regnum[] = { AMD64_RDI_REGNUM, /* %rdi */ AMD64_RSI_REGNUM, /* %rsi */ AMD64_RDX_REGNUM, /* %rdx */ AMD64_RCX_REGNUM, /* %rcx */ 8, /* %r8 */ 9 /* %r9 */ }; static int sse_regnum[] = { /* %xmm0 ... %xmm7 */ AMD64_XMM0_REGNUM + 0, AMD64_XMM1_REGNUM, AMD64_XMM0_REGNUM + 2, AMD64_XMM0_REGNUM + 3, AMD64_XMM0_REGNUM + 4, AMD64_XMM0_REGNUM + 5, AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7, }; struct value **stack_args = alloca(nargs * sizeof(struct value *)); int num_stack_args = 0; int num_elements = 0; int element = 0; int integer_reg = 0; int sse_reg = 0; int i; /* Reserve a register for the "hidden" argument: */ if (struct_return) integer_reg++; for (i = 0; i < nargs; i++) { struct type *type = value_type(args[i]); int len = TYPE_LENGTH(type); enum amd64_reg_class reg_class[2]; int needed_integer_regs = 0; int needed_sse_regs = 0; int j; /* Classify argument: */ amd64_classify(type, reg_class); /* Calculate the number of integer and SSE registers needed for this argument. */ for (j = 0; j < 2; j++) { if (reg_class[j] == AMD64_INTEGER) needed_integer_regs++; else if (reg_class[j] == AMD64_SSE) needed_sse_regs++; } /* Check whether enough registers are available, and if the argument should be passed in registers at all. */ if (((size_t)(integer_reg + needed_integer_regs) > ARRAY_SIZE(integer_regnum)) || ((size_t)(sse_reg + needed_sse_regs) > ARRAY_SIZE(sse_regnum)) || ((needed_integer_regs == 0) && (needed_sse_regs == 0))) { /* The argument will be passed on the stack: */ num_elements += ((len + 7) / 8); stack_args[num_stack_args++] = args[i]; } else { /* The argument will be passed in registers: */ const gdb_byte *valbuf = value_contents(args[i]); gdb_byte buf[8]; gdb_assert(len <= 16); for (j = 0; len > 0; j++, len -= 8) { int regnum = -1; int offset = 0; switch (reg_class[j]) { case AMD64_INTEGER: regnum = integer_regnum[integer_reg++]; break; case AMD64_SSE: regnum = sse_regnum[sse_reg++]; break; case AMD64_SSEUP: gdb_assert(sse_reg > 0); regnum = sse_regnum[sse_reg - 1]; offset = 8; break; default: gdb_assert(!"Unexpected register class."); } gdb_assert(regnum != -1); memset(buf, 0, sizeof(buf)); memcpy(buf, (valbuf + j * 8), min(len, 8)); /* APPLE LOCAL: We keep the XMM registers in "user's view" * byte order inside gdb, so we need to unswap them before * the ABI read/writes, which assume the byte order of the * actual machine: */ if ((reg_class[j] == AMD64_SSE) || (reg_class[j] == AMD64_SSEUP)) swapped_regcache_raw_write_part(regcache, regnum, offset, 8, buf); else regcache_raw_write_part(regcache, regnum, offset, 8, buf); } } } /* Allocate space for the arguments on the stack: */ sp -= (num_elements * 8); /* The psABI says that "The end of the input argument area shall be aligned on a 16 byte boundary." */ sp &= ~0xf; /* Write out the arguments to the stack: */ for (i = 0; i < num_stack_args; i++) { struct type *type = value_type(stack_args[i]); const gdb_byte *valbuf = value_contents(stack_args[i]); int len = TYPE_LENGTH(type); write_memory(sp + element * 8, valbuf, len); element += ((len + 7) / 8); } /* The psABI says that "For calls that may call functions that use varargs or stdargs (prototype-less calls or calls to functions containing ellipsis (...) in the declaration) %al is used as hidden argument to specify the number of SSE registers used. */ regcache_raw_write_unsigned(regcache, AMD64_RAX_REGNUM, sse_reg); return sp; }
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; }