Skip to content

Commit

Permalink
[POWERPC] ptrace updates & new, better requests
Browse files Browse the repository at this point in the history
The powerpc ptrace interface is dodgy at best. We have defined our
"own" versions of GETREGS/SETREGS/GETFPREGS/SETFPREGS that strangely
take arguments in reverse order from other archs (in addition to having
different request numbers) and have subtle issue, like not accessing
all of the registers in their respective categories.

This patch moves the implementation of those to a separate function
in order to facilitate their deprecation in the future, and provides
new ptrace requests that mirror the x86 and sparc ones and use the
same numbers:

   PTRACE_GETREGS    : returns an entire pt_regs (the whole thing,
                       not only the 32 GPRs, though that doesn't
                       include the FPRs etc... There's a compat version
                       for 32 bits that returns a 32 bits compatible
                       pt_regs (44 uints)

   PTRACE_SETREGS    : sets an entire pt_regs (the whole thing,
                       not only the 32 GPRs, though that doesn't
                       include the FPRs etc... Some registers cannot be
                       written to and will just be dropped, this is the
                       same as with POKEUSR, that is anything above MQ
                       on 32 bits and CCR on 64 bits. There is a compat
                       version as well.

   PTRACE_GETFPREGS  : returns all the FP registers -including- the FPSCR
                       that is 33 doubles (regardless of 32/64 bits)

   PTRACE_SETFPREGS  : sets all the FP registers -including- the FPSCR
                       that is 33 doubles (regardless of 32/64 bits)

And two that only exist on 64 bits kernels:

   PTRACE_GETREGS64  : Same as PTRACE_GETREGS, except there is no compat
                       function, a 32 bits process will obtain the full 64
                       bits registers

   PTRACE_SETREGS64  : Same as PTRACE_SETREGS, except there is no compat
                       function, a 32 bits process will set the full 64
                       bits registers

The two later ones makes things easier to have a 32 bits debugger on a
64 bits program (or on a 32 bits program that uses the full 64 bits of
the GPRs, which is possible though has issues that will be fixed in a
later patch).

Finally, while at it, the patch removes a whole bunch of code duplication
between ptrace32.c and ptrace.c, in large part by having the former call
into the later for all requests that don't need any special "compat"
treatment.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Benjamin Herrenschmidt authored and Paul Mackerras committed Jun 14, 2007
1 parent acd8982 commit e17666b
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 170 deletions.
23 changes: 23 additions & 0 deletions arch/powerpc/kernel/ptrace-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,29 @@ static inline int put_reg(struct task_struct *task, int regno,
}


static inline int get_fpregs(void __user *data,
struct task_struct *task,
int has_fpscr)
{
unsigned int count = has_fpscr ? 33 : 32;

if (copy_to_user(data, task->thread.fpr, count * sizeof(double)))
return -EFAULT;
return 0;
}

static inline int set_fpregs(void __user *data,
struct task_struct *task,
int has_fpscr)
{
unsigned int count = has_fpscr ? 33 : 32;

if (copy_from_user(task->thread.fpr, data, count * sizeof(double)))
return -EFAULT;
return 0;
}


#ifdef CONFIG_ALTIVEC
/*
* Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
Expand Down
148 changes: 99 additions & 49 deletions arch/powerpc/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,62 @@ void ptrace_disable(struct task_struct *child)
clear_single_step(child);
}

/*
* Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
* we mark them as obsolete now, they will be removed in a future version
*/
static long arch_ptrace_old(struct task_struct *child, long request, long addr,
long data)
{
int ret = -EPERM;

switch(request) {
case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
int i;
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
unsigned long __user *tmp = (unsigned long __user *)addr;

for (i = 0; i < 32; i++) {
ret = put_user(*reg, tmp);
if (ret)
break;
reg++;
tmp++;
}
break;
}

case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
int i;
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
unsigned long __user *tmp = (unsigned long __user *)addr;

for (i = 0; i < 32; i++) {
ret = get_user(*reg, tmp);
if (ret)
break;
reg++;
tmp++;
}
break;
}

case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
flush_fp_to_thread(child);
ret = get_fpregs((void __user *)addr, child, 0);
break;
}

case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
flush_fp_to_thread(child);
ret = set_fpregs((void __user *)addr, child, 0);
break;
}

}
return ret;
}

long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int ret = -EPERM;
Expand Down Expand Up @@ -214,71 +270,58 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = ptrace_detach(child, data);
break;

case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
int i;
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
unsigned long __user *tmp = (unsigned long __user *)addr;

for (i = 0; i < 32; i++) {
ret = put_user(*reg, tmp);
if (ret)
break;
reg++;
tmp++;
#ifdef CONFIG_PPC64
case PTRACE_GETREGS64:
#endif
case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
int ui;
if (!access_ok(VERIFY_WRITE, (void __user *)data,
sizeof(struct pt_regs))) {
ret = -EIO;
break;
}
ret = 0;
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
ret |= __put_user(get_reg(child, ui),
(unsigned long __user *) data);
data += sizeof(long);
}
break;
}

case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
int i;
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
unsigned long __user *tmp = (unsigned long __user *)addr;

for (i = 0; i < 32; i++) {
ret = get_user(*reg, tmp);
#ifdef CONFIG_PPC64
case PTRACE_SETREGS64:
#endif
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
unsigned long tmp;
int ui;
if (!access_ok(VERIFY_READ, (void __user *)data,
sizeof(struct pt_regs))) {
ret = -EIO;
break;
}
ret = 0;
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
ret = __get_user(tmp, (unsigned long __user *) data);
if (ret)
break;
reg++;
tmp++;
put_reg(child, ui, tmp);
data += sizeof(long);
}
break;
}

#ifdef CONFIG_PPC64
case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
int i;
unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
unsigned long __user *tmp = (unsigned long __user *)addr;

case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
flush_fp_to_thread(child);

for (i = 0; i < 32; i++) {
ret = put_user(*reg, tmp);
if (ret)
break;
reg++;
tmp++;
}
ret = get_fpregs((void __user *)data, child, 1);
break;
}

case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
int i;
unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
unsigned long __user *tmp = (unsigned long __user *)addr;

case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
flush_fp_to_thread(child);

for (i = 0; i < 32; i++) {
ret = get_user(*reg, tmp);
if (ret)
break;
reg++;
tmp++;
}
ret = set_fpregs((void __user *)data, child, 1);
break;
}
#endif /* CONFIG_PPC64 */

#ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS:
Expand Down Expand Up @@ -311,11 +354,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
#endif

/* Old reverse args ptrace callss */
case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */
ret = arch_ptrace_old(child, request, addr, data);
break;

default:
ret = ptrace_request(child, request, addr, data);
break;
}

return ret;
}

Expand Down
Loading

0 comments on commit e17666b

Please sign in to comment.