Commit 912000e7 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[POWERPC] Allow ptrace write to pt_regs trap and orig_r3

This patch allows a ptracer to write to the "trap" and "orig_r3" words
of the pt_regs.

This, along with a subsequent patch to the signal restart code, should
enable gdb to properly handle syscall restarting after executing a separate
function (at least when there's no restart block).

This patch also removes ptrace32.c code toying directly with the registers
and makes it use the ptrace_get/put_reg() accessors for everything so that
the logic for checking what is permitted is in only one place.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 1b6610d6
...@@ -75,10 +75,15 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) ...@@ -75,10 +75,15 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
if (task->thread.regs == NULL) if (task->thread.regs == NULL)
return -EIO; return -EIO;
if (regno <= PT_MAX_PUT_REG) { if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
if (regno == PT_MSR) if (regno == PT_MSR)
data = (data & MSR_DEBUGCHANGE) data = (data & MSR_DEBUGCHANGE)
| (task->thread.regs->msr & ~MSR_DEBUGCHANGE); | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
/* We prevent mucking around with the reserved area of trap
* which are used internally by the kernel
*/
if (regno == PT_TRAP)
data &= 0xfff0;
((unsigned long *)task->thread.regs)[regno] = data; ((unsigned long *)task->thread.regs)[regno] = data;
return 0; return 0;
} }
...@@ -409,8 +414,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ...@@ -409,8 +414,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break; break;
CHECK_FULL_REGS(child->thread.regs); CHECK_FULL_REGS(child->thread.regs);
if (index == PT_ORIG_R3)
break;
if (index < PT_FPR0) { if (index < PT_FPR0) {
ret = ptrace_put_reg(child, index, data); ret = ptrace_put_reg(child, index, data);
} else { } else {
......
...@@ -206,7 +206,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, ...@@ -206,7 +206,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
else else
part = 0; /* want the 1st half of the register (left-most). */ part = 0; /* want the 1st half of the register (left-most). */
/* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */ /* Validate the input - check to see if address is on the wrong boundary
* or beyond the end of the user area
*/
if ((addr & 3) || numReg > PT_FPSCR) if ((addr & 3) || numReg > PT_FPSCR)
break; break;
...@@ -270,8 +272,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, ...@@ -270,8 +272,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
if ((addr & 3) || (index > PT_FPSCR32)) if ((addr & 3) || (index > PT_FPSCR32))
break; break;
if (index == PT_ORIG_R3)
break;
if (index < PT_FPR0) { if (index < PT_FPR0) {
ret = ptrace_put_reg(child, index, data); ret = ptrace_put_reg(child, index, data);
} else { } else {
...@@ -302,24 +302,25 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, ...@@ -302,24 +302,25 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
/* Determine which register the user wants */ /* Determine which register the user wants */
index = (u64)addr >> 2; index = (u64)addr >> 2;
numReg = index / 2; numReg = index / 2;
/* /*
* Validate the input - check to see if address is on the * Validate the input - check to see if address is on the
* wrong boundary or beyond the end of the user area * wrong boundary or beyond the end of the user area
*/ */
if ((addr & 3) || (numReg > PT_FPSCR)) if ((addr & 3) || (numReg > PT_FPSCR))
break; break;
/* Insure it is a register we let them change */ if (numReg < PT_FPR0) {
if ((numReg == PT_ORIG_R3) unsigned long freg = ptrace_get_reg(child, numReg);
|| ((numReg > PT_CCR) && (numReg < PT_FPR0))) if (index % 2)
break; freg = (freg & ~0xfffffffful) | (data & 0xfffffffful);
if (numReg >= PT_FPR0) { else
freg = (freg & 0xfffffffful) | (data << 32);
ret = ptrace_put_reg(child, numReg, freg);
} else {
flush_fp_to_thread(child); flush_fp_to_thread(child);
} ((unsigned int *)child->thread.regs)[index] = data;
if (numReg == PT_MSR)
data = (data & MSR_DEBUGCHANGE)
| (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
((u32*)child->thread.regs)[index] = data;
ret = 0; ret = 0;
}
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment