int arch_fetch_retval(struct fetch_context *ctx, enum tof type, struct process *proc, struct arg_type_info *info, struct value *valuep) { if (fetch_register_banks(proc, ctx) < 0) return -1; if (ctx->hardfp && !ctx->in_varargs) { int rc; if ((rc = consider_vfp(ctx, proc, info, valuep)) != 1) return rc; } size_t sz = type_sizeof(proc, info); assert(sz != (size_t)-1); switch (info->type) { unsigned char *data; case ARGTYPE_VOID: return 0; case ARGTYPE_FLOAT: case ARGTYPE_DOUBLE: if (ctx->hardfp && !ctx->in_varargs) { unsigned char *data = value_reserve(valuep, sz); if (data == NULL) return -1; memmove(data, &ctx->fpregs, sz); return 0; } goto pass_in_registers; case ARGTYPE_ARRAY: case ARGTYPE_STRUCT: if (sz > 4) { value_in_inferior(valuep, ctx->ret_struct); return 0; } /* Fall through. */ case ARGTYPE_CHAR: case ARGTYPE_SHORT: case ARGTYPE_USHORT: case ARGTYPE_INT: case ARGTYPE_UINT: case ARGTYPE_LONG: case ARGTYPE_ULONG: case ARGTYPE_POINTER: pass_in_registers: if ((data = value_reserve(valuep, sz)) == NULL) return -1; memmove(data, ctx->regs.uregs, sz); return 0; } assert(info->type != info->type); abort(); }
static int allocate_gpr_pair(struct fetch_context *ctx, struct Process *proc, struct arg_type_info *info, struct value *valuep, size_t sz) { assert(!s390x(ctx)); assert(sz <= 8); if (ctx->greg > 5) { ctx->greg = 7; return allocate_stack_slot(ctx, proc, info, valuep, sz); } if (value_reserve(valuep, sz) == NULL) return -1; unsigned char *ptr = value_get_raw_data(valuep); union { struct { uint32_t a; uint32_t b; }; unsigned char buf[8]; } u; u.a = ctx->regs.gprs[ctx->greg++]; u.b = ctx->regs.gprs[ctx->greg++]; memcpy(ptr, u.buf, sz); return 0; }
static int allocate_fpr(struct fetch_context *ctx, struct Process *proc, struct arg_type_info *info, struct value *valuep, size_t sz) { int pool = s390x(ctx) ? 6 : 2; if (ctx->freg > pool) return allocate_stack_slot(ctx, proc, info, valuep, sz); if (value_reserve(valuep, sz) == NULL) return -1; memcpy(value_get_raw_data(valuep), &ctx->regs.fp_regs.fprs[ctx->freg], sz); ctx->freg += 2; return 0; }
/* 0 is success, 1 is failure, negative value is an error. */ static int pass_in_vfp(struct fetch_context *ctx, struct process *proc, enum arg_type type, size_t count, struct value *valuep) { assert(type == ARGTYPE_FLOAT || type == ARGTYPE_DOUBLE); unsigned max = type == ARGTYPE_DOUBLE ? NUM_VFP_REGS : 2 * NUM_VFP_REGS; if (count > max) return 1; size_t i; size_t j; for (i = 0; i < max; ++i) { for (j = i; j < i + count; ++j) if ((type == ARGTYPE_DOUBLE && ctx->alloc.d[j] != 0) || (type == ARGTYPE_FLOAT && ctx->alloc.s[j] != 0)) goto next; /* Found COUNT consecutive unallocated registers at I. */ const size_t sz = (type == ARGTYPE_FLOAT ? 4 : 8) * count; unsigned char *data = value_reserve(valuep, sz); if (data == NULL) return -1; for (j = i; j < i + count; ++j) if (type == ARGTYPE_DOUBLE) ctx->alloc.d[j] = -1; else ctx->alloc.s[j] = -1; if (type == ARGTYPE_DOUBLE) memcpy(data, ctx->fpregs.d + i, sz); else memcpy(data, ctx->fpregs.s + i, sz); return 0; next: continue; } return 1; }
int arch_fetch_arg_next(struct fetch_context *ctx, enum tof type, struct process *proc, struct arg_type_info *info, struct value *valuep) { const size_t sz = type_sizeof(proc, info); assert(sz != (size_t)-1); if (ctx->hardfp && !ctx->in_varargs) { int rc; if ((rc = consider_vfp(ctx, proc, info, valuep)) != 1) return rc; } /* IHI0042E_aapcs: If the argument requires double-word * alignment (8-byte), the NCRN is rounded up to the next even * register number. */ const size_t al = type_alignof(proc, info); assert(al != (size_t)-1); if (al == 8) ctx->ncrn = ((ctx->ncrn + 1) / 2) * 2; /* If the size in words of the argument is not more than r4 * minus NCRN, the argument is copied into core registers, * starting at the NCRN. */ /* If the NCRN is less than r4 and the NSAA is equal to the * SP, the argument is split between core registers and the * stack. */ const size_t words = (sz + 3) / 4; if (ctx->ncrn < 4 && ctx->nsaa == ctx->sp) { unsigned char *data = value_reserve(valuep, words * 4); if (data == NULL) return -1; size_t i; for (i = 0; i < words && ctx->ncrn < 4; ++i) { memcpy(data, &ctx->regs.uregs[ctx->ncrn++], 4); data += 4; } const size_t rest = (words - i) * 4; if (rest > 0) { umovebytes(proc, ctx->nsaa, data, rest); ctx->nsaa += rest; } return 0; } assert(ctx->ncrn == 4); /* If the argument required double-word alignment (8-byte), * then the NSAA is rounded up to the next double-word * address. */ if (al == 8) /* XXX double cast. */ ctx->nsaa = (arch_addr_t)((((uintptr_t)ctx->nsaa + 7) / 8) * 8); else ctx->nsaa = (arch_addr_t)((((uintptr_t)ctx->nsaa + 3) / 4) * 4); value_in_inferior(valuep, ctx->nsaa); ctx->nsaa += sz; return 0; }