From 4c35bf3ae948d6232f3d2c6fbf2008c341490683 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 6 Jun 2020 17:55:02 -0400 Subject: [ia64] sanitize elf_access_gpreg() The function takes the register number, finds the corresponding field of pt_regs for registers that are saved there or does the unwind for the registers that end up spilled on the kernel stack. Then it reads from or writes to the resulting location. Unfortunately, finding the required pt_regs field is done by rather horrible switch. It's microoptimized in all the wrong places - it even uses the knowledge that fields for r8..r11 follow each other in pt_regs layout, while r12..r13 are not adjacent to those, etc. All of that is to encode the mapping from register numbers to offsets + the information that r4..r7 are not to be found in pt_regs. It's deeply in nasal demon territory, at that - the games it plays with pointer arithmetics on addresses of structure members are undefined behaviour. Valid C ends up with better code in this case: just initialize a constant array with offsets of relevant pt_regs fields and we don't need that switch anymore. Signed-off-by: Al Viro --- arch/ia64/kernel/ptrace.c | 57 +++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 34 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 82aaacf64583..b9d068903b98 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1273,52 +1273,41 @@ struct regset_getset { int ret; }; +static const ptrdiff_t pt_offsets[16] = +{ +#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), +#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 -- cgit v1.2.3 From e2115cf3cc57fc4b3f6b0ea4f746e5ab6dc9c2c0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 6 Jun 2020 17:55:02 -0400 Subject: [ia64] teach elf_access_reg() to handle the missing range (r16..r31) Now it's easy to make elf_access_gpreg() handle the rest of global registers (r16..r31). That gets rid of the hole in the registers elf_access_reg() can handle, which will allow to simplify its callers later in the series. Signed-off-by: Al Viro --- arch/ia64/kernel/ptrace.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index b9d068903b98..37b5140d0dfe 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1273,12 +1273,14 @@ struct regset_getset { int ret; }; -static const ptrdiff_t pt_offsets[16] = +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 }; @@ -1479,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); -- cgit v1.2.3 From a79ca8e7b9d56c762c3cd53465fde62f8ca41acf Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 6 Jun 2020 18:00:56 -0400 Subject: [ia64] regularize do_gpregs_[gs]et() now access_elf_reg() does the right thing for everything other than r0, we can simplify do_grepgs_[gs]et() Signed-off-by: Al Viro --- arch/ia64/kernel/ptrace.c | 155 ++++++++++------------------------------------ 1 file changed, 31 insertions(+), 124 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 37b5140d0dfe..be635f6f93c9 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1491,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; @@ -1517,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) - 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) { - 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) - 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) + if (dst->ret) 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) { + 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_NAT_OFFSET, ELF_CR_IIP_OFFSET); - if (dst->ret || dst->count == 0) + dst->pos, to); + if (dst->ret) 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; } - /* 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); - 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); - 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; - } + while (dst->count && dst->pos < ELF_AR_END_OFFSET) { + unsigned int n, from, to; + elf_greg_t tmp[16]; - /* 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); + 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_CR_IIP_OFFSET, ELF_AR_END_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) { + /* 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; } -- cgit v1.2.3 From 6bc4f16c6c9bed6ce5c3ab77b95397c8c88bdb66 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 6 Jun 2020 18:46:45 -0400 Subject: [ia64] access_uarea(): stop bothering with gpregs_[gs]et() We know this won't be called for child == current, so we don't need to bother with callbacks, etc. - just do unw_init_from_blocked_task(), unw_unwind_to_user() and do the payload of gpregs_[gs]et(). For one register. Which is to say, access_elf_reg(). Signed-off-by: Al Viro --- arch/ia64/kernel/ptrace.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index be635f6f93c9..e0813c8e4b47 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1936,15 +1936,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 */ -- cgit v1.2.3 From e3fdfa37a3fabea38b01af05893050136a6cd136 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 6 Jun 2020 20:22:32 -0400 Subject: [ia64] access_uarea(): don't bother with fpregs_[gs]et() similar to previous commit... Signed-off-by: Al Viro --- arch/ia64/kernel/ptrace.c | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index e0813c8e4b47..eae7b094f608 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1811,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) { @@ -1843,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; } -- cgit v1.2.3 From 4ff8a356daafaafbf90141ee7a3b8fdc18e560a8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2020 11:20:51 -0400 Subject: ia64: switch to ->regset_get() Signed-off-by: Al Viro --- arch/ia64/kernel/ptrace.c | 149 ++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 91 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index eae7b094f608..33ca9fa0fbf5 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1489,9 +1489,17 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info, return access_elf_areg(target, info, addr, data, write_access); } +struct regset_membuf { + struct membuf to; + int ret; +}; + void do_gpregs_get(struct unw_frame_info *info, void *arg) { - struct regset_getset *dst = arg; + struct regset_membuf *dst = arg; + struct membuf to = dst->to; + unsigned int n; + elf_greg_t reg; if (unw_unwind_to_user(info) < 0) return; @@ -1509,35 +1517,13 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg) /* Skip r0 */ - if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { - dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count, - &dst->u.get.kbuf, - &dst->u.get.ubuf, - 0, ELF_GR_OFFSET(1)); - if (dst->ret) + membuf_zero(&to, 8); + for (n = 8; to.left && n < ELF_AR_END_OFFSET; n += 8) { + if (access_elf_reg(info->task, info, n, ®, 0) < 0) { + dst->ret = -EIO; return; - } - - 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, - dst->pos, to); - if (dst->ret) - return; + membuf_store(&to, reg); } } @@ -1588,60 +1574,36 @@ void do_gpregs_set(struct unw_frame_info *info, void *arg) void do_fpregs_get(struct unw_frame_info *info, void *arg) { - struct regset_getset *dst = arg; - struct task_struct *task = dst->target; - elf_fpreg_t tmp[30]; - int index, min_copy, i; + struct task_struct *task = info->task; + struct regset_membuf *dst = arg; + struct membuf to = dst->to; + elf_fpreg_t reg; + unsigned int n; if (unw_unwind_to_user(info) < 0) return; /* Skip pos 0 and 1 */ - if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) { - dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count, - &dst->u.get.kbuf, - &dst->u.get.ubuf, - 0, ELF_FP_OFFSET(2)); - if (dst->count == 0 || dst->ret) - return; - } + membuf_zero(&to, 2 * sizeof(elf_fpreg_t)); /* fr2-fr31 */ - if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) { - index = (dst->pos - ELF_FP_OFFSET(2)) / sizeof(elf_fpreg_t); - - min_copy = min(((unsigned int)ELF_FP_OFFSET(32)), - dst->pos + dst->count); - for (i = dst->pos; i < min_copy; i += sizeof(elf_fpreg_t), - index++) - if (unw_get_fr(info, i / sizeof(elf_fpreg_t), - &tmp[index])) { - dst->ret = -EIO; - return; - } - dst->ret = user_regset_copyout(&dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, - ELF_FP_OFFSET(2), ELF_FP_OFFSET(32)); - if (dst->count == 0 || dst->ret) + for (n = 2; to.left && n < 32; n++) { + if (unw_get_fr(info, n, ®)) { + dst->ret = -EIO; return; + } + membuf_write(&to, ®, sizeof(reg)); } /* fph */ - if (dst->count > 0) { - ia64_flush_fph(dst->target); - if (task->thread.flags & IA64_THREAD_FPH_VALID) - dst->ret = user_regset_copyout( - &dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, - &dst->target->thread.fph, - ELF_FP_OFFSET(32), -1); - else - /* Zero fill instead. */ - dst->ret = user_regset_copyout_zero( - &dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, - ELF_FP_OFFSET(32), -1); - } + if (!to.left) + return; + + ia64_flush_fph(task); + if (task->thread.flags & IA64_THREAD_FPH_VALID) + membuf_write(&to, &task->thread.fph, 96 * sizeof(reg)); + else + membuf_zero(&to, 96 * sizeof(reg)); } void do_fpregs_set(struct unw_frame_info *info, void *arg) @@ -1717,6 +1679,20 @@ void do_fpregs_set(struct unw_frame_info *info, void *arg) } } +static void +unwind_and_call(void (*call)(struct unw_frame_info *, void *), + struct task_struct *target, void *data) +{ + if (target == current) + unw_init_running(call, data); + else { + struct unw_frame_info info; + memset(&info, 0, sizeof(info)); + unw_init_from_blocked_task(&info, target); + (*call)(&info, data); + } +} + static int do_regset_call(void (*call)(struct unw_frame_info *, void *), struct task_struct *target, @@ -1728,27 +1704,18 @@ do_regset_call(void (*call)(struct unw_frame_info *, void *), .pos = pos, .count = count, .u.set = { .kbuf = kbuf, .ubuf = ubuf }, .ret = 0 }; - - if (target == current) - unw_init_running(call, &info); - else { - struct unw_frame_info ufi; - memset(&ufi, 0, sizeof(ufi)); - unw_init_from_blocked_task(&ufi, target); - (*call)(&ufi, &info); - } - + unwind_and_call(call, target, &info); return info.ret; } static int gpregs_get(struct task_struct *target, const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) + struct membuf to) { - return do_regset_call(do_gpregs_get, target, regset, pos, count, - kbuf, ubuf); + struct regset_membuf info = {.to = to}; + unwind_and_call(do_gpregs_get, target, &info); + return info.ret; } static int gpregs_set(struct task_struct *target, @@ -1790,11 +1757,11 @@ fpregs_active(struct task_struct *target, const struct user_regset *regset) static int fpregs_get(struct task_struct *target, const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) + struct membuf to) { - return do_regset_call(do_fpregs_get, target, regset, pos, count, - kbuf, ubuf); + struct regset_membuf info = {.to = to}; + unwind_and_call(do_fpregs_get, target, &info); + return info.ret; } static int fpregs_set(struct task_struct *target, @@ -2033,14 +2000,14 @@ static const struct user_regset native_regsets[] = { .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, .size = sizeof(elf_greg_t), .align = sizeof(elf_greg_t), - .get = gpregs_get, .set = gpregs_set, + .regset_get = gpregs_get, .set = gpregs_set, .writeback = gpregs_writeback }, { .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, .size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t), - .get = fpregs_get, .set = fpregs_set, .active = fpregs_active + .regset_get = fpregs_get, .set = fpregs_set, .active = fpregs_active }, }; -- cgit v1.2.3