forked from luck/tmp_suning_uos_patched
Merge branches 'regset.x86', 'regset.ia64', 'regset.sparc' and 'regset.arm64' into work.regset
This commit is contained in:
commit
1e56f6d289
|
@ -1237,6 +1237,22 @@ enum compat_regset {
|
|||
REGSET_COMPAT_VFP,
|
||||
};
|
||||
|
||||
static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int idx)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(task);
|
||||
|
||||
switch (idx) {
|
||||
case 15:
|
||||
return regs->pc;
|
||||
case 16:
|
||||
return pstate_to_compat_psr(regs->pstate);
|
||||
case 17:
|
||||
return regs->orig_x0;
|
||||
default:
|
||||
return regs->regs[idx];
|
||||
}
|
||||
}
|
||||
|
||||
static int compat_gpr_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
|
@ -1255,23 +1271,7 @@ static int compat_gpr_get(struct task_struct *target,
|
|||
return -EIO;
|
||||
|
||||
for (i = 0; i < num_regs; ++i) {
|
||||
unsigned int idx = start + i;
|
||||
compat_ulong_t reg;
|
||||
|
||||
switch (idx) {
|
||||
case 15:
|
||||
reg = task_pt_regs(target)->pc;
|
||||
break;
|
||||
case 16:
|
||||
reg = task_pt_regs(target)->pstate;
|
||||
reg = pstate_to_compat_psr(reg);
|
||||
break;
|
||||
case 17:
|
||||
reg = task_pt_regs(target)->orig_x0;
|
||||
break;
|
||||
default:
|
||||
reg = task_pt_regs(target)->regs[idx];
|
||||
}
|
||||
compat_ulong_t reg = compat_get_user_reg(target, start + i);
|
||||
|
||||
if (kbuf) {
|
||||
memcpy(kbuf, ®, sizeof(reg));
|
||||
|
@ -1541,9 +1541,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
|
|||
else if (off == COMPAT_PT_TEXT_END_ADDR)
|
||||
tmp = tsk->mm->end_code;
|
||||
else if (off < sizeof(compat_elf_gregset_t))
|
||||
return copy_regset_to_user(tsk, &user_aarch32_view,
|
||||
REGSET_COMPAT_GPR, off,
|
||||
sizeof(compat_ulong_t), ret);
|
||||
tmp = compat_get_user_reg(tsk, off >> 2);
|
||||
else if (off >= COMPAT_USER_SZ)
|
||||
return -EIO;
|
||||
else
|
||||
|
@ -1555,8 +1553,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
|
|||
static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
|
||||
compat_ulong_t val)
|
||||
{
|
||||
int ret;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
struct pt_regs newregs = *task_pt_regs(tsk);
|
||||
unsigned int idx = off / 4;
|
||||
|
||||
if (off & 3 || off >= COMPAT_USER_SZ)
|
||||
return -EIO;
|
||||
|
@ -1564,14 +1562,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
|
|||
if (off >= sizeof(compat_elf_gregset_t))
|
||||
return 0;
|
||||
|
||||
set_fs(KERNEL_DS);
|
||||
ret = copy_regset_from_user(tsk, &user_aarch32_view,
|
||||
REGSET_COMPAT_GPR, off,
|
||||
sizeof(compat_ulong_t),
|
||||
&val);
|
||||
set_fs(old_fs);
|
||||
switch (idx) {
|
||||
case 15:
|
||||
newregs.pc = val;
|
||||
break;
|
||||
case 16:
|
||||
newregs.pstate = compat_psr_to_pstate(val);
|
||||
break;
|
||||
case 17:
|
||||
newregs.orig_x0 = val;
|
||||
break;
|
||||
default:
|
||||
newregs.regs[idx] = val;
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (!valid_user_regs(&newregs.user_regs, tsk))
|
||||
return -EINVAL;
|
||||
|
||||
*task_pt_regs(tsk) = newregs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
|
|
|
@ -1273,52 +1273,43 @@ struct regset_getset {
|
|||
int ret;
|
||||
};
|
||||
|
||||
static const ptrdiff_t pt_offsets[32] =
|
||||
{
|
||||
#define R(n) offsetof(struct pt_regs, r##n)
|
||||
[0] = -1, R(1), R(2), R(3),
|
||||
[4] = -1, [5] = -1, [6] = -1, [7] = -1,
|
||||
R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15),
|
||||
R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
|
||||
R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
|
||||
#undef R
|
||||
};
|
||||
|
||||
static int
|
||||
access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info,
|
||||
unsigned long addr, unsigned long *data, int write_access)
|
||||
{
|
||||
struct pt_regs *pt;
|
||||
unsigned long *ptr = NULL;
|
||||
int ret;
|
||||
char nat = 0;
|
||||
struct pt_regs *pt = task_pt_regs(target);
|
||||
unsigned reg = addr / sizeof(unsigned long);
|
||||
ptrdiff_t d = pt_offsets[reg];
|
||||
|
||||
pt = task_pt_regs(target);
|
||||
switch (addr) {
|
||||
case ELF_GR_OFFSET(1):
|
||||
ptr = &pt->r1;
|
||||
break;
|
||||
case ELF_GR_OFFSET(2):
|
||||
case ELF_GR_OFFSET(3):
|
||||
ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2));
|
||||
break;
|
||||
case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7):
|
||||
if (d >= 0) {
|
||||
unsigned long *ptr = (void *)pt + d;
|
||||
if (write_access)
|
||||
*ptr = *data;
|
||||
else
|
||||
*data = *ptr;
|
||||
return 0;
|
||||
} else {
|
||||
char nat = 0;
|
||||
if (write_access) {
|
||||
/* read NaT bit first: */
|
||||
unsigned long dummy;
|
||||
|
||||
ret = unw_get_gr(info, addr/8, &dummy, &nat);
|
||||
int ret = unw_get_gr(info, reg, &dummy, &nat);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return unw_access_gr(info, addr/8, data, &nat, write_access);
|
||||
case ELF_GR_OFFSET(8) ... ELF_GR_OFFSET(11):
|
||||
ptr = (void *)&pt->r8 + addr - ELF_GR_OFFSET(8);
|
||||
break;
|
||||
case ELF_GR_OFFSET(12):
|
||||
case ELF_GR_OFFSET(13):
|
||||
ptr = (void *)&pt->r12 + addr - ELF_GR_OFFSET(12);
|
||||
break;
|
||||
case ELF_GR_OFFSET(14):
|
||||
ptr = &pt->r14;
|
||||
break;
|
||||
case ELF_GR_OFFSET(15):
|
||||
ptr = &pt->r15;
|
||||
return unw_access_gr(info, reg, data, &nat, write_access);
|
||||
}
|
||||
if (write_access)
|
||||
*ptr = *data;
|
||||
else
|
||||
*data = *ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1490,7 +1481,7 @@ static int
|
|||
access_elf_reg(struct task_struct *target, struct unw_frame_info *info,
|
||||
unsigned long addr, unsigned long *data, int write_access)
|
||||
{
|
||||
if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(15))
|
||||
if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(31))
|
||||
return access_elf_gpreg(target, info, addr, data, write_access);
|
||||
else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7))
|
||||
return access_elf_breg(target, info, addr, data, write_access);
|
||||
|
@ -1500,10 +1491,7 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info,
|
|||
|
||||
void do_gpregs_get(struct unw_frame_info *info, void *arg)
|
||||
{
|
||||
struct pt_regs *pt;
|
||||
struct regset_getset *dst = arg;
|
||||
elf_greg_t tmp[16];
|
||||
unsigned int i, index, min_copy;
|
||||
|
||||
if (unw_unwind_to_user(info) < 0)
|
||||
return;
|
||||
|
@ -1526,160 +1514,70 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg)
|
|||
&dst->u.get.kbuf,
|
||||
&dst->u.get.ubuf,
|
||||
0, ELF_GR_OFFSET(1));
|
||||
if (dst->ret || dst->count == 0)
|
||||
if (dst->ret)
|
||||
return;
|
||||
}
|
||||
|
||||
/* gr1 - gr15 */
|
||||
if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
|
||||
index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
|
||||
min_copy = ELF_GR_OFFSET(16) > (dst->pos + dst->count) ?
|
||||
(dst->pos + dst->count) : ELF_GR_OFFSET(16);
|
||||
for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
|
||||
index++)
|
||||
if (access_elf_reg(dst->target, info, i,
|
||||
&tmp[index], 0) < 0) {
|
||||
while (dst->count && dst->pos < ELF_AR_END_OFFSET) {
|
||||
unsigned int n, from, to;
|
||||
elf_greg_t tmp[16];
|
||||
|
||||
from = dst->pos;
|
||||
to = from + min(dst->count, (unsigned)sizeof(tmp));
|
||||
if (to > ELF_AR_END_OFFSET)
|
||||
to = ELF_AR_END_OFFSET;
|
||||
for (n = 0; from < to; from += sizeof(elf_greg_t), n++) {
|
||||
if (access_elf_reg(dst->target, info, from,
|
||||
&tmp[n], 0) < 0) {
|
||||
dst->ret = -EIO;
|
||||
return;
|
||||
}
|
||||
}
|
||||
dst->ret = user_regset_copyout(&dst->pos, &dst->count,
|
||||
&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
|
||||
ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
|
||||
if (dst->ret || dst->count == 0)
|
||||
dst->pos, to);
|
||||
if (dst->ret)
|
||||
return;
|
||||
}
|
||||
|
||||
/* r16-r31 */
|
||||
if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
|
||||
pt = task_pt_regs(dst->target);
|
||||
dst->ret = user_regset_copyout(&dst->pos, &dst->count,
|
||||
&dst->u.get.kbuf, &dst->u.get.ubuf, &pt->r16,
|
||||
ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
|
||||
if (dst->ret || dst->count == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
/* nat, pr, b0 - b7 */
|
||||
if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
|
||||
index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
|
||||
min_copy = ELF_CR_IIP_OFFSET > (dst->pos + dst->count) ?
|
||||
(dst->pos + dst->count) : ELF_CR_IIP_OFFSET;
|
||||
for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
|
||||
index++)
|
||||
if (access_elf_reg(dst->target, info, i,
|
||||
&tmp[index], 0) < 0) {
|
||||
dst->ret = -EIO;
|
||||
return;
|
||||
}
|
||||
dst->ret = user_regset_copyout(&dst->pos, &dst->count,
|
||||
&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
|
||||
ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
|
||||
if (dst->ret || dst->count == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
|
||||
* ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
|
||||
*/
|
||||
if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) {
|
||||
index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
|
||||
min_copy = ELF_AR_END_OFFSET > (dst->pos + dst->count) ?
|
||||
(dst->pos + dst->count) : ELF_AR_END_OFFSET;
|
||||
for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
|
||||
index++)
|
||||
if (access_elf_reg(dst->target, info, i,
|
||||
&tmp[index], 0) < 0) {
|
||||
dst->ret = -EIO;
|
||||
return;
|
||||
}
|
||||
dst->ret = user_regset_copyout(&dst->pos, &dst->count,
|
||||
&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
|
||||
ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
void do_gpregs_set(struct unw_frame_info *info, void *arg)
|
||||
{
|
||||
struct pt_regs *pt;
|
||||
struct regset_getset *dst = arg;
|
||||
elf_greg_t tmp[16];
|
||||
unsigned int i, index;
|
||||
|
||||
if (unw_unwind_to_user(info) < 0)
|
||||
return;
|
||||
|
||||
if (!dst->count)
|
||||
return;
|
||||
/* Skip r0 */
|
||||
if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) {
|
||||
if (dst->pos < ELF_GR_OFFSET(1)) {
|
||||
dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count,
|
||||
&dst->u.set.kbuf,
|
||||
&dst->u.set.ubuf,
|
||||
0, ELF_GR_OFFSET(1));
|
||||
if (dst->ret || dst->count == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
/* gr1-gr15 */
|
||||
if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
|
||||
i = dst->pos;
|
||||
index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
|
||||
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
|
||||
&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
|
||||
ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
|
||||
if (dst->ret)
|
||||
return;
|
||||
for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++)
|
||||
if (access_elf_reg(dst->target, info, i,
|
||||
&tmp[index], 1) < 0) {
|
||||
dst->ret = -EIO;
|
||||
return;
|
||||
}
|
||||
if (dst->count == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
/* gr16-gr31 */
|
||||
if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
|
||||
pt = task_pt_regs(dst->target);
|
||||
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
|
||||
&dst->u.set.kbuf, &dst->u.set.ubuf, &pt->r16,
|
||||
ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
|
||||
if (dst->ret || dst->count == 0)
|
||||
return;
|
||||
}
|
||||
while (dst->count && dst->pos < ELF_AR_END_OFFSET) {
|
||||
unsigned int n, from, to;
|
||||
elf_greg_t tmp[16];
|
||||
|
||||
/* nat, pr, b0 - b7 */
|
||||
if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
|
||||
i = dst->pos;
|
||||
index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
|
||||
from = dst->pos;
|
||||
to = from + sizeof(tmp);
|
||||
if (to > ELF_AR_END_OFFSET)
|
||||
to = ELF_AR_END_OFFSET;
|
||||
/* get up to 16 values */
|
||||
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
|
||||
&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
|
||||
ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
|
||||
from, to);
|
||||
if (dst->ret)
|
||||
return;
|
||||
for (; i < dst->pos; i += sizeof(elf_greg_t), index++)
|
||||
if (access_elf_reg(dst->target, info, i,
|
||||
&tmp[index], 1) < 0) {
|
||||
dst->ret = -EIO;
|
||||
return;
|
||||
}
|
||||
if (dst->count == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
|
||||
* ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
|
||||
*/
|
||||
if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) {
|
||||
i = dst->pos;
|
||||
index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
|
||||
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
|
||||
&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
|
||||
ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET);
|
||||
if (dst->ret)
|
||||
return;
|
||||
for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++)
|
||||
if (access_elf_reg(dst->target, info, i,
|
||||
&tmp[index], 1) < 0) {
|
||||
/* now copy them into registers */
|
||||
for (n = 0; from < dst->pos; from += sizeof(elf_greg_t), n++)
|
||||
if (access_elf_reg(dst->target, info, from,
|
||||
&tmp[n], 1) < 0) {
|
||||
dst->ret = -EIO;
|
||||
return;
|
||||
}
|
||||
|
@ -1913,7 +1811,6 @@ access_uarea(struct task_struct *child, unsigned long addr,
|
|||
unsigned long *data, int write_access)
|
||||
{
|
||||
unsigned int pos = -1; /* an invalid value */
|
||||
int ret;
|
||||
unsigned long *ptr, regnum;
|
||||
|
||||
if ((addr & 0x7) != 0) {
|
||||
|
@ -1945,14 +1842,39 @@ access_uarea(struct task_struct *child, unsigned long addr,
|
|||
}
|
||||
|
||||
if (pos != -1) {
|
||||
if (write_access)
|
||||
ret = fpregs_set(child, NULL, pos,
|
||||
sizeof(unsigned long), data, NULL);
|
||||
else
|
||||
ret = fpregs_get(child, NULL, pos,
|
||||
sizeof(unsigned long), data, NULL);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
unsigned reg = pos / sizeof(elf_fpreg_t);
|
||||
int which_half = (pos / sizeof(unsigned long)) & 1;
|
||||
|
||||
if (reg < 32) { /* fr2-fr31 */
|
||||
struct unw_frame_info info;
|
||||
elf_fpreg_t fpreg;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
unw_init_from_blocked_task(&info, child);
|
||||
if (unw_unwind_to_user(&info) < 0)
|
||||
return 0;
|
||||
|
||||
if (unw_get_fr(&info, reg, &fpreg))
|
||||
return -1;
|
||||
if (write_access) {
|
||||
fpreg.u.bits[which_half] = *data;
|
||||
if (unw_set_fr(&info, reg, fpreg))
|
||||
return -1;
|
||||
} else {
|
||||
*data = fpreg.u.bits[which_half];
|
||||
}
|
||||
} else { /* fph */
|
||||
elf_fpreg_t *p = &child->thread.fph[reg - 32];
|
||||
unsigned long *bits = &p->u.bits[which_half];
|
||||
|
||||
ia64_sync_fph(child);
|
||||
if (write_access)
|
||||
*bits = *data;
|
||||
else if (child->thread.flags & IA64_THREAD_FPH_VALID)
|
||||
*data = *bits;
|
||||
else
|
||||
*data = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2038,15 +1960,14 @@ access_uarea(struct task_struct *child, unsigned long addr,
|
|||
}
|
||||
|
||||
if (pos != -1) {
|
||||
if (write_access)
|
||||
ret = gpregs_set(child, NULL, pos,
|
||||
sizeof(unsigned long), data, NULL);
|
||||
else
|
||||
ret = gpregs_get(child, NULL, pos,
|
||||
sizeof(unsigned long), data, NULL);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
struct unw_frame_info info;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
unw_init_from_blocked_task(&info, child);
|
||||
if (unw_unwind_to_user(&info) < 0)
|
||||
return 0;
|
||||
|
||||
return access_elf_reg(child, &info, pos, data, write_access);
|
||||
}
|
||||
|
||||
/* access debug registers */
|
||||
|
|
|
@ -99,15 +99,13 @@ static int genregs32_get(struct task_struct *target,
|
|||
if (ret || !count)
|
||||
return ret;
|
||||
|
||||
if (pos < 32 * sizeof(u32)) {
|
||||
if (regwindow32_get(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
uregs,
|
||||
16 * sizeof(u32), 32 * sizeof(u32));
|
||||
if (ret || !count)
|
||||
return ret;
|
||||
}
|
||||
if (regwindow32_get(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
uregs,
|
||||
16 * sizeof(u32), 32 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uregs[0] = regs->psr;
|
||||
uregs[1] = regs->pc;
|
||||
|
@ -139,19 +137,18 @@ static int genregs32_set(struct task_struct *target,
|
|||
if (ret || !count)
|
||||
return ret;
|
||||
|
||||
if (pos < 32 * sizeof(u32)) {
|
||||
if (regwindow32_get(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
uregs,
|
||||
16 * sizeof(u32), 32 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (regwindow32_set(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
if (!count)
|
||||
return 0;
|
||||
}
|
||||
if (regwindow32_get(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
uregs,
|
||||
16 * sizeof(u32), 32 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (regwindow32_set(target, regs, uregs))
|
||||
return -EFAULT;
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&psr,
|
||||
32 * sizeof(u32), 33 * sizeof(u32));
|
||||
|
@ -243,13 +240,11 @@ static int fpregs32_set(struct task_struct *target,
|
|||
user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
32 * sizeof(u32),
|
||||
33 * sizeof(u32));
|
||||
if (!ret && count > 0) {
|
||||
if (!ret)
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fsr,
|
||||
33 * sizeof(u32),
|
||||
34 * sizeof(u32));
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
34 * sizeof(u32), -1);
|
||||
|
@ -288,6 +283,125 @@ static const struct user_regset sparc32_regsets[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int getregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const struct pt_regs *regs = target->thread.kregs;
|
||||
u32 v[4];
|
||||
int ret;
|
||||
|
||||
if (target == current)
|
||||
flush_user_windows();
|
||||
|
||||
v[0] = regs->psr;
|
||||
v[1] = regs->pc;
|
||||
v[2] = regs->npc;
|
||||
v[3] = regs->y;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
v,
|
||||
0 * sizeof(u32), 4 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs->u_regs + 1,
|
||||
4 * sizeof(u32), 19 * sizeof(u32));
|
||||
}
|
||||
|
||||
static int setregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct pt_regs *regs = target->thread.kregs;
|
||||
u32 v[4];
|
||||
int ret;
|
||||
|
||||
if (target == current)
|
||||
flush_user_windows();
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
v,
|
||||
0, 4 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
|
||||
(v[0] & (PSR_ICC | PSR_SYSCALL));
|
||||
regs->pc = v[1];
|
||||
regs->npc = v[2];
|
||||
regs->y = v[3];
|
||||
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
regs->u_regs + 1,
|
||||
4 * sizeof(u32) , 19 * sizeof(u32));
|
||||
}
|
||||
|
||||
static int getfpregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const unsigned long *fpregs = target->thread.float_regs;
|
||||
int ret = 0;
|
||||
|
||||
#if 0
|
||||
if (target == current)
|
||||
save_and_clear_fpu();
|
||||
#endif
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs,
|
||||
0, 32 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fsr,
|
||||
32 * sizeof(u32), 33 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
33 * sizeof(u32), 68 * sizeof(u32));
|
||||
}
|
||||
|
||||
static int setfpregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
unsigned long *fpregs = target->thread.float_regs;
|
||||
int ret;
|
||||
|
||||
#if 0
|
||||
if (target == current)
|
||||
save_and_clear_fpu();
|
||||
#endif
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs,
|
||||
0, 32 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fsr,
|
||||
32 * sizeof(u32),
|
||||
33 * sizeof(u32));
|
||||
}
|
||||
|
||||
static const struct user_regset ptrace32_regsets[] = {
|
||||
[REGSET_GENERAL] = {
|
||||
.n = 19, .size = sizeof(u32),
|
||||
.get = getregs_get, .set = setregs_set,
|
||||
},
|
||||
[REGSET_FP] = {
|
||||
.n = 68, .size = sizeof(u32),
|
||||
.get = getfpregs_get, .set = setfpregs_set,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct user_regset_view ptrace32_view = {
|
||||
.regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_sparc32_view = {
|
||||
.name = "sparc", .e_machine = EM_SPARC,
|
||||
.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
|
||||
|
@ -315,74 +429,44 @@ long arch_ptrace(struct task_struct *child, long request,
|
|||
{
|
||||
unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
|
||||
void __user *addr2p;
|
||||
const struct user_regset_view *view;
|
||||
struct pt_regs __user *pregs;
|
||||
struct fps __user *fps;
|
||||
int ret;
|
||||
|
||||
view = task_user_regset_view(current);
|
||||
addr2p = (void __user *) addr2;
|
||||
pregs = (struct pt_regs __user *) addr;
|
||||
fps = (struct fps __user *) addr;
|
||||
|
||||
switch(request) {
|
||||
case PTRACE_GETREGS: {
|
||||
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u32),
|
||||
4 * sizeof(u32),
|
||||
&pregs->psr);
|
||||
if (!ret)
|
||||
copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u32),
|
||||
15 * sizeof(u32),
|
||||
&pregs->u_regs[0]);
|
||||
ret = copy_regset_to_user(child, &ptrace32_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u32),
|
||||
pregs);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETREGS: {
|
||||
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u32),
|
||||
4 * sizeof(u32),
|
||||
&pregs->psr);
|
||||
if (!ret)
|
||||
copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u32),
|
||||
15 * sizeof(u32),
|
||||
&pregs->u_regs[0]);
|
||||
ret = copy_regset_from_user(child, &ptrace32_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u32),
|
||||
pregs);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_GETFPREGS: {
|
||||
ret = copy_regset_to_user(child, view, REGSET_FP,
|
||||
0 * sizeof(u32),
|
||||
32 * sizeof(u32),
|
||||
&fps->regs[0]);
|
||||
if (!ret)
|
||||
ret = copy_regset_to_user(child, view, REGSET_FP,
|
||||
33 * sizeof(u32),
|
||||
1 * sizeof(u32),
|
||||
&fps->fsr);
|
||||
|
||||
if (!ret) {
|
||||
if (__put_user(0, &fps->fpqd) ||
|
||||
__put_user(0, &fps->flags) ||
|
||||
__put_user(0, &fps->extra) ||
|
||||
clear_user(fps->fpq, sizeof(fps->fpq)))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
ret = copy_regset_to_user(child, &ptrace32_view,
|
||||
REGSET_FP, 0,
|
||||
68 * sizeof(u32),
|
||||
fps);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETFPREGS: {
|
||||
ret = copy_regset_from_user(child, view, REGSET_FP,
|
||||
0 * sizeof(u32),
|
||||
32 * sizeof(u32),
|
||||
&fps->regs[0]);
|
||||
if (!ret)
|
||||
ret = copy_regset_from_user(child, view, REGSET_FP,
|
||||
33 * sizeof(u32),
|
||||
1 * sizeof(u32),
|
||||
&fps->fsr);
|
||||
ret = copy_regset_from_user(child, &ptrace32_view,
|
||||
REGSET_FP, 0,
|
||||
33 * sizeof(u32),
|
||||
fps);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@ static int genregs64_get(struct task_struct *target,
|
|||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs->u_regs,
|
||||
0, 16 * sizeof(u64));
|
||||
if (!ret && count && pos < (32 * sizeof(u64))) {
|
||||
if (!ret && count) {
|
||||
struct reg_window window;
|
||||
|
||||
if (regwindow64_get(target, regs, &window))
|
||||
|
@ -506,6 +506,112 @@ static const struct user_regset sparc64_regsets[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int getregs64_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
int ret;
|
||||
|
||||
if (target == current)
|
||||
flushw_user();
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs->u_regs + 1,
|
||||
0, 15 * sizeof(u64));
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
15 * sizeof(u64), 16 * sizeof(u64));
|
||||
if (!ret) {
|
||||
/* TSTATE, TPC, TNPC */
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
®s->tstate,
|
||||
16 * sizeof(u64),
|
||||
19 * sizeof(u64));
|
||||
}
|
||||
if (!ret) {
|
||||
unsigned long y = regs->y;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&y,
|
||||
19 * sizeof(u64),
|
||||
20 * sizeof(u64));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int setregs64_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
unsigned long y = regs->y;
|
||||
unsigned long tstate;
|
||||
int ret;
|
||||
|
||||
if (target == current)
|
||||
flushw_user();
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
regs->u_regs + 1,
|
||||
0 * sizeof(u64),
|
||||
15 * sizeof(u64));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret =user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
15 * sizeof(u64), 16 * sizeof(u64));
|
||||
if (ret)
|
||||
return ret;
|
||||
/* TSTATE */
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&tstate,
|
||||
16 * sizeof(u64),
|
||||
17 * sizeof(u64));
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Only the condition codes and the "in syscall"
|
||||
* state can be modified in the %tstate register.
|
||||
*/
|
||||
tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
|
||||
regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
|
||||
regs->tstate |= tstate;
|
||||
|
||||
/* TPC, TNPC */
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
®s->tpc,
|
||||
17 * sizeof(u64),
|
||||
19 * sizeof(u64));
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Y */
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&y,
|
||||
19 * sizeof(u64),
|
||||
20 * sizeof(u64));
|
||||
if (!ret)
|
||||
regs->y = y;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct user_regset ptrace64_regsets[] = {
|
||||
/* Format is:
|
||||
* G1 --> G7
|
||||
* O0 --> O7
|
||||
* 0
|
||||
* TSTATE, TPC, TNPC, Y
|
||||
*/
|
||||
[REGSET_GENERAL] = {
|
||||
.n = 20, .size = sizeof(u64),
|
||||
.get = getregs64_get, .set = setregs64_set,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct user_regset_view ptrace64_view = {
|
||||
.regsets = ptrace64_regsets, .n = ARRAY_SIZE(ptrace64_regsets)
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_sparc64_view = {
|
||||
.name = "sparc64", .e_machine = EM_SPARCV9,
|
||||
.regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
|
||||
|
@ -518,10 +624,10 @@ static int genregs32_get(struct task_struct *target,
|
|||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
compat_ulong_t __user *reg_window;
|
||||
compat_ulong_t *k = kbuf;
|
||||
compat_ulong_t __user *u = ubuf;
|
||||
compat_ulong_t reg;
|
||||
u32 uregs[16];
|
||||
u32 reg;
|
||||
|
||||
if (target == current)
|
||||
flushw_user();
|
||||
|
@ -533,52 +639,25 @@ static int genregs32_get(struct task_struct *target,
|
|||
for (; count > 0 && pos < 16; count--)
|
||||
*k++ = regs->u_regs[pos++];
|
||||
|
||||
reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
|
||||
reg_window -= 16;
|
||||
if (target == current) {
|
||||
for (; count > 0 && pos < 32; count--) {
|
||||
if (get_user(*k++, ®_window[pos++]))
|
||||
return -EFAULT;
|
||||
}
|
||||
} else {
|
||||
for (; count > 0 && pos < 32; count--) {
|
||||
if (access_process_vm(target,
|
||||
(unsigned long)
|
||||
®_window[pos],
|
||||
k, sizeof(*k),
|
||||
FOLL_FORCE)
|
||||
!= sizeof(*k))
|
||||
return -EFAULT;
|
||||
k++;
|
||||
pos++;
|
||||
}
|
||||
if (count) {
|
||||
if (get_from_target(target, regs->u_regs[UREG_I6],
|
||||
uregs, sizeof(uregs)))
|
||||
return -EFAULT;
|
||||
for (; count > 0 && pos < 32; count--)
|
||||
*k++ = uregs[pos++ - 16];
|
||||
|
||||
}
|
||||
} else {
|
||||
for (; count > 0 && pos < 16; count--) {
|
||||
for (; count > 0 && pos < 16; count--)
|
||||
if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
|
||||
reg_window -= 16;
|
||||
if (target == current) {
|
||||
for (; count > 0 && pos < 32; count--) {
|
||||
if (get_user(reg, ®_window[pos++]) ||
|
||||
put_user(reg, u++))
|
||||
if (count) {
|
||||
if (get_from_target(target, regs->u_regs[UREG_I6],
|
||||
uregs, sizeof(uregs)))
|
||||
return -EFAULT;
|
||||
for (; count > 0 && pos < 32; count--)
|
||||
if (put_user(uregs[pos++ - 16], u++))
|
||||
return -EFAULT;
|
||||
}
|
||||
} else {
|
||||
for (; count > 0 && pos < 32; count--) {
|
||||
if (access_process_vm(target,
|
||||
(unsigned long)
|
||||
®_window[pos++],
|
||||
®, sizeof(reg),
|
||||
FOLL_FORCE)
|
||||
!= sizeof(reg))
|
||||
return -EFAULT;
|
||||
if (put_user(reg, u++))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (count > 0) {
|
||||
|
@ -867,6 +946,150 @@ static const struct user_regset sparc32_regsets[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int getregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
u32 uregs[19];
|
||||
int i;
|
||||
|
||||
if (target == current)
|
||||
flushw_user();
|
||||
|
||||
uregs[0] = tstate_to_psr(regs->tstate);
|
||||
uregs[1] = regs->tpc;
|
||||
uregs[2] = regs->tnpc;
|
||||
uregs[3] = regs->y;
|
||||
for (i = 1; i < 16; i++)
|
||||
uregs[3 + i] = regs->u_regs[i];
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
uregs,
|
||||
0, 19 * sizeof(u32));
|
||||
}
|
||||
|
||||
static int setregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
unsigned long tstate;
|
||||
u32 uregs[19];
|
||||
int i, ret;
|
||||
|
||||
if (target == current)
|
||||
flushw_user();
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
uregs,
|
||||
0, 19 * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tstate = regs->tstate;
|
||||
tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
|
||||
tstate |= psr_to_tstate_icc(uregs[0]);
|
||||
if (uregs[0] & PSR_SYSCALL)
|
||||
tstate |= TSTATE_SYSCALL;
|
||||
regs->tstate = tstate;
|
||||
regs->tpc = uregs[1];
|
||||
regs->tnpc = uregs[2];
|
||||
regs->y = uregs[3];
|
||||
|
||||
for (i = 1; i < 15; i++)
|
||||
regs->u_regs[i] = uregs[3 + i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getfpregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const unsigned long *fpregs = task_thread_info(target)->fpregs;
|
||||
unsigned long fprs;
|
||||
compat_ulong_t fsr;
|
||||
int ret = 0;
|
||||
|
||||
if (target == current)
|
||||
save_and_clear_fpu();
|
||||
|
||||
fprs = task_thread_info(target)->fpsaved[0];
|
||||
if (fprs & FPRS_FEF) {
|
||||
fsr = task_thread_info(target)->xfsr[0];
|
||||
} else {
|
||||
fsr = 0;
|
||||
}
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs,
|
||||
0, 32 * sizeof(u32));
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&fsr,
|
||||
32 * sizeof(u32),
|
||||
33 * sizeof(u32));
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
33 * sizeof(u32), 68 * sizeof(u32));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int setfpregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
unsigned long *fpregs = task_thread_info(target)->fpregs;
|
||||
unsigned long fprs;
|
||||
int ret;
|
||||
|
||||
if (target == current)
|
||||
save_and_clear_fpu();
|
||||
|
||||
fprs = task_thread_info(target)->fpsaved[0];
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs,
|
||||
0, 32 * sizeof(u32));
|
||||
if (!ret) {
|
||||
compat_ulong_t fsr;
|
||||
unsigned long val;
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&fsr,
|
||||
32 * sizeof(u32),
|
||||
33 * sizeof(u32));
|
||||
if (!ret) {
|
||||
val = task_thread_info(target)->xfsr[0];
|
||||
val &= 0xffffffff00000000UL;
|
||||
val |= fsr;
|
||||
task_thread_info(target)->xfsr[0] = val;
|
||||
}
|
||||
}
|
||||
|
||||
fprs |= (FPRS_FEF | FPRS_DL);
|
||||
task_thread_info(target)->fpsaved[0] = fprs;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct user_regset ptrace32_regsets[] = {
|
||||
[REGSET_GENERAL] = {
|
||||
.n = 19, .size = sizeof(u32),
|
||||
.get = getregs_get, .set = setregs_set,
|
||||
},
|
||||
[REGSET_FP] = {
|
||||
.n = 68, .size = sizeof(u32),
|
||||
.get = getfpregs_get, .set = setfpregs_set,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct user_regset_view ptrace32_view = {
|
||||
.regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_sparc32_view = {
|
||||
.name = "sparc", .e_machine = EM_SPARC,
|
||||
.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
|
||||
|
@ -898,7 +1121,6 @@ struct compat_fps {
|
|||
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||
compat_ulong_t caddr, compat_ulong_t cdata)
|
||||
{
|
||||
const struct user_regset_view *view = task_user_regset_view(current);
|
||||
compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
|
||||
struct pt_regs32 __user *pregs;
|
||||
struct compat_fps __user *fps;
|
||||
|
@ -916,58 +1138,31 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
|||
break;
|
||||
|
||||
case PTRACE_GETREGS:
|
||||
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u32),
|
||||
4 * sizeof(u32),
|
||||
&pregs->psr);
|
||||
if (!ret)
|
||||
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u32),
|
||||
15 * sizeof(u32),
|
||||
&pregs->u_regs[0]);
|
||||
ret = copy_regset_to_user(child, &ptrace32_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u32),
|
||||
pregs);
|
||||
break;
|
||||
|
||||
case PTRACE_SETREGS:
|
||||
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u32),
|
||||
4 * sizeof(u32),
|
||||
&pregs->psr);
|
||||
if (!ret)
|
||||
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u32),
|
||||
15 * sizeof(u32),
|
||||
&pregs->u_regs[0]);
|
||||
ret = copy_regset_from_user(child, &ptrace32_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u32),
|
||||
pregs);
|
||||
break;
|
||||
|
||||
case PTRACE_GETFPREGS:
|
||||
ret = copy_regset_to_user(child, view, REGSET_FP,
|
||||
0 * sizeof(u32),
|
||||
32 * sizeof(u32),
|
||||
&fps->regs[0]);
|
||||
if (!ret)
|
||||
ret = copy_regset_to_user(child, view, REGSET_FP,
|
||||
33 * sizeof(u32),
|
||||
1 * sizeof(u32),
|
||||
&fps->fsr);
|
||||
if (!ret) {
|
||||
if (__put_user(0, &fps->flags) ||
|
||||
__put_user(0, &fps->extra) ||
|
||||
__put_user(0, &fps->fpqd) ||
|
||||
clear_user(&fps->fpq[0], 32 * sizeof(unsigned int)))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
ret = copy_regset_to_user(child, &ptrace32_view,
|
||||
REGSET_FP, 0,
|
||||
68 * sizeof(u32),
|
||||
fps);
|
||||
break;
|
||||
|
||||
case PTRACE_SETFPREGS:
|
||||
ret = copy_regset_from_user(child, view, REGSET_FP,
|
||||
0 * sizeof(u32),
|
||||
32 * sizeof(u32),
|
||||
&fps->regs[0]);
|
||||
if (!ret)
|
||||
ret = copy_regset_from_user(child, view, REGSET_FP,
|
||||
33 * sizeof(u32),
|
||||
1 * sizeof(u32),
|
||||
&fps->fsr);
|
||||
ret = copy_regset_from_user(child, &ptrace32_view,
|
||||
REGSET_FP, 0,
|
||||
33 * sizeof(u32),
|
||||
fps);
|
||||
break;
|
||||
|
||||
case PTRACE_READTEXT:
|
||||
|
@ -1026,31 +1221,17 @@ long arch_ptrace(struct task_struct *child, long request,
|
|||
break;
|
||||
|
||||
case PTRACE_GETREGS64:
|
||||
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u64),
|
||||
15 * sizeof(u64),
|
||||
&pregs->u_regs[0]);
|
||||
if (!ret) {
|
||||
/* XXX doesn't handle 'y' register correctly XXX */
|
||||
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u64),
|
||||
4 * sizeof(u64),
|
||||
&pregs->tstate);
|
||||
}
|
||||
ret = copy_regset_to_user(child, &ptrace64_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u64),
|
||||
pregs);
|
||||
break;
|
||||
|
||||
case PTRACE_SETREGS64:
|
||||
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
1 * sizeof(u64),
|
||||
15 * sizeof(u64),
|
||||
&pregs->u_regs[0]);
|
||||
if (!ret) {
|
||||
/* XXX doesn't handle 'y' register correctly XXX */
|
||||
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
|
||||
32 * sizeof(u64),
|
||||
4 * sizeof(u64),
|
||||
&pregs->tstate);
|
||||
}
|
||||
ret = copy_regset_from_user(child, &ptrace64_view,
|
||||
REGSET_GENERAL, 0,
|
||||
19 * sizeof(u64),
|
||||
pregs);
|
||||
break;
|
||||
|
||||
case PTRACE_GETFPREGS64:
|
||||
|
|
|
@ -34,7 +34,6 @@ extern int fpu__copy(struct task_struct *dst, struct task_struct *src);
|
|||
extern void fpu__clear_user_states(struct fpu *fpu);
|
||||
extern void fpu__clear_all(struct fpu *fpu);
|
||||
extern int fpu__exception_code(struct fpu *fpu, int trap_nr);
|
||||
extern int dump_fpu(struct pt_regs *ptregs, struct user_i387_struct *fpstate);
|
||||
|
||||
/*
|
||||
* Boot time FPU initialization functions:
|
||||
|
|
|
@ -356,20 +356,4 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* FPU state for core dumps.
|
||||
* This is only used for a.out dumps now.
|
||||
* It is declared generically using elf_fpregset_t (which is
|
||||
* struct user_i387_struct) but is in fact only used for 32-bit
|
||||
* dumps, so on 64-bit it is really struct user_i387_ia32_struct.
|
||||
*/
|
||||
int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
|
||||
return !fpregs_get(tsk, NULL, 0, sizeof(struct user_i387_ia32_struct),
|
||||
ufpu, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(dump_fpu);
|
||||
|
||||
#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
|
||||
|
|
|
@ -170,14 +170,14 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
|
|||
ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||
|
||||
IS_ENABLED(CONFIG_IA32_EMULATION));
|
||||
|
||||
if (!static_cpu_has(X86_FEATURE_FPU)) {
|
||||
struct user_i387_ia32_struct fp;
|
||||
fpregs_soft_get(current, NULL, 0, sizeof(fp), &fp, NULL);
|
||||
return copy_to_user(buf, &fp, sizeof(fp)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
if (!access_ok(buf, size))
|
||||
return -EACCES;
|
||||
|
||||
if (!static_cpu_has(X86_FEATURE_FPU))
|
||||
return fpregs_soft_get(current, NULL, 0,
|
||||
sizeof(struct user_i387_ia32_struct), NULL,
|
||||
(struct _fpstate_32 __user *) buf) ? -1 : 1;
|
||||
|
||||
retry:
|
||||
/*
|
||||
* Load the FPU registers if they are not valid for the current task.
|
||||
|
|
Loading…
Reference in New Issue
Block a user