Commit 2df556fd authored by Anton Blanchard's avatar Anton Blanchard

ppc64: ptrace cleanup from Stephen Rothwell

parent c1aa8ae8
/*
* linux/arch/ppc/kernel/ptrace.c
* linux/arch/ppc64/kernel/ptrace.c
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
......@@ -30,59 +30,13 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
/*
* Set of msr bits that gdb can change on behalf of a process.
*/
#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
#include <asm/ptrace-common.h>
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/
/*
* Get contents of register REGNO in task TASK.
*/
static inline unsigned long get_reg(struct task_struct *task, int regno)
{
if (regno < sizeof(struct pt_regs) / sizeof(unsigned long))
return ((unsigned long *)task->thread.regs)[regno];
return (0);
}
/*
* Write contents of register REGNO in task TASK.
*/
static inline int put_reg(struct task_struct *task, int regno,
unsigned long data)
{
if (regno < PT_SOFTE) {
if (regno == PT_MSR)
data = (data & MSR_DEBUGCHANGE)
| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
((unsigned long *)task->thread.regs)[regno] = data;
return 0;
}
return -EIO;
}
static inline void
set_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;
if (regs != NULL)
regs->msr |= MSR_SE;
}
static inline void
clear_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;
if (regs != NULL)
regs->msr &= ~MSR_SE;
}
/*
* Called by kernel/ptrace.c when detaching..
*
......@@ -148,16 +102,17 @@ int sys_ptrace(long request, long pid, long addr, long data)
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long index, tmp;
unsigned long index;
unsigned long tmp;
ret = -EIO;
/* convert to index and check */
index = (unsigned long) addr >> 3;
if ((addr & 7) || index > PT_FPSCR)
if ((addr & 7) || (index > PT_FPSCR))
break;
if (index < PT_FPR0) {
tmp = get_reg(child, (int) index);
tmp = get_reg(child, (int)index);
} else {
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
......@@ -171,7 +126,8 @@ int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
ret = 0;
if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
if (access_process_vm(child, addr, &data, sizeof(data), 1)
== sizeof(data))
break;
ret = -EIO;
break;
......@@ -183,7 +139,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
ret = -EIO;
/* convert to index and check */
index = (unsigned long) addr >> 3;
if ((addr & 7) || index > PT_FPSCR)
if ((addr & 7) || (index > PT_FPSCR))
break;
if (index == PT_ORIG_R3)
......@@ -216,11 +172,11 @@ int sys_ptrace(long request, long pid, long addr, long data)
break;
}
/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL: {
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
......@@ -249,56 +205,50 @@ int sys_ptrace(long request, long pid, long addr, long data)
ret = ptrace_detach(child, data);
break;
case PPC_PTRACE_GETREGS:
{ /* Get GPRs 0 - 31. */
case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
u64 tmp;
u64 cntr;
ret = 0;
for (cntr=0; cntr<32 && ret==0; ++cntr)
{
for (cntr=0; cntr<32 && ret==0; ++cntr) {
tmp = ((u64*)child->thread.regs)[cntr];
ret = put_user(tmp, (u64*)(data+cntr));
}
break;
}
case PPC_PTRACE_SETREGS:
{ /* Set GPRs 0 - 31. */
case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
u64 cntr;
ret = 0;
for (cntr=0; cntr<32 && ret==0; ++cntr)
{
ret = put_reg(child, cntr, *(u64*)(data+cntr));
}
break;
}
case PPC_PTRACE_GETFPREGS:
{ /* Get FPRs 0 - 31. */
case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
u64 tmp;
u64 cntr;
ret = -EIO;
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
ret = 0;
for (cntr=0; cntr<32 && ret==0; ++cntr)
{
for (cntr=0; cntr<32 && ret==0; ++cntr) {
tmp = ((u64*)child->thread.fpr)[cntr];
ret = put_user(tmp, (u64*)(data+cntr));
}
break;
}
case PPC_PTRACE_SETFPREGS:
{ /* Get FPRs 0 - 31. */
case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
u64 cntr;
ret = -EIO;
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
for (cntr=0; cntr<32; ++cntr)
{
((u64*)child->thread.fpr)[cntr] = *(u64*)(data+cntr);
}
ret = 0;
break;
}
......@@ -334,4 +284,3 @@ void do_syscall_trace(void)
current->exit_code = 0;
}
}
/*
* linux/arch/ppc/kernel/ptrace32.c
* linux/arch/ppc64/kernel/ptrace32.c
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
......@@ -30,64 +30,18 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
/*
* Set of msr bits that gdb can change on behalf of a process.
*/
#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
#include <asm/ptrace-common.h>
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/
/*
* Get contents of register REGNO in task TASK.
*/
static inline unsigned long get_reg(struct task_struct *task, int regno)
{
if (regno < sizeof(struct pt_regs) / sizeof(unsigned long))
return ((unsigned long *)task->thread.regs)[regno];
return (0);
}
/*
* Write contents of register REGNO in task TASK.
* (Put DATA into task TASK's register REGNO.)
*/
static inline int put_reg(struct task_struct *task, int regno, unsigned long data)
{
if (regno < PT_SOFTE)
{
if (regno == PT_MSR)
data = (data & MSR_DEBUGCHANGE) | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
((unsigned long *)task->thread.regs)[regno] = data;
return 0;
}
return -EIO;
}
static inline void
set_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;
if (regs != NULL)
regs->msr |= MSR_SE;
}
static inline void
clear_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;
if (regs != NULL)
regs->msr &= ~MSR_SE;
}
int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
{
struct task_struct *child;
int ret = -EPERM;
int ret = -EPERM;
lock_kernel();
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
......@@ -120,92 +74,95 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
if (ret < 0)
goto out_tsk;
switch (request)
{
/* Read word at location ADDR */
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA:
{
unsigned int tmp_mem_value;
case PTRACE_PEEKDATA: {
unsigned int tmp;
int copied;
copied = access_process_vm(child, addr, &tmp_mem_value, sizeof(tmp_mem_value), 0);
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
ret = -EIO;
if (copied != sizeof(tmp_mem_value))
if (copied != sizeof(tmp))
break;
ret = put_user(tmp_mem_value, (u32*)data); // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data".
ret = put_user(tmp, (u32*)data);
break;
}
/* Read 4 bytes of the other process' storage */
/* data is a pointer specifying where the user wants the 4 bytes copied into */
/* addr is a pointer in the user's storage that contains an 8 byte address in the other process of the 4 bytes that is to be read */
/* (this is run in a 32-bit process looking at a 64-bit process) */
/* when I and D space are separate, these will need to be fixed. */
/*
* Read 4 bytes of the other process' storage
* data is a pointer specifying where the user wants the
* 4 bytes copied into
* addr is a pointer in the user's storage that contains an 8 byte
* address in the other process of the 4 bytes that is to be read
* (this is run in a 32-bit process looking at a 64-bit process)
* when I and D space are separate, these will need to be fixed.
*/
case PPC_PTRACE_PEEKTEXT_3264:
case PPC_PTRACE_PEEKDATA_3264:
{
u32 tmp_mem_value;
int copied;
case PPC_PTRACE_PEEKDATA_3264: {
u32 tmp;
int copied;
u32* addrOthers;
ret = -EIO;
/* Get the addr in the other process that we want to read */
if (get_user(addrOthers,(u32**)addr) != 0)
if (get_user(addrOthers, (u32**)addr) != 0)
break;
copied = access_process_vm(child, (u64)addrOthers, &tmp_mem_value, sizeof(tmp_mem_value), 0);
if (copied != sizeof(tmp_mem_value))
copied = access_process_vm(child, (u64)addrOthers, &tmp,
sizeof(tmp), 0);
if (copied != sizeof(tmp))
break;
ret = put_user(tmp_mem_value, (u32*)data); // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data".
ret = put_user(tmp, (u32*)data);
break;
}
/* Read a register (specified by ADDR) out of the "user area" */
case PTRACE_PEEKUSR: {
int index;
unsigned int reg32bits;
unsigned long tmp_reg_value;
unsigned long tmp;
ret = -EIO;
/* convert to index and check */
index = (unsigned long) addr >> 2;
if ((addr & 3) || index > PT_FPSCR32)
if ((addr & 3) || (index > PT_FPSCR32))
break;
if (index < PT_FPR0) {
tmp_reg_value = get_reg(child, index);
tmp = get_reg(child, index);
} else {
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
/* the user space code considers the floating point to be
* an array of unsigned int (32 bits) - the index passed
* in is based on this assumption.
/*
* the user space code considers the floating point
* to be an array of unsigned int (32 bits) - the
* index passed in is based on this assumption.
*/
tmp_reg_value = ((unsigned int *)child->thread.fpr)[index - PT_FPR0];
tmp = ((unsigned int *)child->thread.fpr)[index - PT_FPR0];
}
reg32bits = tmp_reg_value;
ret = put_user(reg32bits, (u32*)data); // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data".
ret = put_user((unsigned int)tmp, (u32*)data);
break;
}
/* Read 4 bytes out of the other process' pt_regs area */
/* data is a pointer specifying where the user wants the 4 bytes copied into */
/* addr is the offset into the other process' pt_regs structure that is to be read */
/* (this is run in a 32-bit process looking at a 64-bit process) */
case PPC_PTRACE_PEEKUSR_3264:
{
/*
* Read 4 bytes out of the other process' pt_regs area
* data is a pointer specifying where the user wants the
* 4 bytes copied into
* addr is the offset into the other process' pt_regs structure
* that is to be read
* (this is run in a 32-bit process looking at a 64-bit process)
*/
case PPC_PTRACE_PEEKUSR_3264: {
u32 index;
u32 reg32bits;
u64 tmp_reg_value;
u64 tmp;
u32 numReg;
u32 part;
ret = -EIO;
/* Determine which register the user wants */
index = (u64)addr >> 2; /* Divide addr by 4 */
index = (u64)addr >> 2;
numReg = index / 2;
/* Determine which part of the register the user wants */
if (index % 2)
......@@ -217,117 +174,115 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
if ((addr & 3) || numReg > PT_FPSCR)
break;
if (numReg >= PT_FPR0)
{
if (numReg >= PT_FPR0) {
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
}
tmp_reg_value = get_reg(child, numReg);
reg32bits = ((u32*)&tmp_reg_value)[part];
ret = put_user(reg32bits, (u32*)data); /* copy 4 bytes of data into the user location specified by the 8 byte pointer in "data". */
tmp = get_reg(child, numReg);
reg32bits = ((u32*)&tmp)[part];
ret = put_user(reg32bits, (u32*)data);
break;
}
/* Write the word at location ADDR */
/* If I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA: {
unsigned int tmp_value_to_write;
tmp_value_to_write = data;
unsigned int tmp;
tmp = data;
ret = 0;
if (access_process_vm(child, addr, &tmp_value_to_write, sizeof(tmp_value_to_write), 1) == sizeof(tmp_value_to_write))
if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1)
== sizeof(tmp))
break;
ret = -EIO;
break;
}
/* Write 4 bytes into the other process' storage */
/* data is the 4 bytes that the user wants written */
/* addr is a pointer in the user's storage that contains an 8 byte address in the other process where the 4 bytes that is to be written */
/* (this is run in a 32-bit process looking at a 64-bit process) */
/* when I and D space are separate, these will need to be fixed. */
/*
* Write 4 bytes into the other process' storage
* data is the 4 bytes that the user wants written
* addr is a pointer in the user's storage that contains an
* 8 byte address in the other process where the 4 bytes
* that is to be written
* (this is run in a 32-bit process looking at a 64-bit process)
* when I and D space are separate, these will need to be fixed.
*/
case PPC_PTRACE_POKETEXT_3264:
case PPC_PTRACE_POKEDATA_3264:
{
u32 tmp_value_to_write = data;
case PPC_PTRACE_POKEDATA_3264: {
u32 tmp = data;
u32* addrOthers;
int bytesWritten;
/* Get the addr in the other process that we want to write into */
ret = -EIO;
if (get_user(addrOthers,(u32**)addr) != 0)
if (get_user(addrOthers, (u32**)addr) != 0)
break;
ret = 0;
bytesWritten = access_process_vm(child, (u64)addrOthers, &tmp_value_to_write, sizeof(tmp_value_to_write), 1);
if (bytesWritten == sizeof(tmp_value_to_write))
if (access_process_vm(child, (u64)addrOthers, &tmp,
sizeof(tmp), 1) == sizeof(tmp))
break;
ret = -EIO;
break;
}
/* Write DATA into location ADDR within the USER area */
/* write the word at location addr in the USER area */
case PTRACE_POKEUSR: {
unsigned long index;
ret = -EIO;
/* convert to index and check */
index = (unsigned long) addr >> 2;
if ((addr & 3) || index > PT_FPSCR32)
if ((addr & 3) || (index > PT_FPSCR32))
break;
if (index == PT_ORIG_R3)
break;
if (index < PT_FPR0) {
ret = put_reg(child, index, data);
} else {
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
/* the user space code considers the floating point to be
* an array of unsigned int (32 bits) - the index passed
* in is based on this assumption.
*/
/*
* the user space code considers the floating point
* to be an array of unsigned int (32 bits) - the
* index passed in is based on this assumption.
*/
((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data;
ret = 0;
}
break;
}
/* Write 4 bytes into the other process' pt_regs area */
/* data is the 4 bytes that the user wants written */
/* addr is the offset into the other process' pt_regs structure that is to be written into */
/* (this is run in a 32-bit process looking at a 64-bit process) */
case PPC_PTRACE_POKEUSR_3264:
{
/*
* Write 4 bytes into the other process' pt_regs area
* data is the 4 bytes that the user wants written
* addr is the offset into the other process' pt_regs structure
* that is to be written into
* (this is run in a 32-bit process looking at a 64-bit process)
*/
case PPC_PTRACE_POKEUSR_3264: {
u32 index;
u32 numReg;
ret = -EIO;
/* Determine which register the user wants */
index = (u64)addr >> 2; /* Divide addr by 4 */
index = (u64)addr >> 2;
numReg = index / 2;
/* 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)
/*
* 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))
break;
/* Insure it is a register we let them change */
if ((numReg == PT_ORIG_R3) || ((numReg > PT_CCR) && (numReg < PT_FPR0)))
if ((numReg == PT_ORIG_R3)
|| ((numReg > PT_CCR) && (numReg < PT_FPR0)))
break;
if (numReg >= PT_FPR0)
{
if (numReg >= PT_FPR0) {
if (child->thread.regs->msr & MSR_FP)
giveup_fpu(child);
}
if (numReg == PT_MSR)
data = (data & MSR_DEBUGCHANGE) | (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
data = (data & MSR_DEBUGCHANGE)
| (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
((u32*)child->thread.regs)[index] = data;
ret = 0;
break;
......@@ -351,8 +306,8 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
}
/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL: {
......
/*
* linux/arch/ppc64/kernel/ptrace-common.h
*
* Copyright (c) 2002 Stephen Rothwell, IBM Coproration
* Extracted from ptrace.c and ptrace32.c
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file README.legal in the main directory of
* this archive for more details.
*/
/*
* Set of msr bits that gdb can change on behalf of a process.
*/
#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
/*
* Get contents of register REGNO in task TASK.
*/
static inline unsigned long get_reg(struct task_struct *task, int regno)
{
if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
return ((unsigned long *)task->thread.regs)[regno];
return 0;
}
/*
* Write contents of register REGNO in task TASK.
*/
static inline int put_reg(struct task_struct *task, int regno,
unsigned long data)
{
if (regno < PT_SOFTE) {
if (regno == PT_MSR)
data = (data & MSR_DEBUGCHANGE)
| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
((unsigned long *)task->thread.regs)[regno] = data;
return 0;
}
return -EIO;
}
static inline void set_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;
if (regs != NULL)
regs->msr |= MSR_SE;
}
static inline void clear_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;
if (regs != NULL)
regs->msr &= ~MSR_SE;
}
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